Access Desktop Data from Mobile Devices
Java ME has made it possible to write platform-independent applications for mobile devices and deploy them fairly easily. Now that we have a number of computing platforms strewn all over--office, home, and pocket--we need to think of interconnecting them. As far as desktop devices are concerned, wired internet has provided the necessary linkage for quite some time now. With the advent of GPRS, it has now become fairly easy to access data residing on desktops through mobile devices.
In this article we look at an application called Access that enables a MIDP-2.0-compatible mobile phone to locate an entry in a phone directory on a desktop PC and to call that number. The application also implements a rudimentary password-based authentication scheme that will not be dealt with in detail here.
In order to run this application you will need a PC that can be accessed from the internet. You may need to talk to your ISP to make sure you can do this.
You also need to have a servlet container running on the PC. I have used Apache Tomcat as the servlet container for implementing this project. Downloading Tomcat and installing in your computer is fairly simple; a good tutorial is Marty Hall's " Configuring and Using Apache Tomcat." The root directory for this project is AccessServlet in the C:\j2sdk1.4.2_05 directory. The web.xml file and the entry for <Tomcat root>/conf/server.xml are available as a .zip in the Resources section. For my computer, <Tomcat root> is C:\jakarta-tomcat-4.1.31. Note that I have not changed the operating port to 80.
The application was developed on WTK 2.2. As noted in the concluding paragraph, the application can also be tested on the toolkit's emulator (except for call initiation). If you are testing the application on the same PC that hosts the server, you may do without an internet connection provided you use 127.0.0.1 as the server URL. This is the URL in the source code provided here. If, on the other hand, you want to try it out from a mobile device, the server address will have to be changed accordingly.
I assume that the reader is familiar with basic Java programming, including Swing and servlets. Familiarity with J2ME is also assumed.
The Mobile Client
The mobile client comprises the following elements:
- The
AccessMIDlet, which serves primarily as the entry point. - A set of user interfaces (UIs or screens).
CommandProcessor: This class has a method corresponding to every user interaction and completion of each system activity.DisplayController: This class sets up screens and alerts to be displayed.RecordStoreHandler: This class takes care of reading from and writing to persistent storage.- Communication controllers that extend
HttpGetCommController: These classes communicate with the servlet in the desktop.
Access kicks off the application by calling the
selectLoginMode method in
CommandProcessor. This method then calls
accessRecordExists in RecordStoreHandler
to check if the username and password have been already saved in
the device. If login information exists, the user is prompted to
select a login mode, auto or manual (see Figure 1). Otherwise, only
the manual login screen is displayed.

Figure 1. Selecting login mode
In the case of manual login, the user is asked whether she would like to save the information (as seen in Figure 2).

