HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML

Somewhere in the conglomerate of sponsor companies and forum management, the Wireless Application Protocol (WAP) specification committees lost track of their objectives. If you look at the challenges faced by developers of wireless applications, you'll find that WAP does not address the main problems.

First, we don't have 100% wireless coverage by any carrier and most likely we never will. One of the design constraints a wireless application must address is a disconnected mode of operation. WAP's protocol is a connectionless protocol; however, WAP does not run in a disconnected mode of operation. Strike one!

The WAP specification describes the user interface components; however, it does not define implementation details. This causes applications to work differently based on the phone's WAP browser. For example, a simple select list functions differently on an OpenWave browser than it does on a Nokia browser. Nokia Select lists are a three-screen process (see Figures 1-3). The OpenWave Select list is a single screen (see Figure 4). This causes lots of implementation issues; especially when trying to write an application that will work in the United States and Europe. Ball one.

Figure 1
Figure 1
Figure 2
Figure 2
Figure 3
Figure 3
Figure 4
Figure 4

As mobile networks increase speed, bandwidth, and coverage, mobile applications must be adaptable to take advantage of these features. While WAP will run faster in these networks, it doesn't have the ability to take advantage of the networks' increased bandwidth. For example, let's say I have a wireless PDA device and I'm downloading a 2MB spreadsheet. If I'm on a 3G, the download request should be split into multiple downloads over multiple downlink channels to increase throughput and decrease the download time. In a WAP environment this is done with a single channel in a serial manner. Strike two!

A WAP microbrowser is a software application so it's always being enhanced with new capabilities. It would be nice to be able to update the browser on the phone to the newest release and not have to buy a new phone. I've been told there are phones that can be upgraded but I have yet to find one. Ball two.

New devices with increased functionality, memory, processing power, communication channels, and graphical capabilities are rapidly being released. When writing a mobile or wireless application, it's extremely beneficial to be able to use these new features to allocate memory and storage, and to take advantage of the increased graphics capabilities of the device. Unfortunately, WAP only addresses communication down the carrier network and does not provide a way to adapt to the device's increased capabilities. Strike three!

I can continue, but in my book three strikes and you're out. WAP is out! It's no surprise that the adoption rates (the percentage of users who use an available application on a regular basis) for deployed WAP applications fall below 3% ­ and I didn't even go into the problems of usability with WAP's list-based application design. So what options do you have for wireless application development? In one word: Java.

J2ME
What Java did for the world of Web-based applications, it's now doing for the world of wireless applications. Java provides storage capabilities, multiple network channel interfaces, adaptable components, and advanced graphical capabilities, making it far superior to other languages.

Storage
How does J2ME address the lack of coverage? By providing Java components for persistent storage known as the Record Management System (RMS). RMS allows a developer to create single or multiple data stores for the application, allowing applications to be run without a network connection. A simple example is mail.

In J2ME I can write a mail application that will allow me to create draft e-mails, save them to storage, review and modify them, and not use a single minute of wireless time or a single byte of data traffic. Try doing this with a WAP solution.

The following example demonstrates how you can achieve localized storage using WAP. Normally, if you wanted to save user information between decks (WML is organized into decks and cards where a deck consists of one or more cards), you would pass the information in the parameters section of an HTTP Post request. However, you can save a variable and reference that variable in subsequent decks. Be careful not to initialize the variable in a subsequent deck because you'll lose the value. Note: If one of the incoming decks performs a newcontext, the current variables will be cleared.

Listing 1 defines how storage might be done in a J2ME application. In addition, J2ME provides components for filtering, comparing, enumerating, and listening for record modification events.

Communication
In a J2ME architecture, the Mobile Information Device Profile (MIDP) sits on top of the Connected Limited Device Configuration (CLDC). Among other things, the CLDC provides an interface to the device's I/O channels. These channels can be for the wireless connection, serial connection, or other I/O channels handled by the device and KVM. Not only does a developer have a choice of channels, but he or she can also choose the type of communication such as HTTP(S), Datagram, and even socket protocol.

