by Mario La Menza

XML data interchange in Java ME applications

how-to
Oct 23, 200720 mins

Use XML and the DTO pattern for object serialization in JME

Learn how the Data Transfer Object design pattern is implemented in Java ME architectures and why you might want to use XML-based DTOs rather than Java beans for faster data interchange between tiers. Author Mario La Menza presents an example architecture that supports the use of XML-based DTOs and also introduces MockMe, a free tool for generating XML-based mock objects so you can test the presentation layer of your Java mobile applications without waiting for server-side data.

This article introduces the use of XML-based objects for data transport in multi-tier Java ME applications. I first explain how the DTO design pattern is commonly implemented in multi-tier Java ME architectures. I then explain the shortcomings of using Java beans as DTOs and propose using XML-based data transfer objects instead. I discuss the advantages of this approach and present an example architecture that supports using XML for data interchange. In a sidebar to this article I also introduce MockMe, a tool for generating XML-based mock objects so you can test your application’s presentation layer sooner.

The DTO pattern in Java mobile application development

Data Transfer Object is a Java enterprise design pattern for exchanging data between tiers in a multi-tier application or between components in a distributed application. Data access from a remote component often implies collecting data from more than one information source. The number of data access calls required to satisfy a request can affect the performance of the calling application or client. The purpose of the DTO pattern is to resolve the performance problems associated with distributed components remotely accessing data from business objects.

By definition, a DTO is an object created exclusively to transport data. The data, which may originate from one or more information sources, are packed into a Java bean. The bean then travels through the application locally, or (more importantly) is serialized and sent across the network. Serializing the Java bean enables clients to access model information from just one object with just one call.

Because a DTO is a Java bean, it does not usually provide business logic or validation logic of any kind. It only provides access to the bean properties. Some developers stress that the bean in a DTO pattern implementation must be immutable because its changes must not be reflected in the system. However, this obviously clashes with the JavaBeans specification, which requires all private attributes to have set and get methods.

As usual, you, the developer, have the last word, as well as the responsibility for deciding how to manage the DTO’s mutability. Whatever the case, DTOs should be considered part of your model because they are immutable copies of business objects.

Serialization in Java ME

I briefly mentioned object serialization in the DTO design pattern. Serialization is the process of transforming an object into a byte stream before sending it across a network. On arrival, the byte stream is reassembled into an object and used locally. Java ME does not support serialization or reflection (that is, the mechanism by which objects inspect themselves to discover their methods, attributes, parameters, constructors and so on). Subsequently, whatever serialization you do in your Java mobile applications must be developed ad-hoc and is subject to some restrictions — for instance, it cannot be fully automated.

To achieve serialization in Java ME, you start by creating a serializable interface with methods such as writeObject(ObjectOutputStream out) and readObject(ObjectInputStream in). You then provide the DTOs made to implement each method (a specialized implementation of each method) for each object.

For example, if you had an object with the following attributes:

Long dock;
Long bb;
Int cc;
String route;
Int x;

the methods for its serialization would be as shown in Listing 1.

Listing 1. Serialization methods

public void writeObject(ObjectOutputStream out) throws IOException{
out.writeLong(dock);
out.writeLong(bb);
out.writeInt(cc);
out.writeUTF(route);
out.writeInt(x);
}

public void readObject(ObjectInputStream in) throws IOException{
dock = in.readLong();
bb = in.readLong();
cc = in.readInt();
route = in.readUTF();
x = in.readInt();

Note that both methods use ObjectInputStream and ObjectOutputStream classes. You must create these classes because they do not exist in Java ME. ObjectInputStream and ObjectOutputStream extend from DataInputStream and DataOutputStream, respectively. They therefore have methods for adding or extracting different kinds of data from a stream, as well as their own methods for reading objects from an ObjectInputStream (readObject()) and for writing in the stream of an ObjectOutputStream (writeObject()).

See the Resources section to learn more about Java object serialization.

Using XML for data interchange in a JME architecture

While many Java mobile application developers do go the route of serializing DTOs, this approach is limited by the fact that DTOs by definition have no logic, and Java ME does not support object serialization. Without support for serialization it is not possible to make an object exchange transparent. An alternative approach is to use XML to encode the objects to be exchanged.

In addition to the fact that an object-XML-object mechanism doesn’t differ much from object serialization, it is readable by both computers and humans, unlike a serialized object. Human readability simplifies the process of debugging application code because generating different instances of the same object is just a matter of editing an XML file. Furthermore, you can use any browser to send a request to the server and observe its response. Finally, using XML for data interchange means that your application can interact with clients built using different technologies, not just Java ME but also Java Standard Edition and .Net, for example.

On the other hand, the almost universally recognized downside of using XML for data interchange is the inherent parsing processes and syntactic analysis involved. Rather than spending a lot of time on this aspect of your code, or being frustrated by Java ME’s lack of support for XML, you can use a small-memory XML parser. Examples later in this article are based on the KXML library.

I’ll briefly go over the process of developing a client-server application on the Java ME platform, after which I’ll present a sample architecture using XML for data interchange. Note that the architecture proposed in the next section is adaptable to any project and is highly scalable.

Client-server data interchange with XML

MockMe basics

MockMe is a very simple and adaptable tool that allows you to test your application client without having to wait for the service layer to become available. In complex applications this means not having to wait for data to become available for processing.

MockMe is essentially a configurable servlet based on properties files, which searches for XML files from a local directory according to a parameter passed in with a data access request. It then emulates the future server to facilitate testing. Once you have defined the XML and configured MockMe both parts can work in parallel.

If you’re interested in using MockMe to facilitate XML-based client-server development in JME, see this article’s sidebar “Get started with MockMe.”

When developing a multi-layer client-server application one of the first things you will do is define the data objects to be passed between the front-end and back-end layers. The definition of data objects is strongly conditioned by the view aspect of the client or clients in your architecture.

Once you have defined your data interchange objects you will build the services to satisfy the application’s data requirements, as well as the clients that will consume the data. (In reality many of these tasks would be allocated between front-end engineers and back-end engineers, but I’ll keep the discussion simple.) At this point what usually happens is that the presentation layer cannot be tested until the business layer has been developed. One way to get around this, and test your presentation layer sooner, is to use mock XML objects. (See the “MockMe basics” sidebar to learn about a tool that can help you test your application’s presentation layer sooner.)

Separation of objects

Partly due to the requirement that DTOs be immutable and partly as a matter of neatness and organization, it is a good idea to have two types of data objects in your client-server architecture: local objects and DTOs. For example, if you used a Person object internally and needed to send its data beyond the JVM, you would want to create a PersonDTO, which would be the version of Person that would circulate across the network. To put it differently: if the server sent your client a Person object in XML format, you would want the client to process it and send back a PersonDTO object. The conversion, based on using XML as the mechanism for data interchange, would be as follows:

On receiving: XML --> Object
To send Object --> XML

Figure 1 further visualizes the conversion of a server-side object to XML, followed by its passage through the client, where it is re-defined as a DTO.

Patterns for client-side development

MVC (Model-View-Controller) is one of the most important patterns for achieving a solid client architecture. For more complex models, where several subsystems are used, it is sometimes useful to combine MVC with the Facade pattern. In the next sections I’ll briefly discuss how these patterns can be adapted to the JME environment, then show you the example client architecture for JME.

The MVC pattern

In a MIDlet implementation, MVC basically consists of a factotum class (the controller) that generates views by calling model services. These services can, in turn, be hidden behind a Facade object. You would usually create this type of object from the startApp() method of the MIDlet, passing it a reference to the MIDlet itself as a parameter. The Controller then uses this reference to obtain a Display object for rendering views.

Listing 2 shows the creation of objects representing the Facade and Controller in a MIDlet. Many Controller methods require calls to Facade to obtain the services of the model, so a reference to Facade is passed as a parameter in the Controller constructor.

Listing 2. Creating Facade and Controller objects

protected void startApp() {
              try {
                  model = new ModelFacade(getService());
                  controller = new Controller(this, model);
                  controller.init();
              } catch (ApplicationException ae) {
                  . . .
              }
          }

Applications that support communication should be able to trigger threads for each instance of network access, so that the application does not stop to wait for the return of a connection. To trigger threads, it is common to use an internal class of Controller that inherits the Thread. In its run() method, for example, it is possible to locate a Switch-type sentence that receives a constant (task ID) and derives, according to the ID, the piece of code that will carry it out. In general, if a Facade is implemented, methods of the Facade object will be invoked here.

As an example, consider the Controller method for logging in, shown in Listing 3. It receives the typical log-in parameters (user/password), followed by an instance of the EventDispatcher thread, passing to it as a parameter the ID of the log-in operation (EVENT_ID_LOGIN constant). It then invokes the runConexion() method shown below.

Listing 3. Controller method for logging in

public void loginProcessRequested(String user, String password)
{
            this.user = user;
            this.password = password;
            mythread = new EventDispatcher(EventIds.EVENT_ID_LOGIN, mainMenuUI);
            runConexionUI(mythread, getString(UIConstants.PROCESSING));
 }

The runConexionUI method’s main tasks are to initialize values on a screen and trigger the thread, as shown in Listing 4.

Listing 4. The runConexionUI method

public void runConexionUI(Thread thread, String title)
{
                    thread = (EventDispatcher) thread;
                    conexionUI.initializar();
                    conexionUI.setTitle(title);
                    nextScreenWithoutSaveLastScreen(conexionUI);
                    thread.start();
}

The Facade pattern

The main function of a Facade object is to provide a unified interface that contains all the subsystems the client may require. In this, the Facade pattern implements what is usually known as the Principle of Least Knowledge. For simple architectures you can omit the Facade, but if your architecture includes several subsystems it is recommended. Using the Facade pattern increases the legibility of your code and enables you to add new functionality without affecting the client.

Listing 5 shows a Facade object that encapsulates the functionality of both local and remote models — RMS and HTTP, respectively.

Listing 5. A Facade object

public Facade(String serviceURL) throws ApplicationException {
        try {
                  localModel = new LocalModel();
            } catch (ApplicationException e) {
           ...
            }
        remoteModel = new RemoteModelProxy(serviceURL);
            ...
            }

A Facade method to support the login example is shown in Listing 6. It receives the appropriate parameters, encapsulates them in a new object (User), and finally calls the remote model.

Listing 6. A Facade method for login

public AuthVO login(String user, String password) throws ApplicationException
{
    User user = new User(user, password, getMovilID());
    return remoteModel.login(user);
}

A client architecture for Java ME

Figure 2 shows an example client architecture for a JME application using the MVC and Facade patterns.

The goal of this client is to generate views by obtaining model information. The client is an MVC implementation, where the Controller object invokes methods on the Facade object to call both local and remote services.

To implement data transfer via XML it is useful to make the objects implement certain interfaces. For example, I’d like to make my business objects use an interface like this one:

<IBusinessObject>

        public String toShow();
        public String toRequestString();

The toShow() method allows me to visualize the object at the user interface, which is also useful for debugging. The toRequestString() method is necessary for developing the URL encoding generated by the request for that object.

Listing 7 shows the toShow() and toRequestString() methods at work.

Listing 7. toShow() and toRequestString() at work

public String toShow() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getDate());
        String txt = "EmployeeID = " + get EmployeeID ()
               + " nDate check-in = " + DateUtil.formatDate(getDate())
               + " nStart shift = " + getStartShift()
               + " nShifts = " + getShifts()
               + " nSubstitutes = " + (isSubstitute()? "YES":"NO");
        return txt;
}
 public String toRequestString() {
        StringBuffer buff = new StringBuffer();
        buff.append("codoper=" + getCodoper()
                 + "&startshift=" + getStartShift()
                 + "&shifts=" + get Shifts()
                 + "&substitute=" + isSubstitute()
                 + "&cellphone=" + getCellPhone());
return buff.toString();
}

Figure 3 shows the client architecture sending a request.

The process of receiving a server response and transforming it into an object is shown in Figure 4. It is made up of a series of intermediate steps, implemented by methods of the remote model.

DTO implementation

Given the objects will be circulating between layers as XML streams, the DTOs must have methods both for extracting data from the object and, conversely, giving state to the object from a set of values encapsulated in a hashtable. It will be necessary to define a contract with them. The following is the interface for the example application’s DTOs:

<IObjectDTO>
public void populateFields(Hashtable fields)
Hashtable extractFields()

Having your DTOs implement this interface will also simplify the recovery of objects using polymorphism. For example, if you were dealing with a Person object with the attributes

id
birthDate
status
expertise
address
country

you could implement the methods as shown in Listing 8.

Listing 8. DTO methods for populating and extracting data

public void populateFields(Hashtable fields) {
        this.id = (String) fields.get("id");
        this. birthDate = new Date(Long.parseLong((String)fields.get("birthDate")));
        this.state = Integer.parseInt((String)fields.get("state"));
        this.expertise = Integer.parseInt((String)fields.get("expertise"));
    this.address = (String) fields.get("address");
    this.country = (String) fields.get("country");
    }

public Hashtable extractFields() {
    Hashtable fields = new Hashtable();
    fields.put("id", this.id);
    fields.put("birthDate", "" + this.birthDate.getTime());
    fields.put("state", "" + this.state);
    fields.put("expertise", "" + this.expertise);
    fields.put("address", this.address);
    fields.put("country", this.country);
    return fields;
    }

