Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Server-side Java: Build distributed applications with Java and XML

Use Xbeans to process your XML as DOM Documents

  • Print
  • Feedback

Page 2 of 5

Xbeans

As you will see, the three implementations of the sender and receiver described here are implemented as Xbeans. An Xbean is a software component that takes XML as input, processes it, and then passes XML on to the next Xbean. Xbeans consume and produce XML as DOM documents. That is, the data passed to Xbeans are not strings that need to be parsed by an XML parser; rather, they make up an already parsed document object accessed via the W3C standard DOM API. Figure 2 illustrates an Xbean.

Figure 2. Xbeans consume and produce XML as DOM documents

Xbeans are JavaBeans, which support the packaging, reuse, connection, and customization of Java code. With the appropriate set of Xbeans and a JavaBean design tool, you can build useful distributed applications with little or no programming.

Xbeans are inspired by IBM's XML Productivity Kit for Java. They are focused on distributed applications and thus have a modified interface. Xbeans are freely available through the Xbeans.org open source project.

Approaches to implementing sender and receiver

Now I'll describe for you the three different approaches to implementing the sender and the receiver, complete with Java code. After presenting them, I'll analyze the performance of each approach.

Approach 1: Use a standard Web server

The first approach is to simply send the XML as text to the Web server on a remote machine. The sender must convert the DOM representation of the XML into text and communicate the text to the receiver. Then, the receiver must convert the text back to the DOM representation. Figure 3 illustrates this approach.

Figure 3. A sender and receiver sending XML text via HTTP

The following code fragment uses HTTP to implement the sender. The code uses the DOMWriter class in IBM's Productivity Kit for Java to convert the DOM representation to a textual XML representation. See Resources for the complete code.

public void documentReady(DOMEvent evt) 
        throws XbeansException {
    try {
        URL receiver = new URL(getRemoteURL());
        URLConnection receiverConnection = 
            receiver.openConnection();
        receiverConnection.setDoOutput(true);

// open an output stream to the sender and // send the xml in text form OutputStream out = receiverConnection.getOutputStream(); DOMWriter writer = new DOMWriter(); writer.setPrintWriter(new PrintWriter(out)); writer.documentReady( new com.ibm.xml.xpk4j.dom.DOMEvent( this,evt.getDocument())); out.close();
// open an input stream for result BufferedReader in = new BufferedReader(new InputStreamReader( receiverConnection.getInputStream())); // process result: "OK" indicates success, // "Exception" indicates input stream contains // serialized exception. ...
in.close(); } catch (Throwable e) { e.printStackTrace(System.err); } }


Note that the above documentReady() method uses the remoteURL property to get the URL of the CGI script on the server.

To be compatible with HTTP, the CGI script class wraps the receiver's output with the string "Content-type: text/html". The script then invokes the Java Virtual Machine and the receiverMain() on the server. Here's the code for the CGI script on the server:

#!/bin/sh
echo "Content-type: text/html"
echo
/usr/local/bin/java org.xbeans.communication.http.receiverMain 2>&1


The main() method simply instantiates the receiver and invokes receiveDocument() on the receiver.

import org.xbeans.communication.stdio.receiver.*;

public class receiverMain { static Bean theReceiver = new Bean();
public static void main(String[] args) { theReceiver.receiveDocument(); } }


Finally, here's a code fragment from receiveDocument() to recreate the DOM representation and pass it on for further processing. This code depends on IBM's XML parser.

// Create a parser
DOMParser parser = new DOMParser();
// Invoke the parser.
try {
    parser.parse(new InputSource(System.in));
} catch (Throwable e) {
    throw new XbeansException(
        "",
        "receiver",
        "io error parsing incoming document",
        "io error parsing incoming document "+e
    );
}
// Pass the document on to the next bean
DOMListener.documentReady(new DOMEvent(this,parser.getDocument()));

 

Approach 2: Serialized representation via Java RMI

The second approach uses Java RMI and DOM serialization to transfer the DOM from the sender to the receiver. Figure 4 illustrates this approach.

Figure 4. Communicating a serialized DOM using Java RMI

The following code implements the sender using Java RMI to communicate with the receiver.

public void documentReady(DOMEvent evt) 
        throws XbeansException {
    if (DOMListener==null) {
        try {
            DOMListener = 
                (DOMListener)Naming.lookup(getReceiverName());
        } catch (Exception e) {
            throw new XbeansException(
                evt.getDocument().getNodeName(),
                "sender",
                "error obtaining remote receiver",
                "The name may be wrong or the network may be down."
                );
        }
    }
    DOMListener.documentReady(evt);
}


The following code implements the receiver using Java RMI. The setName() method exports the receiver to the RMI registry and the documentReady() method simply passes on the received document to the next component.

public void setReceiverName(String newName) {
    try {
        if (receiverName!=null) Naming.unbind(receiverName);
        receiverName = newName;
        Naming.rebind(receiverName, this );
    } catch( Exception e ) {
        System.out.println( e );
    }
}

public void documentReady(Document incomingDocument) throws RemoteException, XbeansException { if (DOMListener==null) { throw new XbeansException( incomingDocument.getNodeName(), "rmiReceiver", "next component not established", "The component needs to be configured." ); } DOMListener.documentReady(new DOMEvent(this,incomingDocument)); }

Approach 3: CORBA-IIOP

The third approach uses CORBA-IIOP (CORBA over Internet Inter-ORB Protocol) as a transport. The Object Management Group (OMG) currently has a request for proposal (Resources) for extending the Interface Definition Language (IDL) to include an XML data type. Thus, in the future, CORBA products will be able to transmit XML natively. Figure 5 illustrates this approach.

Figure 5. Transmitting XML natively using CORBA

Since today's CORBA products cannot represent XML natively, the code presented here uses Java serialization of the DOM and communicates it to the receiver as a sequence of octets. It is very similar to the Java RMI approach. The only difference is that the distributed object infrastructure is provided by CORBA systems.

The following OMG IDL gives the interface between the CORBA implementation of the sender and the receiver:

exception RemoteReceiverException {
    string remoteIdentifier;
    string documentName;
    string componentName;
    string message;
    string moreMessage;
};

typedef sequence<octet> byteArray;
interface XMLReceiver { void documentReady(in byteArray serializedDocument) raises(RemoteReceiverException); };


The following code implements the sender using Java serialization of the DOM and CORBA:

public void documentReady(DOMEvent evt) 
        throws XbeansException {
    Document documentToSend = evt.getDocument();
    try {
        ByteArrayOutputStream bastream = 
            new ByteArrayOutputStream();
        ObjectOutputStream p = 
            new ObjectOutputStream(bastream);
        p.writeObject(documentToSend);
        p.flush();
        org.omg.CORBA.ORB orb = 
            org.omg.CORBA.ORB.init(
                                 new String[0],
                                 System.getProperties());
        XMLReceiver receiver = 
            urlToObject(orb,getReceiverURL());
        receiver.documentReady(bastream.toByteArray());
    } catch (RemoteReceiverException rre) {
        throw new XbeansException(
            rre.remoteIdentifier,
            rre.documentName,
            rre.componentName,
            rre.message,
            rre.moreMessage
            );
    } catch (Throwable e) {
        throw new XbeansException(
                    "",
                    "sender",
                    "error sending document "+e,
                    "error sending document "+e
                    );
    }
}

The following code implements the receiver using Java serialization of the DOM and CORBA:

public void documentReady(byte[] serializedDocument) 
        throws RemoteReceiverException {

// Deserialize the byte stream. ByteArrayInputStream bais = new ByteArrayInputStream(serializedDocument); Document theDocument; try { ObjectInputStream ois = new ObjectInputStream(bais); theDocument = (Document)ois.readObject(); } catch(Throwable e) { throw new RemoteReceiverException( corbaName, "incoming document", "receiver", "error deserializing document", "error deserializing document"+e ); } // Pass on the document to the listener try { local.DOMListener.documentReady( new DOMEvent(this,theDocument)); } catch (XbeansException xbe) { throw new RemoteReceiverException( xbe.remoteIdentifier(), xbe.documentName(), xbe.componentName(), xbe.message(), xbe.moreMessage() ); } }

  • Print
  • Feedback