Wednesday, October 8, 2008

HTTP GET/POST from J2ME Application

For network support, J2SE defines over 100 interfaces, classes, and exceptions between the java.io and java.net packages. J2ME defines a subset of this functionality and provides a consolidated package for networking and file access in the javax.microedition.io package. Due to the wide variety of mobile devices, this package merely defines a set of interfaces, leaving the actual implementation up to each vendor.

The abstract networking and file I/O framework defined by the javax.microedition.io classes are referred to as the Generic Connection Framework (GCF). The GCF defines a set of related abstractions to represent different communication methods. The top-level abstraction is called Connection, from which six more interfaces are declared. These seven interfaces are declared as a part of J2ME's Connected Limited Device Configuration (CLDC), which is the configuration used by most Java-enabled wireless devices. This is designed to provide common networking and file I/O capabilities for all CLDC devices.

Code snippet for sending HTTP GET request to a URL is given below.

private String SendHttpGet( String url )
{
    HttpConnection hcon = null;
    DataInputStream dis = null;
    StringBuffer responseMessage = new StringBuffer();

    try
    {
        hcon = ( HttpConnection )Connector.open( url );

        // Obtain a DataInputStream from the HttpConnection
        dis = new DataInputStream( hcon.openInputStream() );

        // Retrieve response from server
        int ch;
        while ( ( ch = dis.read() ) != -1 )
        {
            responseMessage.append( (char) ch );
        }
    }        
    finally
    {
        try
        {
            if ( hcon != null )
                hcon.close();
            if ( dis != null )
                dis.close();
        } catch ( IOException ioe )
        {
            ioe.printStackTrace();
        }
    }

    return responseMessage.toString();
}

Sample code for sending HTTP POST request to a URL is given below.

private String SendHttpPost( String url, String requestString )
{
    HttpConnection hcon = null;
    DataInputStream dis = null;
    DataOutputStream dos = null;
    StringBuffer responseMessage = new StringBuffer();

    try
    {
        // Open HttpConnection with both read and write access
        hcon = ( HttpConnection )Connector.open( url, Connector.READ_WRITE );

        // Set the request method to POST
        hcon.setRequestMethod( HttpConnection.POST );

        // Obtain DataOutputStream for sending the request string
        dos = hcon.openDataOutputStream();
        byte[] request_body = requestString.getBytes();

        // Send request string to server
        for( int i = 0; i < request_body.length; i++ )
        {
            dos.writeByte( request_body[i] );
        }

        // Obtain DataInputStream for receiving server response
        dis = new DataInputStream( hcon.openInputStream() );

        // Retrieve the response from server
        int ch;
        while( ( ch = dis.read() ) != -1 )
        {
            responseMessage.append( (char)ch );
        }
    }
    finally
    {
        try
        {
            if ( hcon != null )
                hcon.close();
            if ( dis != null )
                dis.close();
            if ( dos != null )
                dos.close();
        }
        catch ( IOException ioe )
        {
            ioe.printStackTrace();
        }
    }

    return responseMessage.toString();
}

RecordStore management in J2ME Applications

The Record Management System (RMS) provides a mechanism through which MIDlets can persistently store data and retrieve it later. In a record-oriented approach, J2ME RMS comprises multiple record stores. Each record store can be visualized as a collection of records, which will remain persistent across multiple invocations of the MIDlet. The device platform is responsible for maintaining the integrity of the record stores.

A record store is created in platform-dependent locations, like nonvolatile device memory, which are not directly exposed to the MIDlets. The RMS classes call into the platform-specific native code to perform the actual database operations. Record store implementations ensure that all individual record store operations are atomic, synchronous, and serialized, so no corruption of data will occur with multiple accesses. The record store is timestamped to denote the last time it was modified. It also maintains a version, which is an integer that is incremented for each operation that modifies the contents of the record store. Versions and timestamps are useful for synchronization purposes.

The javax.microedition.rms.RecordStore class represents a RMS record store. Each record in a record store is an array of bytes and has a unique integer identifier. The openRecordStore() is used to open a record store. The record store should be opened to perform any operation in it. Sample code for opening the store is given below.

RecordStore store = RecordStore.openRecordStore(recordStoreName, true );

The second parameter determines whether to create the record store, if it does not exist.

Once all operations are done, the closeRecordStore() is called to close the record store. Also, the deleteRecordStore() can be used to delete the record store. This function accepts the name of the store as the parameter.

Sample code for inserting a record to the record store is given below:

public void createRecord(String data) throws RecordStoreException,
                                            RecordStoreFullException,
                                            RecordStoreNotFoundException,
                                            IOException