Method A in Figure 4 could be implemented as shown in Listing 9. backendComms() would be in charge of opening the connection with the server (its entry parameters are the server URL and the request) and returning a String object with the XML.

Listing 9. Implementation of Method A (see Figure 4)

public static String backendComms(String requestURL, String requeststring) throws ApplicationException {
    hc = null;
    dis = null;
    StringBuffer messagebuffer = new StringBuffer();
    String requestString = requestURL + requeststring;

        try {
            hc = (HttpConnection) Connector.open(requestString,
                    Connector.READ_WRITE, true);
            hc.setRequestMethod(HttpConnection.GET);
            hc.setRequestProperty("User-Agent",
                    "Profile/MIDP-2.0 Configuration/CLDC-1.1");
            hc.setRequestProperty("Content-Language", "en-EN");
            dis = new DataInputStream(hc.openInputStream());
            int ch;
            long len = hc.getLength();
            if (len != -1) {
                for (int i = 0; i < len; i++) {
                        if ((ch = dis.read()) != -1) {
                        messagebuffer.append((char) ch);
                    }
                }
            } else {
                while ((ch = dis.read()) != -1) {
                    messagebuffer.append((char) ch);
                }
            }
            dis.close();

        } catch (InterruptedIOException iioe) {
            messagebuffer = new StringBuffer("Net time-out.");
            throw new ApplicationException(messagebuffer.toString());

        } catch (IOException ioe) {
            messagebuffer = new StringBuffer("Server down. Try again later");
            throw new ApplicationException(messagebuffer.toString());

        } catch (ApplicationException ae) {
            messagebuffer = new StringBuffer("Interrupted process.");
            throw new ApplicationException(messagebuffer.toString());

        } catch (Exception e) {
            messagebuffer = new StringBuffer("Net troubles. Try again later");
            throw new ApplicationException(messagebuffer.toString());

        }finally {
            cerrarConexion();
        }
        return messagebuffer.toString();
    }

