Author: veithen
Date: Wed Feb  2 22:01:51 2011
New Revision: 1066651

URL: http://svn.apache.org/viewvc?rev=1066651&view=rev
Log:
Updated the user guide to reflect current best practices in using the Axiom 
API. Also added a section describing changes in Axiom 1.2.11.

Modified:
    webservices/commons/trunk/modules/axiom/src/docbkx/userguide.xml

Modified: webservices/commons/trunk/modules/axiom/src/docbkx/userguide.xml
URL: 
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/src/docbkx/userguide.xml?rev=1066651&r1=1066650&r2=1066651&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/src/docbkx/userguide.xml (original)
+++ webservices/commons/trunk/modules/axiom/src/docbkx/userguide.xml Wed Feb  2 
22:01:51 2011
@@ -252,46 +252,17 @@
                 implementation.
             </para>
         </section>
-        <section id="creation">
-            <title>Creation</title>
-            <para>
-                Creation is the first and foremost action when using an Object
-                representation. This part explains how the object model can be 
built from an existing
-                document or simply programmatically. Axiom provides a notion 
of a factory and a
-                builder to create objects. The factory helps to keep the code 
at the
-                interface level and the implementations separately as shown in
-                <xref linkend="fig_api"/>. Since Axiom is tightly bound to 
StAX, a StAX
-                compliant reader should be created first with the desired 
input stream. Then
-                one can select one of the different builders available.
-            </para>
-            <para>
-                <classname>StAXOMBuilder</classname> will build pure XML 
infoset compliant object model whilst
-                the <classname>SOAPModelBuilder</classname> returns SOAP 
specific objects (such as the <classname>SOAPEnvelope</classname>,
-                which are sub classes of the <classname>OMElement</classname>) 
through its builder methods. The
-                following piece of code shows the correct method of creating 
an object model
-                from an input stream.
-            </para>
-            <example id="list1">
-                <title>Creating an object model from an input stream</title>
-<programlisting>//create the parser
-XMLStreamReader parser = 
XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(file));
-
-//create the builder
-StAXOMBuilder builder = new StAXOMBuilder(parser);
-
-//get the root element (in this case the envelope)
-OMElement documentElement =  builder.getDocumentElement();</programlisting>
-            </example>
+        <section>
+            <title>Creating an object model programmatically</title>
             <para>
-                As the example shows, creating an object model from an input 
stream is pretty
-                straightforward. However, elements and nodes can be created 
programmatically
-                to modify the structure as well. The recommended way to create 
Axiom objects
-                programmatically is to use the factory. 
<methodname>OMAbstractFactory.getOMFactory()</methodname> will
-                return the proper factory and the creator methods for each 
type that should
-                be called. Currently Axiom has two builders, namely the OM 
builder
-                (<classname>StAXOMBuilder</classname>) and the SOAP model 
builder (<classname>StAXSOAPModelBuilder</classname>). These
-                builders provide the necessary information to the XML infoset 
model to build
-                itself.
+                An object model instance can be created programmatically by 
instantiating the objects
+                representing the individual nodes of the document and then 
assembling them into a
+                tree structure. Axiom defines a set of interfaces representing 
the different node types.
+                E.g. <classname>OMElement</classname> represents an element, 
while <classname>OMText</classname>
+                represents character data that appears inside an element.
+                Axiom requires that all node instances are created using a 
factory.
+                The reason for this is to cater for different implementations 
of the Axiom API,
+                as shown in <xref linkend="fig_api"/>.
             </para>
             <figure id="fig_api">
                 <title>The Axiom API with different implementations</title>
@@ -302,7 +273,28 @@ OMElement documentElement =  builder.get
                 </mediaobject>
             </figure>
             <para>
-                A simple example is shown below:
+                Two implementations are currently shipped with Axiom:
+            </para>
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        The Linked List implementation (LLOM). This is the 
standard implementation. As the
+                        name implies, it uses linked lists to store 
collections of nodes.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        DOOM (DOM over OM), which adds support for the DOM API.
+                    </para>
+                </listitem>
+            </itemizedlist>
+            <para>
+                For each implementation, there are actually three factories: 
one for plain XML, and the other
+                ones for the two SOAP versions. The factories for the default 
implementation can be obtained
+                by calling the appropriate static methods in 
<classname>OMAbstractFactory</classname>.
+                E.g. <methodname>OMAbstractFactory.getOMFactory()</methodname> 
will return the proper
+                factory for plain XML. <xref linkend="list2"/> shows how this 
factory is used to create
+                several <classname>OMElement</classname> instances.
             </para>
             <example id="list2">
                 <title>Creating an object model programmatically</title>
@@ -317,11 +309,71 @@ OMElement elt11 = factory.createOMElemen
 OMElement elt12 = factory.createOMElement("foo2",ns1);</programlisting>
             </example>
             <para>
-                The reason as to have a set of <code>factory.createXXX</code> 
methods is to cater for
-                different implementations, but keep the programmers code 
intact. Its highly
-                recommended to use the factory for creating Axiom objects as 
this will ease the
-                switching of different Axiom implementations. Several 
differences exist between
-                a programmatically created <classname>OMNode</classname> and a 
conventionally built <classname>OMNode</classname>. The most
+                The Axiom API defines several methods to assemble individual 
objects into a tree
+                structure. The most prominent ones are the following two 
methods available on
+                <classname>OMElement</classname> instances:
+            </para>
+<programlisting>public void addChild(OMNode omNode);
+public void addAttribute(OMAttribute attr);</programlisting>
+            <para>
+                <methodname>addChild</methodname> will always add the child as 
the last child of the parent.
+                <xref linkend="ex-addChild"/> shows how this method is used to 
assemble the three elements
+                created in <xref linkend="list2"/> into a tree structure.
+            </para>
+            <example id="ex-addChild">
+                <title>Usage of <methodname>addChild</methodname></title>
+<programlisting>//set the children
+elt11.addChild(elt21);
+elt12.addChild(elt22);
+root.addChild(elt11);
+root.addChild(elt12);</programlisting>
+            </example>
+            <para>
+                A given node can be removed from the tree by calling the 
<methodname>detach()</methodname>
+                method. A node can also be removed from the tree by calling 
the remove
+                method of the returned iterator which will also call the 
detach method of
+                the particular node internally.
+            </para>
+        </section>
+        <section>
+            <title>Creating an object model by parsing an XML document</title>
+            <para>
+                Creating an object model from an existing document involves a 
second concept, namely
+                that of a <firstterm>builder</firstterm>. The responsibility 
of the builder is to
+                instantiate nodes corresponding to the information items in 
the document being parsed.
+                Note that as for programmatically created object models, this 
still involves the
+                factory, but it is now the builder that will call the 
<methodname>createXxx</methodname>
+                methods of the factory.
+            </para>
+            <para>
+                There are different types of builders, corresponding to 
different types of
+                input documents, namely: plain XML, SOAP, XOP and MTOM. The 
appropriate type of
+                builder should be created using the corresponding static 
method in
+                <classname>OMXMLBuilderFactory</classname>. <xref 
linkend="list1"/> shows the
+                correct method of creating an object model for a plain XML 
document from an input stream.
+            </para>
+            <note>
+                <para>
+                    As explained in <xref linkend="OMXMLBuilderFactory"/>, 
this is the recommended way
+                    of creating a builder starting with Axiom 1.2.11. In 
previous versions, this was done
+                    by instantiating <classname>StAXOMBuilder</classname> or 
one of its subclasses directly.
+                    This approach is still supported as well.
+                </para>
+            </note>
+            <example id="list1">
+                <title>Creating an object model from an input stream</title>
+<programlisting>//create the input stream
+InputStream in = new FileInputStream(file);
+
+//create the builder
+OMXMLParserWrapper builder = OMXMLBuilderFactory.createOMBuilder(in);
+
+//get the root element
+OMElement documentElement = builder.getDocumentElement();</programlisting>
+            </example>
+            <para>
+                Several differences exist between
+                a programmatically created <classname>OMNode</classname> and 
<classname>OMNode</classname> instances created by a builder. The most
                 important difference is that the former will have no builder 
