Wednesday, April 6, 2011

Http Connecton in J2ME
There is 1 class (Connector) and 7 connection interfaces (Connection, ContentConnection, DatagramConnection, InputConnection, OutputConnection, StreamConnection, and StreamConnectionNotifier) defined in the Generic Connection framework. They can be found in the javax.microedition.io package that comes with J2ME CLDC. Please note that there is no implementation of the connection interfaces at the CLDC level. The actual implementation is left to MIDP.

The 7 connection interfaces define the abstractions of 6 basic types of communications: basic serial input, basic serial output, datagrams communications, sockets communications, notification mechanism in a client-server communication, and basic HTTP communication with a Web server.

The relationships between these interfaces are illustrated in the following diagram:



As shown in the figure, Connection is the base interface and the root of the connection interface hierarchy. All the other connection interfaces derive from Connection. StreamConnection derives from InputConnection and OutputConnection. It defines both the input and output capabilities for a stream connection. ContentConnection derives from StreamConnection. It adds three additional methods from MIME handling on top of the I/O methods in StreamConnection.

The Connector class is the core of Generic Connection framework. The reason we say that is because all connection objects we mentioned above are created by the static method open defined in Connector class. Different types of communication can be created by the same method with different parameters. The connection could be file I/O, serial port communication, datagram connection, or an http connection depending on the string parameter passed to the method. Such design makes J2ME implementation very extensible and flexible in supporting new devices and products.

Here is how the method is being used:


Connector.open(String connect);

The parameter connect_is a String variable. It has a URL-like format: {protocol}:[{target}][{params}] and it consists of three parts: protocol, target, and params.

protocol dictates what type of connection will be created by the method. There are several possible values for protocol: file, socket, comm, datagram and http. file indicates that the connection will be used for file I/O, comm indicates that the connection will be used for serial port communication, and http indicates that the connection is created for accessing web servers.

target can be a host name, a network port number, a file name, or a communication port number.

params is optional, it specifies the additional information needed to complete the connect string.

The following examples illustrate how to use the open method to create different types of communication based on different protocols:


HTTP communication:


Connection hc = Connector.open("http://www.wirelessdevnet.com");
Stream-based Socket communication:


Connection sc = Connector.open("socket://localhost:9000");
Datagram-based socket communication:

Connection dc = Connector.open("datagram://:9000");
Serial port communication:

Connection cc = Connector.open("comm:0;baudrate=9000");
File I/O

Connection fc = Connector.open("file://foo.dat");

The HttpConnection Class

The HttpConnection class is defined in J2ME MIDP to allow developer to handle http connections in their wireless applications. The HttpConnection class is guaranteed available on all MIDP devices.

Theoretically you may use either sockets, or datagrams for remote communication in your J2ME applications if your MIDP device manufacturer supports them. But this creates a portability issue for your applications, because you can’t always count on that other device manufacturers will support them as well. This means that your program may run on one MIDP device but fail on others. So you should consider using the HttpConnection class in your application first, because HTTPConnection is mandatory for all MIDP implementations.

In this section, a complete sample program using HttpConnection is shown in the next section.

The HttpConnection interface derives from the ContentConnection interface in CLDC. It inherits all I/O stream methods from StreamConnection, all the MIME handling methods from ContentConnection and adds several additional methods for handling http protocol specific needs.

Here is a laundry list of all the methods available in HttpConnection:

Input Stream and OutputStream

An input stream can be used to read contents from a Web server while output stream can be used to send request to a Web server. These streams can be obtained from the HttpConnection object after the connection has been established with the Web Server. In the following example, an http connection is established with Web server www.wirelessdevnet.com at port 80 (the default http port). Then an input stream is obtained for reading response from the Web:

HttpConnection hc = (HttpConnection);
Connector.open("http://www.wirelessdevnet.com");
InputStream is = new hc.openInputStream();
int ch; // Check the Content-Length first
long len = hc.getLength();
if(len!=-1)
{

for(int i = 0;i<len;i++)

if((ch = is.read())!= -1)
System.out.print((char) ch));
}
else
{
// if the content-length is not available
while ((ch = is.read()) != -1)

System.out.print((char) ch));
}
is.close();
hc.close();
The below sample code is for sending the bulky data over network by using StringBuffer