After obtaining the String with the XML, the relevant IObjectDTO must be extracted from it. Clearly, in addition to the relevant data, the XML will have to identify the implementation of the IObjectDTO corresponding to those data. In this example, it will be done in two steps: first the XML will be parsed generically to obtain an object using the IObjectDTO interface, then it will be led to the expected object by casting.

The XML parsing, as you’ll see later, requires a class of XMLUtil that will use the API provided by the KXML. Let’s suppose, for example, that you wanted to obtain a Person DTO type object. In the model, there would be different methods for obtaining different DTOs. In this case you would use one called getPerson().

Listing 10. Using getPerson() to obtain a DTO

public PersonDTO getPerson(Person person) throws ApplicationException {
    StringBuffer requestString = new StringBuffer();
    String tempStr = QUESTION + person.toRequestString();
    requestString.append(tempStr);
    String xml = backendComms(LOAD_URL, requestString.toString());
    PersonDTO personDTO = convertXMLToPersonDTO(xml);
        return personDTO;
}

The bold type shows the call to Method C from Figure 4, which does the casting after calling the method that obtains the object from the XML (convertXMLToIObjectDTO(String xml)).

private static PersonDTO convertXMLToPersonDTO(String xml) {
   PersonDTO person = (PersonDTO)convertXMLToIObjectDTO(xml);
   return person;
}

Listing 11 shows a Method B from Figure 4, which is the one that uses the XMLutil class to parse the XML.

Listing 11. Parsing the application XML

private static IObjectDTO convertXMLToIObjectDTO(String xml) {
    InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(
                xml.getBytes()));
    IObjectDTO ioDto = null;
    try {
        ioDto = XMLUtil.getObjectFromXML(isr);
    } catch (IOException ioe) {
        System.out.println("Troubles getting IObjectDTO");
        ioe.printStackTrace();
        }
return ioDto;
}

Listing 12 shows a possible implementation for the XMLUtil class:

Listing 12. XMLUtil class implementation

public class XMLUtil {

public static IObjectDTO getObjectFromXML(InputStreamReader insr) throws IOException {

    IObjectDTO obj = null;
    XmlParser parser = new XmlParser(insr);
    Document document = new Document();
    document.parse(parser);

        // To show the XML document, to use document.write( new XmlWriter( new
                // OutputStreamWriter(System.out) ) );

    Element objectElement = document.getElement("object");
    obj = getObjectFromXMLElement(objectElement);

return obj;
}

public static IObjectDTO getObjectFromXMLElement(Element objectElement)
{

    String className = getTextFromElement(objectElement, "classname");
    Element fieldsElement = objectElement.getElement("fields");
    int childCount = fieldsElement.getChildCount();
    Hashtable fields = new Hashtable();
    Element fieldElement = null;

    for (int i = 0; i < childCount; i++) {
    if (fieldsElement.getType(i) == Xml.ELEMENT) {
        fieldElement = fieldsElement.getElement(i);

        String fieldName = getTextFromElement(fieldElement, "name");

        // The field is an object
        if (fieldElement.getElement("value").getAttributeCount() > 0) {
            IObjectDTO object = getObjectFromXMLElement(fieldElement.getElement("value").getElement("object"));
            fields.put(fieldName, object);
        }
        // The field is an String
        else {
        String fieldValue = stripCData(getTextFromElement(fieldElement, "value"));
        fields.put(fieldName, fieldValue);
                }
            }
        }

        // To create the classname specified object
        IObjectDTO obj = null;
        try {
            Class clase = Class.forName(className);
            obj = (IObjectDTO) clase.newInstance();
            obj.populateFields(fields);
        } catch (Exception e) {
        System.out.println("Excepci?n creating: " + e.getMessage());
        e.printStackTrace();
        }

        return obj;
    }

public static StringBuffer getXMLFromObject(IObjectDTO object, int level) throws IOException {
    StringBuffer objectToXML = new StringBuffer();
    String tabs = "";
    Class clase = object.getClass();
    String className = clase.getName();

    // To obtain tabs quantity
    for (int i = 0; i < level; i++)
        tabs += "tttt";

    // If it is an document beginning, show the xml header
    if (level == 0)
    objectToXML.append("<?xml version="1.0" encoding="ISO-8859-1"?>nn");

    // Show objects data
    objectToXML.append(tabs + "<object>n");
    objectToXML.append(tabs + "t<classname>" + className + "</classname>n");
    objectToXML.append(tabs + "t<fields>n");

    Hashtable fields = object.extractFields();
    Enumeration e = fields.keys();

    while (e.hasMoreElements()) {
        Object key = e.nextElement();
        objectToXML.append(tabs + "tt<field>n");

        objectToXML.append(tabs + "ttt<name>" + key + "</name>n");
        if (fields.get(key) instanceof String) {
        objectToXML.append(tabs + "ttt<value><![CDATA[" + fields.get(key) + "]]></value>n");
        } else if (fields.get(key) instanceof IObjectDTO) {
        objectToXML.append(tabs + "ttt<value nested="true">n");
        objectToXML.append(getXMLFromObject((IObjectDTO) fields.get(key), level + 1));
        objectToXML.append(tabs + "ttt</value>n");
            }

        objectToXML.append(tabs + "tt</field>n");
        }

    objectToXML.append(tabs + "t</fields>n");
    objectToXML.append(tabs + "</object>n");

    return objectToXML;

    }

private static String getTextFromElement(Element elementRoot, String elementName) {
    String returnText = elementRoot.getElement(elementName).getText();

    return returnText;
    }

private static String stripCData(String value) {
    String prefix = "<![CDATA[";
    String sufix = "]]>";

    if (value.indexOf(prefix) >= 0)
        value = value.substring(value.indexOf(prefix) + prefix.length());
    if (value.indexOf(sufix) >= 0)
        value = value.substring(value.indexOf(sufix));

    return value;
    }

}