Note: The MIDP 1.0 specification does not require a socket protocol, so it's not guaranteed to be there. However, HTTP is a socket-based protocol so it seems logical that the socket protocol would be available. So far all my testing has found that the socket protocol is available. Socket communication means that you now have the ability to provide an always-on, two-way connection. Why is this significant? It allows an application to have data pushed from the server to the application. For example, a developer could add functionality to the e-mail program to allow for new e-mail to be pushed to the device as soon as it's received on the server. No more clicking a button and asking the server for data.

Interfaces
Now that the devices may have a Bluetooth and 802.11(x) card built in, it's desirable to take advantage of these interfaces. Good luck doing this with WAP! Not a problem with Java. Because Java has an abstraction layer for communication, your program will work the same whether you're using the mobile operator's communication channel or the onboard local wireless channel. This also opens the door to using the mobile device as a gateway and sharing the mobile operator wireless channel with other devices like a PDA, telematics system, or laptop. Just think, you can use your laptop to communicate with your phone via a Bluetooth connection. If the connection seems too slow, turn on a second phone, make it available to the laptop, and now you've doubled your bandwidth.

The following code demonstrates how to establish and read from different types of protocols.

String connectionString = "socket://servername.company.com:port";
StreamConnection sc = (StreamConnection)Connector.open( connectionString );

read = sc.read( readBuf , 0 , readMax );

connectionString = "serial://comm:0";
StreamConnection sc2 = (StreamConnection)Connector.open( connectionString );

Read2 = sc2.read( readBuf2 , 0 , readMax2 );

By using the Connector class you simply provide the connection string and you can access any channel on the device that's accessible from the KVM. The connection strings vary by device vendor so you'll need to check with your device's users guide to determine which interfaces are available and the proper connection string properties.

Want to take advantage of next-generation networks and the enhanced power of the mobile device? You can do this with Java's threading capabilities and the ability to create multiple connection objects. The most advantageous is creating multiple download channels so data can be collected in parallel rather than in a serial manner, making the download much faster. This is very similar to how download accelerators work on the Internet.

Do you currently pass your business card to others using an infrared port? Using J2ME you can write a simple Web server and pass your business card using HTTP via a Bluetooth or live Internet connection. It's all possible in Java.

The most significant difference that Java has over WAP is the graphical user interface. The graphical interface capabilities of Java is the main reason for Java's high level of adoption. The one drawback is that the graphical capabilities of Java are not exploited by the standard components, which are actually very WAP-like. One reason the adoption rate of WAP applications is so low is the nature of list-based user interfaces. It takes time to learn the navigation paths and requires a lot of unnecessary user interaction to get to the information a user might want.

It's also easy to get lost within the lists. Java provides a canvas component, so with a little bit of imagination, some coding, and a lot of testing you can develop an application that functions much like a desktop application. A canvas works well for creating screens to select items from the screen, but due to midlet size restrictions it's not well suited for text entry. Under MIDP 1.0, you're stuck with the standard item­based components that don't provide methods for color, font, or orientation.

Good news: this has been addressed in MIDP 2.0 by the CustomItem component. This component can be extended to provide an almost canvas-like functionality to a single item that can be appended to a form component. Listing 2 provides a sample of what could be used to draw a map or other picture (see Figure 5).

Figure 5
Figure 5

Listing 2 demonstrates the drawing capabilities of a canvas. The canvas also has an event listener that listens for the pressing of a key or the touching of the screen. Listing 3 demonstrates how you would listen for the menu key to be selected, creates a pop-up menu component, and finally determines which menu option was selected (see Figure 6).

Figure 6
Figure 6

Take this code to the next level and try building pop-up toolbars, drop-down menus, graphical buttons, and many more components to which users are accustomed. It's this type of functionality that will make the transition from desktops to smaller mobile devices possible. No more learning a complex list scheme that changes at a moment's notice. Now wireless devices can use common desktop components that you already know how to use.

Goodbye WAP, we hardly knew ya.

Author Bio
Chuck Gautney is chief technology officer and vice president of product development for Defywire, a leading provider of wireless enterprise software solutions. By utilizing Java, Defywire's solutions are device- and network-agnostic, allowing enterprises to gain a competitive advantage by retaining and leveraging their current IT investments. cgautney@defywire.com

"The Mighty WAP Strikes Out!"
Vol. 8, Issue 3, p. 56

	



Listing 1

        //mail message variables
        String subject = "Subject line of mail message";
        String to 	= "username@company.com";
        String cc	= "username@company.com";
        String text	= "This is a draft email I will store and send at a later date";

        RecordStore dataStore=null;  //define recordstore
        try {
            //open record store and create if it doesn't exist.
            dataStore = RecordStore.openRecordStore("draftMail",true);
            //add subject row
            dataStore.addRecord(subject.getBytes(),0,subject.getBytes().length);
            //add to row
            dataStore.addRecord(to.getBytes(),0,to.getBytes().length);
            //add cc row
            dataStore.addRecord(cc.getBytes(),0,cc.getBytes().length);
            //add text row
            dataStore.addRecord(text.getBytes(),0,text.getBytes().length);

            //close data store
            dataStore.closeRecordStore();

            //code to retrieve data from store

            int rowsPerRecord = 4;  //total rows that make up a message

            //open data store and create if it doesn't exist.
            dataStore = RecordStore.openRecordStore("draftMail",true);

            int totalDraftMessages = dataStore.getNumRecords() // rowsPerRecord; 
            //loop through each full mail message
            for (int i=0;i<totalDraftMessages;iI=I+rowsPerRecord++) {  
//retrieve the subject line from the dataStore
                               String subjectLine = new String (dataStore.getRecord(j));
//retrieve the to line from the dataStore
                               String toLine = new String (dataStore.getRecord(j));
//retrieve the cc line from the dataStore
                               String ccLine = new String (dataStore.getRecord(j));
//retrieve the text line from the dataStore
                               String textLine = new String (dataStore.getRecord(j));
            }
            dataStore.closeRecordStore();
        
        }
        catch (Exception ex) {
                    System.out.println("Exception In myRMS " + ex);
        }

Listing 2

public class myCanvas extends Canvas 
{
    Image backGroundScreen;
    private static final int COLOR_BLACK = 0x00000000;
    private static final int COLOR_WHITE = 0x00FFFFFF;
    private static final int COLOR_MEDIUM_GRAY = 0x00666666;
    myMenu mainmenu;
    Display display;
    
    //Constructor
    public myCanvas() 
    {
        super();
    }
    public void drawMap(Display display) 
    {

            this.display = display;  //reference to current display
            int width = super.getWidth();  //get width of devices screen
            int height = super.getHeight(); //get height of devices screen

            //setup background image so we do not affect the current screen while drawing
            backGroundScreen = Image.createImage( width, height );
            //get graphics context of screen for draw methods.
            Graphics backGroundGraphics = backGroundScreen.getGraphics();
            //set color to white and clear current screen.
            backGroundGraphics.setColor( COLOR_WHITE );
            backGroundGraphics.fillRect( 0, 0, width, height );
            //set color to black for normal text 
            backGroundGraphics.setColor( COLOR_BLACK );
            //draw a rectangle around the drawing area
            backGroundGraphics.drawRect(1,14,width-4,height-16);
            
   //The following code will draw street  segments with the major highway being drawn
   //in black and the smaller roads drawn in medium gray
            backGroundGraphics.drawString("My Map",0,0,Graphics.TOP|Graphics.LEFT);
            this.drawLine(backGroundGraphics, COLOR_BLACK,5,16,11,24);
            this.drawLine(backGroundGraphics, COLOR_BLACK, 11,24,16,56);
            this.drawLine(backGroundGraphics, COLOR_BLACK, 16,56,64,96);
            this.drawLine(backGroundGraphics, COLOR_MEDIUM_GRAY,
                                15,35,22,23);
            this.drawLine(backGroundGraphics, COLOR_MEDIUM_GRAY,
                                22,23,26,24);
            this.drawLine(backGroundGraphics, COLOR_MEDIUM_GRAY,
                                12,90,60,24);
            //set this Canvas as the current displayed screen.
            display.setCurrent(this);  

        
    }
    //Draw a line on the passed in graphics component 
    public void drawLine(Graphics g, int color, int startX, 
                         int startY, int endX, int endY) 
    {
            int currentColor = g.getColor();  
			//save current color
            g.setColor( color );   
			//set color to passed in color
            g.drawLine( startX, startY, endX, endY);  
			//draw line
            g.setColor( currentColor ); 
			//set color back to original color

    }
    /**
     * paint
     */
    public void paint(Graphics g) {
        //paint background image on screen
        g.drawImage( backGroundScreen, 0, 0, Graphics.TOP | Graphics.LEFT );        
    }
}

