GCF Examples

Now that you know about the connection types provided by CLDC, MIDP 1.0, and 2.0, you are ready to implement two example applications: a terminal program and a chat application. These example applications will be CLDC-based.

GCF Terminal Program

Prior to the PC era, it was quite common to have a single centralized computer and a set of simple hardware terminals providing text-based interfaces to the main computer. A terminal program is an application that simulates this kind of interface by providing a local text interface to a remote process. Before the World Wide Web became popular, terminal programs were widely used to access so-called mailboxes or bulletin board systems (BBS) over a serial modem connection. Today, terminal programs implementing the telnet protocol are still used for command line access; for example, for server configuration.

For the sample terminal application, we will take advantage of the fact that the GCF is indeed very generic. You will enter a URI, and your terminal program will connect to the given address and display what the other end of the connection sends. For example, if you connect to an HTTP address, the program will display the HTML code of the requested page. You may also use the example to view the raw positioning data read from a GPS receiver using a serial connection. An input line allows you to send data over the connection.

Here, we will only describe the network related parts of the application. The complete sources of the MIDP and PDAP versions are shown in Listings 6.2 and 6.3, respectively. The MidpTerminal and PdapTerminal application user interfaces consist of a widget in which you can enter a URL that is used to open a particular connection. The connection is established by activating the Connect command or by pressing the Connect button, depending on the platform in which the application is running.

The core of the Terminal implementation is contained in an inner class of the main application called Handler. This class “handles” establishing the connection and receiving new data in the background. For that purpose, the Handler stores the connection, as well as the corresponding input and output streams in member variables. It also contains a variable leave that determines whether the handler should leave the receive loop and terminate itself:

class Handler extends Thread {

