Merged latest changes from trunk.
diff --git a/code-coverage/pom.xml b/code-coverage/pom.xml
index ba6483a..f0c51bd 100644
--- a/code-coverage/pom.xml
+++ b/code-coverage/pom.xml
@@ -80,7 +80,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>axiom-impl</artifactId>
<version>${project.version}</version>
- <classifier>original</classifier>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -100,7 +99,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>axiom-dom</artifactId>
<version>${project.version}</version>
- <classifier>original</classifier>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -169,6 +167,14 @@
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>spring-ws-tests</artifactId>
+ <version>${project.version}</version>
+ <classifier>jacoco</classifier>
+ <type>exec</type>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>axiom-samples</artifactId>
<version>${project.version}</version>
<classifier>jacoco</classifier>
diff --git a/devguide/src/docbkx/devguide.xml b/devguide/src/docbkx/devguide.xml
index 63815a3..c573300 100644
--- a/devguide/src/docbkx/devguide.xml
+++ b/devguide/src/docbkx/devguide.xml
@@ -170,7 +170,41 @@
</chapter>
<chapter>
- <title>OSGi integration</title>
+ <title>OSGi integration and separation between API and implementation</title>
+ <section>
+ <title>Introduction</title>
+ <para>
+ This chapter addresses two related architectural questions:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ OSGi support was originally introduced in Axiom 1.2.9, but the implementation had
+ a couple of flaws. This chapter discusses the rationale behind the new OSGi
+ support introduced in Axiom 1.2.13.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Axiom is designed as a set of abstract APIs for which two implementations are
+ provided: LLOM and DOOM. It is important to make a clear distinction between what
+ is part of the public API and what should be considered implementation classes that
+ must not be used by application code directly. This also implies that Axiom must
+ provide the necessary APIs to allow application code to access all features without
+ the need to access implementation classes directly. This chapter in particular
+ discusses the question how application code can request factories that support DOM
+ without the need to refer directly to DOOM.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ These two questions are closely related because OSGi allows to enforce the distinction
+ between public API and implementation classes by carefully selecting the packages
+ exported by the different bundles: only classes belonging to the public API
+ should be exported, while implementation classes should be private to the bundles
+ containing them. This in turn has implications for the packaging of these artifacts.
+ </para>
+ </section>
<section>
<title>Requirements</title>
<formalpara id="osgi-req-no-separate-bundles">
@@ -195,6 +229,13 @@
doesn't need to be rewritten.
</para>
</formalpara>
+ <note>
+ <para>
+ This requirement was already satisfied by the OSGi support introduced in Axiom 1.2.9.
+ It therefore also ensures that the transition to the new OSGi support in Axiom 1.2.13
+ is transparent for applications that already use Axiom in an OSGi container.
+ </para>
+ </note>
<formalpara id="osgi-req-same-impl-selection">
<title>Requirement 3</title>
<para>
@@ -205,19 +246,12 @@
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.
+ Only classes belonging to the public API should be exported by the OSGi bundles.
+ Implementation classes should not be exported. In particular,
+ 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.
@@ -234,31 +268,32 @@
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:
+ Although this requirement is easy to implement for the Axiom project, it requires
+ changes to downstreams project to make this actually 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>.
+ there used to be many places in Axis2 that still referred directly to Axiom implementation classes.
+ The same was true for Rampart and Sandesha2. This has now been fixed and all three projects
+ use <literal>axiom-impl</literal> and <literal>axiom-dom</literal> as dependencies in scope
+ <literal>runtime</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
+ magic will be required here to create Abdera OSGi bundles that work properly with
the Axiom bundles.
</para>
</listitem>
+ <listitem>
+ <para>
+ For Spring Web Services this issue is addressed by
+ <ulink url="https://jira.springsource.org/browse/SWS-822">SWS-822</ulink>.
+ </para>
+ </listitem>
</itemizedlist>
</note>
<formalpara id="osgi-req-dropin">
@@ -515,8 +550,9 @@
<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.
+ implement the complete Axiom API (e.g. it doesn't support <classname>OMSourcedElement</classname>).
+ In addition, in earlier versions of Axiom, the factory classes for DOOM were not stateless
+ (see <ulink url="https://issues.apache.org/jira/browse/AXIOM-412">AXIOM-412</ulink>).
</para>
</note>
<para>
@@ -603,6 +639,119 @@
Axiom implementations (e.g. if the JAR is an uber-JAR repackaged from the standard Axiom JARs).
</para>
</section>
+ <section>
+ <title>Common implementation classes</title>
+ <para>
+ Obviously the LLOM and DOOM implementations share some amount of common code. Historically,
+ implementation classes reusable between LLOM and DOOM were placed in <literal>axiom-api</literal>.
+ This however tends to blur the distinction between the public API and implementation classes.
+ Starting with Axiom 1.2.13 such classes are placed into a separate module called
+ <literal>axiom-common-impl</literal>. However, <literal>axiom-common-impl</literal> cannot simply
+ be a dependency of <literal>axiom-impl</literal> and <literal>axiom-dom</literal>.
+ The reason is that in an OSGi environment, the <literal>axiom-common-impl</literal> bundle
+ would have to export these shared classes, which is in contradiction with <xref linkend="osgi-ref-impl-not-exported"/>.
+ Therefore the code from <literal>axiom-common-impl</literal> needs to be packaged into
+ <literal>axiom-impl</literal> and <literal>axiom-dom</literal> by the build process so that
+ the <literal>axiom-common-impl</literal> artifact is not required at runtime.
+ <xref linkend="osgi-req-no-separate-bundles"/> forbids using embedded JARs to achieve this.
+ Instead <literal>maven-shade-plugin</literal> is used to include the classes
+ from <literal>axiom-common-impl</literal> into <literal>axiom-impl</literal> and <literal>axiom-dom</literal>
+ (and to modify the POMs to remove the dependencies on <literal>axiom-common-impl</literal>).
+ </para>
+ <para>
+ This raises the question whether <literal>maven-shade-plugin</literal> should be configured to
+ simply copy the classes or to relocate them (i.e. to change their package names). There are a couple
+ of arguments in favor of relocating them:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ According to <xref linkend="osgi-req-no-separate-bundles"/>, the Axiom artifacts should be
+ usable both as normal JARs and as OSGi bundles. Obviously the expectation is that from the
+ point of view of application code, they should work in the same in OSGi and non OSGi environments.
+ Relocation is required if one wants to strictly satisfy this requirement even if different versions
+ of <literal>axiom-impl</literal> and <literal>axiom-dom</literal> are mixed.
+ Since the container creates separate class loaders for the <literal>axiom-impl</literal> and <literal>axiom-dom</literal> bundles,
+ it is always possible to do that in an OSGi environment: even if the shared classes
+ included in <literal>axiom-impl</literal> and <literal>axiom-dom</literal> are
+ not relocated, but have the same names, this will not result in conflicts.
+ The situation is different in a non OSGi environment where the classes in <literal>axiom-impl</literal>
+ and <literal>axiom-dom</literal> are loaded by the same class loader. If the shared classes
+ are not relocated, then there may be a conflict if the versions don't match.
+ </para>
+ <para>
+ However, in practice it is unlikely that there are valid use case where one would use
+ <literal>axiom-impl</literal> and <literal>axiom-dom</literal> artifacts from different Axiom versions.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Relocation allows to preserve compatibility when duplicate code from
+ <literal>axiom-impl</literal> and <literal>axiom-dom</literal> is merged and moved
+ to <literal>axiom-common-impl</literal>. The <classname>OMNamespaceImpl</classname>,
+ <classname>OMNavigator</classname> and <classname>OMStAXWrapper</classname> classes
+ from <literal>axiom-impl</literal> and the <classname>NamespaceImpl</classname>,
+ <classname>DOMNavigator</classname> and <classname>DOMStAXWrapper</classname>
+ classes from <literal>axiom-dom</literal> that existed in earlier versions of Axiom
+ are examples of this. The classes in <literal>axiom-dom</literal> were almost identical
+ to the corresponding classes in <literal>axiom-impl</literal>. These classes have been
+ merged and moved to <literal>axiom-common-impl</literal>. Relocation then allows them
+ to retain their original name (including the original package name) in the
+ <literal>axiom-impl</literal> and <literal>axiom-dom</literal> artifacts.
+ </para>
+ <para>
+ However, this is only a concern if one wants to preserve compatibility with existing
+ code that directly uses these implementation specific classes (which is something that is
+ strongly discouraged). One example where this was relevant was the SAAJ implementation
+ in Axis2 which used to be very strongly coupled to the DOOM implementation. This however
+ has been fixed now.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Using relocation also has some serious disadvantages:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Stack traces may contain class names that don't match class names in the Axiom source
+ code, making debugging harder.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Axiom now uses JaCoCo to produce code coverage reports. However these reports are
+ incomplete if relocation is used. This doesn't affect test cases executed in
+ the <literal>axiom-impl</literal> and <literal>axiom-dom</literal> modules
+ (because they are executed with the original classes), but tests in separate modules
+ (such as integration tests). There are actually two issues:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ For the relocated classes, JaCoCo is unable to find the corresponding source code.
+ This means that the reported code coverage is inaccurate for classes in
+ <literal>axiom-common-impl</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Relocation not only modifies the classes in <literal>axiom-common-impl</literal>, but
+ also the classes in <literal>axiom-impl</literal> and <literal>axiom-dom</literal>
+ that use them. JaCoCo <ulink url="https://github.com/jacoco/jacoco/issues/51">detects this</ulink>
+ and excludes the data from the coverage analysis. This means that the
+ reported code coverage will also be inaccurate for classes in
+ <literal>axiom-impl</literal> and <literal>axiom-dom</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ In Axiom 1.2.14 relocation was used, but this has been changed in Axiom 1.2.15 because the disadvantages
+ outweigh the advantages.
+ </para>
+ </section>
</chapter>
<chapter>
diff --git a/modules/axiom-common-impl-testsuite/pom.xml b/modules/axiom-common-impl-testsuite/pom.xml
deleted file mode 100644
index cc127a1..0000000
--- a/modules/axiom-common-impl-testsuite/pom.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.ws.commons.axiom</groupId>
- <artifactId>axiom</artifactId>
- <version>1.2.15-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
- <artifactId>axiom-common-impl-testsuite</artifactId>
- <name>Axiom Common Implementation Test Suite</name>
- <description>
- Test suite containing test cases that apply only to implementations based on
- axiom-common-impl.
- </description>
- <!-- This needs to be set explicitly because the project structure implies that the Maven calculated defaults are wrong -->
- <scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/axiom/modules/axiom-common-impl-testsuite</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/axiom/modules/axiom-common-impl-testsuite</developerConnection>
- <url>http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-common-impl-testsuite</url>
- </scm>
- <!-- This also needs to be set explicitly because the Maven calculated URL would point to nowhere -->
- <url>http://ws.apache.org/axiom/</url>
- <dependencies>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>axiom-common-impl</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>axiom-testutils</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>axiom-api</artifactId>
- <classifier>tests</classifier>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>xmlunit</groupId>
- <artifactId>xmlunit</artifactId>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-site-plugin</artifactId>
- <configuration>
- <skip>true</skip>
- <skipDeploy>true</skipDeploy>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestCase.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestCase.java
deleted file mode 100644
index d066da1..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestCase.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts;
-
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.testutils.suite.TestCaseEx;
-
-public abstract class CommonImplTestCase extends TestCaseEx {
- protected final OMMetaFactory metaFactory;
-
- public CommonImplTestCase(OMMetaFactory metaFactory) {
- this.metaFactory = metaFactory;
- }
-}
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestSuiteBuilder.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestSuiteBuilder.java
deleted file mode 100644
index 81fe7d4..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/CommonImplTestSuiteBuilder.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts;
-
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.testutils.suite.TestSuiteBuilder;
-import org.apache.axiom.ts.om.navigator.TestFullyBuilt;
-import org.apache.axiom.ts.om.navigator.TestHalfBuilt;
-import org.apache.axiom.ts.om.navigator.TestHalfBuiltStep;
-
-public class CommonImplTestSuiteBuilder extends TestSuiteBuilder {
- private final OMMetaFactory metaFactory;
-
- public CommonImplTestSuiteBuilder(OMMetaFactory metaFactory) {
- this.metaFactory = metaFactory;
- }
-
- protected void addTests() {
- addTest(new TestFullyBuilt(metaFactory));
- addTest(new TestHalfBuilt(metaFactory));
- addTest(new TestHalfBuiltStep(metaFactory));
- }
-}
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/OMNavigatorTestCase.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/OMNavigatorTestCase.java
deleted file mode 100644
index 096cdb3..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/OMNavigatorTestCase.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts.om.navigator;
-
-import javax.xml.stream.XMLStreamReader;
-
-import org.apache.axiom.om.AbstractTestCase;
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.om.TestConstants;
-import org.apache.axiom.om.util.StAXUtils;
-import org.apache.axiom.soap.SOAPEnvelope;
-import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
-import org.apache.axiom.ts.CommonImplTestCase;
-
-public abstract class OMNavigatorTestCase extends CommonImplTestCase {
- protected SOAPEnvelope envelope;
- protected StAXSOAPModelBuilder builder;
-
- public OMNavigatorTestCase(OMMetaFactory metaFactory) {
- super(metaFactory);
- }
-
- protected void setUp() throws Exception {
- XMLStreamReader xmlStreamReader = StAXUtils.
- createXMLStreamReader(AbstractTestCase.getTestResource(TestConstants.SOAP_SOAPMESSAGE1));
- builder = new StAXSOAPModelBuilder(metaFactory, xmlStreamReader, null);
- envelope = (SOAPEnvelope) builder.getDocumentElement();
- }
-
- protected void tearDown() throws Exception {
- builder.close();
- }
-}
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestFullyBuilt.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestFullyBuilt.java
deleted file mode 100644
index e6da5f9..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestFullyBuilt.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts.om.navigator;
-
-import java.io.ByteArrayOutputStream;
-
-import javax.xml.stream.XMLStreamWriter;
-
-import org.apache.axiom.om.OMConstants;
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.om.OMSerializable;
-import org.apache.axiom.om.impl.common.OMNavigator;
-import org.apache.axiom.om.util.StAXUtils;
-
-public class TestFullyBuilt extends OMNavigatorTestCase {
- public TestFullyBuilt(OMMetaFactory metaFactory) {
- super(metaFactory);
- }
-
- protected void runTest() throws Throwable {
- assertNotNull(envelope);
- //dump the out put to a temporary file
- XMLStreamWriter output =
- StAXUtils.createXMLStreamWriter(
- new ByteArrayOutputStream(), OMConstants.DEFAULT_CHAR_SET_ENCODING);
- envelope.serialize(output);
-
- //now the OM is fully created -> test the navigation
- OMNavigator navigator = new OMNavigator(envelope);
- OMSerializable node = null;
- while (navigator.isNavigable()) {
- node = navigator.next();
- assertNotNull(node);
- }
- }
-}
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuilt.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuilt.java
deleted file mode 100644
index fb5b682..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuilt.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts.om.navigator;
-
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.om.OMSerializable;
-import org.apache.axiom.om.impl.common.OMNavigator;
-
-public class TestHalfBuilt extends OMNavigatorTestCase {
- public TestHalfBuilt(OMMetaFactory metaFactory) {
- super(metaFactory);
- }
-
- protected void runTest() throws Throwable {
- assertNotNull(envelope);
- //now the OM is not fully created. Try to navigate it
- OMNavigator navigator = new OMNavigator(envelope);
- OMSerializable node = null;
- while (navigator.isNavigable()) {
- node = navigator.next();
- assertNotNull(node);
- }
- }
-}
diff --git a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuiltStep.java b/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuiltStep.java
deleted file mode 100644
index b7a6f32..0000000
--- a/modules/axiom-common-impl-testsuite/src/main/java/org/apache/axiom/ts/om/navigator/TestHalfBuiltStep.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.ts.om.navigator;
-
-import org.apache.axiom.om.OMMetaFactory;
-import org.apache.axiom.om.OMSerializable;
-import org.apache.axiom.om.impl.common.OMNavigator;
-
-public class TestHalfBuiltStep extends OMNavigatorTestCase {
- public TestHalfBuiltStep(OMMetaFactory metaFactory) {
- super(metaFactory);
- }
-
- protected void runTest() throws Throwable {
- assertNotNull(envelope);
-
- //now the OM is not fully created
- OMNavigator navigator = new OMNavigator(envelope);
- OMSerializable node = null;
- while (!navigator.isCompleted()) {
- if (navigator.isNavigable()) {
- node = navigator.next();
- } else {
- builder.next();
- navigator.step();
- node = navigator.next();
- }
- assertNotNull(node);
-
- }
- }
-}
diff --git a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMNavigator.java b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMNavigator.java
deleted file mode 100644
index 1dd2687..0000000
--- a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMNavigator.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.axiom.om.impl.common;
-
-import org.apache.axiom.om.OMContainer;
-import org.apache.axiom.om.OMDocument;
-import org.apache.axiom.om.OMNode;
-import org.apache.axiom.om.OMSerializable;
-import org.apache.axiom.om.OMSourcedElement;
-import org.apache.axiom.om.impl.OMNodeEx;
-
-/**
- * Refer to the test, org.apache.axiom.om.OMNavigatorTest, to find out how to use features like
- * isNavigable, isComplete and step.
- */
-public class OMNavigator {
- /** Field node */
- protected OMSerializable node;
-
- /** Field visited */
- private boolean visited;
-
- /** Field next */
- private OMSerializable next;
-
- // root is the starting element. Once the navigator comes back to the
- // root, the traversal is terminated
-
- /** Field root */
- private OMContainer root;
-
- /** Field backtracked */
- private boolean backtracked;
-
- // flags that tell the status of the navigator
-
- /** Field end */
- private boolean end = false;
-
- /** Field start */
- private boolean start = true;
-
- // Indicates if an OMSourcedElement with an OMDataSource should
- // be considered as an interior node or a leaf node.
- private boolean isDataSourceALeaf = false;
-
- /**
- * Constructor OMNavigator.
- *
- * @param node
- */
- public OMNavigator(OMContainer node) {
- next = node;
- root = node;
- backtracked = false;
- }
-
- /**
- * Indicate if an OMSourcedElement with a OMDataSource
- * should be considered as an interior element node or as
- * a leaf.
- * @param value boolean
- */
- public void setDataSourceIsLeaf(boolean value) {
- isDataSourceALeaf = value;
- }
-
- /**
- * Get the next information item.
- *
- * @return the next information item in the sequence of preorder traversal. Note however that a
- * container (document or element) is treated slightly differently. Once the container
- * is passed it returns the same item in the next encounter as well.
- */
- public OMSerializable getNext() {
- if (next == null) {
- return null;
- }
- node = next;
- visited = backtracked;
- backtracked = false;
- updateNextNode();
-
- // set the starting and ending flags
- if (root.equals(node)) {
- if (!start) {
- end = true;
- } else {
- start = false;
- }
- }
- return node;
- }
-
- /**
- * Get the next node. This method only exists for compatibility with existing code. It may throw
- * a {@link ClassCastException} if an attempt is made to use it on a navigator that was created
- * from an {@link OMDocument}.
- *
- * @return the next node
- * @see #getNext()
- */
- public OMNode next() {
- return (OMNode)getNext();
- }
-
- /** Private method to encapsulate the searching logic. */
- private void updateNextNode() {
- if (!isLeaf(next) && !visited) {
- OMNode firstChild = _getFirstChild((OMContainer) next);
- if (firstChild != null) {
- next = firstChild;
- } else if (next.isComplete()) {
- backtracked = true;
- } else {
- next = null;
- }
- } else {
- if (next instanceof OMDocument) {
- next = null;
- } else {
- OMNode nextNode = (OMNode)next;
- OMContainer parent = nextNode.getParent();
- OMNode nextSibling = getNextSibling(nextNode);
- if (nextSibling != null) {
- next = nextSibling;
- } else if ((parent != null) && parent.isComplete()) {
- next = parent;
- backtracked = true;
- } else {
- next = null;
- }
- }
- }
- }
-
- /**
- * @param n OMNode
- * @return true if this OMNode should be considered a leaf node
- */
- private boolean isLeaf(OMSerializable n) {
- if (n instanceof OMContainer) {
- return this.isDataSourceALeaf && isOMSourcedElement(n) && n != root;
- } else {
- return true;
- }
- }
-
- private boolean isOMSourcedElement(OMSerializable node) {
- if (node instanceof OMSourcedElement) {
- try {
- return ((OMSourcedElement)node).getDataSource() != null;
- } catch (UnsupportedOperationException e) {
- // Operation unsupported for some implementations
- return false;
- }
- } else {
- return false;
- }
- }
-
- /**
- * @param node
- * @return first child or null
- */
- private OMNode _getFirstChild(OMContainer node) {
- // TODO: We have a problem if the tree has parts constructed by different builders; this is related to AXIOM-201 and AXIOM-431
- if (node.getBuilder() != root.getBuilder()) {
- OMNode first = node.getFirstOMChild();
- OMNode sibling = first;
- while (sibling != null) {
- sibling = sibling.getNextOMSibling();
- }
- return first;
- } else {
- return ((IContainer)node).getFirstOMChildIfAvailable();
- }
- }
-
- /**
- * @param node
- * @return next sibling or null
- */
- private OMNode getNextSibling(OMNode node) {
- if (isOMSourcedElement(node)) {
- return node.getNextOMSibling();
- } else {
- return ((OMNodeEx) node).getNextOMSiblingIfAvailable();
- }
- }
-
- /**
- * Method visited.
- *
- * @return Returns boolean.
- */
- public boolean visited() {
- return visited;
- }
-
- /**
- * This is a very special method. This allows the navigator to step once it has reached the
- * existing OM. At this point the isNavigable method will return false but the isComplete method
- * may return false which means that the navigating the given element is not complete and the
- * navigator cannot proceed.
- */
- public void step() {
- if (!end) {
- next = node;
- updateNextNode();
- }
- }
-
- /**
- * Returns the navigable status.
- *
- * @return Returns boolean.
- */
- public boolean isNavigable() {
- if (end) {
- return false;
- } else {
- return !(next == null);
- }
- }
-
- /**
- * Returns the completed status.
- *
- * @return Returns boolean.
- */
- public boolean isCompleted() {
- return end;
- }
-}
diff --git a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/SwitchingWrapper.java b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/SwitchingWrapper.java
index 1de241f..92ea5f0 100644
--- a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/SwitchingWrapper.java
+++ b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/SwitchingWrapper.java
@@ -26,7 +26,6 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
-import java.util.Stack;
import javax.activation.DataHandler;
import javax.xml.namespace.NamespaceContext;
@@ -46,7 +45,6 @@
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMEntityReference;
-import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMProcessingInstruction;
@@ -54,6 +52,7 @@
import org.apache.axiom.om.OMSourcedElement;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.OMXMLParserWrapper;
+import org.apache.axiom.om.impl.OMNodeEx;
import org.apache.axiom.om.impl.builder.StAXBuilder;
import org.apache.axiom.om.impl.exception.OMStreamingException;
import org.apache.axiom.util.namespace.MapBasedNamespaceContext;
@@ -70,8 +69,26 @@
private static final Log log = LogFactory.getLog(SwitchingWrapper.class);
- /** Field navigator */
- private OMNavigator navigator;
+ /**
+ * The current node, corresponding to the current event.
+ */
+ private OMSerializable node;
+
+ /**
+ * If the current node is an {@link OMContainer}, then this flag indicates whether the current
+ * event is the start event ({@link XMLStreamConstants#START_DOCUMENT} or
+ * {@link XMLStreamConstants#START_ELEMENT}) or the end event
+ * ({@link XMLStreamConstants#END_DOCUMENT} or {@link XMLStreamConstants#END_ELEMENT}) for that
+ * node. In the latter case, we have already visited the node before, hence the name of the
+ * attribute.
+ */
+ private boolean visited;
+
+ /**
+ * Indicates if an OMSourcedElement with an OMDataSource should
+ * be considered as an interior node or a leaf node.
+ */
+ private boolean isDataSourceALeaf;
/** Field builder */
private OMXMLParserWrapper builder;
@@ -85,14 +102,13 @@
*/
private DataHandlerReader dataHandlerReader;
- private boolean _isClosed = false; // Indicate if parser is closed
- private boolean _releaseParserOnClose = false; // Defaults to legacy behavior, which is keep the reference
+ private boolean isClosed = false; // Indicate if parser is closed
+ private boolean releaseParserOnClose = false; // Defaults to legacy behavior, which is keep the reference
- /** Field rootNode */
- private OMContainer rootNode;
-
- /** Field isFirst */
- private boolean isFirst = true;
+ /**
+ * The root node, i.e. the node from which the {@link XMLStreamReader} has been requested.
+ */
+ private final OMContainer rootNode;
// Navigable means the output should be taken from the navigator.
// As soon as the navigator returns a null navigable will be reset
@@ -101,7 +117,6 @@
/** Field NAVIGABLE */
private static final short NAVIGABLE = 0;
- private static final short SWITCH_AT_NEXT = 1;
/**
* Indicates that the last event before the final {@link XMLStreamConstants#END_DOCUMENT} event
@@ -137,27 +152,6 @@
*/
private final boolean preserveNamespaceContext;
- /** Field elementStack */
- private Stack nodeStack = null;
-
- // keeps the next event. The parser actually keeps one step ahead to
- // detect the end of navigation. (at the end of the stream the navigator
- // returns a null
-
- /** Field nextNode */
- private OMSerializable nextNode = null;
-
- // holder for the current node. Needs this to generate events from the
- // current node
-
- /** Field currentNode */
- private OMSerializable currentNode = null;
-
- // needs this to refer to the last known node
-
- /** Field lastNode */
- private OMSerializable lastNode = null;
-
/** Track depth to ensure we stop generating events when we are done with the root node. */
int depth = 0;
@@ -181,29 +175,18 @@
public SwitchingWrapper(OMXMLParserWrapper builder, OMContainer startNode,
boolean cache, boolean preserveNamespaceContext) {
- // create a navigator
- this.navigator = new OMNavigator(startNode);
this.builder = builder;
this.rootNode = startNode;
this.cache = cache;
this.preserveNamespaceContext = preserveNamespaceContext;
- // initiate the next and current nodes
- // Note - navigator is written in such a way that it first
- // returns the starting node at the first call to it
-
- currentNode = navigator.getNext();
- updateNextNode(!cache);
+ // If the start node is a document it become the current node. If the start node
+ // is an element, then there is no current node, because there is no node
+ // corresponding to the current event (START_DOCUMENT).
if (startNode instanceof OMDocument) {
- currentEvent = -1;
- try {
- next();
- } catch (XMLStreamException ex) {
- throw new OMException(ex);
- }
- } else {
- currentEvent = START_DOCUMENT;
+ node = startNode;
}
+ currentEvent = START_DOCUMENT;
}
/**
@@ -216,7 +199,7 @@
} else {
if ((currentEvent == START_ELEMENT)
|| (currentEvent == END_ELEMENT)) {
- return ((OMElement)lastNode).getPrefix();
+ return ((OMElement)node).getPrefix();
} else {
throw new IllegalStateException();
}
@@ -233,7 +216,7 @@
} else {
if ((currentEvent == START_ELEMENT)
|| (currentEvent == END_ELEMENT)) {
- return ((OMElement)lastNode).getNamespaceURI();
+ return ((OMElement)node).getNamespaceURI();
} else {
throw new IllegalStateException();
}
@@ -264,9 +247,9 @@
switch (currentEvent) {
case START_ELEMENT:
case END_ELEMENT:
- return ((OMElement)lastNode).getLocalName();
+ return ((OMElement)node).getLocalName();
case ENTITY_REFERENCE:
- return ((OMEntityReference)lastNode).getName();
+ return ((OMEntityReference)node).getName();
default:
throw new IllegalStateException();
}
@@ -283,7 +266,7 @@
} else {
if ((currentEvent == START_ELEMENT)
|| (currentEvent == END_ELEMENT)) {
- return ((OMElement)lastNode).getQName();
+ return ((OMElement)node).getQName();
} else {
throw new IllegalStateException();
}
@@ -368,11 +351,11 @@
// and the other ones in getTextFromNode().
switch (currentEvent) {
case DTD:
- String internalSubset = ((OMDocType)lastNode).getInternalSubset();
+ String internalSubset = ((OMDocType)node).getInternalSubset();
// Woodstox returns the empty string if there is no internal subset
return internalSubset != null ? internalSubset : "";
case ENTITY_REFERENCE:
- return ((OMEntityReference)lastNode).getReplacementText();
+ return ((OMEntityReference)node).getReplacementText();
default:
return getTextFromNode();
}
@@ -391,9 +374,9 @@
case CHARACTERS:
case CDATA:
case SPACE:
- return ((OMText)lastNode).getText();
+ return ((OMText)node).getText();
case COMMENT:
- return ((OMComment)lastNode).getValue();
+ return ((OMComment)node).getValue();
default:
throw new IllegalStateException();
}
@@ -407,7 +390,7 @@
case CHARACTERS:
case CDATA:
case SPACE:
- OMText text = (OMText)lastNode;
+ OMText text = (OMText)node;
if (text.isCharacters()) {
writer.write(text.getTextCharacters());
} else {
@@ -416,7 +399,7 @@
}
break;
case COMMENT:
- writer.write(((OMComment)lastNode).getValue());
+ writer.write(((OMComment)node).getValue());
break;
default:
throw new IllegalStateException();
@@ -437,7 +420,7 @@
private void loadAttributes() {
if (attributeCount == -1) {
attributeCount = 0;
- for (Iterator it = ((OMElement)lastNode).getAllAttributes(); it.hasNext(); ) {
+ for (Iterator it = ((OMElement)node).getAllAttributes(); it.hasNext(); ) {
OMAttribute attr = (OMAttribute)it.next();
if (attributeCount == attributes.length) {
OMAttribute[] newAttributes = new OMAttribute[attributes.length*2];
@@ -458,11 +441,11 @@
private void loadNamespaces() {
if (namespaceCount == -1) {
namespaceCount = 0;
- for (Iterator it = ((OMElement)lastNode).getAllDeclaredNamespaces(); it.hasNext(); ) {
+ for (Iterator it = ((OMElement)node).getAllDeclaredNamespaces(); it.hasNext(); ) {
addNamespace((OMNamespace)it.next());
}
- if (preserveNamespaceContext && lastNode == rootNode) {
- OMElement element = (OMElement)lastNode;
+ if (preserveNamespaceContext && node == rootNode) {
+ OMElement element = (OMElement)node;
while (true) {
OMContainer container = element.getParent();
if (container instanceof OMElement) {
@@ -736,7 +719,7 @@
} else {
if (isStartElement()) {
QName qname = new QName(s, s1);
- OMAttribute attrib = ((OMElement) lastNode).getAttribute(qname);
+ OMAttribute attrib = ((OMElement) node).getAttribute(qname);
if (attrib != null) {
returnString = attrib.getAttributeValue();
}
@@ -819,9 +802,9 @@
} else {
if (isStartElement() || isEndElement()) {
- if (lastNode instanceof OMElement) {
+ if (node instanceof OMElement) {
OMNamespace namespaceURI =
- ((OMElement) lastNode).findNamespaceURI(prefix);
+ ((OMElement) node).findNamespaceURI(prefix);
return namespaceURI != null ? namespaceURI.getNamespaceURI() : null;
}
}
@@ -848,9 +831,9 @@
parser.close();
}
} finally {
- _isClosed = true;
+ isClosed = true;
// Release the parser so that it can be GC'd or reused.
- if (_releaseParserOnClose) {
+ if (releaseParserOnClose) {
setParser(null);
}
}
@@ -883,6 +866,94 @@
}
}
+ /** Private method to encapsulate the searching logic. */
+ private void nextNode() {
+ if (node == null) {
+ // We get here if rootNode is an element and the current event is START_DOCUMENT
+ node = rootNode;
+ } else if (!isLeaf(node) && !visited) {
+ OMNode firstChild = _getFirstChild((OMContainer) node);
+ if (firstChild != null) {
+ node = firstChild;
+ visited = false;
+ } else if (node.isComplete()) {
+ visited = true;
+ } else {
+ node = null;
+ }
+ } else {
+ OMNode nextNode = (OMNode)node;
+ OMContainer parent = nextNode.getParent();
+ OMNode nextSibling = getNextSibling(nextNode);
+ if (nextSibling != null) {
+ node = nextSibling;
+ visited = false;
+ } else if (parent.isComplete()) {
+ node = parent;
+ visited = true;
+ } else {
+ node = null;
+ }
+ }
+ }
+
+ /**
+ * @param n OMNode
+ * @return true if this OMNode should be considered a leaf node
+ */
+ private boolean isLeaf(OMSerializable n) {
+ if (n instanceof OMContainer) {
+ return this.isDataSourceALeaf && isOMSourcedElement(n) && n != rootNode;
+ } else {
+ return true;
+ }
+ }
+
+ private boolean isOMSourcedElement(OMSerializable node) {
+ if (node instanceof OMSourcedElement) {
+ try {
+ return ((OMSourcedElement)node).getDataSource() != null;
+ } catch (UnsupportedOperationException e) {
+ // Operation unsupported for some implementations
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param node
+ * @return first child or null
+ */
+ private OMNode _getFirstChild(OMContainer node) {
+ if (cache) {
+ return node.getFirstOMChild();
+ } else if (node.getBuilder() != rootNode.getBuilder()) {
+ // TODO: We have a problem if the tree has parts constructed by different builders; this is related to AXIOM-201 and AXIOM-431
+ OMNode first = node.getFirstOMChild();
+ OMNode sibling = first;
+ while (sibling != null) {
+ sibling = sibling.getNextOMSibling();
+ }
+ return first;
+ } else {
+ return ((IContainer)node).getFirstOMChildIfAvailable();
+ }
+ }
+
+ /**
+ * @param node
+ * @return next sibling or null
+ */
+ private OMNode getNextSibling(OMNode node) {
+ if (cache || isOMSourcedElement(node)) {
+ return node.getNextOMSibling();
+ } else {
+ return ((OMNodeEx) node).getNextOMSiblingIfAvailable();
+ }
+ }
+
/**
* Method next.
*
@@ -897,35 +968,32 @@
state = DOCUMENT_COMPLETE;
currentEvent = END_DOCUMENT;
break;
- case SWITCH_AT_NEXT:
- state = SWITCHED;
-
- // load the parser
- try {
- setParser((XMLStreamReader) builder.getParser());
- } catch (Exception e) {
- throw new XMLStreamException("problem accessing the parser. " + e.getMessage(),
- e);
- }
-
- // We should throw an END_DOCUMENT
- if ((currentEvent == START_DOCUMENT)
- && (currentEvent == parser.getEventType())) {
- currentEvent = parser.next();
- } else {
- currentEvent = parser.getEventType();
- }
- updateCompleteStatus();
- break;
case NAVIGABLE:
- currentEvent = generateEvents(currentNode);
+ nextNode();
+ if (node != null) {
+ currentEvent = generateEvents(node);
+ attributeCount = -1;
+ namespaceCount = -1;
+ } else {
+ // reset caching (the default is ON so it was not needed in the
+ // earlier case!
+ builder.setCache(false);
+ state = SWITCHED;
+
+ // load the parser
+ try {
+ setParser((XMLStreamReader) builder.getParser());
+ } catch (Exception e) {
+ throw new XMLStreamException("problem accessing the parser. " + e.getMessage(),
+ e);
+ }
+
+ currentEvent = parser.next();
+ }
updateCompleteStatus();
- updateLastNode();
break;
case SWITCHED:
- if (parser.hasNext()) {
- currentEvent = parser.next();
- }
+ currentEvent = parser.next();
updateCompleteStatus();
break;
default:
@@ -970,57 +1038,6 @@
return null;
}
- /**
- * This is a very important method. It keeps the navigator one step ahead and pushes it one
- * event ahead. If the nextNode is null then navigable is set to false. At the same time the
- * parser and builder are set up for the upcoming event generation.
- *
- * @throws XMLStreamException
- */
- private void updateLastNode() throws XMLStreamException {
- lastNode = currentNode;
- attributeCount = -1;
- namespaceCount = -1;
- currentNode = nextNode;
- updateNextNode(!cache);
- }
-
- /** Method updateNextNode. */
- private void updateNextNode(boolean switchingAllowed) {
- if (navigator.isNavigable()) {
- nextNode = navigator.getNext();
- } else {
- if (!switchingAllowed) {
- if (navigator.isCompleted() || builder == null || builder.isCompleted()) {
- nextNode = null;
- if (log.isDebugEnabled()) {
- if (builder == null || builder.isCompleted()) {
- log.debug("Builder is complete. Next node is set to null.");
- }
- }
- } else {
- builder.next();
- navigator.step();
- nextNode = navigator.getNext();
- }
- } else {
- //at this point check whether the navigator is done
- //if the navigator is done then we are fine and can directly
- // jump to the complete state ?
- if (navigator.isCompleted()) {
- nextNode = null;
- } else {
- // reset caching (the default is ON so it was not needed in the
- // earlier case!
- if (builder != null) {
- builder.setCache(false);
- }
- state = SWITCH_AT_NEXT;
- }
- }
- }
- }
-
/** Method updateCompleteStatus. */
private void updateCompleteStatus() {
if (currentEvent == START_ELEMENT) {
@@ -1029,10 +1046,8 @@
depth--;
}
if (state == NAVIGABLE) {
- if (rootNode == currentNode) {
- if (isFirst) {
- isFirst = false;
- } else if (currentEvent == END_DOCUMENT) {
+ if (rootNode == node && visited) {
+ if (currentEvent == END_DOCUMENT) {
state = DOCUMENT_COMPLETE;
} else {
state = COMPLETED;
@@ -1061,7 +1076,7 @@
return currentEvent == END_DOCUMENT ? new MapBasedNamespaceContext(Collections.EMPTY_MAP) : parser.getNamespaceContext();
} else {
return new MapBasedNamespaceContext(
- currentEvent == END_DOCUMENT ? Collections.EMPTY_MAP : getAllNamespaces(lastNode));
+ currentEvent == END_DOCUMENT ? Collections.EMPTY_MAP : getAllNamespaces(node));
}
}
@@ -1075,8 +1090,8 @@
return parser.getEncoding();
} else {
if (currentEvent == START_DOCUMENT) {
- if (lastNode instanceof OMDocument) {
- return ((OMDocument)lastNode).getCharsetEncoding();
+ if (node instanceof OMDocument) {
+ return ((OMDocument)node).getCharsetEncoding();
} else {
return null;
}
@@ -1123,8 +1138,8 @@
return parser.getCharacterEncodingScheme();
} else {
if (currentEvent == START_DOCUMENT) {
- if (lastNode instanceof OMDocument) {
- return ((OMDocument)lastNode).getXMLEncoding();
+ if (node instanceof OMDocument) {
+ return ((OMDocument)node).getXMLEncoding();
} else {
return null;
}
@@ -1144,7 +1159,7 @@
return parser.getPITarget();
} else {
if (currentEvent == PROCESSING_INSTRUCTION) {
- return ((OMProcessingInstruction)lastNode).getTarget();
+ return ((OMProcessingInstruction)node).getTarget();
} else {
throw new IllegalStateException();
}
@@ -1161,7 +1176,7 @@
return parser.getPIData();
} else {
if (currentEvent == PROCESSING_INSTRUCTION) {
- return ((OMProcessingInstruction)lastNode).getValue();
+ return ((OMProcessingInstruction)node).getValue();
} else {
throw new IllegalStateException();
}
@@ -1184,8 +1199,8 @@
return false;
}
} else {
- if (lastNode instanceof OMText) {
- return ((OMText)lastNode).isBinary();
+ if (node instanceof OMText) {
+ return ((OMText)node).isBinary();
} else {
return false;
}
@@ -1200,8 +1215,8 @@
throw new IllegalStateException();
}
} else {
- if (lastNode instanceof OMText) {
- return ((OMText)lastNode).isOptimized();
+ if (node instanceof OMText) {
+ return ((OMText)node).isOptimized();
} else {
throw new IllegalStateException();
}
@@ -1216,7 +1231,7 @@
throw new IllegalStateException();
}
} else {
- if (lastNode instanceof OMText) {
+ if (node instanceof OMText) {
// TODO: we should support deferred building of the DataHandler
return false;
} else {
@@ -1233,8 +1248,8 @@
throw new IllegalStateException();
}
} else {
- if (lastNode instanceof OMText) {
- return ((OMText)lastNode).getContentID();
+ if (node instanceof OMText) {
+ return ((OMText)node).getContentID();
} else {
throw new IllegalStateException();
}
@@ -1249,8 +1264,8 @@
throw new IllegalStateException();
}
} else {
- if (lastNode instanceof OMText) {
- return (DataHandler)((OMText)lastNode).getDataHandler();
+ if (node instanceof OMText) {
+ return (DataHandler)((OMText)node).getDataHandler();
} else {
throw new IllegalStateException();
}
@@ -1284,34 +1299,15 @@
* @return Returns int.
*/
private int generateEvents(OMSerializable node) {
- if (node == null) {
- if (log.isDebugEnabled()) {
- log.debug("Node is null...returning END_DOCUMENT");
- }
- return END_DOCUMENT;
- }
- if (node instanceof OMDocument) {
- return generateContainerEvents((OMDocument)node, true);
- } else {
- int nodeType = ((OMNode)node).getType();
- if (nodeType == OMNode.ELEMENT_NODE) {
- return generateContainerEvents((OMElement)node, false);
+ if (node instanceof OMContainer) {
+ OMContainer container = (OMContainer)node;
+ if (visited) {
+ return container instanceof OMDocument ? END_DOCUMENT : END_ELEMENT;
} else {
- return nodeType;
+ return container instanceof OMDocument ? START_DOCUMENT : START_ELEMENT;
}
- }
- }
-
- private int generateContainerEvents(OMContainer container, boolean isDocument) {
- if (nodeStack == null) {
- nodeStack = new Stack();
- }
- if (!nodeStack.isEmpty() && nodeStack.peek().equals(container)) {
- nodeStack.pop();
- return isDocument ? END_DOCUMENT : END_ELEMENT;
} else {
- nodeStack.push(container);
- return isDocument ? START_DOCUMENT : START_ELEMENT;
+ return ((OMNode)node).getType();
}
}
@@ -1373,7 +1369,7 @@
if (builder != null && builder instanceof StAXBuilder) {
return ((StAXBuilder) builder).isClosed();
} else {
- return _isClosed;
+ return isClosed;
}
}
@@ -1395,7 +1391,7 @@
if (isClosed() && value) {
setParser(null);
}
- _releaseParserOnClose = value;
+ releaseParserOnClose = value;
}
}
@@ -1405,15 +1401,14 @@
*/
public OMDataSource getDataSource() {
if (getEventType() != XMLStreamReader.START_ELEMENT ||
- !(state == NAVIGABLE ||
- state == SWITCH_AT_NEXT)) {
+ state != NAVIGABLE) {
return null;
}
OMDataSource ds = null;
- if (lastNode != null &&
- lastNode instanceof OMSourcedElement) {
+ if (node != null &&
+ node instanceof OMSourcedElement) {
try {
- ds = ((OMSourcedElement) lastNode).getDataSource();
+ ds = ((OMSourcedElement) node).getDataSource();
} catch (UnsupportedOperationException e) {
// Some implementations throw an UnsupportedOperationException.
ds =null;
@@ -1436,6 +1431,6 @@
* @param value boolean
*/
public void enableDataSourceEvents(boolean value) {
- navigator.setDataSourceIsLeaf(value);
+ isDataSourceALeaf = value;
}
}
diff --git a/modules/axiom-dom/pom.xml b/modules/axiom-dom/pom.xml
index 4789059..69cc1d6 100644
--- a/modules/axiom-dom/pom.xml
+++ b/modules/axiom-dom/pom.xml
@@ -144,31 +144,6 @@
<include>${project.groupId}:axiom-common-impl</include>
</includes>
</artifactSet>
- <relocations>
- <!-- We try to preserve as much as possible the class names from previous releases in
- order to support old code and code that is tightly coupled to the DOOM implementation
- (such as the SAAJ implementation in Axis2). -->
- <relocation>
- <pattern>org.apache.axiom.om.impl.common.OMNamespaceImpl</pattern>
- <shadedPattern>org.apache.axiom.om.impl.dom.NamespaceImpl</shadedPattern>
- </relocation>
- <relocation>
- <pattern>org.apache.axiom.om.impl.common.OMNavigator</pattern>
- <shadedPattern>org.apache.axiom.om.impl.dom.DOMNavigator</shadedPattern>
- </relocation>
- <relocation>
- <pattern>org.apache.axiom.om.impl.common.OMStAXWrapper</pattern>
- <shadedPattern>org.apache.axiom.om.impl.dom.DOMStAXWrapper</shadedPattern>
- </relocation>
- <relocation>
- <pattern>org.apache.axiom.om.impl.common</pattern>
- <shadedPattern>org.apache.axiom.om.impl.dom</shadedPattern>
- </relocation>
- <relocation>
- <pattern>org.apache.axiom.soap.impl.common</pattern>
- <shadedPattern>org.apache.axiom.soap.impl.dom</shadedPattern>
- </relocation>
- </relocations>
<transformers>
<transformer implementation="org.apache.axiom.buildutils.OSGiManifestResourceTransformer" />
</transformers>
@@ -183,27 +158,6 @@
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-original-jar</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/original-${project.build.finalName}.jar</file>
- <classifier>original</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
<!-- Attach a JAR with the test classes so that we can reuse them in other modules
(see http://maven.apache.org/guides/mini/guide-attached-tests.html). -->
<plugin>
diff --git a/modules/axiom-dom/src/test/java/org/apache/axiom/om/impl/dom/CommonImplTest.java b/modules/axiom-dom/src/test/java/org/apache/axiom/om/impl/dom/CommonImplTest.java
deleted file mode 100644
index f4905d1..0000000
--- a/modules/axiom-dom/src/test/java/org/apache/axiom/om/impl/dom/CommonImplTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.om.impl.dom;
-
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-import org.apache.axiom.om.impl.dom.factory.OMDOMMetaFactory;
-import org.apache.axiom.ts.CommonImplTestSuiteBuilder;
-
-public class CommonImplTest extends TestCase {
- public static TestSuite suite() {
- return new CommonImplTestSuiteBuilder(new OMDOMMetaFactory()).build();
- }
-}
diff --git a/modules/axiom-impl/pom.xml b/modules/axiom-impl/pom.xml
index 9022063..867803e 100644
--- a/modules/axiom-impl/pom.xml
+++ b/modules/axiom-impl/pom.xml
@@ -142,16 +142,6 @@
<include>${project.groupId}:axiom-common-impl</include>
</includes>
</artifactSet>
- <relocations>
- <relocation>
- <pattern>org.apache.axiom.om.impl.common</pattern>
- <shadedPattern>org.apache.axiom.om.impl.llom</shadedPattern>
- </relocation>
- <relocation>
- <pattern>org.apache.axiom.soap.impl.common</pattern>
- <shadedPattern>org.apache.axiom.soap.impl.llom</shadedPattern>
- </relocation>
- </relocations>
<transformers>
<transformer implementation="org.apache.axiom.buildutils.OSGiManifestResourceTransformer" />
</transformers>
@@ -166,27 +156,6 @@
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-original-jar</id>
- <phase>package</phase>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/original-${project.build.finalName}.jar</file>
- <classifier>original</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
<!-- Attach a JAR with the test classes so that we can reuse them in other modules
(see http://maven.apache.org/guides/mini/guide-attached-tests.html). -->
<plugin>
diff --git a/modules/axiom-impl/src/test/java/org/apache/axiom/om/impl/llom/CommonImplTest.java b/modules/axiom-impl/src/test/java/org/apache/axiom/om/impl/llom/CommonImplTest.java
deleted file mode 100644
index 0799773..0000000
--- a/modules/axiom-impl/src/test/java/org/apache/axiom/om/impl/llom/CommonImplTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.apache.axiom.om.impl.llom;
-
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-
-import org.apache.axiom.om.impl.llom.factory.OMLinkedListMetaFactory;
-import org.apache.axiom.ts.CommonImplTestSuiteBuilder;
-
-public class CommonImplTest extends TestCase {
- public static TestSuite suite() {
- return new CommonImplTestSuiteBuilder(new OMLinkedListMetaFactory()).build();
- }
-}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/OMTestSuiteBuilder.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/OMTestSuiteBuilder.java
index 1027f60..691aee9 100644
--- a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/OMTestSuiteBuilder.java
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/OMTestSuiteBuilder.java
@@ -292,6 +292,7 @@
addTest(new org.apache.axiom.ts.om.element.TestGetXMLStreamReaderWithOMSourcedElementDescendant(metaFactory));
}
addTest(new org.apache.axiom.ts.om.element.TestGetXMLStreamReaderWithoutCachingPartiallyBuilt(metaFactory));
+ addTest(new org.apache.axiom.ts.om.element.TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified(metaFactory));
addTest(new org.apache.axiom.ts.om.element.TestGetXMLStreamReaderWithPreserveNamespaceContext(metaFactory));
addTest(new org.apache.axiom.ts.om.element.TestIsCompleteAfterAddingIncompleteChild(metaFactory));
addTest(new org.apache.axiom.ts.om.element.TestMultipleDefaultNS(metaFactory));
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/element/TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/element/TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified.java
new file mode 100644
index 0000000..4f53183
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/element/TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+package org.apache.axiom.ts.om.element;
+
+import java.io.StringReader;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMMetaFactory;
+import org.apache.axiom.om.OMXMLBuilderFactory;
+import org.apache.axiom.ts.AxiomTestCase;
+
+/**
+ * Tests the behavior of {@link OMContainer#getXMLStreamReaderWithoutCaching()} in the specific case
+ * where the element is partially built and the last created node has been modified. In Axiom 1.2.14
+ * the information returned for that node was incorrect because the builder switched too early to
+ * pull through mode.
+ */
+public class TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified extends AxiomTestCase {
+ public TestGetXMLStreamReaderWithoutCachingPartiallyBuiltModified(OMMetaFactory metaFactory) {
+ super(metaFactory);
+ }
+
+ protected void runTest() throws Throwable {
+ OMElement root = OMXMLBuilderFactory.createOMBuilder(metaFactory.getOMFactory(),
+ new StringReader("<root><a/><b/><c/></root>")).getDocumentElement();
+
+ OMElement b = root.getFirstChildWithName(new QName("b"));
+ b.addAttribute("att", "value", null);
+ assertFalse(b.isComplete());
+
+ XMLStreamReader reader = root.getXMLStreamReaderWithoutCaching();
+
+ // Skip to the START_ELEMENT event corresponding to b
+ for (int i=0; i<4; i++) {
+ reader.next();
+ }
+ assertEquals(XMLStreamReader.START_ELEMENT, reader.getEventType());
+ assertEquals("b", reader.getLocalName());
+
+ // The previously added attribute must be visible
+ assertEquals(1, reader.getAttributeCount());
+ assertEquals("att", reader.getAttributeLocalName(0));
+ assertEquals("value", reader.getAttributeValue(0));
+ }
+}
diff --git a/pom.xml b/pom.xml
index 98f2dcd..3a889f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -736,7 +736,6 @@
<module>modules/axiom-api</module>
<module>modules/axiom-testsuite</module>
<module>modules/axiom-common-impl</module>
- <module>modules/axiom-common-impl-testsuite</module>
<module>modules/axiom-impl</module>
<module>modules/axiom-dom</module>
<module>modules/axiom-compat</module>