| <?xml version="1.0" encoding="UTF-8"?> |
| <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
| <!-- |
| ~ Licensed to the Apache Software Foundation (ASF) under one |
| ~ or more contributor license agreements. See the NOTICE file |
| ~ distributed with this work for additional information |
| ~ regarding copyright ownership. The ASF licenses this file |
| ~ to you under the Apache License, Version 2.0 (the |
| ~ "License"); you may not use this file except in compliance |
| ~ with the License. You may obtain a copy of the License at |
| ~ |
| ~ http://www.apache.org/licenses/LICENSE-2.0 |
| ~ |
| ~ Unless required by applicable law or agreed to in writing, |
| ~ software distributed under the License is distributed on an |
| ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| ~ KIND, either express or implied. See the License for the |
| ~ specific language governing permissions and limitations |
| ~ under the License. |
| --> |
| <book> |
| <bookinfo> |
| <title>Axiom Developer Guide</title> |
| <releaseinfo>&version;</releaseinfo> |
| |
| <legalnotice> |
| <para> |
| Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See |
| the NOTICE file distributed with this work for additional information regarding copyright ownership. The |
| ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use |
| this file except in compliance with the License. You may obtain a copy of the License at |
| </para> |
| <para> |
| <ulink url="http://www.apache.org/licenses/LICENSE-2.0"/> |
| </para> |
| <para> |
| Unless required by applicable law or agreed to in writing, software distributed under the License is |
| distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing permissions and limitations under the |
| License. |
| </para> |
| </legalnotice> |
| </bookinfo> |
| |
| <toc/> |
| |
| <chapter> |
| <title>Testing</title> |
| <section> |
| <title>Unit test organization</title> |
| <para> |
| Historically, all unit tests were placed in the <filename>axiom-tests</filename> project. |
| One specific problem with this is that since all tests are in a common Maven module |
| which depends on both <filename>axiom-impl</filename> and <filename>axiom-dom</filename>, |
| it is not rare to see DOOM tests that accidentally use the LLOM implementation (which is the default). |
| The project description in <filename>axiom-tests/pom.xml</filename> indicates that it |
| was the intention to split the <filename>axiom-tests</filename> project into several parts |
| and make them part of <filename>axiom-api</filename>, <filename>axiom-impl</filename> and |
| <filename>axiom-dom</filename>. This reorganization is not complete |
| yet<footnote><para>See <ulink url="https://issues.apache.org/jira/browse/WSCOMMONS-419">WSCOMMONS-419</ulink>.</para></footnote>. |
| For new test cases (or when refactoring existing tests), the following guidelines should be applied: |
| </para> |
| <orderedlist> |
| <listitem> |
| <para> |
| Tests that validate the code in <filename>axiom-api</filename> and that do not require |
| an Axiom implementation to execute should be placed in <filename>axiom-api</filename>. |
| This primarily applies to tests that validate utility classes in <filename>axiom-api</filename>. |
| </para> |
| </listitem> |
| <listitem id="test.category.api"> |
| <para> |
| The code of unit tests that apply to all Axiom implementations and that check conformance |
| to the specifications of the Axiom API should be added |
| to <filename>axiom-api</filename> and executed in <filename>axiom-impl</filename> and |
| <filename>axiom-dom</filename>. Currently, the recommended way is to create a |
| base class in <filename>axiom-api</filename> (with suffix <classname>TestBase</classname>) and |
| to create subclasses in <filename>axiom-impl</filename> and <filename>axiom-dom</filename>. |
| This makes sure that the DOOM tests never accidentally use LLOM (because |
| <filename>axiom-impl</filename> is not a dependency of <filename>axiom-dom</filename>). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Tests that check integration with other libraries should be placed in |
| <filename>axiom-integration</filename>. Note that this is the only module that requires |
| Java 1.5 (so that e.g. integration with JAXB2 can be tested). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Tests related to code in <filename>axiom-api</filename> and requiring an Axiom |
| implementation to execute, but that don't fall into category <xref linkend="test.category.api"/> |
| should stay in <filename>axiom-tests</filename>. |
| </para> |
| </listitem> |
| </orderedlist> |
| </section> |
| <section> |
| <title>Testing Axiom with different StAX implementations</title> |
| <para> |
| The following StAX implementations are available to test compatibility with Axiom: |
| </para> |
| <variablelist> |
| <varlistentry> |
| <term>Woodstox</term> |
| <listitem> |
| <para> |
| This is the StAX implementation that Axiom uses by default. |
| </para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>Sun Java Streaming XML Parser (SJSXP)</term> |
| <listitem> |
| <para> |
| This implementation is available as Maven artifact <literal>com.sun.xml.stream:sjsxp:1.0.1</literal>. |
| </para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>StAX Reference Implementation</term> |
| <listitem> |
| <para> |
| The reference implementation was written by BEA and is available as Maven artifact |
| <literal>stax:stax:1.2.0</literal>. The homepage is <ulink url="http://stax.codehaus.org/Home"/>. |
| Note that the JAR doesn't contain the necessary files to enable service discovery. |
| Geronimo's implementation of the StAX API library will not be able to locate |
| the reference implementation unless the following system properties are set: |
| </para> |
| <programlisting>javax.xml.stream.XMLInputFactory=com.bea.xml.stream.MXParserFactory |
| javax.xml.stream.XMLOutputFactory=com.bea.xml.stream.XMLOutputFactoryBase</programlisting> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term>XL XP-J</term> |
| <listitem> |
| <para> |
| <quote>XL XML Processor for Java</quote> is IBM's implementation of StAX 1.0 |
| and is part of IBM's JRE/JDK v6. Note that due |
| to an agreement between IBM and Sun, IBM's Java implementation for the Windows |
| platform is not available as a separate download, but only bundled with another |
| IBM product, e.g. <ulink url="http://www.ibm.com/developerworks/downloads/ws/wasdevelopers/">WebSphere |
| Application Server for Developers</ulink>. |
| </para> |
| <para> |
| On the other hand, the JDK for Linux can be downloaded as a separate package from the |
| <link url="https://www.ibm.com/developerworks/java/jdk/linux/download.html">developerWorks |
| site</link>. There are versions for 32-bit x86 (<quote>xSeries</quote>) and 64-bit AMD. |
| They are available as RPMs and tarballs. To install the JDK properly on a Debian |
| based system (including Ubuntu), follow the instructions given in |
| <xref linkend="install.ibm.jdk"/>. |
| </para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| </section> |
| </chapter> |
| |
| <chapter> |
| <title>OSGi integration</title> |
| <section> |
| <title>Requirements</title> |
| <formalpara id="osgi-req-no-separate-bundles"> |
| <title>Requirement 1</title> |
| <para> |
| The Axiom artifacts SHOULD be usable both as normal JAR files and as OSGi bundles. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| The alternative would be to produce two sets of artifacts during the build. This |
| should be avoided in order to keep the build process as simple as possible. |
| It should also be noted that the Geronimo Spec artifacts also meet this requirement. |
| </para> |
| </note> |
| <formalpara id="osgi-req-same-api"> |
| <title>Requirement 2</title> |
| <para> |
| All APIs defined by the <literal>axiom-api</literal> module, and in particular the |
| <classname>OMAbstractFactory</classname> API MUST continue to work |
| as expected in an OSGi environment, so that code in downstream projects |
| doesn't need to be rewritten. |
| </para> |
| </formalpara> |
| <formalpara id="osgi-req-same-impl-selection"> |
| <title>Requirement 3</title> |
| <para> |
| <classname>OMAbstractFactory</classname> MUST select the same implementation |
| regardless of the type of container (OSGi or non OSGi). The only exception is |
| related to the usage of system properties to specify the default <classname>OMMetaFactory</classname> |
| implementation: in an OSGi environment, selecting an implementation class using |
| a system property is not meaningful. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| This is currently not the case. In a non OSGi environment, recent versions of Axiom |
| use JDK 1.3 service discovery to locate the default implementation and fall back to |
| LLOM if none is found. DOOM will never be selected as the default implementation. |
| On the other hand, the current OSGi integration will select any Axiom implementation |
| as default implementation, but gives priority to LLOM. |
| </para> |
| </note> |
| <formalpara id="osgi-ref-impl-not-exported"> |
| <title>Requirement 4</title> |
| <para> |
| The bundles for the LLOM and DOOM implementations MUST NOT export any packages. |
| This is required to keep a clean separation between the public API and implementation |
| specific classes and to make sure that the implementations can be modified without the |
| risk of breaking existing code. |
| </para> |
| <para> |
| An exception MAY be made for factory classes related to foreign APIs, such as the |
| <classname>DocumentBuilderFactory</classname> implementation for an Axiom implementation |
| supporting DOM. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| When the Axiom artifacts are used as normal JAR files in a Maven build, this requirement implies that |
| they should be used in scope <literal>runtime</literal>. |
| </para> |
| <para> |
| Although this requirement is easy to implement for the Axiom project, there are |
| currently a couple of issues in the downstreams project that need to be addressed |
| to make this work: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| As explained in <ulink url="https://issues.apache.org/jira/browse/AXIS2-4902">AXIS2-4902</ulink>, |
| there are many places in Axis2 that still refer directly to Axiom implementation classes. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The <literal>axis2-saaj</literal> module is tightly coupled to <literal>axiom-dom</literal>. |
| Making this work will probably require using <literal>maven-shade-plugin</literal> to |
| include (a relocated copy of) the DOOM classes into <literal>axis2-saaj</literal>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Abdera extends the LLOM implementation. Probably, some <literal>maven-shade-plugin</literal> |
| magic will be required here as well to create Abdera OSGi bundles that work properly with |
| the Axiom bundles. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </note> |
| <formalpara id="osgi-req-dropin"> |
| <title>Requirement 5</title> |
| <para> |
| It MUST be possible to use a non standard (third party) Axiom implementation as a drop-in replacement |
| for the standard LLOM and DOOM implementation, i.e. the <literal>axiom-impl</literal> |
| and <literal>axiom-dom</literal> bundles. It MUST be possible to replace <literal>axiom-impl</literal> |
| (resp. <literal>axiom-dom</literal>) by any Axiom implementation that supports the full Axiom API |
| (resp. that supports DOM in addition to the Axiom API), without the need to change any application code. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| This requirement has several important implications: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| It restricts the allowable exceptions to <xref linkend="osgi-ref-impl-not-exported"/>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| It implies that there must be an API that allows application code to select an Axiom |
| implementation based on its capabilities (e.g. DOM support) without introducing a |
| hard dependency on a particular Axiom implementation. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| In accordance with <xref linkend="osgi-req-same-api"/> and <xref linkend="osgi-req-same-impl-selection"/> |
| this requirement not only applies to an OSGi environment, but extends to non OSGi environments as well. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </note> |
| <formalpara> |
| <title>Requirement 6</title> |
| <para> |
| The OSGi integration SHOULD remove the necessity for downstreams projects |
| to produce their own custom OSGi bundles for Axiom. There SHOULD be one |
| and only one set of OSGi bundles for Axiom, namely the ones released by the Axiom project. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| Currently there are at least two projects that create their own modified Axiom bundles: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Apache Geronimo has a custom Axiom bundle to support the Axis2 integration. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| ServiceMix also has custom bundles to support Abdera; see |
| <ulink url="https://issues.apache.org/jira/browse/SMX4-877">SMX4-877</ulink>. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| Note that this requirement can't be satisfied directly by Axiom. It requires that |
| the above mentioned projects (Geronimo, Axis2 and Abdera) use Axiom in a way that is |
| compatible with its design, and in particular with <xref linkend="osgi-ref-impl-not-exported"/>. |
| Nevertheless, Axiom must provide the necessary APIs and features to meet the needs |
| of these projects. |
| </para> |
| </note> |
| <formalpara id="osgi-reg-no-framework"> |
| <title>Requirement 7</title> |
| <para> |
| The Axiom OSGi integration SHOULD NOT rely on any particular OSGi framework such |
| as Felix SCR (Declarative Services). When deployed in an OSGi environment, Axiom should have the same |
| runtime dependencies as in a non OSGi environment (i.e. StAX, Activation and JavaMail). |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| Axiom 1.2.12 relies on Felix SCR. Although there is no real issue with that, getting rid |
| of this extra dependency is seen as a nice to have. One of the reasons for using Felix SCR |
| was to avoid introducing OSGi specific code into Axiom. However, there is no issue with |
| having such code, provided that <xref linkend="osgi-req-no-osgi-dep"/> is satisfied. |
| </para> |
| </note> |
| <formalpara id="osgi-req-no-osgi-dep"> |
| <title>Requirement 8</title> |
| <para> |
| In a non OSGi environment, Axiom MUST NOT have any OSGi related dependencies. That means |
| that the OSGi integration must be written in such a way that no OSGi specific classes are |
| ever loaded in a non OSGi environment. |
| </para> |
| </formalpara> |
| <formalpara id="osgi-req-best-practices"> |
| <title>Requirement 9</title> |
| <para> |
| The OSGi integration MUST follow established best practices. It SHOULD be inspired by |
| what has been done to add OSGi integration to APIs that have a similar structure as Axiom. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| Axiom is designed around an abstract API and allows for the existence of multiple |
| independent implementations. A factory (<classname>OMAbstractFactory</classname>) is used to |
| locate and instantiate the desired implementation. This is similar to APIs such as |
| JAXP (<classname>DocumentBuilderFactory</classname>, etc.) and JAXB (<classname>JAXBContext</classname>). |
| These APIs have been successfully "OSGi-fied" e.g. by the Apache Geronimo project. |
| Instead of reinventing the wheel, we should leverage that work and adapt it to |
| Axiom's specific requirements. |
| </para> |
| <para> |
| It should be noted that because of the way the Axiom API is designed and taking into account |
| <xref linkend="osgi-req-same-api"/>, it is not possible to make Axiom entirely compatible |
| with OSGi paradigms (the same is true for JAXB). In an OSGi-only world, each Axiom |
| implementation would simply expose itself as an OSGi service (of type <classname>OMMetaFactory</classname> e.g.) |
| and code depending on Axiom would bind to one (or more) of these services depending on its needs. |
| That is not possible because it would conflict with <xref linkend="osgi-req-same-api"/>. |
| </para> |
| </note> |
| <formalpara> |
| <title>Non-Requirement 1</title> |
| <para> |
| APIs such as JAXP and JAXB have been designed from the start for inclusion into the JRE. |
| They need to support scenarios where an application bundles its own implementation |
| (e.g. an application may package a version of Apache Xerces, which would then be |
| instantiated by the <methodname>newInstance</methodname> method in |
| <classname>DocumentBuilderFactory</classname>). That implies that the selected implementation |
| depends on the thread context class loader. It is assumed that there is no such requirement |
| for Axiom, which means that in a non OSGi environment, the Axiom implementations are always loaded from the same |
| class loader as the <literal>axiom-api</literal> JAR. |
| </para> |
| </formalpara> |
| <note> |
| <para> |
| This (non-)requirement is actually not directly relevant for the OSGi support, but it |
| nevertheless has some importance because of <xref linkend="osgi-req-same-impl-selection"/> |
| (which implies that the OSGi support needs to be designed in parallel with the implementation |
| discovery strategy applicable in a non OSGi environment). |
| </para> |
| </note> |
| </section> |
| <section> |
| <title>Analysis of the Geronimo JAXB bundles</title> |
| <para> |
| As noted in <xref linkend="osgi-req-best-practices"/> the Apache Geronimo has successfully |
| added OSGi support to the JAXB API which has a structure similar to the Axiom API. This section briefly describes |
| how this works. The analysis refers to the following Geronimo artifacts: |
| <literal>org.apache.geronimo.specs:geronimo-jaxb_2.2_spec:1.0.1</literal> (called the "API bundle" hereafter), |
| <literal>org.apache.geronimo.bundles:jaxb-impl:2.2.3-1_1</literal> (the "implementation bundle"), |
| <literal>org.apache.geronimo.specs:geronimo-osgi-locator:1.0</literal> (the "locator bundle") and |
| <literal>org.apache.geronimo.specs:geronimo-osgi-registry:1.0</literal> (the "registry bundle"): |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| The implementation bundle retains the <filename>META-INF/services/javax.xml.bind.JAXBContext</filename> |
| resource from the original artifact (<literal>com.sun.xml.bind:jaxb-impl</literal>). |
| In a non OSGi environment, that resource will be used to discover the implementation, following |
| the standard JDK 1.3 service discovery algorithm will (as required by the JAXB specification). |
| This is the equivalent of our <xref linkend="osgi-req-no-separate-bundles"/>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The manifest of the implementation bundle has an attribute <literal>SPI-Provider: true</literal> that indicates |
| that it contains provider implementations that are discovered using the JDK 1.3 service discovery. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The registry bundle creates a <classname>BundleTracker</classname> that looks for |
| the <literal>SPI-Provider</literal> attribute in active bundles. For each bundle |
| that has this attribute set to <literal>true</literal>, it will scan the content of |
| <filename>META-INF/services</filename> and add the discovered services to a registry |
| (Note that the registry bundle supports other ways to declare SPI providers, |
| but this is not really relevant for the present discussion). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The <classname>ContextFinder</classname> class (the interface of which is defined by |
| the JAXB specification and that is used by the <methodname>newInstance</methodname> |
| method in <classname>JAXBContext</classname>) in the API bundle delegates the discovery |
| of the SPI implementation to a static method of the <classname>ProviderLocator</classname> |
| class defined by the locator bundle (which is not specific to JAXB and is used by other |
| API bundles as well). This is true both in an OSGi environment and in a non OSGi environment. |
| </para> |
| <para> |
| The build is configured (using a <literal>Private-Package</literal> instruction) |
| such that the classes of the locator bundle are actually included into the API bundle, thus |
| avoiding an additional dependency. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The <classname>ProviderLocator</classname> class and related code provided by the locator bundle is designed |
| such that in a non OSGi environment, it will simply use JDK 1.3 service discovery to locate |
| the SPI implementation, without ever loading any OSGi specific class. On the other hand, |
| in an OSGi environment, it will query the registry maintained by the registry bundle to locate |
| the provider. The reference to the registry is injected into the <classname>ProviderLocator</classname> |
| class using a bundle activator. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Finally, it should also be noted that the API bundle is configured with <literal>singleton=true</literal>. |
| There is indeed no meaningful way how providers could be matched with different versions of the same API |
| bundle. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| This is an example of a particularly elegant way to satisfy <xref linkend="osgi-req-no-separate-bundles"/>, |
| <xref linkend="osgi-req-same-api"/> and <xref linkend="osgi-req-same-impl-selection"/>, especially because |
| it relies on the same metadata (the <filename>META-INF/services/javax.xml.bind.JAXBContext</filename> resources) |
| in OSGi and non OSGi environments. |
| </para> |
| <para> |
| Obviously, Axiom could reuse the registry and locator bundles developed by Geronimo. This however would |
| contradict <xref linkend="osgi-reg-no-framework"/>. In addition, for Axiom there is no requirement to |
| strictly follow the JDK 1.3 service discovery algorithm. Therefore Axiom should reuse the pattern |
| developed by Geronimo, but not the actual implementation. |
| </para> |
| </section> |
| <section> |
| <title>New abstract APIs</title> |
| <para> |
| Application code rarely uses DOOM as the default Axiom implementation. Several downstream projects |
| (e.g. the Axis2/Rampart combination) use both the default (LLOM) implementation and DOOM. They select |
| the implementation based on the particular context. As of Axiom 1.2.12, the only way to create an object |
| model instance with the DOOM implementation is to use the <classname>DOOMAbstractFactory</classname> API |
| or to instantiate one of the factory classes (<classname>OMDOMMetaFactory</classname>, <classname>OMDOMFactory</classname> |
| or one of the subclasses of <classname>DOMSOAPFactory</classname>). All these classes are part of |
| the <literal>axiom-dom</literal> artifact. This is clearly in contradiction with <xref linkend="osgi-ref-impl-not-exported"/> |
| and <xref linkend="osgi-req-dropin"/>. |
| </para> |
| <para> |
| To overcome this problem the Axiom API must be enhanced to make it possible to select an Axiom |
| implementation based on capabilities/features requested by the application code. E.g. in the case |
| of DOOM, the application code would request a factory that implements the DOM API. It is then up |
| to the Axiom API classes to locate an appropriate implementation, which may be DOOM or another |
| drop-in replacement, as per <xref linkend="osgi-req-dropin"/>. |
| </para> |
| <para> |
| If multiple Axiom implementations are available (on the class path in non OSGi environment or |
| deployed as bundles in an OSGi environment), then the Axiom API must also be able to select an |
| appropriate default implementation if no specific feature is requested by the application code. |
| This can be easily implemented by defining a special feature called "default" that would be |
| declared by any Axiom implementation that is suitable as a default implementation. |
| </para> |
| <note> |
| <para> |
| DOOM is generally not considered suitable as a default implementation because it doesn't |
| implement the complete Axiom API (e.g. it doesn't support <classname>OMSourcedElement</classname>) |
| and because the factory classes are not stateless. |
| </para> |
| </note> |
| <para> |
| Finally, to make the selection algorithm deterministic, there should also be a concept |
| of priority: if multiple Axiom implementations are found for the same feature, then the Axiom API |
| would select the one with the highest priority. |
| </para> |
| <para> |
| This leads to the following design: |
| </para> |
| <orderedlist> |
| <listitem> |
| <para> |
| Every Axiom implementation declares a set of features that it supports. A feature is |
| simply identified by a string. Two features are predefined by the Axiom API: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| <literal>default</literal>: indicates that the implementation is a complete |
| implementation of the Axiom API and may be used as a default implementation. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <literal>dom</literal>: indicates that the implementation supports DOM |
| in addition to the Axiom API. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| For every feature it declares, the Axiom implementation specifies a priority, |
| which is a positive integer. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The relevant Axiom APIs are enhanced so that they take an optional argument |
| specifying the feature requested by the application code. If no explicit feature |
| is requested, then Axiom will use the <literal>default</literal> feature. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| To determine the <classname>OMMetaFactory</classname> to be used, Axiom locates |
| the implementations declaring the requested feature and selects the one that |
| has the highest priority for that feature. |
| </para> |
| </listitem> |
| </orderedlist> |
| <para> |
| A remaining question is how the implementation declares the feature/priority information. |
| There are two options: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Add a method to <classname>OMMetaFactory</classname> that allows the Axiom API |
| to query the feature/priority information from the implementation (i.e. the |
| features and priorities are hardcoded in the implementation). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Let the implementation provide this information declaratively in its metadata |
| (either in the manifest or in a separate resource with a well defined name). |
| Note that in a non OSGi environment, such a metadata resource must be used anyway |
| to enable the Axiom API to locate the <classname>OMMetaFactory</classname> implementations. |
| Therefore this would be a natural place to declare the features as well. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| The second option has the advantage to make it easier for users to debug and tweak |
| the implementation discovery process (e.g. there may be a need to |
| customize the features and priorities declared by the different implementations to ensure |
| that the right implementation is chosen in a particular use case). |
| </para> |
| <para> |
| This leads to the following design decision: |
| the features and priorities (together with the class name of the <classname>OMMetaFactory</classname> |
| implementation) will be defined in an XML descriptor with resource name <filename>META-INF/axiom.xml</filename>. |
| The format of that descriptor must take into account that a single JAR may contain several |
| Axiom implementations (e.g. if the JAR is an uber-JAR repackaged from the standard Axiom JARs). |
| </para> |
| </section> |
| </chapter> |
| |
| <chapter> |
| <title>Release process</title> |
| <section> |
| <title>Release preparation</title> |
| <para> |
| The following items should be checked before starting the release process: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Check for the latest Apache parent POM version (artifact <literal>org.apache:apache</literal>) |
| and if necessary, change the parent of the Axiom root POM. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check the dependencies between Java packages in the <filename>axiom-api</filename> module. |
| The <package>org.apache.axiom.util</package> package (including its subpackages) is specified |
| to contain utility classes that don't depend on higher level APIs. More precisely, |
| <package>org.apache.axiom.util</package> should only have dependencies on |
| <package>org.apache.axiom.ext</package>, but not e.g. on <package>org.apache.axiom.om</package>. |
| <ulink url="http://www.hello2morrow.com/products/sonarj">SonarJ</ulink> can be used |
| to check these dependencies. The following figure shows the expected structure: |
| </para> |
| <figure> |
| <title>Package dependencies for r944680</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="sonarj-944680.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| <para> |
| In contrast, the following figure shows an earlier trunk version of <filename>axiom-api</filename> |
| with incorrect layering and cyclic dependencies involving <package>org.apache.axiom.util</package>: |
| </para> |
| <figure> |
| <title>Package dependencies for r939984</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="sonarj-939984.png" format="PNG"/> |
| </imageobject> |
| </mediaobject> |
| </figure> |
| <para> |
| The check can also be done using <ulink url="http://mojo.codehaus.org/jdepend-maven-plugin/">jdepend-maven-plugin</ulink>. |
| To do this, execute the following command in the <filename>axiom-api</filename> module: |
| </para> |
| <screen>mvn jdepend:generate</screen> |
| <para> |
| Then open <filename>target/site/jdepend-report.html</filename> and go the the "Cycles" section. |
| The report should not show any package cycles involving <package>org.apache.axiom.mime</package>, |
| <package>org.apache.axiom.util</package> and <package>org.apache.axiom.ext</package>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check that the generated Javadoc contains the appropriate set of packages. |
| In particular, unit test related classes should be excluded, except for the test suite |
| classes in <package>org.apache.axiom.ts</package> (we don't need to hide the fact that we have |
| a reusable test suite...). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check that all dependencies and plugins are available from standard |
| repositories. To do this, clean the local repository and execute |
| <command>mvn clean install</command> followed by <command>mvn site</command>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check that the set of license files in the <filename>legal</filename> directory |
| is complete and accurate. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check that the Maven site conforms to the latest version of the |
| <ulink url="http://apache.org/foundation/marks/pmcs">Apache Project |
| Branding Guidelines</ulink>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Check that the <literal>apache-release</literal> profile can be executed properly. |
| To do this, issue the following command: |
| </para> |
| <screen>mvn clean install -Papache-release -Dmaven.test.skip=true</screen> |
| <para> |
| You may also execute a dry run of the release process: |
| </para> |
| <screen>mvn release:prepare -DdryRun=true</screen> |
| <para> |
| After this, you need to clean up using the following command: |
| </para> |
| <screen>mvn release:clean</screen> |
| </listitem> |
| <listitem> |
| <para> |
| Prepare the release note. This should include a description of the major |
| changes in the release as well as a list of resolved JIRA issues. Note that |
| both <filename>index.apt</filename> and <filename>RELEASE-NOTE.txt</filename> |
| need to be updated. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Add an entry for the release to the <filename>download.xml.vm</filename> file and |
| change the links for older releases so that they point to <literal>archive.apache.org</literal> |
| (Since the Axiom project doesn't use branches and produces releases directly from the trunk, |
| there should only be a single mirrored release). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Preview and validate the changes that will be done by the release plugin |
| to the POM files. In order to do this, execute the following command: |
| </para> |
| <screen>mvn release:prepare -DdryRun=true -Dmaven.test.skip=true</screen> |
| <para> |
| Next, compare the <filename>pom.xml.tag</filename> files to the corresponding |
| <filename>pom.xml</filename> files: |
| </para> |
| <screen>for pom in $(find . -name "pom.xml"); do diff $pom $pom.tag; done</screen> |
| <para> |
| The differences should be limited to <sgmltag class="element">version</sgmltag> |
| and <sgmltag class="element">scm</sgmltag> tags. If necessary, change the |
| original POM files to avoid spurious changes. After that, clean up using: |
| </para> |
| <screen>mvn release:clean</screen> |
| </listitem> |
| </itemizedlist> |
| </section> |
| <section> |
| <title>Prerequisites</title> |
| <para> |
| The following things are required to perform the actual release: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| A PGP key that conforms to the <ulink url="http://www.apache.org/dev/release-signing.html">requirement |
| for Apache release signing</ulink>. To make the release process easier, the passphrase for the |
| code signing key should be configured in <filename>${user.home}/.m2/settings.xml</filename>: |
| </para> |
| <screen><![CDATA[<settings> |
| ... |
| <profiles> |
| <profile> |
| <id>apache-release</id> |
| <properties> |
| <gpg.passphrase> <!-- YOUR KEY PASSPHRASE --> </gpg.passphrase> |
| </properties> |
| </profile> |
| </profiles> |
| ... |
| </settings>]]></screen> |
| </listitem> |
| <listitem> |
| <para> |
| The release process uses a Nexus staging repository. Every committer should have access to the corresponding |
| staging profile in Nexus. To validate this, login to <literal>repository.apache.org</literal> and check that |
| you can see the <literal>org.apache.ws</literal> staging profile. The credentials used to deploy to Nexus |
| should be added to <filename>settings.xml</filename>: |
| </para> |
| <screen><![CDATA[<servers> |
| ... |
| <server> |
| <id>apache.releases.https</id> |
| <username><!-- ASF username --></username> |
| <password><!-- ASF LDAP password --></password> |
| </server> |
| ... |
| </servers>]]></screen> |
| </listitem> |
| </itemizedlist> |
| </section> |
| <section> |
| <title>Release</title> |
| <para> |
| In order to prepare the release artifacts for vote, execute the following steps: |
| </para> |
| <procedure> |
| <step> |
| <para> |
| Update the release date in <filename>download.xml.vm</filename> and <filename>index.apt</filename>. |
| </para> |
| </step> |
| <step> |
| <para> |
| Temporarily disable the Jenkins build(s) for Axiom, in order to avoid accidental |
| deployment of the release candidate to the local repository of a Jenkins executor |
| if the release process fails somewhere in the middle and/or a Jenkins build |
| starts at the wrong moment. |
| </para> |
| </step> |
| <step> |
| <para> |
| Start the release process with the following command: |
| </para> |
| <screen>mvn release:prepare</screen> |
| <para> |
| When asked for the "SCM release tag or label", override the default value |
| (<literal>axiom-x.y.z</literal>) by entering a tag in the form |
| <literal>x.y.z</literal>, which is compatible with the tag names used for |
| previous releases. |
| </para> |
| <para> |
| The above command will create a tag in Subversion and increment the version |
| number of the trunk to the next development version. It will also create |
| a <filename>release.properties</filename> file that will be used in the next step. |
| </para> |
| </step> |
| <step> |
| <para> |
| Perform the release using the following command: |
| </para> |
| <screen>mvn release:perform</screen> |
| <para> |
| This will upload the release artifacts to the Nexus staging repository. |
| </para> |
| </step> |
| <step> |
| <para> |
| Log in to the Nexus repository (<ulink url="https://repository.apache.org/"/> |
| and close the staging repository. The name of the staging profile is |
| <literal>org.apache.ws</literal>. See <ulink url="http://maven.apache.org/developers/release/apache-release.html"/> |
| for a more thorough description of this step. |
| </para> |
| </step> |
| <step> |
| <para> |
| Generate and deploy the Maven site on a public Web server. You may use |
| <literal>people.apache.org</literal> for this. |
| </para> |
| </step> |
| <step> |
| <para> |
| Start the release vote by sending a mail to <literal>dev@ws.apache.org</literal>. |
| The mail should mention the following things: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| The list of issues solved in the release (by linking to the relevant |
| JIRA view). |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The location of the Nexus staging repository. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The location where source and binary packages may be downloaded. |
| This can be a reference to the location inside the staging repository. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| A link to the preview of the Maven site. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </step> |
| <step> |
| <para> |
| Reenable the Jenkins build(s). |
| </para> |
| </step> |
| </procedure> |
| <para> |
| If the vote passes, execute the following steps: |
| </para> |
| <procedure> |
| <step> |
| <para> |
| Promote the artifacts in the staging repository. See |
| <ulink url="http://maven.apache.org/developers/release/apache-release.html"/> |
| for detailed instructions for this step. |
| </para> |
| </step> |
| <step> |
| <para> |
| Log in to <literal>people.apache.org</literal> and publish the release |
| distributions to <literal>www.apache.org</literal>. The <filename>etc/dist.py</filename> |
| script can be used for that: |
| </para> |
| <screen>cd /www/www.apache.org/dist/ws/commons/axiom |
| umask 0002 |
| python <replaceable>path_to_etc</replaceable>/dist.py <replaceable>version</replaceable></screen> |
| <para> |
| <replaceable>version</replaceable> is the release version, e.g. <literal>1.2.9</literal>. |
| </para> |
| <para> |
| If not yet done, export your public key and append it to the <filename>KEYS</filename> |
| file located in <filename>/www/www.apache.org/dist/ws/commons/axiom</filename>. The command |
| to export a public key is as follows: |
| </para> |
| <screen>gpg --armor --export <replaceable>key_id</replaceable></screen> |
| </step> |
| <step> |
| <para> |
| Check out the release tag from Subversion and generate the Maven site. |
| Also check out the existing site: |
| </para> |
| <screen>svn co https://svn.apache.org/repos/asf/webservices\ |
| /axiom/site axiom-site</screen> |
| <para> |
| The existing site needs to be overwritten with the site generated for the new |
| release. This can be done easily using the <filename>etc/syncsite.py</filename> script |
| (requires Python 2.6). It will copy the files and execute any necessary Subversion |
| commands to add new files and to delete files that no longer exist. After executing the |
| script, commit the changes to Subversion. |
| </para> |
| <important> |
| <para> |
| When generating the site, please use a recent JDK version, because some older versions |
| generate broken links. |
| </para> |
| </important> |
| </step> |
| <step> |
| <para> |
| Log in to <literal>people.apache.org</literal> and update the site: |
| </para> |
| <screen>cd /www/ws.apache.org/axiom/ |
| umask 0002 |
| svn update</screen> |
| <para> |
| The umask setting makes sure that other members of the ws group will be able |
| to update the site as well. |
| </para> |
| </step> |
| </procedure> |
| <para> |
| It may take several hours before all the updates have been synchronized to the relevant |
| ASF systems. Before proceeding, check that |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| the Maven artifacts for the release are available from the Maven central repository; |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| the Maven site has been synchronized to <ulink url="http://ws.apache.org/axiom/"/>; |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| the binary and source distributions can be downloaded from <ulink url="http://ws.apache.org/axiom/download.cgi"/>. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| Once everything is in place, send announcements to <literal>users@ws.apache.org</literal> |
| and <literal>announce@apache.org</literal>. Since the two lists have different conventions, audiences |
| and moderation policies, to send the announcement separately to the two lists. |
| </para> |
| <para> |
| Sample announcement: |
| </para> |
| <blockquote> |
| <para> |
| Apache Axiom Team is pleased to announce the release of Axiom x.y.z. The release is available |
| for download at: |
| </para> |
| <para> |
| http://ws.apache.org/axiom/download.cgi |
| </para> |
| <para> |
| Apache Axiom is a StAX-based, XML Infoset compliant object model which supports on-demand building |
| of the object tree. It supports a novel "pull-through" model which allows one to turn off the tree |
| building and directly access the underlying pull event stream. It also has built in support for |
| XML Optimized Packaging (XOP) and MTOM, the combination of which allows XML to carry binary |
| data efficiently and in a transparent manner. The combination of these is an easy to use API |
| with a very high performant architecture! |
| </para> |
| <para> |
| Developed as part of Apache Axis2, Apache Axiom is the core of Apache Axis2. However, it is a |
| pure standalone XML Infoset model with novel features and can be used independently of Apache Axis2. |
| </para> |
| <para> |
| Highlights in this release: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| ... |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| ... |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| Resolved JIRA issues: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| [WSCOMMONS-513] Behavior of insertSiblingAfter and insertSiblingBefore is not well defined for orphan nodes |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| [WSCOMMONS-488] The sequence of events produced by OMStAXWrapper with inlineMTOM=false is inconsistent |
| </para> |
| </listitem> |
| </itemizedlist> |
| </blockquote> |
| <para> |
| For <literal>users@ws.apache.org</literal>, the subject (<quote>Axiom x.y.z released</quote>) should be |
| prefixed with <quote>[ANN][Axiom]</quote>, while for <literal>announce@apache.org</literal> |
| <quote>[ANN]</quote> is enough. Note that mail to <literal>announce@apache.org</literal> must be |
| sent from an <literal>apache.org</literal> address. |
| </para> |
| </section> |
| <section> |
| <title>Post-release actions</title> |
| <itemizedlist> |
| <listitem> |
| <para> |
| Update the DOAP file (see <filename>etc/axiom.rdf</filename>) and add a new entry |
| for the release. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Update the status of the release version in the AXIOM project in JIRA. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Remove archived releases from <filename>/www/www.apache.org/dist/ws/commons/axiom</filename> |
| on <literal>people.apache.org</literal>. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| <section> |
| <title>References</title> |
| <para> |
| The following documents are useful when preparing and executing the release: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| <ulink url="http://www.apache.org/legal/src-headers.html">ASF Source Header and Copyright Notice Policy</ulink> |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <ulink url="http://apache.org/foundation/marks/pmcs">Apache Project Branding Guidelines</ulink> |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <ulink url="http://projects.apache.org/doap.html">DOAP Files</ulink> |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <ulink url="http://www.apache.org/dev/release-publishing.html">Publishing Releases</ulink> |
| </para> |
| </listitem> |
| </itemizedlist> |
| </section> |
| </chapter> |
| |
| <chapter> |
| <title>The StAX specification</title> |
| <para> |
| The StAX specification comprises two parts: a specification document titled <quote>Streaming API |
| For XML JSR-173 Specification</quote> and a Javadoc describing the API. Both can be downloaded from the |
| <ulink url="http://jcp.org/en/jsr/detail?id=173">JSR-173 page</ulink>. Since StAX is part of Java 6, |
| the Javadocs can also be viewed |
| <ulink url="http://java.sun.com/javase/6/docs/api/javax/xml/stream/package-summary.html">online</ulink>. |
| </para> |
| <section> |
| <title>Semantics of the <methodname>setPrefix</methodname> method</title> |
| <para> |
| Probably one of the more obscure parts of the StAX specifications is the meaning of the |
| <methodname>setPrefix</methodname><footnote><para>For simplicity, we only discuss |
| <methodname>setPrefix</methodname> here. The same remarks also apply to |
| <methodname>setDefaultNamespace</methodname>.</para></footnote> method defined by <classname>XMLStreamWriter</classname>. |
| To understand how this method works, it is necessary to look at different parts of the specification: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| The Javadoc of the <methodname>setPrefix</methodname> method. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The table shown in the Javadoc of the <classname>XMLStreamWriter</classname> class |
| in Java 6<footnote><para>This table is not included in the Javadoc in the original StAX |
| specification.</para></footnote>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Section 5.2.2, <quote>Binding Prefixes</quote> of the specification. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The example shown in section 5.3.2, <quote>XMLStreamWriter</quote> of the specification. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| In addition, it is important to note the following facts: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| The terms <firstterm>defaulting prefixes</firstterm> used in section 5.2.2 of the |
| specification and <firstterm>namespace repairing</firstterm> used in the Javadocs |
| of <classname>XMLStreamWriter</classname> are synonyms. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| The methods writing namespace qualified information items, i.e. |
| <methodname>writeStartElement</methodname>, <methodname>writeEmptyElement</methodname> |
| and <methodname>writeAttribute</methodname> all come in two variants: one that |
| takes a namespace URI and a prefix as arguments and one that only takes a |
| namespace URI, but no prefix. |
| </para> |
| </listitem> |
| </itemizedlist> |
| <para> |
| The purpose of the <methodname>setPrefix</methodname> method is simply to define the prefixes that |
| will be used by the variants of the <methodname>writeStartElement</methodname>, |
| <methodname>writeEmptyElement</methodname> and <methodname>writeAttribute</methodname> methods |
| that only take a namespace URI (and the local name). This becomes clear by looking at the |
| table in the <classname>XMLStreamWriter</classname> Javadoc. Note that a call to |
| <methodname>setPrefix</methodname> doesn't cause any output and it is still necessary |
| to use <methodname>writeNamespace</methodname> to actually write the necessary |
| namespace declarations. Otherwise the produced document will not be well formed with |
| respect to namespaces. |
| </para> |
| <para> |
| The Javadoc of the <methodname>setPrefix</methodname> method also clearly defines the scope |
| of the prefix bindings defined using that method: a prefix bound using |
| <methodname>setPrefix</methodname> remains valid till the invocation of |
| <methodname>writeEndElement</methodname> corresponding to the last invocation of |
| <methodname>writeStartElement</methodname>. While not explicitly mentioned in the |
| specifications, it is clear that a prefix binding may be masked by another binding |
| for the same prefix defined in a nested element. |
| </para> |
| <para> |
| An aspect that may cause confusion is the fact that in the example shown in section |
| 5.3.2 of the specifications, the calls to <methodname>setPrefix</methodname> (and |
| <methodname>setDefaultNamespace</methodname>) all appear immediately before a |
| call to <methodname>writeStartElement</methodname> or <methodname>writeEmptyElement</methodname>. |
| This may lead people to incorrectly believe that a prefix binding defined using |
| <methodname>setPrefix</methodname> only applies to the next element |
| written<footnote><para>Another factor that contributes to the confusion is that in SAX, |
| prefix mappings are always generated before the corresponding <methodname>startElement</methodname> |
| event and that their scope ends with the corresponding <methodname>endElement</methodname> |
| event. This is so because the <classname>ContentHandler</classname> interface specifies that |
| <quote>all <methodname>startPrefixMapping</methodname> events will occur immediately before the |
| corresponding <methodname>startElement</methodname> event, and all <methodname>endPrefixMapping</methodname> |
| events will occur immediately after the corresponding <methodname>endElement</methodname> |
| event</quote>.</para></footnote>. |
| This interpretation is clearly in contradiction with the <methodname>setPrefix</methodname> |
| Javadoc, unless one assumes that <quote>the current START_ELEMENT / END_ELEMENT pair</quote> |
| means the element opened by a call to <methodname>writeStartElement</methodname> immediately following |
| the call to <methodname>setPrefix</methodname>. This however would be a very arbitrary interpretation |
| of the Javadoc<footnote><para>Early versions of XL XP-J were based on this interpretation of the |
| specifications, but this has been corrected. Versions conforming to the specifications support |
| a special property called <varname>javax.xml.stream.XMLStreamWriter.isSetPrefixBeforeStartElement</varname>, |
| which always returns <code>Boolean.FALSE</code>. This allows to easily distinguish the non |
| conforming versions from the newer versions. Note that in contrast to what the usage of the reserved |
| <literal>javax.xml.stream</literal> prefix suggests, this is a vendor specific property that |
| is not supported by other implementations.</para></footnote>. |
| </para> |
| <para> |
| The correctness of the comments in the previous paragraph can be checked using the following |
| code snippet: |
| </para> |
| <programlisting>XMLOutputFactory f = XMLOutputFactory.newInstance(); |
| XMLStreamWriter writer = f.createXMLStreamWriter(System.out); |
| writer.writeStartElement("root"); |
| writer.setPrefix("p", "urn:ns1"); |
| writer.writeEmptyElement("urn:ns1", "element1"); |
| writer.writeEmptyElement("urn:ns1", "element2"); |
| writer.writeEndElement(); |
| writer.flush(); |
| writer.close();</programlisting> |
| <para> |
| This produces the following output<footnote><para>This has been tested with |
| Woodstox 3.2.9, SJSXP 1.0.1 and version 1.2.0 of the reference |
| implementation.</para></footnote>: |
| </para> |
| <screen><![CDATA[<root><p:element1/><p:element2/></root>]]></screen> |
| <para> |
| Since the code doesn't call <methodname>writeNamespace</methodname>, the output is obviously not |
| well formed with respect to namespaces, but it also clearly shows that the scope of the |
| prefix binding for <literal>p</literal> extends to the end of the |
| <sgmltag class="element">root</sgmltag> element and is not limited to |
| <sgmltag class="element">element1</sgmltag>. |
| </para> |
| <para> |
| To avoid unexpected results and keep the code maintainable, it is in general advisable to keep |
| the calls to <methodname>setPrefix</methodname> and <methodname>writeNamespace</methodname> aligned, |
| i.e. to make sure that the scope (in <classname>XMLStreamWriter</classname>) of the prefix binding |
| defined by <methodname>setPrefix</methodname> is compatible with the scope (in the produced |
| document) of the namespace declaration written by the corresponding call |
| to <methodname>writeNamespace</methodname>. This makes it necessary to write code like this: |
| </para> |
| <programlisting>writer.writeStartElement("p", "element1", "urn:ns1"); |
| writer.setPrefix("p", "urn:ns1"); |
| writer.writeNamespace("p", "urn:ns1");</programlisting> |
| <para> |
| As can be seen from this code snippet, keeping the two scopes in sync makes it necessary to use |
| the <methodname>writeStartElement</methodname> variant which takes an explicit prefix. Note that |
| this somewhat conflicts with the purpose of the <methodname>setPrefix</methodname> method; |
| one may consider this as a flaw in the design of the StAX API. |
| </para> |
| </section> |
| <section> |
| <title>The three <classname>XMLStreamWriter</classname> usage patterns</title> |
| <para> |
| Drawing the conclusions from the previous section and taking into account that |
| <classname>XMLStreamWriter</classname> also has a <quote>namespace repairing</quote> |
| mode, one can see that there are in fact three different ways to use |
| <classname>XMLStreamWriter</classname>. These usage patterns correspond to the |
| three bullets in section 5.2.2 of the StAX specification<footnote><para>The content |
| of this section is largely based on a <ulink url="http://markmail.org/message/olsdl3p3gciqqeob">reply |
| posted by Tatu Saloranta on the Axiom mailing list</ulink>. Tatu is the main developer of the |
| Woodstox project.</para></footnote>: |
| </para> |
| <orderedlist> |
| <listitem> |
| <para> |
| In the <quote>namespace repairing</quote> mode (enabled by the |
| <varname>javax.xml.stream.isRepairingNamespaces</varname> property), the writer |
| takes care of all namespace bindings and declarations, with minimal help from |
| the calling code. This will always produce output that is well-formed with respect |
| to namespaces. On the other hand, this adds some overhead and the result may |
| depend on the particular StAX implementation (though the result produced by |
| different implementations will be equivalent). |
| </para> |
| <para> |
| In repairing mode the calling code should avoid writing namespaces explicitly |
| and leave that job to the writer. There is also no need to call |
| <methodname>setPrefix</methodname>, except to suggest a preferred prefix for |
| a namespace URI. All variants of <methodname>writeStartElement</methodname>, |
| <methodname>writeEmptyElement</methodname> and <methodname>writeAttribute</methodname> |
| may be used in this mode, but the implementation can choose whatever prefix mapping |
| it wants, as long as the output results in proper URI mapping for elements and |
| attributes. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Only use the variants of the writer methods that take an explicit prefix together |
| with the namespace URI. In this usage pattern, <methodname>setPrefix</methodname> |
| is not used at all and it is the responsibility of the calling code to keep |
| track of prefix bindings. |
| </para> |
| <para> |
| Note that this approach is difficult to implement when different parts of the output document |
| will be produced by different components (or even different libraries). Indeed, when |
| passing the <classname>XMLStreamWriter</classname> from one method or component |
| to the other, it will also be necessary to pass additional information about the |
| prefix mappings in scope at that moment, unless the it is acceptable to let the |
| called method write (potentially redundant) namespace declarations for all namespaces |
| it uses. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| Use <methodname>setPrefix</methodname> to keep track of prefix bindings and make sure that |
| the bindings are in sync with the namespace declarations that have been written, |
| i.e. always use <methodname>setPrefix</methodname> immediately before or immediately |
| after each call to <methodname>writeNamespace</methodname>. Note that the code is |
| still free to use all variants of <methodname>writeStartElement</methodname>, |
| <methodname>writeEmptyElement</methodname> and <methodname>writeAttribute</methodname>; |
| it only needs to make sure that the usage it makes of these methods is consistent with |
| the prefix bindings in scope. |
| </para> |
| <para> |
| The advantage of this approach is that it allows to write modular code: when a |
| method receives an <classname>XMLStreamWriter</classname> object (to write |
| part of the document), it can use |
| the namespace context of that writer (i.e. <methodname>getPrefix</methodname> |
| and <methodname>getNamespaceContext</methodname>) to determine which namespace |
| declarations are currently in scope in the output document and to avoid |
| redundant or conflicting namespace declarations. Note that in order to do so, |
| such code will have to check for an existing prefix binding before starting |
| to use a namespace. |
| </para> |
| </listitem> |
| </orderedlist> |
| </section> |
| </chapter> |
| |
| <appendix> |
| <title>Appendix</title> |
| <section id="install.ibm.jdk"> |
| <title>Installing IBM's JDK on Debian Linux</title> |
| <procedure> |
| <step> |
| <para> |
| Make sure that <literal>fakeroot</literal> and <literal>java-package</literal> |
| are installed: |
| </para> |
| <screen># <userinput>apt-get install fakeroot java-package</userinput></screen> |
| </step> |
| <step> |
| <para> |
| Download the <filename>.tgz</filename> version of the JDK from |
| <ulink url="http://www.ibm.com/developerworks/java/jdk/linux/download.html"/>. |
| </para> |
| </step> |
| <step> |
| <para> |
| Edit <filename>/usr/share/java-package/ibm-j2sdk.sh</filename> and (if necessary) |
| add an entry for the particular version of the IBM JDK downloaded in the previous |
| step. |
| </para> |
| </step> |
| <step> |
| <para> |
| Build a Debian package from the tarball: |
| </para> |
| <screen>$ <userinput>fakeroot make-jpkg <replaceable>xxxx</replaceable>.tgz</userinput></screen> |
| </step> |
| <step> |
| <para> |
| Install the Debian package. |
| </para> |
| </step> |
| </procedure> |
| </section> |
| </appendix> |
| </book> |