    StreamConnection connection;
    InputStream in;
    OutputStream out;
    boolean leave;

The constructor of the Handler takes a URL as input and establishes a corresponding stream connection. It is called from the main application when the user enters an address and requests a corresponding connection. The Handler is not able to handle datagram or serversocket protocols. Trying to do so would cause a class cast exception.

When the connection is established, the out and in variables are set. Then, the establishment of the connection is reported using the show() method of the main class:

public Handler (String url) throws IOException {

    connection = (StreamConnection) Connector.open
    (url, Connector.READ_WRITE, true);

    out = connection.openOutputStream ();
    in = connection.openInputStream ();

    show ("opened: "+ url + "
");
}

The main work is performed in the run() method of the Handler thread. The run() method is invoked automatically when the main application calls the start() method, which runs the handler as a separate thread in the background. In the run() method, incoming data is collected in a string buffer until the leave flag is set, no more data is available, or the buffered data reaches a limit of 1024 bytes. In that case, the collected data is shown to the user by handing it over to the show() method. Then, the buffer is cleared and a new iteration of the read loop is entered. If read encounters a -1, that means that the stream is closed remotely. In that case, disconnect() is called in order to terminate the Handler and to release the connection:

    public void run () {

        StringBuffer buf = new StringBuffer ();

        try {
            while (!leave) {
                do {
                    int i = read ();
                    if (i == -1) disconnect ();
                   // ignore control characters except from cr
                    else if (i == '
' || i >= ' ')
                        buf.append ((char) i);
                }
                while (!leave && in.available () > 0 && buf.length () < 1024);

                show (buf.toString ());
                buf.setLength (0);   // clear buffer
            }
        }
        catch (Exception e) {
            if (!leave) show (e.toString () + "
");
            disconnect ();
        }
    }
}

You might have noticed that the method Handler.read() is called for reading data from the stream instead of just calling in.read(). The only difference is that Handler.read() implements telnet parameter negotiation, which allows you to use the Terminal sample application as a telnet client by connecting to port 23 of a corresponding host. The Telnet protocol is widely used to connect computer systems remotely with a command-line interface. For details of the Telnet protocol please refer RFC854.

The main application classes, MidpTermial and PdapTerminal, mainly handle the user interface. The only method that is independent from the user interface is disconnect(), which closes the connection if a connection exists and notifies the corresponding Handler to terminate.

An important difference of the PDAP implementation when compared to the MIDP implementation is that the show() method does not manipulate the user interface directly. Because the PDAP AWT is not thread safe, it is necessary to manipulate the user interface indirectly by calling invokeAndWait() with an instance implementing the Runnable interface. Here, you use the class Appender for that purpose. The Appender instance encapsulates the string to be appended to the list of incoming data. When the AWT calls the run() method of the Appender, AWT has made sure that it is currently safe to manipulate the user interface. Now, the Appender adds its payload to the list showing the data sent from the remote end of the connection.

Figure 6.4 shows an example session of the terminal program. Note that the terminal is only a minimal implementation for demonstration purposes. It does not handle any control sequences such as cursor control, except from carriage return characters ( ). Feel free to extend the sample as you like for your purposes. For example, for applications relying on binary data transfer, it might be better to use a hex format for sending and receiving data. Listing 6.2 contains the MIDP version of the terminal program, and Listing 6.3 shows the PDAP version.

Figure 6.4. An example PdapTerminal connection to an HTTP server using the socket protocol after sending “GET / HTTP 1.0” and an empty MidpTerminal and line.


Listing 6.2. MidpTerminal.java—The MIDP Terminal Application for Using Different Protocols in the Same Application
import java.io.*;

import javax.microedition.midlet.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;


/** The MIDP version of a simple Terminal client */

public class MidpTerminal extends MIDlet implements CommandListener {

    /** The Handler class cares about establishing the connection and
        receiving and displaying data in the background. */

    class Handler extends Thread {

        StreamConnection connection;
        InputStream in;
        OutputStream out;
        boolean leave;


        /** Establishes a connection to the given URI */
        public Handler (String uri) throws IOException {

            connection = (StreamConnection) Connector.open
                (uri, Connector.READ_WRITE, true);

            out = connection.openOutputStream ();
            in = connection.openInputStream ();

            show ("opened: "+uri + "
");
        }

        /* Like in.read (), but additional performs telnet parameter
           negotiations */

        public int read () throws IOException {
            while (true) {
                int i = in.read ();
                if (i != 0x0ff) return i;

                int cmd = in.read ();

                if (cmd == 0x0ff)
                    return 0x0ff;

                int opt = in.read ();

                if (cmd == 0xfd || cmd == 0x0fb) {
                    out.write (0x0ff);
                    out.write (cmd == 0xfd ? 252 : 254);
                    out.write (opt);
                    out.flush ();
                }
            }
        }

        /** Main receive loop running in the background */

        public void run () {

            StringBuffer buf = new StringBuffer ();

            try {
                while (!leave) {
                    do {
                        int i = in.read ();

                        if (i == -1) disconnect ();
                        else if (i == '
' || i >= ' ')
                            buf.append ((char) i);
                    }
                    while (!leave && in.available () > 0
                        && buf.length () < 1024);
                    show (buf.toString ());
                    buf.setLength (0);
                }
            }
            catch (Exception e) {
                if (!leave) show (e.toString () + "
");
                disconnect ();
            }
        }
    }

    List incoming = new List ("MidpTerminal", Choice.IMPLICIT);

    TextBox uriField = new TextBox
        ("Connect to:", "http://www.kawt.de/", 100, TextField.ANY);

    TextBox sendField = new TextBox ("Send:", "", 100, TextField.ANY);

    Command connectCmd = new Command ("Connect", Command.SCREEN, 1);
    Command sendCmd = new Command ("Send", Command.SCREEN, 1);
    Command okCmd = new Command ("Ok", Command.OK, 1);
    Command abortCmd = new Command ("Abort", Command.CANCEL, 1);

    Handler handler = null;
    Display display;


    /** Set up user interface */

    public MidpTerminal () {
        uriField.addCommand (okCmd);
        uriField.addCommand (abortCmd);
        uriField.setCommandListener (this);
        sendField.addCommand (okCmd);
        sendField.addCommand (abortCmd);
        sendField.setCommandListener (this);

        incoming.addCommand (connectCmd);
        incoming.addCommand (sendCmd);
        incoming.setCommandListener (this);

        incoming.append ("", null);
    }

    /** Set display to the URI dialog */

    public void startApp () {
        display = Display.getDisplay (this);
        display.setCurrent (uriField);
    }


    /** Shows the given string by appending it to the
        list with respect to contained line breaks. */


    public void show (String data) {
        int i0 = data.indexOf ('
'),

        if (i0 == -1) i0 = data.length ();

        incoming.set
            (incoming.size ()-1,
             incoming.getString (incoming.size () - 1)
             + data.substring (0, i0), null);
        i0++;
        while (i0 <= data.length ()) {
            int i = data.indexOf ((char) 13, i0);
            if (i == -1) i = data.length ();
            incoming.append (data.substring (i0, i), null);
            i0 = i+1;
        }
    }
    /** Performs the action associated with the given command
        like showing dialogs, opening the connection or sending
        a string */

    public void commandAction (Command c, Displayable d) {

        try {
            if (c == connectCmd)
                display.setCurrent (uriField);
            else if (c == sendCmd && handler != null)
                display.setCurrent (sendField);
            else if (c == abortCmd)
                display.setCurrent (incoming);
            else if (c == okCmd) {
                display.setCurrent (incoming);

                if (d == sendField && handler != null) {
                    handler.out.write (sendField.getString ().getBytes ());
                    handler.out.write ('
'),
                    handler.out.write ('
'),
                    handler.out.flush ();
                    sendField.setString ("");
                }
                else if (d == uriField) {

                    disconnect ();
                    handler = new Handler (uriField.getString ());
                    handler.start ();
                }
            }
        }
        catch (Exception e) {
            show (e.toString ());
            disconnect ();
        }
    }


    public void pauseApp () {
    }
    public void disconnect () {
        if (handler != null) {
            handler.leave = true;
            show ("disconnected!
");
            try {
                handler.connection.close ();
                handler.in.close ();
                handler.out.close ();
            }
            catch (IOException e) {
            }
            handler = null;
        }
    }


    public void destroyApp (boolean unconditional) {
        disconnect ();
    }
}

Listing 6.3. PdapTerminal.java—The PDAP Terminal Application for Using Different Protocols in the Same Application
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.midlet.*;

import java.awt.*;
import java.awt.event.*;

public class PdapTerminal extends MIDlet implements ActionListener {


    /** The Handler class cares about establishing the connection and
        receiving and displaying data in the background. */

    class Handler extends Thread {

        StreamConnection connection;
        InputStream in;
        OutputStream out;
        boolean leave;
        /** Establishes a connection to the given URI */

        public Handler (String uri) throws IOException {

            connection = (StreamConnection) Connector.open
                (uri, Connector.READ_WRITE, true);

            out = connection.openOutputStream ();
            in = connection.openInputStream ();

            show ("opened: "+uri + "
");
        }


        /**  Like in.read (), but additional performs telnet
            parameter negotiations. */

        public int read () throws IOException {
            while (true) {
                int i = in.read ();
                if (i != 0x0ff) return i;

                int cmd = in.read ();

                if (cmd == 0x0ff)
                    return 0x0ff;

                int opt = in.read ();

                if (cmd == 0xfd || cmd == 0x0fb) {
                    out.write (0x0ff);
                    out.write (cmd == 0xfd ? 252 : 254);
                    out.write (opt);
                    out.flush ();
                }
            }
        }


        /** Collects incoming data in the background and
            shows it if the buffer size reaches 1 k or
            no more data is available at the moment. */

        public void run () {

            StringBuffer buf = new StringBuffer ();
            try {
                while (!leave) {

                    do {
                        int i = in.read ();

                        if (i == -1) disconnect ();
                        else if (i == '
' || i >= ' ')
                            buf.append ((char) i);
                    }
                    while (!leave && in.available () > 0
                        && buf.length () < 1024);

                    show (buf.toString ());

                    buf.setLength (0);
                }
            }
            catch (Exception e) {
                if (!leave) show (e.toString () + "
");
                disconnect ();
            }
        }
    }


    /** Class for thread safe appending of information to
        the list of incoming data */

    class Appender implements Runnable {
        String data;
        Appender (String data) {
            this.data = data;
        }

        public void run () {
            int i0 = data.indexOf ('
'),

            //System.out.println ("Adder: cr index is: "+i0);
            if (i0 == -1) i0 = data.length ();

            incoming.replaceItem
                (incoming.getItem (incoming.getItemCount () - 1)
                 + data.substring (0, i0), incoming.getItemCount ()-1);
            i0++;
            while (i0 <= data.length ()) {
                int i = data.indexOf ('
', i0);
                if (i == -1) i = data.length ();
                incoming.add (data.substring (i0, i));
                i0 = i+1;
            }
        }
    }


    Frame frame = new Frame ();
    TextField urlField = new TextField ("");
    List incoming = new List ();
    TextField sendField = new TextField ();

    Button connectButton = new Button ("connect");
    Button sendButton = new Button ("send");


    Handler handler;


    /** Initializes GUI */

    public PdapTerminal () {
        frame = new Frame ("GcfTerminal");

        frame.addWindowListener (new WindowAdapter () {
                public void windowClosing (WindowEvent e) {
                    destroyApp (true);
                    notifyDestroyed ();
                }
            });

        connectButton.addActionListener (this);

        Panel topPanel = new Panel (new BorderLayout ());
        //topPanel.add ("West", protocolChoice);
        topPanel.add ("Center", urlField);
        topPanel.add ("East", connectButton);

        sendButton.addActionListener (this);

        Panel bottomPanel = new Panel (new BorderLayout ());
        bottomPanel.add ("Center", sendField);
        bottomPanel.add ("East", sendButton);

        frame.add ("North", topPanel);
        frame.add ("Center", incoming);
        frame.add ("South", bottomPanel);

        frame.pack ();
    }


    /** Shows the given string thread safe by handing a new Appender
        to invokeLater */

    public void show (String s) {
        try {
            Toolkit.getDefaultToolkit ().getSystemEventQueue ()
                .invokeAndWait (new Appender (s));
        }
        catch (Exception e) {
            throw new RuntimeException (e.toString ());
        }
    }


    /** Shows the main frame on the device screen */

    public void startApp () {
        frame.show ();
    }


    /** Handles the buttons by opening a connection or sending text */

    public void actionPerformed (ActionEvent event) {

        try {
            if (event.getSource () == sendButton && handler != null) {
                handler.out.write (sendField.getText ().getBytes ());
                handler.out.write ('
'),
                handler.out.write ('
'),
                handler.out.flush ();
                sendField.setText ("");
            }
            else if (event.getSource () == connectButton) {
                disconnect ();
                handler = new Handler (urlField.getText ());
                handler.start ();
            }
        }
        catch (Exception e) {
            incoming.add (e.toString ());
            incoming.add ("");
            disconnect ();
        }
    }


    /** Closes the connection if any */

    public void disconnect () {
        if (handler != null) {
            handler.leave = true;
            show ("disconnected!
");
            try {
                handler.connection.close ();
                handler.in.close ();
                handler.out.close ();
            }
            catch (IOException e) {
            }
            handler = null;
        }
    }


    public void pauseApp() {
    }
    public void destroyApp (boolean unconditional) {
        disconnect ();
        frame.setVisible (false);
    }

A Simple HTTP-Based Client-Server Chat Application

In addition to the telnet client, we would like to show you how to build a “real” client-server application, where the server runs on a desktop computer, and the CLDC device takes over the role of the client. To keep things simple, we have chosen a chat application as an example. The idea is that you can connect to a server, see the messages from other people connected to the same server, and write your own messages that become visible to the other users. Because HTTP is the only protocol available for all devices, we will use HTTP as the communication protocol for our application. However, using HTTP includes a significant drawback: HTTP does not provide server initiated transmissions, so the clients need to connect to the server and to “poll” for new data from time to time. It might be possible to work around this limitation by keeping an HTTP connection open for each client and to forward data to all connected clients automatically. However, it might be possible that the gateway used by the device for HTTP access does not support this, so we will stick to polling here.

In order to allow the clients to receive only their new messages, all messages have an unique number, which is managed by a simple server-sided counter. Thus, the client can submit the number of the newest message it has already received, and the server will send only newer messages that have higher numbers assigned. If no number is given, the server will just send the 10 most recent messages.

Thus, we can define the following behaviors for reading:

  • Client—Sends a request of type GET.

  • Server—First it sends a line containing the number that will be assigned to the next message. Then, if the URL is of the form /?start=N, a list of all messages, starting with message number N, is transmitted. For all other URLs, the last 10 messages are submitted. All items are separated by a pair of carriage return and linefeed control characters ( ).

For submitting text, you will use the HTTP POST command with an identical URL, but you will also send the nickname and the text in the body of the request. In return, the server sends the same content as for the GET command:

  • Client—Sends a request of type POST.

  • Server—Sends the same reply as for the GET command. The text just sent by the client is included in the list of messages. Thus, at least one message is sent.

J2SE Chat Server

Now that we have defined the communication protocol, we can start with implementing a corresponding server.

The server depends on the java.io and java.net packages. It stores the number of the current message, a buffer for text, and a J2SE server socket in member variables:

import java.io.*;
import java.net.*;

public class ChatServer {
int current = 0;
String [] lines = new String [256];
ServerSocket serverSocket;

The constructor of the server gets a port number as input and creates a corresponding server socket:

public ChatServer (int port) throws IOException {
    serverSocket = new ServerSocket (port);
    System.out.println ("Serving port: "+port);
}

The run() method of the server contains a loop that waits for incoming connections. When a request is accepted, a buffered reader and a writer corresponding to input and output streams associated with the connection are handed over to the handleRequest() method. Usually, the actual handling of the request would be performed in a separate thread, enabling the server to handle new requests immediately. However, in order to keep the server as simple as possible, you handle the request in the current thread, blocking new requests for the corresponding amount of time:

public void run () {
    while (true) {
        try {
            Socket socket = serverSocket.accept ();
            handleRequest (new BufferedReader
                (new InputStreamReader (socket.getInputStream ())),
                           new OutputStreamWriter (socket.getOutputStream ()));
            socket.close ();
        }
        catch (Exception e) {
            e.printStackTrace (System.err);
        }
    }
}

The main functionality of the chat server is performed in the handleRequest() method. It gets the socket reader and writer as input from the run() method. At first, it reads the HTTP request line from the client and prints it to system.out:

public void handleRequest (BufferedReader reader,
                           Writer writer) throws IOException {

    String request = reader.readLine ();
    System.out.println ("handling: "+request);

The next step is to analyze the request line. For that purpose, it is divided into the method, the requested address, and the version part, which are separated by space characters:

int s0 = request.indexOf (' '),
int s1 = request.indexOf (' ', s0+1);

String method = request.substring (0, s0);
String url = request.substring (s0+1, s1);

Now, the first line to be submitted is determined by analyzing the request URL:

int start = -1;  // default;
int cut = url.indexOf ("?start=");

if (cut != -1)
    start = Integer.parseInt (url.substring (cut+7));
if (start < 0) start = count – 10;

Additional header lines are skipped by reading from the stream until an empty line or the end of the stream is reached. An empty line marks the end of the HTTP headers and the beginning of the content of the request:

while (true) {
    String s = reader.readLine ();
    System.out.println ("header: "+s);
    if (s == null || s.length () == 0) break;
}

Now, if the HTTP-Request method is POST, the nickname and the sender are read from the HTTP content. A corresponding string is appended to the message ring buffer of the server:

if (method.equalsIgnoreCase ("post")) {

    String nick = reader.readLine ().substring (5);
    String text = reader.readLine ().substring (5);

    System.out.println ("nick="+nick);
    System.out.println ("text="+text);

    lines [(current++) % lines.length] = nick + ": "+ text;

    // skip possible additional crlf from bad http implementations
    if (reader.ready ()) reader.readLine ();
}

Finally, an HTTP OK status report is sent back to the client, together with the number that will be assigned to the next incoming messages, and the list of messages that was requested by the client:

    writer.write ("HTTP/1.0 200 OK
");
    writer.write ("Content-Type: text/plain
");

    writer.write ("Connection: close
");

    // Header is separated from content by a blank line.
    writer.write ("
");

    writer.write (""+current+"
");

    if (start < current - lines.length) start = current - lines.length;
    if (start < 0) start = 0;

    for (int i = start; i < current; i++) {
        writer.write (lines [i % lines.length]);
        writer.write ("
");
    }
            writer.close ();
}

The main method of the chat server sets up the server listening to the port given as the command-line parameter. If no port number was given, it defaults to port 8080:

    public static void main (String [] argv) throws IOException {

        if (argv.length == 0)
            new ChatServer (8080).run ();
        else if (argv.length == 1)
            new ChatServer (Integer.parseInt (argv[0])).run ();
        else
            System.out.println ("Usage: java ChatServer [port]");
    }
}
						

Note

The Java Servlet API provides better support for implementing HTTP-based server applications than using raw sockets. However, we did not want to introduce an additional dependency for this example application.


MIDP and PDAP Chat Clients

Now, you have developed a simple HTTP based chat server. You can test it using a simple Web browser. By starting the server on the local machine and pointing a Web browser to the address http://localhost:8080, you can get a list of the 10 most recent messages. This list will probably be empty, but you can use a very simple HTML page to send messages to the server:

<html><head><title>Chat Server Test</title></head>
<body>
 <form target="main" method="post"
       action="http://localhost:8080/"
       enctype="text/plain">

  <table>
    <tr><td>Nickname:</td><td><input name="nick" /></td></tr>
    <tr><td>Text:</td><td><input size="80" name="text" /></td></tr>
   </table>
   <input value="Submit Text" type="submit" />
  </form>
 </body>
</html>

However, the main idea is to use J2ME devices as clients for the chat server. Listings 6.4 and 6.5 contain the MIDP and PDAP versions of the chat client. Again, the main task is performed in the transmit method in both cases, which sends a new string to the server and updates the display of the client with the messages received from the server.

The transfer method is called from two points in the program:

  • From the event handler when the user requests to send some text. In that case, the string to be submitted to the server is given as a parameter.

  • Periodically from a refresh task every four seconds with null as a parameter, in order to keep the message display of the client updated.

The transfer method takes the string to be sent to the server as parameter, or null if the local list of messages should only be updated from the server without sending a new message. Depending on this parameter, a HTTP connection is opened in READ or READ_WRITE mode. The URI is constructed from the hostname that was queried by the user interface and stored in the host variable and the start parameter, denoting from which message number the server should start sending. The count variable is initialized with the value -1, so for the first request, the server will send back the 10 most recent messages. The count variable is updated later in this method from the response of the server. Because IO exceptions might be thrown during the connection, you include the whole method in a try-catch block. The Boolean return value indicates whether the transfer was performed successfully:

boolean transfer (String submit) { // if null, just read
    try {
        HttpConnection connection = (HttpConnection) Connector.open
            (host + "/?start="+count,
             submit != null ? Connector.READ_WRITE : Connector.READ);

If submit is not null, a corresponding writer is obtained from the HTTP connection, and the method is set to POST. Then, the message stored in the submit variable is submitted as content of the request:

Writer writer = null;

if (submit != null) {
    connection.setRequestMethod (HttpConnection.POST);
    writer = new OutputStreamWriter
        (((StreamConnection) connection).openOutputStream ());
    writer.write ("nick="+nick + "
");
    writer.write ("text="+submit+"
");
        writer.close ();
}

Now you open a reader in order to read the new messages submitted with the reply from the server:

Reader reader = new InputStreamReader
    (((StreamConnection) connection).openInputStream ());

First, you read the new count value, denoting the number that will be assigned to the next message arriving at the server. This value is important in order to know where to start the next request. readLine() is a static method of this class that reads a line from the given reader:

count = Integer.parseInt (readLine (reader));

Now you read the messages submitted by the server until you reach the end of the stream:

while (true) {
    String s = readLine (reader);
    if (s == null || s.length () == 0) break;
    addLine (s);
}

Next, you close the readers and the corresponding connection. Also, you return true in order to indicate that the transfer was performed successfully:

                    reader.close ();
    connection.close ();
    return true;
}

Finally, if an exception occurred in the connection, you add the corresponding error string to the display, and then call the disconnect() method which stops the timer that ensures the display is updated periodically. A false value is returned in order to indicate that an exception has occurred:

    catch (Exception e) {
        addLine (e.toString ());
        disconnect ();
        return false;
    }
}

The only other part of the application relevant for communications is RefreshTask:

class RefreshTask extends TimerTask {
    public void run () {
      transfer (null);
    }
}

When a connection is established, it is launched with parameters to request an update of the messages from the server every four seconds:

timer = new Timer ();
timer.schedule (new RefreshTask (), 0, 4000);

Figure 6.5 shows emulated MIDP and PDAP clients connected to a local chat server. Note that the resulting chat application is minimalistic. For example, it does not check if two different users are using the same nickname. The application is intended to show the basic HTTP functionality only. Feel free to extend or change the application as you like for your own purposes.

Figure 6.5. Emulated MIDP and PDAP clients connected to a local chat server.


Listing 6.4. MidpChat.java—A MIDP Chat Client Using the HTTP Protocol to Communicate with the Server
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;

import java.util.*;
import java.io.*;

public class MidpChat extends MIDlet implements CommandListener {

    List list = new List ("MidpChat", Choice.IMPLICIT);
    TextBox text = new TextBox ("Chat Text", "", 100, TextField.ANY);

    int count = -1;
    Timer timer;

    String host = "http://localhost:8080";
    String nick = "guest";

    Display display;

    Command write = new Command ("Write", Command.OK, 1);
    Command submit = new Command ("Submit", Command.OK, 1);
    Command cancel = new Command ("Cancel", Command.BACK, 1);

    class RefreshTask extends TimerTask {

        public void run () {
            if (display.getCurrent () == list)
                transfer (null);
        }
    }

    class ConfigForm extends Form implements CommandListener {

        TextField hostField =
            new TextField ("Host:", host, 50, TextField.ANY);
        TextField nickField =
            new TextField ("Nickname:", nick, 50, TextField.ANY);
        Command connectCommand = new Command ("Connect", Command.OK, 1);
        Command abortCommand = new Command ("Abort", Command.BACK, 1);

        ConfigForm () {
            super ("Configuration");
            append (hostField);
            append (nickField);
            addCommand (connectCommand);
            addCommand (abortCommand);
            setCommandListener (this);
        }

        public void commandAction(Command c, Displayable d) {
            if (c == connectCommand) {
                host = hostField.getString ();
                nick = nickField.getString ();
                connect ();
            }
            display.setCurrent (list);
        }
    }

    static String readLine (Reader reader) throws IOException {
        StringBuffer buf = new StringBuffer ();
        while (true) {
            int c = reader.read ();
            if (c == -1) {
                if (buf.length () == 0) return null;
                break;
            }
            if (c == 10) break;
            if (c != 13) buf.append ((char) c);
        }
        return buf.toString ();
    }

    public MidpChat () {
        list.addCommand (write);
        list.setCommandListener (this);
        text.addCommand (submit);
        text.addCommand (cancel);
        text.setCommandListener (this);
    }

    public void startApp () {
        display = Display.getDisplay (this);
        if (timer == null)
            configure ();
        else
            display.setCurrent (list);
    }
    void configure () {
        disconnect ();
        display.setCurrent (new ConfigForm ());
    }

    void connect () {
        disconnect ();
        if (transfer (null)) {
            timer = new Timer ();
            timer.schedule (new RefreshTask (), 0, 4000);
        }
    }

    void addLine (String line) {
        list.append (line, null);
    }

    void disconnect () {
        if (timer != null) {
            timer.cancel ();
            timer = null;
        }
    }

    boolean transfer (String submit) { // if null, just read
        try {
            HttpConnection connection = (HttpConnection) Connector.open
                (host + "/?start="+count,
                 submit != null ? Connector.READ_WRITE : Connector.READ);

            Writer writer = null;

            if (submit != null) {
                connection.setRequestMethod (HttpConnection.POST);
                writer = new OutputStreamWriter
                    (((StreamConnection) connection).openOutputStream ());
                writer.write ("nick="+nick + "
");
                writer.write ("text="+submit+"
");
                writer.close ();
            }

            Reader reader = new InputStreamReader
                (((StreamConnection) connection).openInputStream ());
            count = Integer.parseInt (readLine (reader));
            while (true) {
                String s = readLine (reader);
                if (s == null || s.length () == 0) break;
                addLine (s);
            }

            reader.close ();
            connection.close ();
            return true;
        }
        catch (Exception e) {
            addLine (e.toString ());
            disconnect ();
            return false;
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c == write) {
            display.setCurrent (text);
        }
        else {
            if (c == submit) {
                transfer (text.getString ());
                text.setString ("");
            }
            display.setCurrent (list);
        }
    }

    public void pauseApp () {
    }

    public void destroyApp (boolean unconditional) {
        disconnect ();
    }
}

Listing 6.5. PdapChat.java—A PDAP Chat Client Using the HTTP Protocol to Communicate with the Server
import java.io.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.microedition.io.*;

import javax.microedition.midlet.*;


public class PdapChat extends MIDlet implements ActionListener, Runnable {

    Frame frame = new Frame ("PdapChat");
    java.awt.List list = new java.awt.List ();
    TextField text = new TextField ();
    Button configButton = new Button ("Config");
    Button submitButton = new Button ("Submit");

    int count = -1;
    Timer timer;
    String host = "http://localhost:8080";
    String nick = "guest";

    class ConfigDialog extends Dialog implements ActionListener {
        TextField hostField = new TextField (host);
        TextField nickField = new TextField (nick);
        Button connectButton = new Button ("Connect");
        Button abortButton = new Button ("Abort");

        ConfigDialog () {
            super (frame, "Configuration", true);
            Panel labels = new Panel (new GridLayout (0, 1));
            Panel fields = new Panel (new GridLayout (0, 1));
            Panel buttons = new Panel ();

            add ("West", labels);
            add ("Center", fields);
            add ("South", buttons);

            labels.add (new Label ("host:"));
            labels.add (new Label ("nick:"));
            fields.add (hostField);
            fields.add (nickField);

            connectButton.addActionListener (this);
            buttons.add (connectButton);
            abortButton.addActionListener (this);
            buttons.add (abortButton);
            pack ();
        }
        public void actionPerformed (ActionEvent ev) {
            if (ev.getSource () == connectButton) {
                host = hostField.getText ();
                nick = nickField.getText ();
                connect ();
            }
            setVisible (false);
        }
    }

    class RefreshTask extends TimerTask {
        public void run () {
            try {
                Toolkit.getDefaultToolkit ()
                    .getSystemEventQueue ()
                    .invokeAndWait (new Runnable () {
                            public void run () {
                                transfer (null);
                            }
                        }
                );
            }
            catch (Exception e) {
            }
        }
    }

    static String readLine (Reader reader) throws IOException {
        StringBuffer buf = new StringBuffer ();
        while (true) {
            int c = reader.read ();
            if (c == -1) {
                if (buf.length () == 0) return null;
                break;
            }
            if (c == '
') break;
            if (c != '
') buf.append ((char) c);
        }
        return buf.toString ();
    }

    public PdapChat () {
        frame.add ("Center", list);
        Panel input = new Panel (new BorderLayout ());
        frame.add ("South", input);
        input.add ("Center", text);
        Panel buttons = new Panel ();
        input.add ("South", buttons);
        buttons.add (submitButton);
        buttons.add (configButton);
        submitButton.addActionListener (this);
        configButton.addActionListener (this);

        frame.addWindowListener (new WindowAdapter () {
                public void windowClosing (WindowEvent e) {
                    destroyApp (true);
                    notifyDestroyed ();
                }
            });
        frame.pack ();
    }

    void configure () {
        disconnect ();
        new ConfigDialog ().show ();
    }

    void connect () {
        disconnect ();
        if (transfer (null)) {
            timer = new Timer ();
            timer.schedule (new RefreshTask (), 0, 4000);
        }
    }

    void disconnect () {
        if (timer != null) {
            timer.cancel ();
            timer = null;
        }
    }

    /** implementation of runnable */

    public void run () {
        transfer (null);
    }
    boolean transfer (String submit) { // if null, just read
        try {
            HttpConnection connection = (HttpConnection) Connector.open
                (host + "/?start="+count, submit != null
                    ? Connector.READ_WRITE : Connector.READ);
            Writer writer = null;
            if (submit != null) {
                connection.setRequestMethod (HttpConnection.POST);
                writer = new OutputStreamWriter
                    (((StreamConnection) connection).openOutputStream ());
                writer.write ("nick="+nick + "
");
                writer.write ("text="+submit+"
");
                                          writer.close ();
            }

            Reader reader = new InputStreamReader
                (((StreamConnection) connection).openInputStream ());
            count = Integer.parseInt (readLine (reader));
            while (true) {
                String s = readLine (reader);
                if (s == null || s.length () == 0) break;
                addLine (s);
            }
                                    reader.close ();
            connection.close ();
            return true;
        }
        catch (Exception e) {
            addLine (e.toString ());
            disconnect ();
            return false;
        }
    }

    public void addLine (String l) {
        list.add (l);
    }

    public void actionPerformed (ActionEvent event) {
        if (event.getSource () == configButton)
            configure ();
        else {
            transfer (text.getText ());
            text.setText ("");
        }
    }

    public void startApp () {
        frame.show ();
        if (timer == null) configure ();
    }

    public void destroyApp (boolean unconditional) {
        frame.setVisible (false);
        disconnect ();
    }

    public void pauseApp() {
    }
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset