WSO2Con 2013 CFP Banner

AXIOM - Fast and Lightweight Object Model for XML - Part 2

Discuss this article on Stack Overflow
By Eran Chinthaka
  • 11 Dec, 2006
  • Level: 
  • Reads: 11545
The First part of this series of articles on AXIOM (AXis Object Model) by Eran Chinthaka, talked about concepts, architecture and introduced the basic API of AXIOM. In this article we will discuss how AXIOM achieves its deferred building capability and how AXIOM is customized and optimized to process SOAP messages.
chinthaka's picture
Eran Chinthaka
Software Engineer
WSO2 Inc.
Concept of Caching If you look at some of the methods in the AXIOM API, you can see two variations of the same method. For example, you will see toString() and toStringWithConsume(). Let's first try to understand the reason behind this: When AXIOM builders receive events from the underlying StAX (Streaming API for XML) parser, they can be configured to just throw the events to the user or to create a tree in the memory while throwing out events. Building the memory model while reading from the parser and throwing events is called caching. User can set the caching flag and if you set caching on, then the builders will build an object model in the memory. So why is this so important? Say, you want to retrieve a bunch of XMLs from a URL and save them in a file, or you want to just print out an XML file to the console. You don't need to build the object model in the memory to do that. You can simply ask AXIOM to read the events and dump them to an output stream. You could achieve it using toStringWithConsume()method. This minimizes the un-necessary usage of memory. But if you want to read the XML to some extent and want to go back and forth, then you set the caching flag on. Caching can be done even when you serialize. When you call the serialize method, by default AXIOM builds the object model. This is because, if you do not build the model, the data you extracted from the input stream is gone. Caching is somewhat similar to the difference between SAX (Simple API for XML) and DOM (Document Object Model). If caching is on, you build the object model, just like in DOM. But if caching is off, you consume the stream, by throwing events, just like in SAX. Let's try to understand this by an example. Let's read an XML and try to write it with and without setting the caching flag and see what happens. Please refer, AxiomCachingTester.testAxiomWithCachingOn(), inside the samples zip file. We first create a document element and call toString() method twice on it. You will see the complete original xml printed twice. This is because we are asking AXIOM to build the object model, by calling toString() method, when we first serialize it. OMElement documentElement = new StAXOMBuilder("resources/soapmessage.xml").getDocumentElement();// now serialize this element while the caching flag is on. For this let's use toString()// method of the OMElementSystem.out.println("documentElement = " + documentElement.toString());// If the object model is built, then we should be able to serialize it again.System.out.println("documentElement = " + documentElement.toString()); Now let's refer AxiomCachingTester.testAxiomWithCachingOff(), the counter part of the above method. Here we first call toStringWithConsume(), forcing AXIOM not to build the object model while serializing, and again calling the serialize method. When you get the document element from the builder, it had already created an OMElement for the document element, the "Envelope" element. When you serialize this without caching, for the first time, AXIOM will just print the input xml out, without bothering to build the object model. So when you try to serialize the same document element for the second time, you will only see the document element and not its children. OMElement documentElement = new StAXOMBuilder("resources/soapmessage.xml").getDocumentElement(); // now serialize this element while the caching flag is off. For this let's use toStringWithConsume() // method of the OMElement System.out.println("documentElement = " + documentElement.toStringWithConsume()); // Now the object model is not built in the memory except for the envelope element. // when you serialize the document element now, you should only see the Envelope and it // should not have any children System.out.println("documentElement = " + documentElement.toString()); Next time when you use the AXIOM API, make sure you use the proper method. Extending AXIOM SOAP Support One of the main advantages of AXIOM is that it can be customized to any XML schema. For example, if we want AXIOM to behave like a SOAP object model, we can do that easily. All the releases of AXIOM contains customization of SOAP, as AXIOM is the core object model in Apache Axis2. This was done by introducing a new builder and creating SOAP specific classes, like SOAPEnvelope, SOAPBody, etc., by extending from the basic API. StAXSOAPModelBuilder acts as the SOAP specific builder. The AXIOM team has implemented the SOAP specific API on top of the AXIOM API, to make the SOAP developer's life easier. Let's try to understand the convenience AXIOM provides to work with SOAP by working with a real SOAP message. First create an instance of the StAXSOAPModelBuilder from the SOAP message we have. The resources folder, inside samples.zip, contains a soapmessage.xml which you can use to test this sample. // let's first read our soap xml files in to StAXSOAPModelBuilder FileReader soapFileReader = new FileReader(fileName); XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(soapFileReader); StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(parser, null); Now let's retrieve the SOAP Envelope object from our builder. SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement(); SOAPEnvelope object provides access to all the information inside the SOAP message. AXIOM SOAP API provides convenience to the users, by defining convenient methods. For example, of you want to retrieve the Header block, simply call envelope.getHeader(). Or if you want to retrieve the SOAP Body, then call envelope.getBody(). What if I want to print the contents of the SOAP body? If you remember we discussed, in Part 1 of this article, the way to print an OMElement to the System.out. Let's use that method to print the contents of the body. // retrieve SOAP body SOAPBody soapBody = envelope.getBody(); // what is inside SOAP Body System.out.println("soapBody = " + soapBody); Now let's try to be more adventurouse in SOAP inside the SOAP envelope. Lets say that there are WS-Addressing headers inside the SOAP message, and you want to know what they are. How can you retrieve them? AXIOM SOAP API has getHeaderBlocksWithNSURI()method in SOAPHeader class, which returns an ArrayList, for that. SOAPHeader soapHeader = envelope.getHeader(); ArrayList addressingHeaders = soapHeader.getHeaderBlocksWithNSURI("http://schemas.xmlsoap.org/ws/2004/03/addressing"); for (int i = 0; i < addressingHeaders.size(); i++) { SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeaders.get(i); System.out.println("SOAP Header Local Name = " + soapHeaderBlock.getLocalName()); } Now let's look at the complete code fragment. This method can be found in org.wso2.articles.axiom.part2.SOAPMessageReader of the samples.zip of this article Part2. try { // let's first read our soap xml files in to StAXSOAPModelBuilder FileReader soapFileReader = new FileReader(fileName); XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(soapFileReader); StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(parser, null); // now let's play around a bit with the SOAP envelope // first retrieve SOAP envelope SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement(); // then retrieve SOAP header SOAPHeader soapHeader = envelope.getHeader(); // retrieve SOAP body SOAPBody soapBody = envelope.getBody(); // what is inside SOAP Body System.out.println("soapBody = " + soapBody); // let's see what addressing headers we have in this message ArrayList addressingHeaders = soapHeader.getHeaderBlocksWithNSURI("http://schemas.xmlsoap.org/ws/2004/03/addressing"); for (int i = 0; i < addressingHeaders.size(); i++) { SOAPHeaderBlock soapHeaderBlock = (SOAPHeaderBlock) addressingHeaders.get(i); System.out.println("SOAP Header Local Name = " + soapHeaderBlock.getLocalName()); }} catch (FileNotFoundException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.} catch (XMLStreamException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.} There are other interesting methods also inside the SOAP API. Let's have a quick look at some of them. SOAPHeader::Iterator examineHeaderBlocks(String role) and SOAPHeader::Iterator extractHeaderBlocks(String role) - If you are in a SOAP node, you might sometimes need to get all the headers that are meant to be read by your SOAP node. And you might want to just read them or remove them while you are reading. These methods help you to get SOAP Headers with a given role and to remove or not remove them while you are reading. SOAPBody::SOAPFault addFault(Exception e) - This method helps you to create a new SOAPFault from a java exception. This method takes care of constructing the proper SOAPFault, extracting enough information from the exception you pass into this method. Handling Multiple SOAP Versions The SOAP message that comes inside the samples.zip is of SOAP 1.1. Change the SOAP version of that message and try to read it using the above code-fragment, without any change in the code. Your code will run the same way irrespective of the version of the SOAP message. How is this possible? There are differences between the XML models of two SOAP versions we have. So When we were designing the SOAP API, we decided to support the latest SOAP version. i.e. SOAP 1.2. We developed an object model to support SOAP 1.2 and use the same model to contain SOAP 1.1 messages as well. When our SOAP builder is reading the SOAP message, it detects the SOAP version of the message, and uses the appropriate builder helper to build the object model. What you always see is a SOAP 1.2 API inside AXIOM. But you can serialize/de-serialize from/to your object model into SOAP 1.1 or SOAP 1.2 without a problem. This feature helps Apache Axis2, not maintain different endpoints for different SOAP versions. Once a service is deployed in Axis2, it can be consumed using both the SOAP versions, without doing anything more. DOM Support AXIOM provides fast and efficient ways to process XMLs. But there are some implementations which need to have a DOM model to work. For example, XML canonicalization is implemented on DOM and requires a DOM model to work with it. So how can AXIOM help to provide an interface to DOM while still achieving the best of AXIOM? The AXIOM team implemented the DOM API, extending from the base AXIOM API, enabling users to work with systems explained above. How is this done? If you can remember, AXIOM has the concept of a factory to create the object model. As I explained in Part 1 of this article, one can implement the AXIOM API and can come up with another object model. This is how we have implemented DOM over AXIOM. We have a set of classes which implements both AXIOM and DOM API. And our builders can be provided with a factory to be used whilst building the object model. Let's now read the above SOAP message in to a DOM/AXIOM model. You just need to pass the DOM factory in to the builder. StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder(parser, new DOMSOAPFactory(), null); If you want to read a generic XML, use OMDOMFactory instead of DOMSOAPFactory. Once you get the objects, you can cast those AXIOM objects to DOM objects. The advantage here is that you have now got a memory efficient and fast performing DOM model. Conclusion We discussed about AXIOM basic API and had a quick look at AXIOM architecture in the first part of this article series. This article, the second of the series, introduced you to the concept of caching and how AXIOM is optimized for processing SOAP messages. The next part of this series will introduce you to the native MTOM and XPath handling support inside Axiom. References Sample code for this article- Part 2 Download the latest AXIOM release. AXIOM - Fast and Lightweight Object Model for XML - Part 1 The Apache AXIOM project Web site. AXIOM Tutorial published on AXIOM web site. SOAP W3C Specification 1.1 & 1.2 Author(s) Eran Chinthaka, Senior Software Engineer, WSO2 Inc. chinthaka(!) at wso2(!) dot com(!)
WSO2Con 2014 USA