SAMPLE CODE


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
 
public class Sample1 extends MIDlet
        implements CommandListener {
/*
* the default value for the URL string is
* http://www.webyu.com/servlets/webyu/wirelessdevnetsample1
*/
 
private static String defaultURL = 
"http://www.webyu.com/servlets/webyu/wirelessdevnetsample1";
 
// GUI component for user to enter String
private Display myDisplay = null;
private Form mainScreen;
private TextField requestField;
 
// GUI component for displaying header information
private Form resultScreen;
private StringItem resultField;
 
// the "SEND" button used on the mainScreen
Command sendCommand = new Command("SEND", Command.OK, 1);
 
// the "BACK" button used on the resultScreen
Command backCommand = new Command("BACK", Command.OK, 1);
 
public Sample1(){
        // initializing the GUI components for entering Web URL
        myDisplay = Display.getDisplay(this);
        mainScreen = new Form("Type in a string:");
        requestField = 
               new TextField(null, "GREAT ARTICLE", 100, TextField.ANY);
        mainScreen.append(requestField);
        mainScreen.addCommand(sendCommand);
        mainScreen.setCommandListener(this);
}
 
public void startApp() {
        myDisplay.setCurrent(mainScreen);
}
 
public void pauseApp() {
}
 
public void destroyApp(boolean unconditional) {
}
 
public void commandAction(Command c, Displayable s) {
        if (c == sendCommand) {
               // retrieving the String that user entered
String requeststring = requestField.getString();
               // sending a POST request to Web server
               String resultstring = sendPostRequest(requeststring);
               // displaying the response back from Web server
               resultScreen = new Form("Result String:");
               resultField = new StringItem(null, resultstring);
               resultScreen.append(resultField);
               resultScreen.addCommand(backCommand);
               resultScreen.setCommandListener(this);
               myDisplay.setCurrent(resultScreen);
        } else if (c == backCommand) {
               // do it all over again
               requestField.setString("SOMETHING GOOD");
               myDisplay.setCurrent(mainScreen);
        }
}
 
// send a POST request to Web server
public String sendPostRequest(String requeststring) {
        HttpConnection hc = null;
        DataInputStream dis = null;
        DataOutputStream dos = null;
        StringBuffer messagebuffer = new StringBuffer();
        try {
               // Open up a http connection with the Web server
               // for both send and receive operations
               hc = (HttpConnection)
               Connector.open(defaultURL, Connector.READ_WRITE);
               // Set the request method to POST
               hc.setRequestMethod(HttpConnection.POST);
               // Send the string entered by user byte by byte
               dos = hc.openDataOutputStream();
               byte[] request_body = requeststring.getBytes();
               for (int i = 0; i &lt; request_body.length; i++) {
                       dos.writeByte(request_body[i]);
               }
               dos.flush();
               dos.close();
               // Retrieve the response back from the servlet
               dis = new DataInputStream(hc.openInputStream());
               int ch;
               // Check the Content-Length first
               long len = hc.getLength(); 
               if(len!=-1) {
                       for(int i = 0;i<len;i++)
                               if((ch = dis.read())!= -1)
                                      messagebuffer.append((char)ch);
                               } else {
                                      // if the content-length is not available
                                      while ((ch = dis.read()) != -1)
                                              messagebuffer.append((char) ch);
                               }
               }
        dis.close();
        } catch (IOException ioe) {
               messagebuffer = new StringBuffer("ERROR!");
        } finally {
               // Free up i/o streams and http connection
               try { 
                       if (hc != null) hc.close();
               } catch (IOException ignored) {}
               try { 
                       if (dis != null) dis.close();
               } catch (IOException ignored) {}
               try { 
                       if (dos != null) dos.close();
               } catch (IOException ignored) {}
        }
        return messagebuffer.toString();
}
 
}



