The Source for Java Technology Collaboration
User: Password:
Register | Login help    

Search

Online Books:
java.net on MarkMail:


 E-mail  Print

Access Desktop Data from Mobile Devices

Thu, 2006-11-30

{cs.r.title}



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 Access MIDlet, 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.

Selecting login mode
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).

Prompt for saving login information
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:

  • command can be either read or changeupw
  • commandinfo can be either target or newupw

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&ltj;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 platformRequest method 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

Biswajit Sarkar is an electrical engineer with a specialization in programmable industrial automation.
Related Topics >> Mobility      
Comments
Comments are listed in date ascending order (oldest first)