Listing 3

    protected  void keyPressed(int keyCode) {
        if (getKeyName(keyCode).equals("SELECT"))  
		//if key name is Menu then popup Menu toolbar
        {
            System.out.println("The Select Key was pressed");
            if (mainmenu == null) 
            {
        //create new Menu Component and pass background image so it can draw itself 
                mainmenu = new myMenu(backGroundScreen);
            }
            else
            {
                int selected = mainmenu.getCurrentSelection();
                switch (selected) {
                    case 1: System.out.println("Selected File");
                            break;
                    case 2: System.out.println("Selected Edit");
                            break;
                    case 3: System.out.println("Selected Exit");
                            break;
                }
                mainmenu=null;
                this.drawMap(display);
            }
            repaint();  //tell the Canvas to repaint to show the main menu.
        }
        else if (getKeyName(keyCode).equals("UP"))  
		//if key name is Menu then popup Menu toolbar
        {
            mainmenu.moveSelection(false);
            repaint();
        }
        else if (getKeyName(keyCode).equals("DOWN"))  
		//if key name is Menu then popup Menu toolbar
        {
            mainmenu.moveSelection(true);
            repaint();
        }
    }

    //Constructor
    public myMenu(Image backGroundScreen) {
        //get Graphics component from screen
        backGroundGraphics = backGroundScreen.getGraphics();
        //clear area for menu
        backGroundGraphics.setColor( COLOR_WHITE );
        backGroundGraphics.fillRect( 9, 12, 30, 70 );
        //shade header area light gray
        backGroundGraphics.setColor( COLOR_LIGHT_GRAY );
        backGroundGraphics.fillRect( 9, 12, 30, 20 );
        //set color to black for drawing
        backGroundGraphics.setColor( COLOR_BLACK );
        
        //draw rectangle around menu area
        backGroundGraphics.drawRect(9,12,30,70);
        //draw rectangle around first Selection.
        backGroundGraphics.drawRect(9,32,30,14);
        //draw menu options.
        backGroundGraphics.drawString("Menu",12,16,Graphics.TOP|Graphics.LEFT);
        backGroundGraphics.drawString("File",12,32,Graphics.TOP|Graphics.LEFT);
        backGroundGraphics.drawString("Edit",12,48,Graphics.TOP|Graphics.LEFT);
        backGroundGraphics.drawString("Exit",12,64,Graphics.TOP|Graphics.LEFT);
         
    }
    
    public void moveSelection(boolean goDown) {
        
        //clear current selection rectangle.
        System.out.println("Last selection: " + currentSelection); 
        backGroundGraphics.setColor( COLOR_WHITE );
        backGroundGraphics.drawRect(9,(currentSelection*16)+16,30,14 );
        backGroundGraphics.setColor( COLOR_BLACK );
        //redraw rectangle around menu area.
        backGroundGraphics.drawRect(9,12,30,70);
        
        //set current selection
        if (goDown)
            currentSelection++;
        else
            currentSelection--;
        //make sure selection is within bounds.  If not then wrap around.
        if (currentSelection<1)
            currentSelection=3;
        else if (currentSelection>3)
            currentSelection=1;
        //draw rectangle around current selection.
        backGroundGraphics.drawRect(9,(currentSelection*16)+16,30,14 );

    }
    
    //return current selection
    public int getCurrentSelection() {
        return currentSelection;
    }
}

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: info@sys-con.com

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.