To store and retrieve record from J2ME RecordStore (J2ME Database Program)

J2ME record management store

The Mobile Information Device Profile -- the platform for mobile Java applications -- provides a mechanism for MIDP applications to persistently store data across multiple invocations. This persistent storage mechanism can be viewed as a simple record-oriented database model and is called the record management system (RMS). Here, Manish Pathak shows how your J2ME application can use RMS to manage and interpret data. You'll also get a demonstration of the concept through a sample phone database. 

The J2ME 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. An overview of J2ME RMS and MIDlet interfacing is given in Figure 1.

Figure 1. Overview of J2ME RMS and MIDlet interfacing

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 making its best effort to maintain the integrity of the MIDlet's record stores throughout the normal use of the platform, including reboots, battery changes, etc.
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 that uses the standard OS data manager functions 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. The record store 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.
When a MIDlet uses multiple threads to access a record store, it is the MIDlet's responsibility to coordinate this access; if it fails to do so, unintended consequences may result. Similarly, if a platform performs a synchronization of a record store with multiple threads trying to access the record store simultaneously, it is the platform's responsibility to enforce exclusive access to the record store between the MIDlet and its synchronization engine.
Each record in a record store is an array of bytes and has a unique integer identifier.

Managing the device database

The javax.microedition.rms.RecordStore class represents a RMS record store. It provides several methods to manage as well as insert, update, and delete records in a record store.

Managing record stores
To open a record store, the openRecordStore() method of javax.microedition.rms.RecordStore is invoked. public static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary) opens a record store with the given name recordStoreName. If there is no record store of that name, invoking this method creates one.
If the record store is already open, this method returns a reference to the same record store object.

Listing 1. Open a RecordStore
RecordStore rs = RecordStore.openRecordStore("MyAppointments",true);

Once all operations are done, a call to closeRecordStore() closes the record store with the given name. When a record store is closed, it is disabled for further operations.

Listing 2. Close a RecordStore
Rs.closeRecordStore();

A named record store can be deleted by invoking the deleteRecordStore() method.

Listing 3. Delete a RecordStore
RecordStore.deleteRecordStore("MyAppointments");

Inserting records
The MIDlet invokes the addRecord() method of javax.microedition.rms.RecordStore class to insert a new record into the record store. This is a blocking atomic operation and returns the recordId for the new record. The record is written to persistent storage before the method returns.
public int addRecord(byte[] data, int offset, int numBytes) inserts a record represented by an array of bytes data with offset as its starting index and numBytes as its length.

Listing 4. Insert a record
String appt = "new record";
byte bytes[] = appt.getBytes();
rs.addRecord(bytes,0,bytes.length);

Updating records
Updating a particular record involves getting a handle for that record and setting new information.
public int getRecord(int recordId, byte[] buffer, int offset) returns the data stored in the given record in the byte array represented by buffer. public byte[] getRecord(int recorded) returns a copy of the data represented by recordId. public void setRecord(int recordId, byte[] newData, int offset, int numBytes) sets new information, a stream of bytes (newData) with offset as its starting index and numBytes as its length, at the record location represented by recordId.

Listing 5. Update a record
String newappt = "update record";
Byte data = newappt.getBytes();
Rs.setRecord(1, data, 0, data.length());

Deleting records
The MIDlet invokes the deleteRecord() method to delete a record from the record store.
public void deleteRecord(int recordId) deletes the record represented by recordId. The recordId for this record is not subsequently reused.

Listing 6. Delete a record
Rs.deleteRecord(1);

Data interpretation
The J2ME API provides certain interfaces to interpret the data stored in a record store. This process involves comparing records to determine their relative sort order. It also involves the filtering of contents depending on given conditions.
Comparing records
The MIDlet implements the RecordComparator interface and defines a compare (byte[] rec1, byte[] rec2) method to compare two candidate records. The return value of this method must indicate the ordering of the two records.