{
    ByteArrayOutputStream bout = null;
    DataOutputStream dout = null;
    RecordStore store = null;

    try
    {
        store = RecordStore.openRecordStore("RECORD_STORE_NAME", true );

        bout = new ByteArrayOutputStream();
        dout = new DataOutputStream( bout );

        dout.writeUTF( data );
        dout.flush();

        int numBytes = bout.size();
        byte[] record = bout.getByteArray();

        store.addRecord(record, 0, numBytes);
    }
    finally
    {
        try
        {
            if ( bout != null)
                bout.close();
            if (dout != null)
                dout.close();
            if (store != null)
                store.closeRecordStore();
        }
        catch (Exception ex)
        {
            /* Do Nothing */
        }
    }
}

Sample function for reading a record from the record store is given below. Each record in the record store is uniquely identified by a record number. So the calling function should have the logic for determining the record id.

public String getRecord(int recordID) throws RecordStoreNotOpenException,
                                                                    InvalidRecordIDException,
                                                                    RecordStoreException,
                                                                    IOException,
                                                                    Exception
{
    ByteArrayInputStream bin = null;
    DataInputStream din = null;
    RecordStore store = null;
    String record = "";

    try
    {
        store = RecordStore.openRecordStore("RECORD_STORE_NAME", false );

        byte[] rawData = store.getRecord(recordId);

        bin = new ByteArrayInputStream( rawData );
        din = new DataInputStream( bin );

        record = din.readUTF();
    }
    finally
    {
        try
        {
            if (bin != null)
                bin.close();
            if (din != null)
                din.close();
            if (store != null)
                store.closeRecordStore();
        }
        catch (Exception ex)
        {
            /* Do Nothing */
        }
    }

    return record;
}

Updating a particular record involves getting a handle for that record and setting new information. The setRecord() is used to update the record, which accepts the record id as one of its parameters. Similarly, the deleteRecord() is used to delete a record from the record store. This function also accepts the record id as the parameter.

One point to be noted is; since the memory available in mobile devices is limited, there is strict limitation for storage. The application should have proper logic for cleanup and data management, wherever necessary.

Send/Receive SMS from MIDlet application

The javax.wireless.messaging has good support for sending/receiving SMS from a MIDlet application. Text or binary messages can be prepared and send using a few lines of code. Sample class for sending the SMS is given below.

class SMSSender implements Runnable
{
    String destinationAddress;
    String smsPort;
    String message;

    SMSSender(String address, String port, String msg)
    {
        this.destinationAddress = address;
        this.smsPort = port;
        this.message = msg;
    }

    public void run()
    {
        //String address = "sms://" + destinationAddress + ":" + smsPort;
        String address = "sms://" + destinationAddress;

        MessageConnection smsconn = null;

        try
        {
            /** Open the message connection. */
            smsconn = (MessageConnection)Connector.open(address);

            TextMessage txtmessage =
                (TextMessage)smsconn.newMessage(MessageConnection.TEXT_MESSAGE);
            txtmessage.setAddress(address);
            txtmessage.setPayloadText(message);

            smsconn.send(txtmessage);
        }
        catch (Throwable t)
        {
            t.printStackTrace();
        }
        finally
        {
            if (smsconn != null)
            {
                try
                {
                    smsconn.close();
                } catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
        }
    }
}

For this code to work, the following packages should be imported to the MIDlet application.

import javax.microedition.io.Connector;
import javax.wireless.messaging.MessageConnection;
import javax.wireless.messaging.TextMessage;

Next, the MIDlet should have permission to send/receive SMS. This permission is granted by adding the required entries to the MIDlet-Permissions attribute in the JAD file. Sample JAD file entry is given below.

MIDlet-Permissions: javax.microedition.io.Connector.sms, javax.wireless.messaging.sms.send, javax.wireless.messaging.mms.receive

In a NetBeans project, this can be done easily from the Project Properties -> Application Descriptor. The required attribute can be added using the GUI option, as shown.

               NetBeans-J2ME-AppDescriptor

For the SMS functionality to work, the device configuration used should be CDLC-1.1 or higher and the device profile should be MIDP-2.0 or higher. In a NetBeans project, this can be set easily from Project Properties -> Platform.

Couple of important points. 1) The address can be of the form "sms://address:port". But this will not work in all devices. 2) Since the sending function works asynchronously, the code for sending SMS must be executed in a separate thread.