object enclosed,
                 where as the latter always carries a reference to its builder.
             </para>
@@ -356,47 +408,15 @@ OMElement elt12 = factory.createOMElemen
             </para>
         </section>
         <section>
-            <title>Addition of Nodes</title>
-            <para>
-                Addition and removal methods are primarily defined in the 
<classname>OMElement</classname>
-                interface. The following are the most important in adding 
nodes.
-            </para>
-<programlisting>public void addChild(OMNode omNode);
-public void addAttribute(OMAttribute attr);</programlisting>
+            <title>Namespaces</title>
             <para>
-                This code segment shows how the addition takes place. Note 
that it is
-                related to the code listings <xref linkend="list1"/> &amp; 
<xref linkend="list2"/> in <xref linkend="creation"/>.
+                Namespaces are a tricky part of any XML object model and is 
the same in
+                Axiom. However, the interface to the namespace have been made 
very simple.
+                <classname>OMNamespace</classname> is the class that 
represents a namespace with intentionally
+                removed setter methods. This makes the 
<classname>OMNamespace</classname> immutable and allows
+                the underlying implementation to share the objects without any
+                difficulty.
             </para>
-<programlisting>//set the children
-elt11.addChild(elt21);
-elt12.addChild(elt22);
-root.addChild(elt11);
-root.addChild(elt12);</programlisting>
-            <itemizedlist>
-                <listitem>
-                    <para>
-                        <methodname>addChild</methodname> will always add the 
child as the last child of the parent.
-                    </para>
-                </listitem>
-                <listitem>
-                    <para>
-                        A given node can be removed from the tree by calling 
the <methodname>detach()</methodname>
-                        method. A node can also be removed from the tree by 
calling the remove
-                        method of the returned iterator which will also call 
the detach method of
-                        the particular node internally.
-                    </para>
-                </listitem>
-                <listitem>
-                    <para>
-                        Namespaces are a tricky part of any XML object model 
and is the same in
-                        Axiom. However, the interface to the namespace have 
been made very simple.
-                        <classname>OMNamespace</classname> is the class that 
represents a namespace with intentionally
-                        removed setter methods. This makes the 
<classname>OMNamespace</classname> immutable and allows
-                        the underlying implementation to share the objects 
without any
-                        difficulty.
-                    </para>
-                </listitem>
-            </itemizedlist>
             <para>
                 Following are the important methods available in 
<classname>OMElement</classname> to handle
                 namespaces.
@@ -468,11 +488,10 @@ while(children.hasNext()){
             </para>
             <important>
                 <para>
-                    All iterator implementations internally stay one
-                    step ahead of their apparent location to provide the 
correct value
-                    for the <methodname>hasNext()</methodname> method. This 
hidden advancement can build elements
-                    that are not intended to be built at all. Hence these 
iterators are
-                    recommended only when caching is not a concern.
+                    As explained in <xref linkend="iterator-changes"/>, in 
Axiom 1.2.10 and earlier, 
+                    all iterator implementations internally stayed one
+                    step ahead of their apparent location. This could have the 
side effect of building elements
+                    that are not intended to be built at all.
                 </para>
             </important>
         </section>
@@ -559,12 +578,13 @@ writer.flush();</programlisting>
                 console. Only the important sections are shown here. The 
complete program
                 listing can be found in <xref linkend="appendix"/>.
             </para>
-<programlisting>//create the parser
-XMLStreamReader parser = 
XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(file));
+<programlisting>//create the input stream
+InputStream in = new FileInputStream(file);
+
 //create the builder
-StAXOMBuilder builder = new StAXOMBuilder(parser);
+OMXMLParserWrapper builder = OMXMLBuilderFactory.createOMBuilder(in);
 
-//get the root element (in this case the envelope)
+//get the root element
 OMElement documentElement = builder.getDocumentElement();
 
 //dump the out put to console with caching
@@ -765,32 +785,6 @@ try {
     <chapter id="advanced">
         <title>Advanced Operations with Axiom</title>
         <section>
-            <title>Use of the <classname>OMNavigator</classname> for 
Traversal</title>
-            <para>
-                Axiom provides a utility class to navigate the object model 
structure. The navigator
-                provides an in-order traversal of the Axiom tree up to the 
last-built node. The
-                Navigator has two states called the navigable state and the 
completion state.
-                Since the navigator provides the navigation starting from an 
<classname>OMElement</classname>, it is
-                deemed to have completed the navigation when the starting node 
is reached
-                again. This state is known as the completion state. Once the 
navigator has
-                reached the complete status its navigation is done and it 
cannot proceed.
-            </para>
-            <para>
-                It is possible that the Axiom tree does not get built 
completely when it is
-                navigated. The navigable status shows whether the tree 
structure is
-                navigable. When the navigator is complete it is not navigable 
anymore.
-                However, it is possible for a navigator to become 
non-navigable without being
-                complete. The following code sample shows how the navigator 
should be used
-                and handled using its states.
-            </para>
-<programlisting>//Create a navigator
-OMNavigator navigator = new OMNavigator(envelope);
-OMNode node = null;
-while (navigator.isNavigable()) {
-     node = navigator.next();
-}</programlisting>
-        </section>
-        <section>
             <title>Accessing the Pull Parser</title>
             <para>
                 Axiom is tightly integrated with StAX and the
@@ -1155,6 +1149,89 @@ with CRLF</root>]]></screen>
                     </para>
                 </section>
             </section>
+            <section>
+                <title>Changes in Axiom 1.2.11</title>
+                <section id="OMXMLBuilderFactory">
+                    <title>Resurrection of the 
<classname>OMXMLBuilderFactory</classname> API</title>
+                    <para>
+                        Historically, 
<classname>org.apache.axiom.om.impl.llom.factory.OMXMLBuilderFactory</classname>
 was used to
+                        create Axiom trees from XML documents. Unfortunately, 
this class is located in the wrong package and JAR
+                        (it is implementation independent but belongs to 
LLOM). In Axiom 1.2.10, the standard way to create an Axiom tree
+                        was therefore to instantiate 
<classname>StAXOMBuilder</classname> or one of its subclasses directly. 
However, this
+                        is not optimal for two reasons:
+                    </para>
+                    <itemizedlist>
+                        <listitem>
+                            <para>
+                                It relies on the assumption that every 
implementation of the Axiom API necessarily uses
+                                <classname>StAXOMBuilder</classname>. This 
means that an implementation doesn't have the freedom to
+                                provide its own builder implementation (e.g. 
in order to implement some special optimizations).
+                            </para>
+                        </listitem>
+                        <listitem>
+                            <para>
+                                <classname>StAXOMBuilder</classname> and its 
subclasses belong to packages which have
+                                <literal>impl</literal> in their names. This 
tends to blur the distinction between the public
+                                API and internal implementation classes.
+                            </para>
+                        </listitem>
+                    </itemizedlist>
+                    <para>
+                        Therefore, in Axiom 1.2.11, a new abstract API for 
creating builder instances was introduced.
+                        It is again called 
<classname>OMXMLBuilderFactory</classname>, but located in the
+                        <package>org.apache.axiom.om</package> package. The 
methods defined by this new API are similar
+                        to the ones in the original (now deprecated) 
<classname>OMXMLBuilderFactory</classname>, so that
+                        migration should be easy.
+                    </para>
+                </section>
+                <section id="iterator-changes">
+                    <title>Changes in the behavior of certain iterators</title>
+                    <para>
+                        In Axiom 1.2.10 and previous versions, iterators 
returned by methods such as <methodname>OMIterator#getChildren()</methodname>
+                        internally stayed one step ahead of the node returned 
by the <methodname>next()</methodname> method.
+                        This meant that sometimes, using such an iterator had 
the side effect of building elements that
+                        were not intended to be built.
+                        In Axiom 1.2.11 this behavior was changed such that 
<methodname>next()</methodname> no longer builds the nodes
+                        it returns. In a few cases, this change may cause 
issues in existing code. One known instance
+                        is the following construct (which was used internally 
by Axiom itself):
+                    </para>
+<programlisting>while (children.hasNext()) { 
+    OMNodeEx omNode = (OMNodeEx) children.next(); 
+    omNode.internalSerializeAndConsume(writer); 
+}</programlisting>
+                    <para>
+                        One would expect that the effect of this code is to 
consume the child nodes. However, in Axiom 1.2.10 this
+                        is not the case because 
<methodname>next()</methodname> actually builds the node.
+                        Note that the code actually doesn't make sense because 
once a child node has been consumed, it is
+                        no longer possible to retrieve the next sibling. Since 
in Axiom 1.2.11 the call to <methodname>next()</methodname>
+                        no longer builds the child node, this code will indeed 
trigger an exception.
+                    </para>
+                    <para>
+                        Another example is the following piece of code which 
removes all child elements with a given name:
+                    </para>
+<programlisting>Iterator iterator = element.getChildrenWithName(qname);
+while (iterator.hasNext()) {
+    OMElement child = (OMElement)iterator.next();
+    child.detach();
+}</programlisting>
+                    <para>
+                        In Axiom 1.2.10 this works as expected. Indeed, since 
the iterator stays one node ahead, the current
+                        node can be safely removed using the 
<methodname>detach()</methodname> method.
+                        In Axiom 1.2.11, this is no longer the case and the 
following code (which also works
+                        with previous versions) should be used instead:
+                    </para>
+<programlisting>Iterator iterator = element.getChildrenWithName(qname);
+while (iterator.hasNext()) {
+    iterator.next();
+    iterator.remove();
+}</programlisting>
+                    <para>
+                        Note that this is actually compatible with the 
behavior of the Java 2 collection framework, where
+                        a 
<classname>ConcurrentModificationException</classname> may be thrown if a 
thread modifies a
+                        collection directly while it is iterating over the 
collection with an iterator.
+                    </para>
+                </section>
+            </section>
         </section>
     </chapter>
 
@@ -1461,13 +1538,13 @@ public InputStream getInputStream() thro
         <section>
             <title>Program Listing for Build and Serialize</title>
 <programlisting>import org.apache.axiom.om.OMElement;
-import org.apache.axiom.om.impl.builder.StAXOMBuilder;
+import org.apache.axiom.om.OMXMLBuilderFactory;
+import org.apache.axiom.om.OMXMLParserWrapper;
 
-import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.InputStream;
 
 public class TestOMBuilder {
 
@@ -1477,9 +1554,10 @@ public class TestOMBuilder {
      */
     public static void main(String[] args) {
         try {
-            //create the parser
-            XMLStreamReader parser = 
XMLInputFactory.newInstance().createXMLStreamReader(new 
FileInputStream(args[0]));
-            StAXOMBuilder builder = new StAXOMBuilder(parser);
+            //create the input stream
+            InputStream in = new FileInputStream(args[0]);
+            //create the builder
+            OMXMLParserWrapper builder = 
OMXMLBuilderFactory.createOMBuilder(in);
             //get the root element
             OMElement documentElement = builder.getDocumentElement();
 
@@ -1492,8 +1570,6 @@ public class TestOMBuilder {
             e.printStackTrace();
         }
     }
-
-
 }</programlisting>
         </section>
         <section id="links">


Reply via email to