⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mar02_ericg.txt

📁 TechTips j2me的常用技巧. 网络功能
💻 TXT
📖 第 1 页 / 共 3 页
字号:

 J 2 M E    T  E  C  H    T  I  P  S

                      TIPS, TECHNIQUES, AND SAMPLE CODE


WELCOME to the Java Developer Connection(sm) (JDC)
Java(tm) 2 Platform, Micro Edition (J2ME(tm)) 
Tech Tips, for March 25, 2002. This issue covers:

     * Simple Store-and-Forward Messaging for MIDP Applications
     * Compressing XML For Faster Wireless Networking
      
The J2ME Tech Tips are written by Eric Giguere
(http://www.ericgiguere.com), an engineer at iAnywhere 
Solutions, inc. Eric is the author of the book "Java 2 Micro
Edition: Professional Developer's Guide" and co-author of the 
book "Mobile Information Device Profile for Java 2 Micro 
Edition," both books in John Wiley & Sons' Professional 
Developer's Guide series.

You can view this issue of the J2ME Tech Tips on the Web at
http://java.sun.com/jdc/J2METechTips/2002/tt0325.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
SIMPLE STORE-AND-FORWARD MESSAGING FOR MIDP APPLICATIONS

Applications written for the Mobile Information Device Profile 
(MIDP) are rarely stand-alone applications. Normally, there's 
some part of the application that involves calling server-side 
code for processing. In MIDP 1.0, the only way to portably invoke 
server-side code is by making HTTP requests to a servlet running
in an external Web server. On a wireless device, this can be 
quite slow, and so the communication is best done on a background 
thread. In fact, it might make more sense to move to a truly 
asynchronous communication model, where your application 
interacts with other devices by sending and receiving messages. 
This Tech Tip shows you how to implement this kind of simple 
store-and-forward messaging system using MIDP's persistent record 
stores.  To run the code in this tip, you need Tomcat or another 
servlet-enabled Web server. You can download Tomcat from the 
Jakarta Project (http://jakarta.apache.org/tomcat/). 

Let's first define the term "message".  A message is simply 
a class that holds some data, as in this example:

import java.io.*;

public class SimpleMessage implements Persistent {
    private String dest;
    private Object data;

    public SimpleMessage(){
    }

    public SimpleMessage( String dest, String data ){
        setDestination( dest );
        setData( data );
    }

    public SimpleMessage( String dest, byte[] data ){
        setDestination( dest );
        setData( data );
    }

    public String getDestination(){
        return dest != null ? dest : "";
    }

    public Object getData(){ return data; }

    public void setDestination( String dest ){
        this.dest = dest;
    }

    public void setData( String data ){
        this.data = data;
    }

    public void setData( byte[] data ){
        this.data = data;
    }

    private static final int IS_NULL = 0;
    private static final int IS_STRING = 1;
    private static final int IS_BINARY = 2;

    public byte[] persist() throws IOException {
        ByteArrayOutputStream bout = 
                           new ByteArrayOutputStream();
        DataOutputStream dout = 
                          new DataOutputStream( bout );

        dout.writeUTF( getDestination() );

        Object obj = getData();
        if( obj instanceof String ){
            dout.writeInt( IS_STRING );
            dout.writeUTF( (String) obj );
        } else if( obj instanceof byte[] ){
            dout.writeInt( IS_BINARY );
            byte[] arr = (byte []) obj;
            dout.writeInt( arr.length );
            dout.write( arr );
        } else {
            dout.writeInt( IS_NULL );
        }
        dout.flush();

        return bout.toByteArray();
    }

    public void resurrect( byte[] indata ) 
                                   throws IOException {
        ByteArrayInputStream bin =
                    new ByteArrayInputStream( indata );
        DataInputStream din = 
                            new DataInputStream( bin );

        dest = din.readUTF();

        int type = din.readInt();
        if( type == IS_STRING ){
            data = din.readUTF();
        } else if( type == IS_BINARY ){
            int len = din.readInt();
            byte[] arr = new byte[ len ];
            if( len > 0 ){
                din.readFully( arr );
            }
            data = arr;
        } else {
            data = null;
        }
    }

    public String toString(){
        StringBuffer buf = new StringBuffer();
        buf.append( "{destination=\"" );
        if( dest != null ) buf.append( dest );
        buf.append( "\",data=" );
        if( data instanceof byte[] ){
            buf.append( "byte array of length " +
              ((byte[]) data).length );
        } else if( data instanceof String ){
            buf.append( '"' );
            buf.append( (String) data );
            buf.append( '"' );
        } else {
            buf.append( "null" );
        }
        buf.append( '}' );
        return buf.toString();
    }
}

The SimpleMessage class holds two things: a destination name
(a string) and some data, which is either a string or a byte 
array. The format of the destination name is arbitrary. It could, 
for example, be the name of a Java Message Service (JMS) queue. 
Or it could be an email address. Later on in this tip you'll see
that a servlet is responsible for interpreting the destination
name.

Notice that the class implements the Persistent interface. This
interface was defined in a previous Tech Tip, "Object 
Serialization in CLDC-Based Profiles" (see
http://java.sun.com/jdc/developer/J2METechTips/2002/tt0226.html). 
You need this capability to serialize the message for storage and 
transport. 

The first step in building a simple store-and-forward messaging 
system is to build the message hub. The hub is the class that the 
application uses to send and receive messages. The hub uses two 
record stores, one to track incoming messages, and the other to 
track outgoing messages. The messages themselves are sent and 
received by a background thread. Using the hub is fairly simple. 
The constructor takes two parameters: the URL of a servlet and 
a timeout value (in milliseconds) for polling:

    String url = 
          "http://localhost:8080/MessagingServlet";
    int timeout = 60000; // every minute
    MessageHub hub = new MessageHub( url, timeout );

You then start the hub's background thread:

    hub.start();

Now the application can send and receive messages. It sends 
messages using the send method:

    SimpleMessage msg = new SimpleMessage( "eric",
                          "Hello!" );
    hub.send( msg );

This send method does not block, it serializes the message and 
adds it to a record store. The hub's background thread is then 
responsible for delivering it. 

Receiving a message, however, is a blocking operation:

    int timeout = 5000; // wait at most 5 seconds
    SimpleMessage msg = hub.receive( timeout );

If the hub receives a message, it returns it immediately. 
Otherwise the calling thread is blocked until a message arrives 
or the given timeout expires.

To suspend message processing, you can call the hub's stop 
method:

    hub.stop();
    
Finally, when the application is about to terminate, it should 
destroy to hub in order to free the hub's resources:

    hub.destroy();

Let's look at the code for the message hub:

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.rms.*;

/**
 * Defines a class that can send and receive
 * messages asynchronously. Messages are stored
 * in record stores and processed by a background
 * thread, which posts them via HTTP to a servlet
 * running on an external web server.
 */

public class MessageHub implements Runnable {

    // Constructor creates two record stores: one for
    // outgoing messages and one for incoming messages.
    // Pass in the URL to the servlet and a timeout 
    // value in milliseconds for how often to poll the 
    // server if no messages are being sent by the 
    // client.

    public MessageHub( String url, int pullTimeout )
                       throws RecordStoreException {
        inrs = RecordStore.openRecordStore( "mhubin",
                                            true );
        outrs = RecordStore.openRecordStore( "mhubout",
                                             true );
        this.url = url;
        this.pullTimeout = pullTimeout;
    }

    // Convenience method.

    private HttpConnection closeConnection(
                                 HttpConnection conn ){
        try {
            if( conn != null ){
                conn.close();
            }
        }
        catch( IOException e ){
        }

        return null;
    }

    // Client calls this to receive a message, passing
    // in an appropriate timeout value in milliseconds.
    // If the timeout expires, null is returned. 
    // Otherwise the message is returned.

    public SimpleMessage receive( int timeout )
             throws IOException, RecordStoreException {
        SimpleMessage msg = null;
        RecordEnumeration enum = null;

        synchronized( inrs ){
            try {
                if( inrs.getNumRecords() == 0 ){
                    inrs.wait( timeout );
                }

                enum = inrs.enumerateRecords( null,
                               null, false );
                if( enum.hasNextElement() ){
                    int id = enum.nextRecordId();
                    byte[] rawdata =
                               inrs.getRecord( id );
                    SimpleMessage tmp =
                               new SimpleMessage();
                    tmp.resurrect( rawdata );
                    msg = tmp;
                    inrs.deleteRecord( id );
                }
            }
            catch( InterruptedException e ){
            }
            finally {
                if( enum != null ){
                    enum.destroy();
                }
            }
        }

        return msg;
    }

    // Client calls this to send a message. The
    // message is queued in the outgoing queue and
    // the background thread is woken up if necessary.

    public int send( SimpleMessage msg ) 
             throws IOException, RecordStoreException {
        int id = 0;

        synchronized( outrs ){
            byte[] rawdata = msg.persist();
            id = outrs.addRecord( 
                          rawdata, 0, rawdata.length );
            outrs.notify();
        }

        return id;
    }

    // The background thread that reads messages
    // from the outgoing queue, POSTs them to the
    // server and places incoming messages into
    // the incoming queue.

    public void run(){
        HttpConnection conn = null;
        boolean        checkForMore = true;

        while( thread == Thread.currentThread() ){
            byte[] record = null;
            int    recordID = 0;

            // First stage: read a record from the
            // outgoing store.  If there is no record,
            // wait for a specific time.
            
            synchronized( outrs ){
                try {
                    if( outrs.getNumRecords() == 0
                        && !checkForMore ){
                        outrs.wait( pullTimeout );
                    }

                    RecordEnumeration e =
                        outrs.enumerateRecords( null,
                                       null, false );
                    while( e.hasNextElement() ){
                        recordID = e.nextRecordId();
                        record =
                           outrs.getRecord( recordID );
                        if( record != null ){
                            outrs.setRecord( recordID,
                                         null, 0, 0 );
                            break;
                        } else {
                            recordID = 0;
                            record = null;
                        }
                    }
                    e.destroy();
                }
                catch( RecordStoreException e ){
                    break;
                }
                catch( InterruptedException e ){
                }
            }

            // Second stage: POST the record, if any,
            // to the web server.  If successful,
            // delete the record, otherwise restore it.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -