Java Web services

Digging into Axis2: AXIOM

The AXIOM document object model is the foundation for Apache Axis2 Web services

Content series:

This content is part # of # in the series: Java Web services

Stay tuned for additional content in this series.

This content is part of the series:Java Web services

Stay tuned for additional content in this series.

Yet another document model?

Apache Axis2 1.1 has been released and offers exciting new features to fans of the long-running Apache series of Web services frameworks. We'll cover Axis2 itself in a future article, but this article digs into the AXIs Object Model (AXIOM) XML document model that lies at the core of Axis2. AXIOM is one of the major innovations behind Axis2, and one of the reasons Axis2 offers the potential for substantially better performance than the original Axis. This article guides you through how AXIOM works, how various parts of Axis2 build on AXIOM, and then finishes with a look at how AXIOM performance compares to other Java™ document object models.

Document models are a commonly used approach to XML processing, and many different flavors are available for Java development, including various implementations of the original W3C DOM specification, JDOM, dom4j, XOM, and more. Each model claims some advantages over the others, whether performance, flexibility, or rigidly enforced adherence to the XML standard, and each has committed supporters. So why did Axis2 need a new model? The answer lies in how SOAP messages are structured, and especially in how extensions are added to the basic SOAP framework.

Getting SOAPy

SOAP itself is really just a thin wrapper around an XML application payload. Listing 1 gives a sample, where the only parts that are actually defined by SOAP are those elements with the soapenv prefix. The bulk of the document is the application data that makes up the content of the soapenv:Body element.

Listing 1. SOAP sample
<soapenv:Envelope xmlns:soapenv="">
    <matchQuakes xmlns="">

Despite the simplicity of the basic SOAP wrapper, it offers the potential for unlimited extensions by using an optional component called the header. The header provides a place for all kinds of metadata to be added which will accompany the application data without being seen by the application (it is possible to include application data in the header, but there isn't a convincing case for why you'd want to do this rather than just using the body for application data). Extensions that build on SOAP (such as the whole WS-* family) can use the header for their own purposes without affecting the application. This allows the extensions to operate as add-ons, where the particular extended functions needed by an application can simply be selected at deployment time rather than baked into the code.

Listing 2 shows the same application data as the sample in Listing 1 SOAP, but with WS-Addressing information included. While the original SOAP message would probably only be usable over an HTTP transport (because HTTP provides a two-way connection for an immediate response to be sent back to the client), the Listing 2 version could operate over other protocols because it includes the response metadata directly in the SOAP request message. It would even be easy to have a store-and-forward step involved in the processing of the message in Listing 2 since the metadata provides both request target and response target information.

Listing 2. SOAP sample with WS-Addressing
<soapenv:Envelope xmlns:soapenv=""
    <matchQuakes xmlns="">

The document model dilemma

Since the whole point of the SOAP header is to allow arbitrary metadata to be added to a message, it's important that SOAP frameworks be able to accept anything that some extension decides to add. Generally speaking, the easiest way to work with arbitrary XML is by using a document model of one form or another. That's the whole point of a document model, after all -- to faithfully represent XML without any assumptions about the form of that XML.

But document models aren't a very efficient way of working with XML that's used to exchange data between applications. Application data normally has a predefined structure, and most developers prefer to work with that data in the form of data objects rather than as raw XML. The job of converting between data objects and XML is in the realm of what's called data binding. Data binding is not only more convenient for developers than working with a document model, it's also much more efficient in terms of both performance and memory use.

So most applications want to use data binding to work with the application payload of a SOAP message, but a document model approach is better for working with the metadata present in the header. The ideal approach would be to combine the two techniques within the SOAP framework, but normal document models aren't set up to allow this. They expect to work with an entire document, or at least an entire subtree of a document. They're not really set up to work with just selected portions of a document, as is best suited to SOAP.

Pulling an AXIOM tree