Figure 2. Prompt for saving login information
The screen shown in Figure 2 is not a standard J2ME
TextBox, nor is it a Form with a
StringItem. This is a customized "window"-like display
created by the MessageCanvas class. The message canvas
is fairly flexible in the sense that it adjusts its dimensions
according to the size of available display area. It is capable of
displaying single- or multi-line strings. It uses its companion
class TextFormatter to break long strings up into an
array of smaller ones. MessageCanvas does have a
couple of weaknesses, though: it cannot understand formatting
instructions like newline and does not support scrolling.
It is important to note that the actual logging in does not take
place at the end of the auto or manual login action. At this point,
the username and password are combined into a single
semicolon-separated string, Base64 encoded, and saved as the
upw field in CommandProcessor.
Once the login information has been made available, the user is shown the screen for selecting a function; he can choose to access the phonebook or change the password. We will walk through the sequence of events that take place if the user selects the "Access phonebook" function. The sequence of screens for this operation (assuming no errors are encountered) can be found in the Resources section.
The mobile client communicates with the server (the desktop,
that is) over an HTTP connection. The communicating classes extend
the abstract HttpGetCommController class, which
provides the basic framework for opening a connection and receiving
a response from a GET method. For getting information
from the phonebook, the client uses the ReadClientH
class. Forming the URL and processing the response as
well as any other customization has to be taken care of by the
subclasses. Since the GET method is being accessed,
the URL incorporates not only the information required
for getting to the servlet but also the required parameters. The
syntax for the parameter is:
command+*+upw+*+commandinfo
where:
commandcan be eitherreadorchangeupwcommandinfocan be eithertargetornewupw
When accessing the phone book, a name has to be specified, and
this is the target. Similarly, when changing the password,
the existing username is combined with the new password to form
newupw. The asterisk is chosen as the separator because it
is one of the few special characters that are allowed to be a part
of a URL.
The actions that take place in the desktop when it receives a
request are described in the next section. However, let us first look
at what happens when the desktop returns information to the client.
Once the response is received, it is checked by
ReadClientH to see if starts with "tel:". If it does
not, then the response contains an error message and is displayed
in a message canvas with an option to try again. If the response
does begin with "tel:", then it is the desired response and is
passed on to InputPage (via
CommandProcessor, of course) for presentation to the
user:
protected void processReply(String reply)
{
if(reply.startsWith("tel:"))
{
//show textfield with phone number and call command
cp.showInfo(reply);
}
else
{
//error info
cp.showNote(reply);
}
}
InputPage parses the response string to separate it
out into its two constituents: the name and the
number. These are then displayed within separate text
fields. A third string--callmessage--is also created
here. One of the commands on InputPage is Call,
which allows the user to initiate a call to the number retrieved
from the phonebook. If Call is selected, then the method
makeCall in CommandProcessor is invoked
with callmessage as the parameter. MIDP 2.0 allows call
initiation through the platformRequest method in the
MIDlet class. Accordingly, the call request is routed
to the setUpCall method in Access. In
case there is a communication error and the response received at
InputPage is not properly formatted, an error message
is displayed. Otherwise the number is called:
protected void setUpCall(String callnumber)
{
//call the number found from the directory
try
{
platformRequest(callnumber);
}
catch(ConnectionNotFoundException cnfe)
{
cp.showConnectAlert(cnfe.getMessage());
}
}
The other function that the user may select is "Edit password." The screens that are displayed during "Edit password" function are available in the Resources section. These screens also show the result of an error, namely entering the wrong password entry for editing.
Once the network activities for the functions are over the user gets a chance to re-run the application, regardless of whether the outcome was successful or not.
The Servlet and Associated Classes
The servlet has only a doGet method, in addition to
the usual init.
The first time the mobile client opens a connection to Tomcat
after it is started, AccessServlet is instantiated and
the init method is executed. Thereafter, for all calls
to AccessServlet, the same instance is reused. When
AccessServlet is instantiated, it checks to see if the
file containing user information (password.pwd) exists. If
not, then it creates one (with a username of "guest" and a password of
"allow") by calling the static method createAccount in
the SetUpAccount class. This is just to provide ease
of use. SetUpAccount can also be called from
the command line with the desired username and password as
arguments. Note that SetUpAccount does not create
multiple accounts, but simply overwrites any existing account
information. This form of user information is used only as an
example. More secure forms will be required for a general-purpose
application. If an application like this is created for a
multi-user environment, then at least three modifications are
required:
- Creating a database for user information. This will also mean a different approach to password editing.
- Making the servlet thread-safe. Of course, this may not be considered critical, as access to the directory is essentially read-only.
- Changing the interfaces for directory access.
The structure of the directory also merits a few comments. The
example shown here is designed for simplicity. It stores
name-number entries as strings separated by a ; character. The name and the
number in each entry are joined by a - character and the name
itself is entered without any spaces so that it can be integrated
into the URL for HTTP connection. The first letter of
each part of the name (first name, middle name or initial if any,
and last name) is capitalized. The phone number also needs to be
entered without intervening spaces. A directory with two entries
could look like this:
JaneDoe-1112222;JohnBSmith-3334444
One consequence of this format and the way the a specific entry
is searched for is that partial matches are accepted. So a
target entered as "J" would be located in the above
directory as the entry for JaneDoe.
The doGet method in AccessServlet
parses the incoming parameter to extract and check the command. If
the command is read, the user information (upw) and the
target entry are then extracted and the open method in
the GetInfo class is called with upw and
target as parameters. However, upw has to be decoded
before open is called.
The actual work of exploring the file structure is performed by
open. Here we create the two objects that are required
for this: a FileChooser object to select both files
and directories, and a FileSystemView object:
public String open(String upw, String target) throws IOException
{
File f, f1;
JFileChooser fc;
FileSystemView fsv;
f = new File("C:\\Access");
fc = new JFileChooser(f);
fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fsv = fc.getFileSystemView();
.
.
.
}
The FileSystemView object (fc) can now be used to
see inside File f. The getFiles method of
FileSystemView returns an array of (non-hidden)
File objects for us to examine and act upon. For example,
we may choose to list out the contents of the array. The user may
then select a folder from this list for further exploration. The
application can then call the getFiles method on the
selected folder to get its contents. Performing this function
repeatedly will allow us to explore the entire file structure.
However, for the present application we are not interested in folders, which is why we do nothing when we encounter a folder. If, on the other hand, we find a file, we check if it is the one we want:
//find number of objects in "Access"
int j = fsv.getFiles(f, true).length;
for(int i=0;i<j;i++)
{
f1 = fsv.getFiles(f, true)[i];
//if the item is a folder
if(f1.isDirectory())
{
// we can unravel the directory structure here
//but right now we do nothing
}
//otherwise it is a file
else
{
//if f1.toString().equals("C:\\Access\\Directory.txt")
//then get the wanted information and return
if(f1.toString().equals("C:\\Access\\Directory.txt"))
{
DataHandler datahandler = new DataHandler();
//check upw
if(datahandler.authenticate(upw))
{
//locate entry by target
try
{
return datahandler.getNumber(f1, target);
}
catch(Exception e)
{
return "Error in accessing information";
}
}
else
{
return "Authentication failure";
}
}
}
}
Once the Directory file is found, the
getNumber method in DataHandler class is
called to locate the desired entry and return the phone number.
Well known methods of the String class are used to find
the target and the entire entry is extracted. The resulting string
is then passed to the parseEntry method, which gets the
number and carries out some simple checks to see whether we have
something that seems to be a phone number. It then creates and
returns the string that has to be sent to the client. This string
is returned to the open method, which, in turn, returns
it to doGet in AccessServlet, where it is
transmitted to the client.
So the calling sequence for methods mentioned above is:
doGet (in AccessServlet) -> open (in GetInfo) -> getNumber (in DataHandler)
Similarly, the retrieved information flows back to the client like this:
getNumber -> open -> doGet -> client
Many of you would be wondering at this point why
FileChooser has been used here. Since we know the path
to the file we are looking for, normal file I/O routines would have
been quite adequate. The reason for bringing in
FileChooser and FileSystemView is to show
that it is possible to create a Windows-Explorer-type front end on
a mobile handset using these classes on the desktop.
Conclusion
This article is meant to show the mechanics of hooking up a desktop with a small device like a cell phone. It also lays the foundation for creating an application for remote exploration of the file structure of a desktop PC. While reading this article, you should keep the following issues in mind:
The application as presented here cannot be fully tested on an emulator because a real phone is required for placing a call. However, I have tested it extensively on a Nokia 6101 and it works just fine.
The
platformRequestmethod is not supported by MIDP 1.0 and that is why the profile setting for the client-side project has to be MIDP 2.0. If this feature is omitted, the project can be compiled under the MIDP 1.0 profile.
Note that there are several enhancements that can be implemented. The issue of security has been paid only token attention here. Stronger security measures can be implemented at various levels. You can find more information in the article " MIDP Application Security 1: Design Concerns and Cryptography."
One weakness of this application, as already mentioned, is that the first partial match is accepted and returned by the search method. A possible approach to improving this would be to return an array of all entries to the client that satisfy partial match. The client could then show the entries one by one to the user for the final selection.
In addition to the two enhancements mentioned above you can, I am sure, think of many more. Trying to implement them will give you many hours of fun.
Resources
- client_src.zip: All client-side code
- server_src.zip: All server-side (desktop) code
- servlet_env.zip: The web.xml file and the entry for <Tomcatroot>/conf/server.xml
- get_entry.zip: Screenshot sequence for accessing the directory
- change_pw.zip: Screenshot sequence for changing password
- "Core Servlets and Java Server Pages" by Marty Hall
- " How to Use File Choosers" from The Java Tutorial
- Designing Software for the Mobile Context: A Practitioner's Guide: A good book to study if you are interested in taking up programming for mobile devices seriously
- " MIDP Application Security 1: Design Concerns and Cryptography" by Jonathan Knudsen.
- "Deploy MIDlets on J2ME-Enabled Devices:" A tutorial on downloading applications to handsets
- Login or register to post comments
- Printer-friendly version
- 2826 reads