Listing 7. Comparing records and determine relative sort order
Int compare (byte[] b1, byte[] b2)
{
String s1 = new String(b1);
String s2 = new String(b2);

If (s1.compareTo(s2) > 0)
     Return RecordComparator.FOLLOWS;
Else if (s1.compareTo(s2) == 0)
     Return RecordComparator.EQUIVALENT;
Else
     Return RecordComparator.PRECEDES;
}

Enumerating records

The RecordEnumeration interface is responsible for enumerating records in a record store. It logically maintains a sequence of the recordIds of the records in a record store. The enumerator will iterate over all of the records (or only a subset, if an optional record filter has been supplied) in an order determined by a record comparator. If neither the filter nor the comparator are specified, the enumeration will traverse all records in the record store in an undefined order.

Listing 8. Enumerating records
RecordEnumeration re = rs.enumerateRecords(null, null, false);
If (re.hasNextElement())
Byte nextRec[] = re.nextRecord();

Filtering records
The MIDlet implements the RecordFilter interface, defining a filter that examines a record to see if it meets application-defined criteria. The application implements the RecordFilter's match() method to select the records to be returned by the RecordEnumeration.

Listing 9. Filtering records

Public boolean matches(byte[] candidate)
{
     String s1 = new String(candidate);
     If (s1.equals("XX"))
          Returns true;
     Else
          Returns false;
}

In below code,

1-  open the connection 
2- perform the operation(store or retrieve)
3- close the connection

For  reading a record from record store ,call method as-
StorageUtility.readRecord("my_record_store",false);

For writing a record from record store ,call method  as-
 StorageUtility.readRecord("my_record_store","my_record",true);




SAMPLE CODE : StorageUtility.java


public class StorageUtility 
{
    static RecordStore tjRecordStore=null;
    static int recordId = 1;
    
    private static RecordStore getRecordStore(String recordStoreName,boolean createIFNecessary )
    {
        try  
        {
            tjRecordStore = RecordStore.openRecordStore(recordStoreName, createIFNecessary);
        }  
        catch (Exception e)  
        {
            tjRecordStore=null;
            e.printStackTrace();
        }
        return tjRecordStore;
    }
    
    private static void closeStore(RecordStore recStore)
    {
        try  
        {
            if(recStore != null)
            {
                recStore.closeRecordStore();
            }
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }
    }
    
    private static int addRecord(RecordStore recStore,String record)
    {
        byte[] data = record.getBytes();
        
        try  
        {
            recordId = recStore.addRecord(data, 0, data.length);
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }
        return recordId;
    }
    
    private static void updateRecord(RecordStore recStore,String record,int recordId)
    {
        byte[] data = record.getBytes();
        try  
        {
            recStore.setRecord(recordId, data, 0, data.length);
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }
    }
    
    private static String getRecord(RecordStore recStore,int recordId)
    {
        String recStr="";
        try  
        {
            byte[] data = recStore.getRecord(recordId);
            recStr = new String(data,0,data.length);
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }    
        return recStr;
    }
    
    private static  void deleteRecord(RecordStore recStore,int recordId)
    {
        try  
        {
            recStore.deleteRecord(recordId);
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }    
    }
    
    private static void deleteRecordStore(String recordStoreName)
    {
        try  
        {
            RecordStore.deleteRecordStore(recordStoreName);
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }    
    }
    
    public static void writeRecord(String recordStoreName,String record, boolean createIFNecessary)
    {
        tjRecordStore = getRecordStore(recordStoreName,createIFNecessary);
        addRecord(tjRecordStore,record);
        closeStore(tjRecordStore);
    }
    
    public static String readRecord(String recordStoreName,boolean createIFNecessary)
    {
        tjRecordStore = getRecordStore(recordStoreName,createIFNecessary);
        String record = getRecord(tjRecordStore,recordId);
        closeStore(tjRecordStore);
        return record;
    }
    
    public static int getNumberOfRecords(RecordStore recStore)
    {
        int records = 0;
        try  
        {
            records = recStore.getNumRecords();
        }  
        catch (Exception e)  
        {
            e.printStackTrace();
        }    
        return records;
    }
    
}