Let the mobile games begin, Part 2

J2ME and .Net Compact Framework in action

In Part 1 of this series, I overviewed the two leading platforms for smart device development: Java 2 Platform, Micro Edition (J2ME) and .Net Compact Framework. The two platforms' ultimate goals are the same: to enable rich clients for users and to improve developer productivity. Both platforms offer similar benefits:

  • Well-designed programming languages for development (Java for J2ME, and C#/Visual Basic .Net (VB.Net) for .Net Compact Framework): Compared with older device development languages such as C/C++ and eVB (eMbedded Visual Basic), these new languages are easy to learn and have a large pool of qualified developers.
  • Managed runtime environments: Applications for both platforms run inside virtual machines that manage security, memory usage, and runtime optimization. Managed memory access improves developers' productivity by freeing them from the error-prone chore of memory management.
  • Rich libraries and components: Object-oriented programming languages like Java, C#, and VB.Net allow developers to reuse software modules. Both platforms come with a rich set of libraries for advanced UI (user interface), network connectivity, data management, and XML Web services. Libraries for accessing common device extensions (e.g., the GPS (global positioning system) or scanner module) are also available.
  • Familiar APIs from standard frameworks: J2ME and .Net Compact Framework allow desktop developers to migrate their skills to mobile development. For example, the Java AWT (Abstract Window Toolkit) UI can be directly used in certain J2ME profiles, and the Windows Forms controls can be used in Compact Framework applications. The IBM Service Management Framework (an OSGi (Open Services Gateway Initiative) implementation) even brings common J2EE (Java 2 Platform, Enterprise Edition) APIs and patterns to devices.
  • Extensive development tools: More than a dozen generic IDEs, development toolkits, and command-line tools are available from leading vendors in the J2ME space. Microsoft's flagship development tool, Visual Studio .Net, is also fully integrated with Compact Framework.

Despite those similarities, the differences between the two platforms are profound. In a nutshell, J2ME is a specification shaped by industry consensus, while .Net Compact Framework is a polished and fast-paced implementation driven by a single powerful vendor. Below, I describe the two platforms' hardware support:

  • J2ME runs on a range of devices from smart phones to set-top boxes from all major vendors, while .Net Compact Framework runs only on devices from Microsoft Pocket PC licensees.
  • Since Microsoft has control over Pocket PC hardware vendors, .Net Compact Framework developers have a specific hardware specification to program against (e.g., screen size) and can assume the availability of certain native software (e.g., Windows Media Player).
  • J2ME is also moving toward reducing the device market fragmentation via specifications like Java Specification Request (JSR) 185 (Java Technology for the Wireless Industry), which specifies the minimum hardware requirement for certain J2ME profiles.

Due to the requirements of uniform and powerful mobile devices, .Net Compact Framework is suitable for cash rich customers with controlled mobile environments. It was initially focused on the enterprise mobile market, especially for Microsoft-centric IT shops, while J2ME was originally active in the consumer sector. However, in the long run, most experts expect both platforms to coexist in all market sectors. As developers, we must choose the right tools and make them all work in heterogeneous environments. For example, we need to make J2ME clients work with .Net backend servers and vice versa. In this article, I walk through an end-to-end mobile GIS (geographic information system) application that mixes Java and .Net on client, server, and middleware layers. However, before we can dive into the sample application's technical aspects, we need to step back and look at the business aspects critical to our architecture design.

Read the whole series: "Let the Mobile Games Begin," Michael Juntao Yuan (JavaWorld):

Note: You can download this article's source code from Resources.

GIS services and the MapPoint Web Service

In this section, I introduce some background to our driving-directions example. I discuss the basic concepts of location-based services and the geographic information system. I also introduce a commercial GIS service: MapPoint Web Service, which is the "brain" of our example mobile application.

What is GIS?

Location-based services (LBS) supply customized information based on the mobile user's current location. For example, a visiting nurse can quickly locate patient information when she is close to that patient's house. LBS is touted as the killer app for mobile commerce because it enables new applications not possible in the fixed location desktop world.

A central piece of any mobile LBS solution is the GIS component, which allows users to determine street addresses from coordinates and vice versa; look up Yellow Pages and landmarks; calculate optimal routes; and render custom maps. The ability to work with GIS servers is a major requirement for any mobile LBS client. In this article, I develop a mobile driving-directions client that utilizes a leading commercial GIS provider: Microsoft MapPoint Web Service.

MapPoint Web Service

Standalone GIS servers capable of geocoding (assigning a latitude-longitude coordinate to an address), rendering maps, and other complex geographic algorithms have been commercially available for a long time. However, running a GIS server by yourself is probably too expensive for most small to midsized businesses. The costs include:

  • Hiring GIS experts to set up and maintain the system.
  • Licensing high-resolution digital maps and business telephone number listings. This could prove expensive if your users roam across many metropolitan areas.
  • Aggregating geographic information updates from many sources (e.g., road construction and business address changes) and frequently updating them to the database.
  • Ongoing server administration for secure and high-availability services.
  • Licensing cost of the GIS server software itself.

For most companies, it makes sense to outsource the GIS operation to specialized providers. One such provider is MapPoint, a managed GIS solution from Microsoft. MapPoint services are accessible via a set of SOAP (Simple Object Access Protocol) Web services APIs, which ensures that the services are available to a variety of client applications. MapPoint also allows users to upload their own geocoding data and points-of-interest listings for customized services. Users can pay for MapPoint services based on the number of queries or get unlimited queries for a flat subscription fee. Developers can evaluate the service for free for 45 days. Important remote methods in MapPoint 3.0 divide into four categories:

  • Common service: Contains utility functions common to other services.
  • Find service: Allows user to do generic geocoding tasks. That includes finding addresses from latitudes and longitudes and vice versa. It also allows searching for nearby points of interest.
  • Route service: Calculates routes and directions based on locations and waypoints. It also generates a map view representation of the calculated routes. The map view can be used to highlight routes on a map.
  • Render service: Renders the map for the locations or routes. It highlights routes, places pushpins and icons, and supports zoom.

The aggregation API

MapPoint offers fine-grained access to its GIS services, which allows us to design flexible applications without arbitrary limitations imposed by preset scripts. However, the tradeoff is that we have to make separate method calls for each small step to complete a task. For example to retrieve driving directions between two addresses, we must complete the following steps:

  1. Convert the addresses to latitude and longitude coordinates
  2. Calculate the route according to options
  3. Render the overview map with the route and start/end locations highlighted
  4. Retrieve turn-by-turn instructions for each route segment
  5. Render highlighted turn-by-turn maps for each route segment

The last two steps need to be performed repeatedly for a long route with many segments. Since all those method calls are remote SOAP calls, those excessive round-trips cause long delays on slow wireless networks. To minimize the data transfer over wireless networks, we can place a portal middleware between the mobile client and MapPoint. The portal takes in two human-readable addresses in a single SOAP call; queries MapPoint via many API calls over the wired Internet; constructs the resultant driving directions; and returns the results. The portal provides a simple API that aggregates functions of the basic MapPoint API methods for specific applications. Figure 1 illustrates the architecture.

Figure 1. The aggregator portal architecture

So, the goal of our sample project is to build an API aggregation portal to MapPoint and then build three mobile clients using J2ME and .Net Compact Framework. To maximize the environment's diversity, we use Apache Axis, a Java Web service toolkit to build the portal.

The Apache Axis portal

As a Microsoft platform, MapPoint was never designed for Java clients. But its SOAP Web service interface makes it platform independent. Java programs can access MapPoint services using Java SOAP toolkits such as Apache Axis and Sun Microsystems' Java Web Services Developer Pack. Those toolkits can also expose Java objects as SOAP Web services for client applications. Here's how to construct the MapPoint API aggregation portal using Axis:

  1. Generate Java SOAP stub classes for the MapPoint SOAP API using the WSDL2Java tool in Axis (WSDL is an acronym for Web Services Description Language)
  2. Use those Java stub classes to develop a Java object, MPClient, which implements the MapPoint API aggregation methods
  3. Publish the MPClient object as a SOAP Web service via Axis's server interface:
    1. Configure and run the Axis server inside a Tomcat server
    2. Copy the jar file containing the MPClient class to the Axis library directory
    3. Specify the service object's scope, methods to expose, and other options via a .wsdd file
    4. Deploy the .wsdd file to Axis through its server administration utility

Detailed tutorials on how to configure and use Axis reach beyond this article's scope. Please refer to Resources if you are not familiar with Apache Axis.

Due to limited space, I show only the public interfaces of remote methods in the MPClient class in Listing 1 below. The API usage is embedded in the code comments. The complete code is available in the AxisPortal downloadable package. The package also contains generated stub classes, Axis libraries, sample .wsdd files, and an Ant script to build and deploy the portal.

Listing 1. The AxisPortal class

public class MPClient {
  // Authentication credentials obtained from
  // MapPoint Website.
  private static String userName = "yourID";
  private static String password = "yourPass";
  // Other variables. 
  // The cached route segments.
  private Segment[] segments;
  // Get the driving directions between 
  // two human-ready addresses. This method
  // also caches the route in the segments array.
  //
  // You have to run this method before you can
  // retrieve maps for the entire route or for 
  // each route segment.
  public String [] getDirections (
   String fromStreet, String fromCity,
   String fromState, String fromZip,
   String toStreet, String toCity,
   String toState, String toZip
                       ) throws Exception {
    // Method body.
  }
  // Return the number of segments of the current
  // cached route. The number is available after
  // you call the getDirections() method.
  public int getSegmentNum () throws Exception {
    // Method body.
  }
  // Get a map from the current cached route.
  // The return value is a byte array for
  // the GIF image.
  // 
  // index == 0 for the overview map
  // index <= segmentNum for a segment map
  public byte [] getMap (int index, 
          int width, int height) throws Exception {
    // Method body.
  }
}

The three clients

The use of the SOAP API to expose the MPClient service object allows us to develop clients on different platforms. In this article, I discuss three mobile clients:

  1. J2ME Personal Profile
  2. .Net Compact Framework
  3. J2ME MIDP (Mobile Information Device Profile)

The J2ME Personal Profile client

Figure 2 shows a J2ME client running on Insignia's Jeode PersonalJava VM on a Pocket PC 2002 device. The same client runs on J2ME Personal Profile and desktop Java platforms without recompilation. Listing 2 details important code segments.

Figure 2. The PersonalJava client in action. Click on thumbnail to view full-size image.

Listing 2. The J2ME Personal Profile client

public class AWTMap extends Frame
    implements WindowListener, ActionListener {
  // UI and handlers
private void listScreen (boolean newSearch) {
    try {
      if (newSearch) {
        SoapObject method = new SoapObject("", "getDirections");
        // Use the SE version for standard JDK Http methods
        HttpTransportSE rpc = new HttpTransportSE(endPointURL, "\"\"");
        rpc.setClassMap(cm);
        method.addProperty("in0", fromStreet.getText());
        method.addProperty("in1", fromCity.getText());
        method.addProperty("in2", fromState.getText());
        method.addProperty("in3", fromZip.getText());
        method.addProperty("in4", toStreet.getText());
        method.addProperty("in5", toCity.getText());
        method.addProperty("in6", toState.getText());
        method.addProperty("in7", toZip.getText());
        Vector v = (Vector) rpc.call (method);
        directionsList = new java.awt.List(10, false);
        directionsList.add("Overview Map");
        for (int i = 0; i < v.size(); i++) {
          directionsList.add((String) v.elementAt(i));
        }
        directionsList.setSize(200, 200);
      }
      Panel top = new Panel ();
      top.setLayout(new FlowLayout(FlowLayout.LEFT));
      top.add(directionsList);
      Panel bottom = new Panel ();
      bottom.setLayout(new FlowLayout(FlowLayout.LEFT));
      bottom.add(startOver);
      bottom.add(showMap);
      
      scroll.remove(content);
      content = new Panel ();
      content.setLayout(new BorderLayout());
      content.add(top, BorderLayout.CENTER);
      content.add(bottom, BorderLayout.SOUTH);
      scroll.add(content);
      setVisible(true);
      
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  private void mapScreen (int i) {
    try {
      ImageItem img;
      byte [] imgarray;
      SoapObject method = new SoapObject("", "getMap");
      HttpTransportSE rpc = new HttpTransportSE(endPointURL, "\"\"");
      rpc.setClassMap(cm);
      method.addProperty("in0", new Integer(i));
      method.addProperty("in1", new Integer(200));
      method.addProperty("in2", new Integer(200));
      imgarray = (byte []) rpc.call (method);
      img = new ImageItem(imgarray, 200, 200);
      
      Panel top = new Panel ();
      top.add(img);
      Panel bottom = new Panel ();
      bottom.add(startOver);
      bottom.add(showDirections);
      
      scroll.remove(content);
      content = new Panel ();
      content.setLayout(new BorderLayout());
      content.add(top, BorderLayout.CENTER);
      content.add(bottom, BorderLayout.SOUTH);
      scroll.add(content);
      setVisible(true);
      
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  // Other methods
}

The UI is handwritten using the Java AWT library. AWT proves sufficient for most mobile tasks although it requires a lot of tinkering before the layout renders properly. Also, since AWT does not support any image display widget, we must implement our own ImageItem class. IDE tools such as CodeWarrior Wireless Studio could help us generate the UI code more quickly.

The Web services code is also handwritten against the kSOAP library. For most mobile applications, the remote SOAP interface is not complex, and handwritten SOAP RPC (remote procedure call) code gives us the maximum control. If you really need automatic SOAP stub generators, plug-ins for kSOAP are available for all leading J2ME IDEs.

The .Net Compact Framework client

Figure 3 shows a .Net Compact Framework client for the driving-directions application running a Pocket PC device.

Figure 3. The .Net Compact Framework client in action. Click on thumbnail to view full-size image.

The first thing we notice about the .Net Compact Framework client is its rich UI. The tabbed page interface reduces screen clutter and is easy to navigate on a small device. However, note that not all standard Windows Forms properties are supported in .Net Compact Framework. For example, the tabpage control's .Net Compact Framework edition does not support auto scroll. To support scroll, we must add in the scrollbar controls and manually implement their behaviors.

A great value of .Net Compact Framework is RAD (rapid application development) support from the Visual Studio .Net (VS.Net) IDE. You can literally click your way through the IDE to build simple applications. The two most useful VS.Net RAD tools are the following:

  • The UI design tool allows us to position components accurately—see Figure 4.
  • The Web services tool makes generating and referencing remote service objects a breeze—see Figure 5.
Figure 4. The Visual Studio .Net visual GUI designer
Figure 5. The Visual Studio .Net Web services stub generator. Click on thumbnail to view full-size image.

Using VS.Net to develop a simple client like this, we need to only write a minimum amount of code:

Listing 3. User-written code for the .Net Compact Framework client

namespace CFMap {
  public class CFMapForm : System.Windows.Forms.Form {
    // Auto-generated UI and initialization code
    
    // You need to dig in and find out the right order
    // of the tabbed pages:
    // ... ...
    this.tabControl1.Controls.Add(this.fromPage);
    this.tabControl1.Controls.Add(this.toPage);
    this.tabControl1.Controls.Add(this.directionsPage);
    this.tabControl1.Controls.Add(this.mapPage);
    // ... ...
    // Event handler for the "GetDirections" button
    private void btnGetDirections_Click(object sender,
              System.EventArgs e) {
      String [] directions = service.getDirections(
                    fromStreet.Text, fromCity.Text, 
                    fromState.Text, fromZip.Text, 
                    toStreet.Text, toCity.Text,
                    toState.Text, toZip.Text);
      ArrayList al = new ArrayList ();
      al.Add("Overview Map");
      for (int i = 0; i < directions.Length; i++ ) {
        al.Add( directions[i] );
      }
      directionsList.DataSource = al;
      tabControl1.SelectedIndex = 2;
    }
    // Event handler for the "GetMap" button
    private void btnGetMap_Click(object sender,
                    System.EventArgs e) {
      byte [] imgarray =
        service.getMap(directionsList.SelectedIndex,
                       200, 200);
      mapBox.Image =
        new Bitmap (new MemoryStream(imgarray));
      tabControl1.SelectedIndex = 3;
    }
    
    // Switch to the "To" screen
    private void btnToAddress_Click(object sender,
         System.EventArgs e) {
      tabControl1.SelectedIndex = 1;
    }
    // Switch to the "From" screen
    private void btnFromAddress_Click(object sender,
         System.EventArgs e) {
      tabControl1.SelectedIndex = 0;
    }
  }
}

Although visual programming is extremely powerful for simple applications, visual tools might not scale well to handle sophisticated applications. Take the UI designer and Web service reference generator as examples:

  • It is hard to develop UI paradigms that don't conform to the scripts in the designer. For example, the UI designer is little help if you want to use screen flow (see the J2ME Personal Profile example) rather than tabbed pages.
  • If we want to expand the application later and need to refactor the variable names, the designer will change only the names in generated code. If we do not manually keep the callback delegate names in sync with component names, the application will soon become unmaintainable.
  • If we want to use custom HTTP transport, use a different endpoint URL, or access specific SOAP elements (e.g., headers), we must hack into the generated Reference.cs file and manually change it. We risk losing those changes if we regenerate the stub reference again.

So, the bottom line is that RAD tools have their limits. Developers still need to understand their software's inner workings. The productivity gain introduced by those tools could prove limited for large-scale real-world applications.

The J2ME MIDP client

Figure 6 demonstrates a J2ME MIDP version of the driving-directions application in action on a Motorola Java phone (model i95cl). It resembles the J2ME Personal Profile application except that MIDP uses its own light UI (liquid crystal display UI, or LCDUI) rather than the standard AWT. Listing 4 shows the MIDP client's source code.

Figure 6. The MIDP client in action. Click on thumbnail to view full-size image.

Listing 4. The MIDP client

public class MIDPDirections extends MIDlet implements CommandListener {
  Display display;
  Command fromNext, toNext, cancel, done, exit;
  TextField fromStreet, fromCity, fromState, fromZip;
  TextField toStreet, toCity, toState, toZip;
  String endPointURL;
  public MIDPDirections () {
    endPointURL = "http://128.83.129.226:8080/axis/services/MapPoint";
    display = Display.getDisplay(this);
    fromNext = new Command("NEXT", Command.SCREEN, 2);
    toNext = new Command("NEXT", Command.SCREEN, 2);
    cancel = new Command("CANCEL", Command.SCREEN, 2);
    done = new Command("DONE", Command.SCREEN, 2);
    exit = new Command("EXIT", Command.SCREEN, 2);
    fromStreet = new TextField("Street", "", 20, TextField.ANY);
    fromCity = new TextField("City", "", 20, TextField.ANY);
    fromState = new TextField("State", "", 10, TextField.ANY);
    fromZip = new TextField("Zip", "", 10, TextField.NUMERIC);
    toStreet = new TextField("Street", "", 20, TextField.ANY);
    toCity = new TextField("City", "", 20, TextField.ANY);
    toState = new TextField("State", "", 10, TextField.ANY);
    toZip = new TextField("Zip", "", 10, TextField.NUMERIC);
  }
  public void startApp() {
    fromScreen ();
  }
  public void pauseApp() {
    // Do nothing
  }
  public void destroyApp(boolean unconditional) {
    // Do nothing
  }
  public void commandAction(Command command, Displayable screen) {
    if (command == exit) {
      destroyApp(false);
      notifyDestroyed();
    } else if ( command == done || command == cancel ) {
      startApp ();
    } else if ( command == fromNext ) {
      toScreen ();
    } else if ( command == toNext ) {
      directionScreen ();
    }
  }
  public void fromScreen () {
    Form form = new Form ("From");
    form.append(fromStreet);
    form.append(fromCity);
    form.append(fromState);
    form.append(fromZip);
    form.addCommand(fromNext);
    form.addCommand(cancel);
    form.setCommandListener( (CommandListener) this);
    display.setCurrent(form);
  }
  public void toScreen () {
    Form form = new Form ("To");
    form.append(toStreet);
    form.append(toCity);
    form.append(toState);
    form.append(toZip);
    form.addCommand(toNext);
    form.addCommand(cancel);
    form.setCommandListener( (CommandListener) this);
    display.setCurrent(form);
  }
  public void directionScreen () {
    Vector v = getDirections ();
    Form form = new Form ("Directions");
    for (int i = 0; i < v.size(); i++) {
      form.append((String) v.elementAt(i) + "\n");
    }
    form.addCommand(done);
    form.addCommand(exit);
    form.setCommandListener( (CommandListener) this);
    display.setCurrent(form);
  }
  private Vector getDirections () {
    Vector v = null;
    try {
      SoapObject method = new SoapObject("", "getDirections");
      method.addProperty("in0", fromStreet.getString());
      method.addProperty("in1", fromCity.getString());
      method.addProperty("in2", fromState.getString());
      method.addProperty("in3", fromZip.getString());
      method.addProperty("in4", toStreet.getString());
      method.addProperty("in5", toCity.getString());
      method.addProperty("in6", toState.getString());
      method.addProperty("in7", toZip.getString());
      HttpTransport rpc = new HttpTransport(endPointURL, "\"\"");
      v = (Vector) rpc.call (method);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return v;
  }
}

For large screen MIDP devices, we could add map displays to the application too. However, MIDP only supports the PNG image format, while MapPoint only renders GIF images. An image format conversion module in the portal server can solve this problem.

Comparison points

In general, all three clients get the job done. But how do they compare with each other?

  • Runtime installation: J2ME/MIDP runtimes are factory installed on millions of handsets today. PersonalJava and Personal Profile runtimes are factory installed on most Linux PDAs (e.g., Sharp). For Pocket PC and Palm devices, the user must install the Java runtime through the synchronization link. The .Net Compact Framework runtime will be preinstalled on all future Pocket PC devices. But for now, the user must install the related CAB (cabinet) files on the device first.
  • Performance: On the Pocket PC device, the Jeode PersonalJava client has comparable performance as the .Net Compact Framework client in both startup time and operational smoothness.
  • User interface: .Net Compact Framework has a rich set of UI controls. Most Windows Forms and Visual Studio .Net developers are already familiar with those components. The C# language also has an excellent programming model for UI applications (e.g., delegates for UI events). The AWT library in J2ME Personal Profile and PersonalJava gets the job done. But most Java developers would agree that programming in AWT is not exactly pleasant. However, help is on the horizon: IBM has just released the SWT (Standard Widget Toolkit), which has proven success in the desktop Java world on the Pocket PC platform. In addition, the new Advanced Graphics and UI for J2ME Optional Package (JSR 209) proposes to add optional Swing capability to the new Personal Profile. The LCDUI for MIDP is powerful and easy to use for phone devices.
  • Web services: SOAP Web services support is tightly integrated into .Net Compact Framework and Visual Studio .Net. They support both RPC style and asynchronous Web services. In our J2ME example, I used a third-party lightweight SOAP library (kSOAP). I actually prefer to work closer to the XML wire protocol using kSOAP. For developers who want to be completely shielded from the underlying XML layer, the J2ME Web services optional package allow us to map SOAP calls to Java Remote Method Invocation (RMI)-style remote calls. An unofficial implementation for this optional package (based on proposed draft v0.7) is already available from IBM.
  • Tools: A big advantage for .Net Compact Framework is the VS.Net IDE. In our example, we discovered that VS.Net can greatly reduce handwritten code. However, as I already mentioned, every code generation tool has its limits. If you do not like the VS.Net way of programming, you are out of luck since VS.Net is the only tool currently available for .Net Compact Framework developers. J2ME, on the other hand, has at least a dozen IDE and command-line tools. They collectively offer all the features VS.Net has, but none is as good as VS.Net in a one-to-one test. The most promising J2ME IDE is IBM's WebSphere Studio Device Developer.

Enhance the application

So far, our driving-directions application is simplistic. It is designed for a single user, lacks support for offline operations, and does not take advantage of the local location context. In this section, I discuss ways to enhance the application and explore options available in both J2ME and .Net Compact Framework.

Session management

Our portal only maintains one global scope MPClient object, and all mobile clients must share it. Since the route cache is stored inside the MPClient object, simultaneous users could prove problematic. Before any stateful Web services specification is widely adopted, we can rely on HTTP's built-in state management mechanisms to track user sessions.

To add session management, on the portal server side, we need to only change the service scope from Application to Session in the wsdd descriptor file. The Axis engine will automatically use the servlet container's HttpSession object to maintain one MPClient for each session. By default, the server tracks sessions using HTTP cookies. Now the client-side stub has to understand cookies too. The J2ME and .Net clients require different techniques:

  • For J2ME applications, we must extend the HttpURLConnection class in Personal Profile and HttpConnection class in MIDP to add cookie support. Interested readers can refer to one of my earlier articles (see Resources) for more details. Then we need to hack the HttpTransport class to replace all connection classes with the cookie-aware ones.
  • Since .Net Compact Framework does not support the cookie classes in the System.net package, we cannot simply plug in cookie-based HTTP session support in generated SOAP stubs. We would have to extend the basic transport classes to add cookie support. That would render the auto stub generator in VS.Net IDE much less useful.

On-device cache

A much-touted benefit of smart mobile clients is their ability to support offline mode through local data caching. Both J2ME and .Net Compact Framework provide excellent support for on-device data stores. My next column will discuss several leading relational databases on the J2ME platform. On the .Net Compact Framework platform, the flagship relational database is Microsoft's SQL Server CE. It is accessible through the common ADO.Net (Active Data Objects) API. The .Net Compact Framework also supports part of ADO.Net, which allows us to persist data to XML files easily.

Location APIs

The driving-directions application I demonstrated above is not particularly easy to use. For example, if we are lost driving, we need to find the route from the current location to the destiny. Finding the current street address and manually entering it into the device could prove a major nuisance. A driving-directions application that is aware of the current location context and automatically fills out the From field can be much more valuable to users. In fact, most LBS business models require access to the mobile client's current location.

As I have discussed, access to device extensions is one of the major benefits for both the J2ME and .Net Compact Framework platforms. Real-time location information can either come from on-device GPS devices or from network operators via network triangling techniques. The list below describes location determination technologies and APIs available on the two platforms:

  • Current GPS-enabled Java phones have proprietary APIs for on-device J2ME applications to access real-time location information. In the future, the Location API for J2ME (JSR 179, currently under public review) will provide a uniform interface to access location information from either GPS devices or network operators.
  • GPS device vendors also develop .Net custom controls for their devices. Those controls are reusable visual components that can plug into Visual Studio .Net. The new Microsoft location server will expose a new set of Web services APIs to integrate with network operator location servers. .Net Compact Framework devices can query the location server to find out real-time locations.

Put .Net Compact Framework and J2ME in action

In this article, I explored how to build GIS mobile clients using a mix of .Net Web services, J2EE, J2ME, and .Net Compact Framework technologies. XML Web services is the key technology that enables this heterogeneous design.

Both J2ME and .Net Compact Framework support similar sets of features and development tools. .Net Compact Framework better supports the Windows UI and is easier to start. On the other hand, J2ME has a rich set of third-party tools that conform to standard specifications. J2ME's abstract design also makes it easier to use advanced design patterns in sophisticated applications.

Due to the two platforms' technical similarities, business requirements, not technical merits, often determine a developer's choice. If the mobile application must work on a variety of devices from low-end cell phones to high-end PDAs, J2ME is the only choice. If you only deploy to Pocket PC devices and your developers already have .Net and VS.Net skills, .Net Compact Framework makes sense.

It has become increasing clear that Java and .Net technologies will in fact coexist for a long time to come. As Java developers, we should not only compete with .Net, but also learn how to interoperate with it. When we make a business case for J2ME, we must keep in mind the other options our clients (or bosses) might consider. That requires us to understand exactly how .Net works and what value it adds. As recently reported by vnunet.com, Microsoft is offering Java training to 140 of its consultants to better compete with Java. Microsoft surely knows the competition. We should too.

Michael Yuan is a PhD candidate at the University of Texas, where he is a research associate at the Center for Research in Electronic Commerce and an open source Java developer. He is the author of the upcoming book Enterprise J2ME: Developing Mobile Java Applications from Prentice Hall, to be released fall 2003.

Learn more about this topic

  • "Let the Mobile Games Begin," Michael Juntao Yuan (JavaWorld)

Join the discussion
Be the first to comment on this article. Our Commenting Policies