As you can see, XMLUtil uses both methods of the interface IObjectsDTO (populateFields(Hashtable fields) and extractFields()) for the conversions from XML to object and object to XML, respectively. Consequently, both the client and the server use this class.

Finally, Listing 13 shows an example XML file sent by the server as a result of a login process.

Listing 13. An example XML file

<?xml version="1.0" encoding="ISO-8859-1"?>

<object>
    <classname>org.lm2a.bebay.dtoobjects.LoginDTO</classname>

    <fields>
        <field>
            <name>version</name>
            <value><![CDATA[1.1.5]]></value>
        </field>

        <field>
            <name>messagesQuantity</name>
            <value><![CDATA[0]]></value>
        </field>
        <field>

            <name>message</name>
            <value><![CDATA[Login OK]]></value>
        </field>
        <field>
            <name>ActionDate</name>

            <value><![CDATA[1161772420625]]></value>
        </field>
        <field>
            <name>code</name>
            <value><![CDATA[00]]></value>

        </field>
    </fields>

</object>

In conclusion

In this article I’ve explained how the DTO pattern is typically implemented for Java object serialization in multi-tier Java ME applications. I’ve explained the benefits of using XML-based DTOs rather than Java beans and introduced an example architecture for using XML-based DTOs for data interchange in Java mobile applications.

The scalability of the architecture presented in this article is excellent. If you wanted to add more objects to the architecture you would only need to create the classes that implement IObjectDTO and the corresponding methods for obtaining objects from your services, both in Facade and in the remote model.

As an addition to the article I also presented MockMe, a tool for generating XML-based mock objects. You are free to use MockMe to test the presentation layer of your Java mobile applications without waiting on the server-side implementation. Note that your JME application architecture must employ XML-based DTOs (not Java beans) in order to use MockMe.

Mario La Menza is a technical and managing architect and programmer. He is an expert JME developer and is a member of lm2a Mobility Solutions, Las Palmas, Spain. These days he is also finishing his PhD in computer science at University of Las Palmas de Gran Canaria. He regularly writes papers and articles about software development.