Receiving SMS is not as straight forward as sending it. First of all, the port number should be specified for accepting the message. While sending an SMS, it is necessary to specify the port number. The message will be delivered to the default inbox of the target device. For receiving, since the port number is to be specified, only messages arriving at that port can be processed by the MIDlet. This is because of security reasons - MIDlets are not allowed to access the default inbox. (if this is allowed, an application written with wrong intention can scan the user's inbox and it will be possible to extract personal information easily). One major problem here is; many devices will not support specifying port number for sending messages. Sample code for receiving SMS is given below.

class SMSReceiver implements Runnable, MessageListener
{
    String portNumber = "";
    MessageConnection conn = null;
    boolean finished = false;

    SMSReceiver(String portNo)
    {
        portNumber = portNo;
    }

    public void run()
    {
        if (conn == null)
        {
            try
            {
                conn = (MessageConnection)Connector.open("sms://:" + portNumber);
                conn.setMessageListener(this);
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }

        try
        {
            while (!finished)
            {
                Message msg = conn.receive();
                if ( msg != null )
                {
                    if (msg instanceof TextMessage)
                    {
                        this.processMessage(msg);
                    }
                    else if (msg instanceof BinaryMessage)
                    {
                        /* Binary message */
                    }
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }

    public void notifyIncomingMessage(MessageConnection conn)
    {
        /* Add code for notification handling */
    }

    public void stopListening()
    {
        finished = true;
    }

    private void processMessage(Message msg)
    {
        /* Add message processing code */
    }
}

When new message arrive at the listening port, notifyIncomingMessage() will be invoked automatically. receive() is a blocking call and so, code for listening for message should be written in a separate thread.

One last point; when this application is executed in the simulator, it will ask permission to use text message functionality.

                                                             Confirmation

This is because the code is in untrusted domain, by default. To avoid this confirmation message, code should be signed with a valid certificate. This process will create the necessary entries in the JAD file and the application will be able to use text message service, without the need of user intervention. Some of the devices like Nokia 6600 will accept unsigned applications, but this is not the case with many other device manufacturers. In the simulator, it will be possible to switch to the trusted or manufacturer domain. But to sign the code for the real device, we need to get the signature from a service provider such as VeriSign or Thawte.

Tuesday, April 8, 2008

Example programs - Set II

Click on the below link to download second set of Java example programs.

Java Example Programs - Set II

Use javac for compiling the programs. Applet programs are executed using the appletviewer command. For this, the applet tag should be present either as a comment in the Java source file or as a separate HTML file. The ZIP archive contains three JPG files, an AU file and an HTML file. These files must be present in the same directory.

Few very useful links...

1. Java programming articles, examples and tips

http://www.javafaq.nu/index.php

2. Free ebooks

http://redhotjava.com

3. Java Examples

http://www.exampledepot.com

4. Java Documentation in Windows Help format

http://www.allimant.org/javadoc/index.php

Friday, February 29, 2008

Example programs - Set I

Download the first set of simple example programs from the below link.
All are simple, console based applications. Use javac for compilation and java for execution. If you have any difficulty in setting up the development environment, check the section of this blog that describes about that topic.

Thursday, February 28, 2008

Setting up the development environment

Let me explain the basics of how to setup a good development environment for Java. You need an idea about this and the pattern is in contrast to the Microsoft products, which are really developer friendly.
To start with; let me try to solve an issue that most beginners face. The question is simple - to learn Java, what software package to download? If you search in the Net or go to the home page of Sun, you will be really confused. You can see so many terms - JDK, J2SE, Java SE, J2EE, Java EE, J2ME etc. Let me explain these terms (packages) in simple terms. (I presume that you know something about JRE - the runtime environment and also about SDK - Software Developer Kit - a term which is commonly used).
JDK - JDK is the acronym for Java Development Kit. This is the right package if you want to develop or just compile simple Java programs [ie .java to .class and if necessary, package as .jar]. In simple terms, if you just want to be able to "run" Java applications, you just need the Java Runtime Environment (JRE). If you want to develop things in Java, you need JDK.
J2SE - J2SE is an acronym for Java 2 Standard Edition. In a very broad sense, we can say that it is JDK + JRE. J2SE is considered to be the foundation edition of Java platform and programming environment in which all other editions are based. J2SE provides the essential compiler, tools, runtimes and APIs for writing, deploying and running applets and applications in the Java programming language. This is what most people need for a Servlet, Beans, JSP, XML, JDBC, Web Application or Swing desktop application.
Java SE - Sun decided to rename J2SE to Java SE. Thats it. It is the acronym of Java Platform, Second Edition. The new versions are given this name.
J2EE - J2EE is the edition of the Java 2 platform targeted at developing multi-tier applications. It is the acronym for Java 2 Enterprise Edition. It consists of a set of specifications, APIs and technologies defining enterprise application development. J2EE implementations enjoy all of the features of J2SE platform with additional frameworks and libraries added to support distributed/Web development. In simple terms, we can say that J2EE is an extension to J2SE, that supplies foremost server-side technologies ie. J2EE = J2SE plus RMI tools, EJB, an EJB server, and other distributed computing tools.
There's a high development overhead in using J2EE features; so don't bother unless you need them. It is complex also. For a beginner, the equation is very simple - stay away from J2EE for the time being.
Java EE - It is the new name given to J2EE. It is the acronym of Java Platform, Enterprise Edition. The name changed after J2EE 1.4. Life of the developer has become more easy now, since some of the things such as Web Services are easy to implement now.
J2ME - J2ME is the acronym for Java 2 Platform, Micro Edition. It is used for the development of software for small, resource-constrained devices such as cell phones, PDAs and set-top boxes. New version of J2ME is renamed to Java Platform, Micro Edition or Java ME.
To conclude; as a beginner, what you really want is the Java SE package. Click here to download the latest version. Install the downloaded package and you are set for Java Development.
Writing simple programs
We can write simple applications using any editor - such as Notepad. Many good editors are available. Some of them are listed below.
1. Notepad++ (Light and simple. One of my personal favorites. Free software).
2. EditPad Lite (Powerful multipurpose editor. Free. Pro version available).
3. JCreator LE (Very powerful. Pro version has features such as code completion).
4. NetBeans (Powerful and big. But resource greedy. Lot of functionality).
If you are using Notepad as the editor, you need to give the filename extension as .java and also select All Files in the Save As Type combo box. The above mentioned editors have features like syntax highlighting, which helps in quick development. But for a beginner, its better to start with Notepad itself, since you can learn many things in the hard way.
Compilation & Execution
To compile a simple Java program, the command is javac. To execute it, the command is java. For the execution of an applet program, we need an external HTML file or applet tag as comment in the source code. Simple applet programs are usually executed using the appletviewer command. On execution, if you get an error such not 'command not recognized' or 'ClassDefNotFoundException', continue reading.
Setting PATH and CLASSPATH
PATH is the environment variable where the system searches for the command (executable file name) specified in the command line. On installing Java, the commands such as javac, java etc. goes to the jdk1.X.x\bin directory. For example, on my laptop, they are in the C:\Program Files\Java\jdk1.5.0_12\bin directory (the OS is Windows XP). The working directory, where the source files are saved, maybe different such as D:\WorkArea\Java>. If we execute the javac or java command from that directory, we will get the 'command not recognized' error if the above mentioned path is not present in the environment variable PATH. We can verify this by executing the following command.
ECHO %PATH%
If the proper path is not displayed in the output of the above command, we need to set the path. We can set the path temporarily or permanently. To set the path temporarily, execute the following command in the command line. Keep in mind that location may be different in your system.
SET PATH=%PATH%;"C:\Program Files\Java\jdk1.5.0_12\bin"
When we say PATH=%PATH%, it preserves the path that is already there in the environment variable. To append the new location, we use the semicolon (;) and then the correct path. Note the double quote (") characters around the new path - it is included for safety - because there is a space in the path, in Program Files. Older operating systems, such as Windows 98 will not support this. If we specify the quotes, everything will be treated as a single string.
To set the path permanently, we need to update the PATH system variable. For that, select System Properties by right clicking My Computer and choosing Properties. Then select Environment Variables from the Advanced tab. Select the PATH variable from the System Variables list and click Edit. Move towards the end of the value given in the Variable Value text field, put a semicolon (;) and add the above mentioned path. Click OK to apply the changes. From now on, whenever a new command window is fired, the path should be set appropriately. Instructions given above are for a Windows XP machine and the same is applicable for other NT family systems such as Windows 2000 or 2003. If you are using Windows 98 or Me, you need to update the Autoexec.bat file for setting the path permanently.
CLASSPATH is specific to the Java environment. It is the location that the JRE searches for classes and other resource files. Sometimes, even if everything is correct in your program, you may get an error such as ClassDefNotFoundException while executing the Java program. This could be because of the CLASSPATH issue. Go through this link to find more about this. The method to solve this issue is mentioned under the section 'Using the CLASSPATH environment variable'. It is very similar to setting PATH. If you are confused, there is a simple thing that can be done to solve this issue. Add the current directory to the existing CLASSPATH by executing the following command.
SET CLASSPATH=%CLASSPATH%;.
Note the dot (.) at the end of the command. It represents the current directory. After the execution of this command, the JRE will start looking into the current directory also for the class file. This will solve the issue of ClassDefNotFoundException.
Just to update you, if you are using a *NX family OS such as Linux, the echo command will be echo $Path. Environment variables are represented using the $ character instead of %. Also, you should note that the commands are case sensitive in these systems.