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"/> &
<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">