In addition to AXIOM, there's another change between Axis and Axis2. While the original Axis used a standard push-style (SAX) parser for processing XML, Axis2 uses a pull-style (StAX) parser. With a push approach, the parser is in control of the parsing operation -- you give the parser a document to parse and a handler reference. It then uses the handler for call-backs into your code as it processes the input document. Your handler code can make use of the information passed by the call-backs, but cannot affect the parsing (except by throwing an exception). With a pull approach, on the other hand, the parser is effectively an iterator for going through the components of a document on demand.

Both push and pull approaches have their uses, but the pull style has a major benefit when it comes to XML that contains logically separate components (such as SOAP). With a pull parser, the code that handles one part of the document can parse only as much as it needs and then hand off the parser to whatever comes next in the document processing.

AXIOM is built around the StAX pull parser interface. AXIOM provides a virtual document model it expands on demand, building only as much of the tree structure document model representation as has been requested by the client application. This virtual document model works at the level of elements in the XML document. An element representation is created when the parser reports the element start tag, but the initial form of that element is essentially just a shell which holds a reference to the parser. If the application needs to get the details of the element's content, it simply requests the information by calling a method of the interface (such as the method). The element then builds the child content from the parser in response to the method call.

Since a parser delivers data in document order (the same order items appear in the XML document text), the on-demand construction implemented by AXIOM requires some clever handling. For instance, it's normal to have multiple elements in an incomplete (under construction) state, but these elements all have to be in a direct line of inheritance. In terms of the standard sort of tree diagram of XML with the root element at the top, the incomplete elements will always be in the line down the right side of the tree. As more data is requested by the application, the tree grows further to the right, with the bottom elements completed first.

Working with AXIOM

All the XML document models have a great deal in common when it comes to their APIs (no big surprise, since they're all working with the same underlying data), but each has some quirks that distinguishes it from the others. The original W3C Document Object Model (DOM) was designed for cross-language and cross-platform compatibility, so it builds on interfaces and avoids using Java-specific collections in favor of its own versions. JDOM uses concrete classes rather than interfaces and incorporates the standard Java collections classes for an API that many Java developers find friendlier than DOM. dom4j combines DOM-like interfaces with Java collections classes for a very flexible API that offers a lot of power -- at the cost of some complexity.

AXIOM has a lot in common with these other document models. It also has a few significant differences related to its on-demand build process, along with some specialized features to support its use in Web services.

AXIOM in action

AXIOM's API is probably closest to DOM in overall feel, but it has its own quirks. For instance, the access methods are designed around using java.util.Iterator instances for access to components (as returned by and related methods), rather than any form of list. Instead of indexing into a list of components, navigation uses and methods to move sequentially through nodes at a level of the document tree (similar to DOM in this respect). This structuring of access and navigation methods matches how on-demand tree construction works, since it means AXIOM can let you move to the first child of your starting element without having to first process all the child elements.

Like DOM and dom4j, AXIOM defines the API used to access and manipulate the tree representation using interfaces. The AXIOM distribution includes several different specialized implementations of these interfaces. One implementation (in package is dual-headed, supporting both AXIOM and DOM interfaces with the same implementation classes. This can be useful because of the number of Web services add-ons that expect to work with a DOM view of the data. For more general use, the package provides an implementation based on linked lists of objects (the "ll" part of the package name). There are also extensions of both the basic interfaces and these implementations in the org.apache.axiom.soap package tree which are customized for use with SOAP messages.

For a quick look at the AXIOM API in action, we'll look at some samples from the code used for performance- testing AXIOM against other document models. Listing 3 gives the first sample, based on the code used to build the AXIOM representation of an input document. As with DOM and dom4j, before doing anything with AXIOM you need to get a factory that builds the component objects of the model. The Listing 3 code selects the basic linked list implementation of the AXIOM interfaces by using the implementation of the interface. The factory interface includes methods to build a document from various sources directly, and includes methods for creating individual components of the XML document representation. Listing 3 uses the method to build a document from an input stream. The object returned by the build() method is actually an instance of, though that's not specified by this code.

Listing 3. Parsing a document into AXIOM
    private XMLInputFactory m_parserFactory = XMLInputFactory.newInstance();
    private OMFactory m_factory = new OMLinkedListImplFactory();
    protected Object build(InputStream in) {
        Object doc = null;
        try {
            XMLStreamReader reader = m_parserFactory.createXMLStreamReader(in);
            StAXOMBuilder builder = new StAXOMBuilder(m_axiomFactory, reader);
            doc = builder.getDocument();
        } catch (Exception ex) {
        return doc;

Listing 3 uses the class to build the document representation by parsing an input stream. This just creates a StAX parser instance and the basic document structure before returning, leaving the parser positioned inside the root element of the document with the rest of the document representation to be built later, if needed. AXIOM doesn't have to be built using a StAX parser. In fact, is a partial implementation of a builder based on the SAX push parser. But if you build it any other way you won't get the benefits of on-demand construction.

Listing 4 shows the code used to "walk" through the elements in a document representation and accumulate summary information (the count of elements, the count and total length of attribute value text, and the count and total length of text content). The walk() method at the bottom takes a document to be summarized, along with the summary data structure, while the walkElement() method at the top processes one element (calling itself recursively to process child elements).

Listing 4. Navigating AXIOM
     * Walk subtree for element. This recursively walks through the document
     * nodes under an element, accumulating summary information.
     * @param element element to be walked
     * @param summary document summary information
    protected void walkElement(OMElement element, DocumentSummary summary) {

        // include attribute values in summary
        for (Iterator iter = element.getAllAttributes(); iter.hasNext();) {
            OMAttribute attr = (OMAttribute);

        // loop through children
        for (Iterator iter = element.getChildren(); iter.hasNext();) {

            // handle child by type
            OMNode child = (OMNode);
            int type = child.getType();
            if (type == OMNode.TEXT_NODE) {
            } else if (type == OMNode.ELEMENT_NODE) {
                walkElement((OMElement)child, summary);


     * Walk and summarize document. This method walks through the nodes
     * of the document, accumulating summary information.
     * @param doc document representation to be walked
     * @param summary output document summary information
    protected void walk(Object doc, DocumentSummary summary) {
        walkElement(((OMDocument)doc).getOMDocumentElement(), summary);

Finally, Listing 5 gives the code used to write the document representation to an output stream. AXIOM defines many output methods as part of the OMNode interface, including variations of destination (as output stream, normal character writer, or StAX stream writer), with and without formatting information, and with and without the ability to access the document representation after it's been written (which requires the full representation to be built, if not already constructed). The OMElement interface defines yet another way of accessing the document information, by getting a StAX parser from the element. This ability to pull XML out of the representation using a parser offers an appealing symmetry, and it works nicely when the AXIOM representation is built on-demand (since the parser being used to build the representation can then be returned directly).

Listing 5. Writing a document from AXIOM
     * Output a document as XML text.
     * @param doc document representation to be output
     * @param out XML document output stream
    protected void output(Object doc, OutputStream out) {
        try {
        } catch (Exception ex) {

AXIOM provides some basic methods for modifying an existing document component (such as OMElement.setText() to set the content of an element to a text value). If you're starting from scratch, you'll need to create new instances of components directly. Since the AXIOM API is based on interfaces, it uses factories to create actual implementations of the components.

For more details on the AXIOM API, see the links for the AXIOM tutorial and JavaDocs in the Resources section.


One of the most interesting features of AXIOM is its built-in support for the W3C XOP and MTOM standards used in the latest version of SOAP attachments. These two standards work together, with XML-binary Optimized Packaging (XOP) providing a way for XML documents to logically include blobs of arbitrary binary data, and with MTOM (SOAP Message Transmission Optimization Mechanism) applying the XOP technique to SOAP messages. XOP and MTOM are crucial features of the new generation of Web services frameworks since they finally provide interoperable attachment support and end the current problems in this area.

XOP works with base64-encoded character data content. Base64 encoding transforms arbitrary data values into printable ASCII characters by using one ASCII character to represent each six bits of the original data. Since binary data cannot generally be embedded inside XML (XML only works with characters, not raw bytes; even a number of character codes are not allowed in XML), base64 encoding is useful for embedding binary data into XML messages.

XOP replaces the actual base64 text with a special "Include" element from the XOP namespace. The include element gives a URI that identifies a separate entity (outside the XML document) which is the actual data to be included in the XML document. Normally this URI will identify a separate block within the same transmission as the XML document (though there's no requirement that it do so, which offers potential benefits for exchanging documents through intermediaries or storing documents). The benefits of replacing the base64 text with a reference to the raw data are somewhat reduced document size (up to 25 percent smaller for normal character encodings) and faster processing without the overhead of encoding and decoding the base64 data.

MTOM builds on XOP, first defining an abstract model of how XOP can be used for SOAP messages, then specializing that model for use with MIME Multipart/Related packaging, and finally applying it to HTTP transport. Altogether, this provides a standard way to apply XOP to SOAP messages using the widely used HTTP transport.

AXIOM supports XOP/MTOM through the interface and the implementations of this interface. OMText defines methods to support text items backed by binary data (in the form of a javax.activation.DataHandler, part of the Java Activation API widely used for attachment support in Java Web services frameworks), along with an "optimize" flag that tells whether the item can be processed using XOP. The implementation adds an MTOM-compatible content ID that can be set when an instance of the class is created, or generated automatically if it is not set.

Listing 6 shows a sample of how to build a message using XOP/MTOM in AXIOM. This code is taken from a performance test example which uses Java serialization to convert a result data structure into an array of bytes, and then returns that array as an attachment.

Listing 6. Creating an XOP/MTOM message
    public OMElement matchQuakes(OMElement req) {
        Query query = new Query();
        Iterator iter = req.getChildElements();
        try {
            // retrieve the matching quakes
            Response response = QuakeBase.getInstance().handleQuery(query);
            // serialize response to byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            byte[]byts = bos.toByteArray();
            // generate response structure with reference to data
            ByteArrayDataSource ds = new ByteArrayDataSource(byts);
            OMFactory fac = OMAbstractFactory.getOMFactory();
            OMNamespace ns =
                fac.createOMNamespace("", "qk");
            OMElement resp = fac.createOMElement("response", ns);
            OMText data = fac.createOMText(new DataHandler(ds), true);
            return resp;
        } catch (ParseException e) {
        } catch (IOException e) {
        return null;

Even though the code in Listing 6 generates a response that can be sent using XOP/MTOM, in the current version of Axis2, XOP/MTOM support is disabled by default. To turn it on, you need to include a parameter <parameter name="enableMTOM">true</parameter> in either the Axis2 axis2.xml file or the services.xml file for your service. We'll provide the full code for this example as part of upcoming performance comparisons, but for now we'll finish with a sample of XOP/MTOM in use.

Listing 7 shows the structure of the response message generated by the Listing 6 service, with and without XOP/MTOM enabled (without the MIME headers and the actual binary attachment, in the first case, and with most of the data left out, in the second case).

Listing 7. Response message with and without XOP/MTOM
<?xml version='1.0' encoding='UTF-8'?>
  <soapenv:Envelope xmlns:soapenv="">
    <soapenv:Header />
      <qk:response xmlns:qk=""
        <xop:Include href=""
            xmlns:xop="" />
[actual binary data follows as separate MIME part with referenced content id]

<?xml version='1.0' encoding='UTF-8'?>
  <soapenv:Envelope xmlns:soapenv="">
    <soapenv:Header />
      <qk:response xmlns:qk=""


Data binding hooks

Most developers working with Web services need to work with data in the form of Java objects, rather than XML documents (or even document models, such as AXIOM). Last-generation frameworks, such as Axis and JAX-RPC, implemented their own forms of data binding to convert between XML and Java objects, but this was a very limited solution. The data binding implementations in Web services frameworks generally couldn't compete with specialized data binding frameworks, so users who wanted better control over the handling of XML had to "glue" the frameworks together with inefficient conversion code. Because of these issues, Axis2 was designed from the beginning to support "plug-in" data binding using a wide range of data binding frameworks.

The data binding support uses customized extensions to the WSDL2Java tool included in Axis2. This tool generates Axis2 linkage code based on a WSDL service description in the form of a stub for the client side or a message receiver for the server side. The client-side stub functions as a proxy for making calls to the service, defining method calls that implement the service operations. The server-side message receiver functions as a proxy for the client, calling the actual user-defined service method. When data binding is requested in the WSDL2Java command line, the tool calls the specified data binding framework extension to generate code in the stub or message receiver that converts between OMElements and Java objects. In the case of the stub, the Java objects (or primitive values) are passed in the method call and the converted XML is sent to the server as a request. The returned XML is then converted back into a Java object, which is then returned as the result of the method call. The message receiver on the server side does the same conversions in reverse.

On the inbound or unmarshalling side (converting received XML to Java objects), the handling is easy. The XML document payload to be converted into Java objects is available in the form of an OMElement, and the data binding framework just needs to process the data from that element. OMElement provides access to the element data in the form of a StAX, which most current data binding frameworks can use directly as input.

The outbound or marshalling side (converting Java objects to transmitted XML) is a little more difficult. The whole point of AXIOM is to avoid building a full representation of XML data unless absolutely necessary. To support this principle when marshalling, there has to be a way for the data binding framework to be invoked only when needed. AXIOM handles this by using an as a wrapper for the data binding conversion. OMDataSource defines methods for writing out the wrapped content using any of the methods supported by AXIOM (to a, a, or a StAX, along with another method that returns a parser instance for the wrapped content. An OMElement implementation can use an instance of OMDataSource to supply data on demand, and the OMFactory interface provides a method to create this type of element.


We'll wrap up coverage of AXIOM with a quick look at performance. At the writing of this article, AXIOM is available as a 1.1 release which means that the interfaces described in this article should be stable. Performance, on the other hand, is subject to change over time as the actual implementation code is modified. We don't expect to see major changes in AXIOM's performance relative to the other document models, but it's possible that some of the details will be different.

To compare AXIOM with other document models, we updated code from an earlier study of document models (see Resource section), adding AXIOM and one other new document model (XOM), converting the code to use the StAX parser standard rather than the older SAX standard, and switching to the improved System.nanoTime() timing method introduced in Java 5. The performance test code first reads the documents to be used in the test into memory, then runs through a sequence of operations on the documents. First, some number of copies of the document representations are built from parsers, with each resulting document object retained. Next, each document object is "walked," meaning the code scans the entire document representation (including all attributes, values, and text content). Finally, each document object is written to an output stream. The time is recorded for each individual operation and averaged at the end of the test run.

Since the main focus of AXIOM (especially its use in Axis2) is on SOAP message handling, we used three different SOAP message test cases to check the performance. The first one is a sample response from a Web service performance test that gives information about earthquakes within a particular time and latitude/longitude range ("quakes," 18 KB). This document contains a many repeated elements with some nesting and heavy use of attributes. The second one is a larger sample from a Microsoft WCF interoperability test, consisting of a single structure repeated with minor variations in values ("persons," 202 KB). This document has child elements with text content but no use of attributes. The third test case is a collection of 30 small SOAP message documents taken from some older interoperability tests (total size 19 KB). All formatting white space was removed from the test documents to make the documents representative of XML exchanged by real production services (which generally turn formatting off to keep message sizes down).

The charts below show the average time required for 50 passes on each document. The test environment was a Compaq notebook system with a 1600 MHz ML-30 AMD Turion processor and 1.5 GB of RAM, running Sun's 1.5.0_07-b03 JVM on Mandriva 2006 Linux. We tested AXIOM 1.0, dom4j 1.6.1, JDOM 1.0, Xerces2 2.7.0, and XOM from the Nux 1.6 distribution. Custom builders from StAX parsers were used for dom4j, JDOM, and Xerces2, and the Nux StAX parser builder was used for XOM. All tests used the Woodstox StAX parser 2.9.3.

Figure 1 shows the sums of the average times required for the first two steps in the test sequence, building a document from the parser, and walking the document representation to check the content. If you look at the first step in isolation (times not shown here), AXIOM does much better than the other document models, at least for the first two documents. However, this just shows that AXIOM is working as expected and is not actually building the full document until needed. We wanted to use the time taken to actually construct the full representation in memory for a fair comparison, which is why the two times in this chart are summed.

Figure 1. Times to build and expand documents (in milliseconds)
Times to build and expand documents
Times to build and expand documents

As seen in Figure 1, AXIOM is slower overall than any of the other document models tested except Xerces2.

Several of the document models showed performance problems when it comes to the collection of small documents ("soaps"). Xerces2 was especially bad in this case, but AXIOM also showed a lot of overhead which is probably the most troubling issue this chart shows. Small messages are common in many Web services, and AXIOM should be able to process them efficiently. Given that AXIOM is really designed around the on-demand expansion of the tree, the timings for the two larger documents are not a big concern since they're at least close to the other document models.

Figure 2. Times to write documents (in milliseconds)
Times to write documents
Times to write documents

Figure 2 shows the average times for writing the documents to an output stream using each model. Here Xerces2 actually gives the best times by a substantial margin (but not enough to make up for its poor performance on the build step; the scales of the two charts are different), while AXIOM is the worst. Here again, AXIOM seems to do an especially poor job with small documents.

Figure 3. Document memory sizes (in KB)
Document memory sizes
Document memory sizes

Finally, Figure 3 shows the memory used by each of the frameworks to represent the documents. dom4j is again the clear best, and AXIOM the worst by a considerable margin. Part of AXIOM's poor performance in memory use is due to the parser being referenced by the constructed document so that the parser instance will be kept around as long as the document instance is in use. That's likely partly why AXIOM again does especially poorly with small documents. However, the objects used by AXIOM as components of the document are also considerably larger than their counterparts in the other document models, and this difference is probably why AXIOM uses much more space even for the two larger test documents (where the fixed-size overhead of the parser and other data structures is smaller in proportion to the total memory usage).

If you sum the times from the first two charts, the overall performance leader is dom4j, while the performance laggard is Xerces2 (with AXIOM just a smidgen ahead of the latter). On memory use, dom4j is again best, but in this contest AXIOM is the undisputed loser. Sound grim for AXIOM?

It would be grim if the full tree representation were always built, but remember that the whole point of AXIOM is that often this full representation is not needed. Figure 4 shows the time from just the initial document construction in AXIOM, compared with the corresponding time for the other document models to build the document representation. Here AXIOM comes out much faster than the others (too fast to even register, in the case of the two larger documents). The same sort of comparison applies on the memory side. The net result is that if you need to work with only part of the document model (the "first" part, in document order terms), AXIOM delivers great performance.

Figure 4. Initial document construction
Document memory sizes
Document memory sizes

On to Axis2

This article has provided an inside view of the AXIOM document object model at the core of Axis2. AXIOM embodies some interesting innovations, especially in terms of its build-on-demand approach to constructing the full representation. It's not quite on a par with other Java document models when you need a fully expanded representation. Its performance with small documents is especially troubling, but the flexibility it provides for Web service processing balances out many of these concerns.

You now know how Axis2 handles SOAP messages representations using AXIOM, including how it passes XML to and from data binding frameworks. The next article looks at how Axis2 support for different data binding frameworks works from a user perspective, including code samples using three of the frameworks.

Downloadable resources

Related topics

  • Build your next development project with IBM trial software, available for download directly from developerWorks.
  • The dom4j document object model is fast, memory-efficient, and also offers great extensibility.
  • The JDOM document object model is known for ease of use.
  • The XOM document object model protects users from common mistakes in the use of XML, while offering good performance and memory-efficiency.
  • Xerces2 is the Apache implementation of the W3C document object model standard.
  • Get the latest Apache Axis2 information and downloads.
  • View the developerWorks Web services standards library for information on a wide range of WS-* technologies.
Zone=Java development, SOA and web services, Open source
ArticleTitle=Java Web services: Digging into Axis2: AXIOM