Merged latest changes from trunk.
diff --git a/apidocs/pom.xml b/apidocs/pom.xml
index 9ed3332..a90cecb 100644
--- a/apidocs/pom.xml
+++ b/apidocs/pom.xml
@@ -123,6 +123,13 @@
                         <link>http://jaxen.codehaus.org/apidocs/</link>
                     </links>
                     <breakiterator>true</breakiterator>
+                    <!-- The notimestamp, windowtitle and bottom parameters are chosen to minimize the number
+                         of changes between releases (to avoid mass changes when committing the site for a new release) -->
+                    <notimestamp>true</notimestamp>
+                    <windowtitle>Apache Axiom</windowtitle>
+                    <bottom>Copyright &#169; {organizationName}. All Rights Reserved.</bottom>
+                    <!-- doctitle only appears in the summary and we should include the version there -->
+                    <doctitle>Apache Axiom ${project.version}</doctitle>
                 </configuration>
             </plugin>
             <plugin>
diff --git a/code-coverage/pom.xml b/code-coverage/pom.xml
index 02ef62c..ba6483a 100644
--- a/code-coverage/pom.xml
+++ b/code-coverage/pom.xml
@@ -153,7 +153,15 @@
         
         <dependency>
             <groupId>${project.groupId}</groupId>
-            <artifactId>axiom-osgi-tests</artifactId>
+            <artifactId>jboss-tests</artifactId>
+            <version>${project.version}</version>
+            <classifier>jacoco</classifier>
+            <type>exec</type>
+        </dependency>
+        
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>osgi-tests</artifactId>
             <version>${project.version}</version>
             <classifier>jacoco</classifier>
             <type>exec</type>
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMContainer.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMContainer.java
index 5275672..1edc0e4 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMContainer.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMContainer.java
@@ -49,6 +49,9 @@
 
     /**
      * Adds the given node as the last child of this container.
+     * <p>
+     * The method may throw an {@link OMException} if the node is not allowed at this position of
+     * the document.
      * 
      * @param omNode
      *            the node to be added to this container
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDataSource.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDataSource.java
index 04e726d..d07f87f 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDataSource.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDataSource.java
@@ -176,6 +176,9 @@
      * It is assumed that this method consumed the content (i.e. destroys the backing object) unless
      * the data source also implements {@link OMDataSourceExt} and
      * {@link OMDataSourceExt#isDestructiveRead()} returns <code>false</code>.
+     * <p>
+     * {@link OMSourcedElement} implementations are expected to call {@link XMLStreamReader#close()}
+     * on the returned reader as soon as the element is completely built.
      * 
      * @return element parser
      * @throws XMLStreamException
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDocument.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDocument.java
index ab0470e..f17defe 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDocument.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMDocument.java
@@ -40,6 +40,9 @@
      * the new document element will be appended as the last child. If the document already has a
      * document element, then it will be replaced by the new one and the position of the other
      * children relative to the document element is preserved.
+     * <p>
+     * Some models (such as SOAP) may throw an exception if the specified element is not allowed as
+     * a root element.
      * 
      * @param documentElement
      *            the new document element; must not be <code>null</code>
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMElement.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMElement.java
index 79598e0..9c078d7 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/OMElement.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/OMElement.java
@@ -233,12 +233,15 @@
      * The iterator returned by this method supports {@link Iterator#remove()} and that method can
      * be used to remove a namespace declaration from this element.
      * 
-     * @return An iterator over the {@link OMNamespace} items declared on this element. Note that
-     *         the iterator may be invalidated by a call to {@link #declareNamespace(OMNamespace)},
-     *         {@link #declareNamespace(String, String)}, {@link #declareDefaultNamespace(String)}
-     *         or any other method that modifies the namespace declarations of this element.
+     * @return An iterator over the {@link OMNamespace} items declared on this element. If the
+     *         element has no namespace declarations, an empty iterator is returned.
+     *         <p>
+     *         Note that the returned iterator may be invalidated by a call to
+     *         {@link #declareNamespace(OMNamespace)}, {@link #declareNamespace(String, String)},
+     *         {@link #declareDefaultNamespace(String)} or any other method that modifies the
+     *         namespace declarations of this element.
      */
-    Iterator getAllDeclaredNamespaces() throws OMException;
+    Iterator getAllDeclaredNamespaces();
 
     /**
      * Get an iterator that returns all namespaces in scope for this element. This method may be
@@ -288,12 +291,12 @@
     
     /**
      * Returns a list of OMAttributes.
-     * <p/>
-     * <p>Note that the iterator returned by this function will be invalidated by any
-     * <tt>addAttribute</tt> call. </p>
-     *
-     * @return Returns an {@link Iterator} of {@link OMAttribute} items associated with the
-     *         element.
+     * <p>
+     * Note that the iterator returned by this function will be invalidated by any
+     * <tt>addAttribute</tt> call.
+     * 
+     * @return An iterator over the {@link OMAttribute} items associated with the element. If the
+     *         element has no attributes, an empty iterator is returned.
      * @see #getAttribute
      * @see #addAttribute(OMAttribute)
      * @see #addAttribute(String, String, OMNamespace)
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java
index 861db93..bbdfb5d 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java
@@ -94,6 +94,12 @@
     // on an OMElement is interned.
     private boolean namespaceURIInterning = false;
     
+    /**
+     * Specifies whether the builder/parser should be automatically closed when the
+     * {@link XMLStreamConstants#END_DOCUMENT} event is reached.
+     */
+    private boolean autoClose;
+    
     private int lookAheadToken = -1;
     
     /**
@@ -273,7 +279,8 @@
                 }
                 
                 if (target == null && !done) {
-                    // We get here if the document has been discarded (using getDocumentElement(true)) and
+                    // We get here if the document has been discarded (by getDocumentElement(true)
+                    // or because the builder is linked to an OMSourcedElement) and
                     // we just processed the END_ELEMENT event for the root element. In this case, we consume
                     // the remaining events until we reach the end of the document. This serves several purposes:
                     //  * It allows us to detect documents that have an epilog that is not well formed.
@@ -282,6 +289,8 @@
                     //    last END_ELEMENT. This improves performance because Woodstox by default interns
                     //    all symbols; if the symbol table can be recycled, then this reduces the number of
                     //    calls to String#intern().
+                    //  * If autoClose is set, the parser will be closed so that even more resources
+                    //    can be released.
                     while (parserNext() != XMLStreamConstants.END_DOCUMENT) {
                         // Just loop
                     }
@@ -652,6 +661,15 @@
     }
     
     /**
+     * For internal use only.
+     * 
+     * @param autoClose
+     */
+    public void setAutoClose(boolean autoClose) {
+        this.autoClose = autoClose;
+    }
+
+    /**
      * Pushes the virtual parser ahead one token.
      * If a look ahead token was calculated it is returned.
      * @return next token
@@ -690,6 +708,9 @@
                     if (elementLevel != 0) {
                         throw new OMException("Unexpected END_DOCUMENT event");
                     }
+                    if (autoClose) {
+                        close();
+                    }
                     break;
             }
             return event;
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/om/util/StAXUtils.java b/modules/axiom-api/src/main/java/org/apache/axiom/om/util/StAXUtils.java
index 5cc5a3d..f0543f4 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/om/util/StAXUtils.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/om/util/StAXUtils.java
@@ -447,7 +447,7 @@
                             factory.setProperty((String)entry.getKey(), entry.getValue());
                         }
                     }
-                    StAXDialect dialect = StAXDialectDetector.getDialect(factory.getClass());
+                    StAXDialect dialect = StAXDialectDetector.getDialect(factory);
                     if (configuration != null) {
                         factory = configuration.configure(factory, dialect);
                     }
@@ -572,7 +572,7 @@
                             factory.setProperty((String)entry.getKey(), entry.getValue());
                         }
                     }
-                    StAXDialect dialect = StAXDialectDetector.getDialect(factory.getClass());
+                    StAXDialect dialect = StAXDialectDetector.getDialect(factory);
                     if (configuration != null) {
                         factory = configuration.configure(factory, dialect);
                     }
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPFactory.java b/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPFactory.java
index c7cd389..1a20d5a 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPFactory.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPFactory.java
@@ -23,6 +23,7 @@
 import org.apache.axiom.om.OMDocument;
 import org.apache.axiom.om.OMFactory;
 import org.apache.axiom.om.OMNamespace;
+import org.apache.axiom.om.OMXMLParserWrapper;
 
 public interface SOAPFactory extends OMFactory {
 
@@ -33,6 +34,12 @@
     SOAPMessage createSOAPMessage();
 
     /**
+     * @deprecated This method only exists for compatibility with Spring-WS and should not be used
+     *             by application code.
+     */
+    SOAPMessage createSOAPMessage(OMXMLParserWrapper builder);
+
+    /**
      * Create a SOAP envelope. The returned element will have the namespace URI specified by the
      * SOAP version that this factory represents. It will have the prefix given by
      * {@link SOAPConstants#SOAP_DEFAULT_NAMESPACE_PREFIX}. It will also have a corresponding
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPMessage.java b/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPMessage.java
index 82f6055..ca73a1d 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPMessage.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/soap/SOAPMessage.java
@@ -20,11 +20,18 @@
 package org.apache.axiom.soap;
 
 import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
 
 public interface SOAPMessage extends OMDocument {
 
     SOAPEnvelope getSOAPEnvelope() throws SOAPProcessingException;
 
-    void setSOAPEnvelope(SOAPEnvelope envelope) throws SOAPProcessingException;
-
+    /**
+     * Sets the SOAP envelope for this message. This method has the same effect as
+     * {@link OMDocument#setOMDocumentElement(OMElement)}.
+     * 
+     * @param envelope
+     *            the envelope to be set as the root element for this message
+     */
+    void setSOAPEnvelope(SOAPEnvelope envelope);
 }
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldInputStream.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldInputStream.java
index 52dda92..c4ef888 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldInputStream.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldInputStream.java
@@ -21,7 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-public class CloseShieldInputStream extends InputStream {
+final class CloseShieldInputStream extends InputStream {
     private final InputStream parent;
 
     public CloseShieldInputStream(InputStream parent) {
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldReader.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldReader.java
index a39f59a..c7bc9c0 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldReader.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldReader.java
@@ -22,7 +22,7 @@
 import java.io.Reader;
 import java.nio.CharBuffer;
 
-public class CloseShieldReader extends Reader {
+final class CloseShieldReader extends Reader {
     private final Reader parent;
 
     public CloseShieldReader(Reader parent) {
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4InputFactoryWrapper.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldXMLInputFactoryWrapper.java
similarity index 66%
rename from modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4InputFactoryWrapper.java
rename to modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldXMLInputFactoryWrapper.java
index d744e69..2256b70 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4InputFactoryWrapper.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/CloseShieldXMLInputFactoryWrapper.java
@@ -25,31 +25,30 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
-public class Woodstox4InputFactoryWrapper extends NormalizingXMLInputFactoryWrapper {
-    private final boolean wstx276;
-    
-    public Woodstox4InputFactoryWrapper(XMLInputFactory parent, AbstractStAXDialect dialect, boolean wstx276) {
-        super(parent, dialect);
-        this.wstx276 = wstx276;
+import org.apache.axiom.util.stax.wrapper.XMLInputFactoryWrapper;
+
+final class CloseShieldXMLInputFactoryWrapper extends XMLInputFactoryWrapper {
+    public CloseShieldXMLInputFactoryWrapper(XMLInputFactory parent) {
+        super(parent);
     }
 
     public XMLStreamReader createXMLStreamReader(InputStream stream, String encoding) throws XMLStreamException {
-        return super.createXMLStreamReader(wstx276 ? new CloseShieldInputStream(stream) : stream, encoding);
+        return super.createXMLStreamReader(new CloseShieldInputStream(stream), encoding);
     }
 
     public XMLStreamReader createXMLStreamReader(InputStream stream) throws XMLStreamException {
-        return super.createXMLStreamReader(wstx276 ? new CloseShieldInputStream(stream) : stream);
+        return super.createXMLStreamReader(new CloseShieldInputStream(stream));
     }
 
     public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException {
-        return super.createXMLStreamReader(wstx276 ? new CloseShieldReader(reader) : reader);
+        return super.createXMLStreamReader(new CloseShieldReader(reader));
     }
 
     public XMLStreamReader createXMLStreamReader(String systemId, InputStream stream) throws XMLStreamException {
-        return super.createXMLStreamReader(systemId, wstx276 ? new CloseShieldInputStream(stream) : stream);
+        return super.createXMLStreamReader(systemId, new CloseShieldInputStream(stream));
     }
 
     public XMLStreamReader createXMLStreamReader(String systemId, Reader reader) throws XMLStreamException {
-        return super.createXMLStreamReader(systemId, wstx276 ? new CloseShieldReader(reader) : reader);
+        return super.createXMLStreamReader(systemId, new CloseShieldReader(reader));
     }
 }
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/JBossFactoryUnwrapper.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/JBossFactoryUnwrapper.java
new file mode 100644
index 0000000..c77d7af
--- /dev/null
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/JBossFactoryUnwrapper.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util.stax.dialect;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Utility class to remove the {@link XMLInputFactory} or {@link XMLOutputFactory} wrapper added by
+ * JBoss 7. This class gives access the actual (implementation dependent) factory. This is important
+ * to correct detect the StAX dialect.
+ */
+final class JBossFactoryUnwrapper {
+    private static final Log log = LogFactory.getLog(JBossFactoryUnwrapper.class);
+    
+    private final Class wrapperClass;
+    private final Field actual;
+    
+    private JBossFactoryUnwrapper(Class factoryType) throws Exception {
+        wrapperClass = Class.forName("__redirected.__" + factoryType.getSimpleName());
+        try {
+            actual = wrapperClass.getDeclaredField("actual");
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    actual.setAccessible(true);
+                    return null;
+                }
+            });
+        } catch (Exception ex) {
+            log.error("Found JBoss wrapper class for " + factoryType.getSimpleName() + ", but unwrapping is not supported", ex);
+            throw ex;
+        }
+    }
+
+    /**
+     * Get the unwrapper for the given factory type.
+     * 
+     * @param factoryType
+     *            the factory type ({@link XMLInputFactory} or {@link XMLOutputFactory})
+     * @return the unwrapper, or <code>null</code> if the unwrapper could not be created (which
+     *         usually means that the code is not executed inside JBoss)
+     */
+    static JBossFactoryUnwrapper create(Class factoryType) {
+        try {
+            return new JBossFactoryUnwrapper(factoryType);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+    
+    Object unwrap(Object factory) {
+        if (wrapperClass.isInstance(factory)) {
+            try {
+                return actual.get(factory);
+            } catch (IllegalAccessException ex) {
+                throw new IllegalAccessError(ex.getMessage());
+            }
+        } else {
+            return factory;
+        }
+    }
+}
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamReaderWrapper.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamReaderWrapper.java
index b91ce33..21c7b30 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamReaderWrapper.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamReaderWrapper.java
@@ -83,7 +83,8 @@
     }
 
     public String getNamespaceURI(String prefix) {
-        return namespaceContext.getNamespaceURI(prefix);
+        String uri = namespaceContext.getNamespaceURI(prefix);
+        return uri.length() == 0 ? null : uri;
     }
 
     public XMLStreamReader getParent() {
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Scanner.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Scanner.java
new file mode 100644
index 0000000..a78043a
--- /dev/null
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Scanner.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util.stax.dialect;
+
+import javax.xml.stream.XMLStreamException;
+
+final class Scanner {
+    private final String s;
+    private int pos;
+    
+    Scanner(String s) {
+        this.s = s;
+    }
+    
+    int peek() {
+        return pos == s.length() ? -1 : s.charAt(pos);
+    }
+    
+    String getName() {
+        int start = pos;
+        while (pos < s.length()) {
+            char c = s.charAt(pos);
+            // This corresponds to the NameChar production, except for characters above 0x80.
+            // We expect that the underlying parser strictly enforces the grammar and we don't
+            // care here about NameStartChar and characters above 0x80.
+            if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == ':' || c == '_' || c == '-' || c == '.' || c > 0x80) {
+                pos++;
+            } else {
+                break;
+            }
+        }
+        return pos == start ? null : s.substring(start, pos);
+    }
+
+    String getQuotedString() throws XMLStreamException {
+        int quoteChar = peek();
+        if (quoteChar == '\'' || quoteChar == '"') {
+            pos++;
+            int start = pos;
+            while (pos < s.length() && s.charAt(pos) != quoteChar) {
+                pos++;
+            }
+            if (peek() == quoteChar) {
+                return s.substring(start, pos++);
+            } else {
+                throw new XMLStreamException("Untermined quoted string");
+            }
+        } else {
+            throw new XMLStreamException("Expected quote char at position " + pos);
+        }
+    }
+    
+    void expect(String seq) throws XMLStreamException {
+        boolean found;
+        if (pos+seq.length() > s.length()) {
+            found = false;
+        } else {
+            found = true;
+            for (int i=0; i<seq.length(); i++) {
+                if (s.charAt(pos+i) != seq.charAt(i)) {
+                    found = false;
+                    break;
+                }
+            }
+        }
+        if (found) {
+            pos += seq.length();
+        } else {
+            throw new XMLStreamException("Expected \"" + seq + "\" at position " + pos);
+        }
+    }
+    
+    void skipSpace() {
+        while (pos < s.length()) {
+            char c = s.charAt(pos);
+            if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+                pos++;
+            } else {
+                break;
+            }
+        }
+    }
+}
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialectDetector.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialectDetector.java
index ea7a695..297ae9c 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialectDetector.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialectDetector.java
@@ -62,6 +62,9 @@
     private static final Attributes.Name BUNDLE_VERSION =
             new Attributes.Name("Bundle-Version");
 
+    private static final JBossFactoryUnwrapper jbossXMLInputFactoryUnwrapper = JBossFactoryUnwrapper.create(XMLInputFactory.class);
+    private static final JBossFactoryUnwrapper jbossXMLOutputFactoryUnwrapper = JBossFactoryUnwrapper.create(XMLOutputFactory.class);
+    
     /**
      * Map that stores detected dialects by location. The location is the URL corresponding to the
      * root folder of the classpath entry from which the StAX implementation is loaded. Note that
@@ -119,7 +122,7 @@
      * @see StAXDialect#normalize(XMLInputFactory)
      */
     public static XMLInputFactory normalize(XMLInputFactory factory) {
-        return getDialect(factory.getClass()).normalize(factory);
+        return getDialect(factory).normalize(factory);
     }
     
     /**
@@ -131,11 +134,16 @@
      * @see StAXDialect#normalize(XMLOutputFactory)
      */
     public static XMLOutputFactory normalize(XMLOutputFactory factory) {
-        return getDialect(factory.getClass()).normalize(factory);
+        return getDialect(factory).normalize(factory);
     }
     
     /**
      * Detect the dialect of a given StAX implementation.
+     * <p>
+     * Note that to detect the StAX dialect of a given {@link XMLInputFactory} or
+     * {@link XMLOutputFactory} instance, it is generally preferable to use
+     * {@link #getDialect(XMLInputFactory)} or {@link #getDialect(XMLOutputFactory)} instead of this
+     * method.
      * 
      * @param implementationClass
      *            any class that is part of the StAX implementation; typically this should be a
@@ -154,6 +162,34 @@
         return getDialect(implementationClass.getClassLoader(), rootUrl);
     }
 
+    /**
+     * Detect the StAX dialect of a given {@link XMLInputFactory} instance.
+     * 
+     * @param factory
+     *            the factory instance
+     * @return the detected dialect
+     */
+    public static StAXDialect getDialect(XMLInputFactory factory) {
+        if (jbossXMLInputFactoryUnwrapper != null) {
+            factory = (XMLInputFactory)jbossXMLInputFactoryUnwrapper.unwrap(factory);
+        }
+        return getDialect(factory.getClass());
+    }
+    
+    /**
+     * Detect the StAX dialect of a given {@link XMLOutputFactory} instance.
+     * 
+     * @param factory
+     *            the factory instance
+     * @return the detected dialect
+     */
+    public static StAXDialect getDialect(XMLOutputFactory factory) {
+        if (jbossXMLOutputFactoryUnwrapper != null) {
+            factory = (XMLOutputFactory)jbossXMLOutputFactoryUnwrapper.unwrap(factory);
+        }
+        return getDialect(factory.getClass());
+    }
+    
     private static StAXDialect getDialect(ClassLoader classLoader, URL rootUrl) {
         StAXDialect dialect = (StAXDialect)dialectByUrl.get(rootUrl);
         if (dialect != null) {
@@ -274,16 +310,22 @@
         // Try Sun's implementation found in JREs
         cls = loadClass(classLoader, rootUrl, "com.sun.xml.internal.stream.XMLOutputFactoryImpl");
         if (cls != null) {
-            // Check if the implementation has the bug fixed here:
-            // https://sjsxp.dev.java.net/source/browse/sjsxp/zephyr/src/com/sun/xml/stream/ZephyrWriterFactory.java?rev=1.8&r1=1.4&r2=1.5
-            boolean isUnsafeStreamResult;
-            try {
-                cls.getDeclaredField("fStreamResult");
-                isUnsafeStreamResult = true;
-            } catch (NoSuchFieldException ex) {
-                isUnsafeStreamResult = false;
+            // Some JREs (such as IBM Java 1.7) include com.sun.xml.internal.stream.XMLOutputFactoryImpl
+            // for compatibility (in which case it extends the XMLOutputFactory implementation from
+            // another StAX implementation, e.g. XLXP). Detect this situation by checking the superclass.
+            Class superClass = cls.getSuperclass();
+            if (superClass == XMLOutputFactory.class || superClass.getName().startsWith("com.sun.")) {
+                // Check if the implementation has the bug fixed here:
+                // https://sjsxp.dev.java.net/source/browse/sjsxp/zephyr/src/com/sun/xml/stream/ZephyrWriterFactory.java?rev=1.8&r1=1.4&r2=1.5
+                boolean isUnsafeStreamResult;
+                try {
+                    cls.getDeclaredField("fStreamResult");
+                    isUnsafeStreamResult = true;
+                } catch (NoSuchFieldException ex) {
+                    isUnsafeStreamResult = false;
+                }
+                return new SJSXPDialect(isUnsafeStreamResult);
             }
-            return new SJSXPDialect(isUnsafeStreamResult);
         }
         
         // Try IBM's XL XP-J
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4Dialect.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4Dialect.java
index 552f895..7468966 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4Dialect.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/Woodstox4Dialect.java
@@ -71,7 +71,11 @@
         // Woodstox 3 used to report whitespace in prolog, but this is no longer the case by default
         // in Woodstox 4. The following property changes that behavior.
         factory.setProperty("org.codehaus.stax2.reportPrologWhitespace", Boolean.TRUE);
-        return new Woodstox4InputFactoryWrapper(factory, this, wstx276);
+        factory = new NormalizingXMLInputFactoryWrapper(factory, this);
+        if (wstx276) {
+            factory = new CloseShieldXMLInputFactoryWrapper(factory);
+        }
+        return factory;
     }
 
     public XMLOutputFactory normalize(XMLOutputFactory factory) {
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1DTDReaderImpl.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1DTDReaderImpl.java
new file mode 100644
index 0000000..51e8390
--- /dev/null
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1DTDReaderImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.util.stax.dialect;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.ext.stax.DTDReader;
+
+final class XLXP1DTDReaderImpl implements DTDReader {
+    private final XMLStreamReader reader;
+    private String rootName;
+    private String publicId;
+    private String systemId;
+
+    XLXP1DTDReaderImpl(XMLStreamReader reader) {
+        this.reader = reader;
+    }
+
+    private void parse() {
+        if (rootName == null) {
+            try {
+                Scanner scanner = new Scanner((String)reader.getProperty("javax.xml.stream.dtd.declaration"));
+                scanner.expect("<!DOCTYPE");
+                scanner.skipSpace();
+                rootName = scanner.getName();
+                scanner.skipSpace();
+                switch (scanner.peek()) {
+                    case 'S':
+                        scanner.expect("SYSTEM");
+                        scanner.skipSpace();
+                        systemId = scanner.getQuotedString();
+                        break;
+                    case 'P':
+                        scanner.expect("PUBLIC");
+                        scanner.skipSpace();
+                        publicId = scanner.getQuotedString();
+                        scanner.skipSpace();
+                        systemId = scanner.getQuotedString();
+                }
+            } catch (XMLStreamException ex) {
+                throw new RuntimeException("Unable to parse DOCTYPE declaration", ex);
+            }
+        }
+    }
+    
+    public String getRootName() {
+        parse();
+        return rootName;
+    }
+
+    public String getPublicId() {
+        parse();
+        return publicId;
+    }
+
+    public String getSystemId() {
+        parse();
+        return systemId;
+    }
+}
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1Dialect.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1Dialect.java
index c6c34a6..60d9ab1 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1Dialect.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1Dialect.java
@@ -61,7 +61,7 @@
 
     public XMLStreamWriter normalize(XMLStreamWriter writer) {
         XMLStreamWriter wrapper = new XLXPStreamWriterWrapper(writer);
-        // Early versions of XLXP the scope of the prefix bindings defined by setPrefix
+        // In early versions of XLXP the scope of the prefix bindings defined by setPrefix
         // is incorrect
         if (isSetPrefixBroken) {
             wrapper = new NamespaceContextCorrectingXMLStreamWriterWrapper(wrapper);
@@ -70,7 +70,7 @@
     }
 
     public XMLInputFactory normalize(XMLInputFactory factory) {
-        return new XLXPInputFactoryWrapper(factory, this);
+        return new CloseShieldXMLInputFactoryWrapper(new XLXPInputFactoryWrapper(factory, this));
     }
 
     public XMLOutputFactory normalize(XMLOutputFactory factory) {
diff --git a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1StreamReaderWrapper.java b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1StreamReaderWrapper.java
index cf28165..7fcdddb 100644
--- a/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1StreamReaderWrapper.java
+++ b/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/XLXP1StreamReaderWrapper.java
@@ -19,16 +19,37 @@
 
 package org.apache.axiom.util.stax.dialect;
 
+import javax.xml.namespace.NamespaceContext;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.axiom.ext.stax.DTDReader;
+
 class XLXP1StreamReaderWrapper extends XLXPStreamReaderWrapper {
     public XLXP1StreamReaderWrapper(XMLStreamReader parent) {
         super(parent);
     }
 
+    public Object getProperty(String name) {
+        if (DTDReader.PROPERTY.equals(name)) {
+            return new XLXP1DTDReaderImpl(getParent());
+        } else {
+            return super.getProperty(name);
+        }
+    }
+
     public String getEncoding() {
         // Under some circumstances, some versions of XLXP return an empty string instead of null
         String encoding = super.getEncoding();
         return encoding == null || encoding.length() == 0 ? null : encoding;
     }
+
+    public String getNamespaceURI(String prefix) {
+        // XLXP may return "" instead of null
+        String uri = super.getNamespaceURI(prefix);
+        return uri == null || uri.length() == 0 ? null : uri;
+    }
+
+    public NamespaceContext getNamespaceContext() {
+        return new NamespaceURICorrectingNamespaceContextWrapper(super.getNamespaceContext());
+    }
 }
diff --git a/modules/axiom-api/src/test/java/org/apache/axiom/attachments/AttachmentCacheMonitorTest.java b/modules/axiom-api/src/test/java/org/apache/axiom/attachments/AttachmentCacheMonitorTest.java
index eb04582..aa1bbd3 100644
--- a/modules/axiom-api/src/test/java/org/apache/axiom/attachments/AttachmentCacheMonitorTest.java
+++ b/modules/axiom-api/src/test/java/org/apache/axiom/attachments/AttachmentCacheMonitorTest.java
@@ -38,15 +38,13 @@
             acm.setTimeout(10); 
 
 
-            File aFile = new File("A");
-            aFile.createNewFile();
+            File aFile = File.createTempFile("fileA", ".tmp");
             String aFileName = aFile.getCanonicalPath();
             acm.register(aFileName);
 
             Thread.sleep(INTERVAL);
 
-            File bFile = new File("B");
-            bFile.createNewFile();
+            File bFile = File.createTempFile("fileB", ".tmp");
             String bFileName = bFile.getCanonicalPath();
             acm.register(bFileName);
 
@@ -66,8 +64,7 @@
 
             Thread.sleep(INTERVAL);
 
-            File cFile = new File("C");
-            cFile.createNewFile();
+            File cFile = File.createTempFile("fileC", ".tmp");
             String cFileName = cFile.getCanonicalPath();
             acm.register(cFileName);
             acm.access(bFileName);
diff --git a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/DialectTestSuite.java b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/DialectTestSuite.java
index 6135925..be31a87 100644
--- a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/DialectTestSuite.java
+++ b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/DialectTestSuite.java
@@ -39,17 +39,28 @@
         
         File targetDir = new File("target");
         
-        // On Java 1.6, also add the StAX implementation from the JRE
-        // The check is not very clean but it should be enough for a unit test...
-        if (System.getProperty("java.version").startsWith("1.6")) {
-            builder.addImplementation(new StAXImplementation("JRE", ClassLoader.getSystemClassLoader(), null));
+        // On Java 1.6 and above, also add the StAX implementation from the JRE
+        if (!System.getProperty("java.version").startsWith("1.5")) {
+            Properties props = new Properties();
+            if (System.getProperty("java.vendor").startsWith("IBM")) {
+                // Necessary for IBM Java 1.6. Note that IBM Java 1.7 also supports
+                // the com.sun.xml.internal.stream.* factories.
+                props.setProperty("javax.xml.stream.XMLInputFactory", "com.ibm.xml.xlxp.api.stax.XMLInputFactoryImpl");
+                props.setProperty("javax.xml.stream.XMLOutputFactory", "com.ibm.xml.xlxp.api.stax.XMLOutputFactoryImpl");
+            } else {
+                props.setProperty("javax.xml.stream.XMLInputFactory", "com.sun.xml.internal.stream.XMLInputFactoryImpl");
+                props.setProperty("javax.xml.stream.XMLOutputFactory", "com.sun.xml.internal.stream.XMLOutputFactoryImpl");
+            }
+            builder.addImplementation(new StAXImplementation("JRE", ClassLoader.getSystemClassLoader(), props));
+            // Neither SJSXP nor XLXP report whitespace in prolog
+            builder.exclude(TestGetTextInProlog.class, "(implementation=JRE)");
         }
         
         addParsersFromDirectory(builder, new File("parsers"));
         addParsersFromDirectory(builder, new File(targetDir, "parsers"));
         
-        // SJSXP doesn't report whitespace in prolog
-        builder.exclude(TestGetTextInProlog.class, "(implementation=sjsxp-1.0.1.jar)");
+        // SJSXP and XLXP don't report whitespace in prolog
+        builder.exclude(TestGetTextInProlog.class, "(|(implementation=sjsxp-1.0.1.jar)(implementation=com.ibm.ws.prereq.xlxp.jar))");
         
         return builder.build();
     }
diff --git a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/StAXImplementation.java b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/StAXImplementation.java
index ec0ad46..2dc250a 100644
--- a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/StAXImplementation.java
+++ b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/StAXImplementation.java
@@ -18,6 +18,9 @@
  */
 package org.apache.axiom.util.stax.dialect;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.Properties;
 
 import javax.xml.stream.FactoryConfigurationError;
@@ -40,24 +43,31 @@
         return name;
     }
 
-    public XMLInputFactory newXMLInputFactory() {
-        String className = props == null ? null : props.getProperty(XMLInputFactory.class.getName());
-        XMLInputFactory factory;
+    private Object newFactory(Class type) {
+        String className = props == null ? null : props.getProperty(type.getName());
         if (className == null) {
-            ClassLoader savedClassLoader = Thread.currentThread().getContextClassLoader();
-            Thread.currentThread().setContextClassLoader(classLoader);
+            // We do the lookup ourselves instead of using the StAX API. This allows
+            // us to completely ignore the system properties. The Axiom build allows
+            // to use system properties to specify the StAX implementation to be used
+            // by unit tests, but this must not interfere with the dialect tests.
             try {
-                factory = XMLInputFactory.newInstance();
-            } finally {
-                Thread.currentThread().setContextClassLoader(savedClassLoader);
-            }
-        } else {
-            try {
-                factory = (XMLInputFactory)classLoader.loadClass(className).newInstance();
-            } catch (Exception ex) {
+                BufferedReader in = new BufferedReader(new InputStreamReader(
+                        classLoader.getResourceAsStream("META-INF/services/" + type.getName()), "UTF-8"));
+                try {
+                    className = in.readLine();
+                } finally {
+                    in.close();
+                }
+            } catch (IOException ex) {
                 throw new FactoryConfigurationError(ex);
             }
         }
+        Object factory;
+        try {
+            factory = classLoader.loadClass(className).newInstance();
+        } catch (Exception ex) {
+            throw new FactoryConfigurationError(ex);
+        }
         // Check that the parser has actually been loaded from the expected class loader.
         // If the parser has been loaded from the JRE, then comparing the class loaders
         // is not reliable (because it may be null). Hence the check on ParentLastURLClassLoader.
@@ -69,6 +79,10 @@
         return factory;
     }
     
+    public XMLInputFactory newXMLInputFactory() {
+        return (XMLInputFactory)newFactory(XMLInputFactory.class);
+    }
+    
     public XMLInputFactory newNormalizedXMLInputFactory() {
         XMLInputFactory factory = newXMLInputFactory();
         if (dialect == null) {
@@ -78,29 +92,7 @@
     }
 
     public XMLOutputFactory newXMLOutputFactory() {
-        String className = props == null ? null : props.getProperty(XMLOutputFactory.class.getName());
-        XMLOutputFactory factory;
-        if (className == null) {
-            ClassLoader savedClassLoader = Thread.currentThread().getContextClassLoader();
-            Thread.currentThread().setContextClassLoader(classLoader);
-            try {
-                factory = XMLOutputFactory.newInstance();
-            } finally {
-                Thread.currentThread().setContextClassLoader(savedClassLoader);
-            }
-        } else {
-            try {
-                factory = (XMLOutputFactory)classLoader.loadClass(className).newInstance();
-            } catch (Exception ex) {
-                throw new FactoryConfigurationError(ex);
-            }
-        }
-        if (classLoader != ClassLoader.getSystemClassLoader()
-                && factory.getClass().getClassLoader() != classLoader) {
-            throw new FactoryConfigurationError("Wrong factory: got " + factory.getClass().getName()
-                    + " loaded from " + factory.getClass().getClassLoader());
-        }
-        return factory;
+        return (XMLOutputFactory)newFactory(XMLOutputFactory.class);
     }
     
     public XMLOutputFactory newNormalizedXMLOutputFactory() {
diff --git a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/TestGetOriginalXMLStreamReader.java b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/TestGetOriginalXMLStreamReader.java
index 9ca0d9f..f46d256 100644
--- a/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/TestGetOriginalXMLStreamReader.java
+++ b/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/dialect/TestGetOriginalXMLStreamReader.java
@@ -34,6 +34,8 @@
         XMLInputFactory factory = staxImpl.newNormalizedXMLInputFactory();
         XMLStreamReader reader = factory.createXMLStreamReader(new StringReader("<root/>"));
         XMLStreamReader originalReader = XMLStreamReaderUtils.getOriginalXMLStreamReader(reader);
-        assertSame(staxImpl.getClassLoader(), originalReader.getClass().getClassLoader());
+        ClassLoader cl = originalReader.getClass().getClassLoader();
+        // cl == null covers the case where the StAX implementation is included in the JRE
+        assertTrue(cl == null || cl == staxImpl.getClassLoader());
     }
 }
diff --git a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/IContainer.java b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/IContainer.java
index b9e64fa..148be2c 100644
--- a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/IContainer.java
+++ b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/IContainer.java
@@ -18,11 +18,22 @@
  */
 package org.apache.axiom.om.impl.common;
 
+import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.OMNode;
 import org.apache.axiom.om.impl.OMContainerEx;
 
 public interface IContainer extends OMContainerEx, IParentNode {
     /**
+     * Check if the node can be added as a child of this container.
+     * 
+     * @param child
+     *            the child that will be added
+     * @throws OMException
+     *             if the node is not allowed as a child of the container
+     */
+    void checkChild(OMNode child);
+    
+    /**
      * forcefully set the first element in this parent element
      * @param omNode
      */
diff --git a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMContainerHelper.java b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMContainerHelper.java
index 10573ed..ef3c15a 100644
--- a/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMContainerHelper.java
+++ b/modules/axiom-common-impl/src/main/java/org/apache/axiom/om/impl/common/OMContainerHelper.java
@@ -99,7 +99,7 @@
         } else {
             // Careful here: if the child was created by another Axiom implementation, it doesn't
             // necessarily implement OMNodeEx
-            if (omNode.getOMFactory().getMetaFactory() == container.getOMFactory().getMetaFactory()) {
+            if (omNode.getOMFactory().getMetaFactory().equals(container.getOMFactory().getMetaFactory())) {
                 child = (OMNodeEx)omNode;
             } else {
                 child = (OMNodeEx)((OMFactoryEx)container.getOMFactory()).importNode(omNode);
@@ -112,6 +112,7 @@
                 // We don't need to detach and re-add it.
                 return;
             }
+            container.checkChild(omNode);
         }
         if (child.getParent() != null) {
             child.detach();
@@ -163,17 +164,17 @@
     
     public static void buildNext(IParentNode that) {
         OMXMLParserWrapper builder = that.getBuilder();
-        if (builder != null) {
-            if (((StAXOMBuilder)builder).isClosed()) {
-                throw new OMException("The builder has already been closed");
-            } else if (!builder.isCompleted()) {
-                builder.next();
-            } else {
-                // If the builder is suddenly complete, but the completion status of the node
-                // doesn't change, then this means that we built the wrong nodes
-                throw new IllegalStateException("Builder is already complete");
-            }         
-        }
+        if (builder == null) {
+            throw new IllegalStateException("The node has no builder");
+        } else if (((StAXOMBuilder)builder).isClosed()) {
+            throw new OMException("The builder has already been closed");
+        } else if (!builder.isCompleted()) {
+            builder.next();
+        } else {
+            // If the builder is suddenly complete, but the completion status of the node
+            // doesn't change, then this means that we built the wrong nodes
+            throw new IllegalStateException("Builder is already complete");
+        }         
     }
     
     public static OMNode getFirstOMChild(IParentNode that) {
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 bbeb629..1de241f 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
@@ -102,8 +102,19 @@
     /** 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
+     * has been generated. The next event will be {@link XMLStreamConstants#END_DOCUMENT} and state
+     * will transition to {@link #DOCUMENT_COMPLETE}.
+     */
     private static final short COMPLETED = 2;
+    
     private static final short SWITCHED = 3;
+    
+    /**
+     * Indicates that the final {@link XMLStreamConstants#END_DOCUMENT} event has been generated.
+     */
     private static final short DOCUMENT_COMPLETE = 4;
 
     /** Field state */
@@ -439,6 +450,11 @@
         }
     }
     
+    private OMAttribute getAttribute(int index) {
+        loadAttributes();
+        return attributes[index];
+    }
+    
     private void loadNamespaces() {
         if (namespaceCount == -1) {
             namespaceCount = 0;
@@ -469,6 +485,11 @@
         }
     }
     
+    private OMNamespace getNamespace(int index) {
+        loadNamespaces();
+        return namespaces[index];
+    }
+    
     private void addNamespace(OMNamespace ns) {
         // TODO: verify if this check is actually still necessary
         // Axiom internally creates an OMNamespace instance for the "xml" prefix, even
@@ -490,28 +511,29 @@
      * @see javax.xml.stream.XMLStreamReader#getNamespaceURI
      */
     public String getNamespaceURI(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getNamespaceURI(i);
+            String uri = parser.getNamespaceURI(i);
+
+            /*
+              The following line is necessary to overcome an issue where the empty
+              namespace URI returning null rather than the empty string. Our resolution
+              is to return "" if the return is actually null
+
+              Note that this is not the case for  getNamespaceURI(prefix) method
+              where the contract clearly specifies that the return may be null
+
+            */
+            if (uri == null) {
+                uri = "";
+            }
+            return uri;
         } else {
             if (isStartElement() || isEndElement()) {
-                loadNamespaces();
-                returnString = namespaces[i].getNamespaceURI();
+                return getNamespace(i).getNamespaceURI();
+            } else {
+                throw new IllegalStateException();
             }
         }
-
-        /*
-          The following line is necessary to overcome an issue where the empty
-          namespace URI returning null rather than the empty string. Our resolution
-          is to return "" if the return is actually null
-
-          Note that this is not the case for  getNamespaceURI(prefix) method
-          where the contract clearly specifies that the return may be null
-
-        */
-        if (returnString == null) returnString = "";
-
-        return returnString;
     }
 
     /**
@@ -520,17 +542,16 @@
      * @see javax.xml.stream.XMLStreamReader#getNamespacePrefix
      */
     public String getNamespacePrefix(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getNamespacePrefix(i);
+            return parser.getNamespacePrefix(i);
         } else {
             if (isStartElement() || isEndElement()) {
-                loadNamespaces();
-                String prefix = namespaces[i].getPrefix();
-                returnString = prefix.length() == 0 ? null : prefix; 
+                String prefix = getNamespace(i).getPrefix();
+                return prefix.length() == 0 ? null : prefix; 
+            } else {
+                throw new IllegalStateException();
             }
         }
-        return returnString;
     }
 
     /**
@@ -576,19 +597,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributeValue
      */
     public String getAttributeValue(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getAttributeValue(i);
+            return parser.getAttributeValue(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                returnString = attributes[i].getAttributeValue();
+                return getAttribute(i).getAttributeValue();
             } else {
                 throw new IllegalStateException(
                         "attribute type accessed in illegal event!");
             }
         }
-        return returnString;
     }
 
     /**
@@ -597,19 +615,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributeType
      */
     public String getAttributeType(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getAttributeType(i);
+            return parser.getAttributeType(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                returnString = attributes[i].getAttributeType();
+                return getAttribute(i).getAttributeType();
             } else {
                 throw new IllegalStateException(
                         "attribute type accessed in illegal event!");
             }
         }
-        return returnString;
     }
 
     /**
@@ -618,25 +633,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributePrefix
      */
     public String getAttributePrefix(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getAttributePrefix(i);
+            return parser.getAttributePrefix(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                OMAttribute attrib = attributes[i];
-                if (attrib != null) {
-                    OMNamespace nameSpace = attrib.getNamespace();
-                    if (nameSpace != null) {
-                        returnString = nameSpace.getPrefix();
-                    }
-                }
+                return getAttribute(i).getPrefix();
             } else {
                 throw new IllegalStateException(
                         "attribute prefix accessed in illegal event!");
             }
         }
-        return returnString;
     }
 
     /**
@@ -645,19 +651,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributeLocalName
      */
     public String getAttributeLocalName(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getAttributeLocalName(i);
+            return parser.getAttributeLocalName(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                returnString = attributes[i].getLocalName();
+                return getAttribute(i).getLocalName();
             } else {
                 throw new IllegalStateException(
                         "attribute localName accessed in illegal event!");
             }
         }
-        return returnString;
     }
 
     /**
@@ -666,25 +669,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributeNamespace
      */
     public String getAttributeNamespace(int i) {
-        String returnString = null;
         if (parser != null) {
-            returnString = parser.getAttributeNamespace(i);
+            return parser.getAttributeNamespace(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                OMAttribute attrib = attributes[i];
-                if (attrib != null) {
-                    OMNamespace nameSpace = attrib.getNamespace();
-                    if (nameSpace != null) {
-                        returnString = nameSpace.getNamespaceURI();
-                    }
-                }
+                return getAttribute(i).getNamespaceURI();
             } else {
                 throw new IllegalStateException(
                         "attribute nameSpace accessed in illegal event!");
             }
         }
-        return returnString;
     }
 
     /**
@@ -693,19 +687,16 @@
      * @see javax.xml.stream.XMLStreamReader#getAttributeName
      */
     public QName getAttributeName(int i) {
-        QName returnQName = null;
         if (parser != null) {
-            returnQName = parser.getAttributeName(i);
+            return parser.getAttributeName(i);
         } else {
             if (isStartElement()) {
-                loadAttributes();
-                returnQName = attributes[i].getQName();
+                return getAttribute(i).getQName();
             } else {
                 throw new IllegalStateException(
                         "attribute count accessed in illegal event!");
             }
         }
-        return returnQName;
     }
 
     /**
@@ -991,11 +982,7 @@
         attributeCount = -1;
         namespaceCount = -1;
         currentNode = nextNode;
-        try {
-            updateNextNode(!cache);
-        } catch (Exception e) {
-            throw new XMLStreamException(e);
-        }
+        updateNextNode(!cache);
     }
 
     /** Method updateNextNode. */
@@ -1052,12 +1039,15 @@
                 }
             }
         } else {
-            if (state == SWITCHED && currentEvent == END_ELEMENT && depth == 0 && rootNode instanceof OMElement) {
+            assert state == SWITCHED;
+            if (depth == 0 && rootNode instanceof OMElement) {
+                // If rootNode is an OMElement and depth == 0, then currentEvent can only be END_ELEMENT
+                // (because we don't generate any other events at depth 0)
+                assert currentEvent == END_ELEMENT;
                 state = COMPLETED;
+            } else if (currentEvent == END_DOCUMENT) {
+                state = DOCUMENT_COMPLETE;
             }
-            state = (currentEvent == END_DOCUMENT)
-                    ? DOCUMENT_COMPLETE
-                    : state;
         }
     }
 
@@ -1350,16 +1340,14 @@
         Map nsMap = new LinkedHashMap();
         while (context != null && !(context instanceof OMDocument)) {
             OMElement element = (OMElement) context;
-            Iterator i = element.getAllDeclaredNamespaces();
-            while (i != null && i.hasNext()) {
-                addNamespaceToMap((OMNamespace) i.next(), nsMap);
+            for (Iterator it = element.getAllDeclaredNamespaces(); it.hasNext(); ) {
+                addNamespaceToMap((OMNamespace) it.next(), nsMap);
             }
             if (element.getNamespace() != null) {
                 addNamespaceToMap(element.getNamespace(), nsMap);
             }
-            for (Iterator iter = element.getAllAttributes();
-                 iter != null && iter.hasNext();) {
-                OMAttribute attr = (OMAttribute) iter.next();
+            for (Iterator it = element.getAllAttributes(); it.hasNext(); ) {
+                OMAttribute attr = (OMAttribute) it.next();
                 if (attr.getNamespace() != null) {
                     addNamespaceToMap(attr.getNamespace(), nsMap);
                 }
diff --git a/modules/axiom-dom-testsuite/pom.xml b/modules/axiom-dom-testsuite/pom.xml
index b8d1c98..da3bef2 100644
--- a/modules/axiom-dom-testsuite/pom.xml
+++ b/modules/axiom-dom-testsuite/pom.xml
@@ -74,6 +74,30 @@
     <build>
         <plugins>
             <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <includeArtifactIds>xml-apis,xercesImpl</includeArtifactIds>
+                            <outputDirectory>${project.build.directory}/endorsed</outputDirectory>
+                            <stripVersion>true</stripVersion>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <!-- This is necessary to execute the tests with the IBM JRE: we need to endorse the particular Xerces version
+                         we want to use because the JRE already contains Xerces. -->
+                    <argLine>${jacoco.surefireArgLine} -Xbootclasspath/p:${project.build.directory}/endorsed/xml-apis.jar${path.separator}${project.build.directory}/endorsed/xercesImpl.jar</argLine>
+                </configuration>
+            </plugin>
+            <plugin>
                 <artifactId>maven-site-plugin</artifactId>
                 <configuration>
                     <skip>true</skip>
diff --git a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentFragmentImpl.java b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentFragmentImpl.java
index 430e841..ef80ee2 100644
--- a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentFragmentImpl.java
+++ b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentFragmentImpl.java
@@ -21,6 +21,7 @@
 
 import org.apache.axiom.om.OMCloneOptions;
 import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMNode;
 import org.apache.axiom.om.OMXMLParserWrapper;
 import org.apache.axiom.om.impl.common.IContainer;
 import org.apache.axiom.om.impl.common.OMContainerHelper;
@@ -125,4 +126,7 @@
     public final String lookupNamespaceURI(String specifiedPrefix) {
         return null;
     }
+
+    public final void checkChild(OMNode child) {
+    }
 }
diff --git a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentImpl.java b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentImpl.java
index ce1358f..9abd91c 100644
--- a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentImpl.java
+++ b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DocumentImpl.java
@@ -22,6 +22,7 @@
 import org.apache.axiom.om.OMCloneOptions;
 import org.apache.axiom.om.OMDocument;
 import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.OMFactory;
 import org.apache.axiom.om.OMNamespace;
 import org.apache.axiom.om.OMNode;
@@ -628,4 +629,17 @@
         return documentElement == null ? null
                 : documentElement.lookupNamespaceURI(specifiedPrefix);
     }
+    
+    public final void checkChild(OMNode child) {
+        if (child instanceof OMElement) {
+            if (getOMDocumentElement() != null) {
+                throw new OMException("Document element already exists");
+            } else {
+                checkDocumentElement((OMElement)child);
+            }
+        }
+    }
+
+    protected void checkDocumentElement(OMElement element) {
+    }
 }
diff --git a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ElementImpl.java b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ElementImpl.java
index c700eb5..8a822ad 100644
--- a/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ElementImpl.java
+++ b/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ElementImpl.java
@@ -1236,4 +1236,7 @@
         ParentNode parent = parentNode();
         return parent == null || parent instanceof Document ? null : parent.lookupNamespaceURI(specifiedPrefix);
     }
+
+    public final void checkChild(OMNode child) {
+    }
 }
diff --git a/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPEnvelopeImpl.java b/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPEnvelopeImpl.java
index 86cde32..133d450 100644
--- a/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPEnvelopeImpl.java
+++ b/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPEnvelopeImpl.java
@@ -90,7 +90,8 @@
      * 
      * @param child
      */
-    private void checkChild(OMNode child) {
+    // TODO: this should be integrated into the checkChild API
+    private void internalCheckChild(OMNode child) {
         if ((child instanceof OMElement)
                 && !(child instanceof SOAPHeader || child instanceof SOAPBody)) {
             throw new SOAPProcessingException(
@@ -103,7 +104,7 @@
         // SOAP 1.1 allows for arbitrary elements after SOAPBody so do NOT check for
         // node types when appending to SOAP 1.1 envelope.
         if (getVersion() instanceof SOAP12Version) {
-            checkChild(child);
+            internalCheckChild(child);
         }
 
         if (child instanceof SOAPHeader) {
diff --git a/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPMessageImpl.java b/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPMessageImpl.java
index 0a110c0..9a1d239 100644
--- a/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPMessageImpl.java
+++ b/modules/axiom-dom/src/main/java/org/apache/axiom/soap/impl/dom/SOAPMessageImpl.java
@@ -20,6 +20,8 @@
 package org.apache.axiom.soap.impl.dom;
 
 import org.apache.axiom.om.OMCloneOptions;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.OMXMLParserWrapper;
 import org.apache.axiom.om.impl.OMNodeEx;
 import org.apache.axiom.om.impl.dom.DocumentImpl;
@@ -46,9 +48,14 @@
         return (SOAPEnvelope) getOMDocumentElement();
     }
 
-    public void setSOAPEnvelope(SOAPEnvelope envelope)
-            throws SOAPProcessingException {
-        this.addChild(envelope, true);
+    public void setSOAPEnvelope(SOAPEnvelope envelope) {
+        setOMDocumentElement(envelope);
+    }
+
+    protected void checkDocumentElement(OMElement element) {
+        if (!(element instanceof SOAPEnvelope)) {
+            throw new OMException("Child not allowed; must be a SOAPEnvelope");
+        }
     }
 
     protected void internalSerialize(XMLStreamWriter writer, boolean cache,
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMDocumentImpl.java b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMDocumentImpl.java
index 1200d02..6085d18 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMDocumentImpl.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMDocumentImpl.java
@@ -149,12 +149,22 @@
     }
 
     public void addChild(OMNode omNode, boolean fromBuilder) {
-        if (!fromBuilder && omNode instanceof OMElement && getOMDocumentElement() != null) {
-            throw new OMException("Document element already exists");
-        }
         OMContainerHelper.addChild(this, omNode, fromBuilder);
     }
 
+    public final void checkChild(OMNode child) {
+        if (child instanceof OMElement) {
+            if (getOMDocumentElement() != null) {
+                throw new OMException("Document element already exists");
+            } else {
+                checkDocumentElement((OMElement)child);
+            }
+        }
+    }
+
+    protected void checkDocumentElement(OMElement element) {
+    }
+
     /**
      * Returns a collection of this element. Children can be of types OMElement, OMText.
      *
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMElementImpl.java b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMElementImpl.java
index e2ffc60..c390534 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMElementImpl.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMElementImpl.java
@@ -225,6 +225,9 @@
         OMContainerHelper.addChild(this, omNode, fromBuilder);
     }
 
+    public void checkChild(OMNode child) {
+    }
+
     /**
      * Searches for children with a given QName and returns an iterator to traverse through the
      * OMNodes. This QName can contain any combination of prefix, localname and URI.
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMSourcedElementImpl.java b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMSourcedElementImpl.java
index 1810f97..968f14e 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMSourcedElementImpl.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMSourcedElementImpl.java
@@ -93,8 +93,6 @@
     
     private static final Log forceExpandLog = LogFactory.getLog(OMSourcedElementImpl.class.getName() + ".forceExpand");
     
-    private XMLStreamReader readerFromDS = null;  // Reader from DataSource
-
     private static OMNamespace getOMNamespace(QName qName) {
         return qName.getNamespaceURI().length() == 0 ? null
                 : new OMNamespaceImpl(qName.getNamespaceURI(), qName.getPrefix());
@@ -251,6 +249,7 @@
                 }
             } else {
                 // Get the XMLStreamReader
+                XMLStreamReader readerFromDS;
                 try {
                     readerFromDS = dataSource.getReader();  
                 } catch (XMLStreamException ex) {
@@ -276,10 +275,10 @@
                 // Set the builder for this element. Note that the StAXOMBuilder constructor will also
                 // update the namespace of the element, so we don't need to do that here.
                 isExpanded = true;
-                super.setBuilder(new StAXOMBuilder(getOMFactory(), 
-                                                   readerFromDS, 
-                                                   this, 
-                                                   characterEncoding));
+                StAXOMBuilder builder = new StAXOMBuilder(getOMFactory(), readerFromDS, this, characterEncoding);
+                builder.setAutoClose(true);
+                builder.releaseParserOnClose(true);
+                super.setBuilder(builder);
                 setComplete(false);
             }
         }
@@ -845,6 +844,10 @@
         super.addChild(omNode, fromBuilder);
     }
 
+    public void checkChild(OMNode child) {
+        super.checkChild(child);
+    }
+
     public Iterator getChildrenWithName(QName elementQName) {
         forceExpand();
         return super.getChildrenWithName(elementQName);
@@ -1029,29 +1032,13 @@
      * expansion process. Thus calls to setCompete should stop here and not propogate up to the
      * parent (which may have a different builder or no builder).
      */
-    public void setComplete(boolean value) {
-        state = value ? COMPLETE : INCOMPLETE;
-        if (value == true) {
-            if (readerFromDS != null) {
-                try {
-                    readerFromDS.close();
-                } catch (XMLStreamException e) {
-                }
-                readerFromDS = null;
+    public void setComplete(boolean complete) {
+        state = complete ? COMPLETE : INCOMPLETE;
+        if (complete && dataSource != null) {
+            if (dataSource instanceof OMDataSourceExt) {
+                ((OMDataSourceExt)dataSource).close();
             }
-            if (dataSource != null) {
-                if (dataSource instanceof OMDataSourceExt) {
-                    ((OMDataSourceExt)dataSource).close();
-                }
-                dataSource = null;
-            }
-        }
-        if (value == true && readerFromDS != null) {
-            try {
-                readerFromDS.close();
-            } catch (XMLStreamException e) {
-            }
-            readerFromDS = null;
+            dataSource = null;
         }
     }
     
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListImplFactory.java b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListImplFactory.java
index aa5cfa8..eae4956 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListImplFactory.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListImplFactory.java
@@ -20,6 +20,7 @@
 package org.apache.axiom.om.impl.llom.factory;
 
 import org.apache.axiom.ext.stax.datahandler.DataHandlerProvider;
+import org.apache.axiom.om.OMAbstractFactory;
 import org.apache.axiom.om.OMAttribute;
 import org.apache.axiom.om.OMComment;
 import org.apache.axiom.om.OMContainer;
@@ -57,10 +58,18 @@
 public class OMLinkedListImplFactory implements OMFactoryEx {
     private final OMLinkedListMetaFactory metaFactory;
     
-    public OMLinkedListImplFactory(OMLinkedListMetaFactory metaFactory) {
+    /**
+     * For internal use only.
+     * 
+     * @param metaFactory
+     */
+    protected OMLinkedListImplFactory(OMLinkedListMetaFactory metaFactory) {
         this.metaFactory = metaFactory;
     }
     
+    /**
+     * @deprecated Use {@link OMAbstractFactory#getOMFactory()} to get an instance of this class.
+     */
     public OMLinkedListImplFactory() {
         this(new OMLinkedListMetaFactory());
     }
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListMetaFactory.java b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListMetaFactory.java
index 30b2167..994244d 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListMetaFactory.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/factory/OMLinkedListMetaFactory.java
@@ -51,4 +51,16 @@
     public SOAPMessage createSOAPMessage(OMXMLParserWrapper builder) {
         return new SOAPMessageImpl(builder, null);
     }
+
+    public int hashCode() {
+        return getClass().hashCode();
+    }
+    
+    public boolean equals(Object obj) {
+        // All instances of this class are considered equal. This is only required
+        // to support legacy code that instantiates OMFactory implementations directly
+        // (in which case the OMMetaFactory implementation is not guaranteed to be
+        // a singleton). May be removed in Axiom 1.3.
+        return obj != null && obj.getClass() == getClass();
+    }
 }
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPEnvelopeImpl.java b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPEnvelopeImpl.java
index 755edee..222ad2c 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPEnvelopeImpl.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPEnvelopeImpl.java
@@ -101,7 +101,8 @@
      * 
      * @param child
      */
-    private void checkChild(OMNode child) {
+    // TODO: this should be integrated into the checkChild API
+    private void internalCheckChild(OMNode child) {
         if ((child instanceof OMElement)
                 && !(child instanceof SOAPHeader || child instanceof SOAPBody)) {
             throw new SOAPProcessingException(
@@ -118,7 +119,7 @@
         // SOAP 1.1 allows for arbitrary elements after SOAPBody so do NOT check for
         // node types when appending to SOAP 1.1 envelope.
         if (getVersion() instanceof SOAP12Version) {
-            checkChild(child);
+            internalCheckChild(child);
         }
 
         if (child instanceof SOAPHeader) {
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPMessageImpl.java b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPMessageImpl.java
index 3ee32a0..668f39d 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPMessageImpl.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/SOAPMessageImpl.java
@@ -22,6 +22,7 @@
 import org.apache.axiom.om.OMCloneOptions;
 import org.apache.axiom.om.OMDocument;
 import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.OMXMLParserWrapper;
 import org.apache.axiom.om.impl.OMNodeEx;
 import org.apache.axiom.om.impl.llom.OMDocumentImpl;
@@ -49,13 +50,14 @@
         return (SOAPEnvelope) getOMDocumentElement();
     }
 
-    public void setSOAPEnvelope(SOAPEnvelope envelope) throws SOAPProcessingException {
-        super.addChild(envelope, true);
+    public void setSOAPEnvelope(SOAPEnvelope envelope) {
+        setOMDocumentElement(envelope);
     }
 
-    public void setOMDocumentElement(OMElement rootElement) {
-        throw new UnsupportedOperationException(
-                "This is not allowed. Use set SOAPEnvelope instead");
+    protected void checkDocumentElement(OMElement element) {
+        if (!(element instanceof SOAPEnvelope)) {
+            throw new OMException("Child not allowed; must be a SOAPEnvelope");
+        }
     }
 
     protected void internalSerialize(XMLStreamWriter writer, boolean cache,
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap11/SOAP11Factory.java b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap11/SOAP11Factory.java
index 91fc28c..aaed2f4 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap11/SOAP11Factory.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap11/SOAP11Factory.java
@@ -19,6 +19,7 @@
 
 package org.apache.axiom.soap.impl.llom.soap11;
 
+import org.apache.axiom.om.OMAbstractFactory;
 import org.apache.axiom.om.OMDataSource;
 import org.apache.axiom.om.OMNamespace;
 import org.apache.axiom.om.OMXMLParserWrapper;
@@ -50,10 +51,19 @@
 /**
  */
 public class SOAP11Factory extends OMLinkedListImplFactory implements SOAPFactoryEx {
+    /**
+     * For internal use only.
+     * 
+     * @param metaFactory
+     */
     public SOAP11Factory(OMLinkedListMetaFactory metaFactory) {
         super(metaFactory);
     }
 
+    /**
+     * @deprecated Use {@link OMAbstractFactory#getSOAP11Factory()} to get an instance of this
+     *             class.
+     */
     public SOAP11Factory() {
     }
 
@@ -324,7 +334,12 @@
     }
 
     public SOAPMessage createSOAPMessage(OMXMLParserWrapper builder) {
-        return new SOAPMessageImpl(builder, this);
+        if (builder == null) {
+            // For Spring-WS compatibility
+            return createSOAPMessage();
+        } else {
+            return new SOAPMessageImpl(builder, this);
+        }
     }
 
     public SOAPEnvelope createSOAPEnvelope(SOAPMessage message, OMXMLParserWrapper builder) {
diff --git a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap12/SOAP12Factory.java b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap12/SOAP12Factory.java
index 84f11a0..d9c16af 100644
--- a/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap12/SOAP12Factory.java
+++ b/modules/axiom-impl/src/main/java/org/apache/axiom/soap/impl/llom/soap12/SOAP12Factory.java
@@ -19,6 +19,7 @@
 
 package org.apache.axiom.soap.impl.llom.soap12;
 
+import org.apache.axiom.om.OMAbstractFactory;
 import org.apache.axiom.om.OMDataSource;
 import org.apache.axiom.om.OMNamespace;
 import org.apache.axiom.om.OMXMLParserWrapper;
@@ -50,10 +51,19 @@
 /**
  */
 public class SOAP12Factory extends OMLinkedListImplFactory implements SOAPFactoryEx {
+    /**
+     * For internal use only.
+     * 
+     * @param metaFactory
+     */
     public SOAP12Factory(OMLinkedListMetaFactory metaFactory) {
         super(metaFactory);
     }
 
+    /**
+     * @deprecated Use {@link OMAbstractFactory#getSOAP12Factory()} to get an instance of this
+     *             class.
+     */
     public SOAP12Factory() {
     }
 
@@ -327,7 +337,12 @@
     }
 
     public SOAPMessage createSOAPMessage(OMXMLParserWrapper builder) {
-        return new SOAPMessageImpl(builder, this);
+        if (builder == null) {
+            // For Spring-WS compatibility
+            return createSOAPMessage();
+        } else {
+            return new SOAPMessageImpl(builder, this);
+        }
     }
 
     public SOAPEnvelope createSOAPEnvelope(SOAPMessage message, OMXMLParserWrapper builder) {
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 d06a841..1027f60 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
@@ -132,6 +132,7 @@
             }
         }
         addTest(new org.apache.axiom.ts.om.document.TestAddChildIncomplete(metaFactory));
+        addTest(new org.apache.axiom.ts.om.document.TestAddChildWithExistingDocumentElement(metaFactory));
         for (int i=0; i<conformanceFiles.length; i++) {
             addTest(new org.apache.axiom.ts.om.document.TestClone(metaFactory, conformanceFiles[i]));
         }
@@ -433,6 +434,7 @@
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestCloneNonDestructive(metaFactory, true));
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestCloneNonDestructive(metaFactory, false));
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestCloneUnknownName(metaFactory));
+            addTest(new org.apache.axiom.ts.om.sourcedelement.TestCloseOnComplete(metaFactory));
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestComplete(metaFactory));
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestExpand(metaFactory));
             addTest(new org.apache.axiom.ts.om.sourcedelement.TestGetDocumentFromBuilder(metaFactory));
@@ -506,7 +508,8 @@
         addTest(new org.apache.axiom.ts.om.text.TestBase64StreamingWithSerialize(metaFactory));
         addTest(new org.apache.axiom.ts.om.text.TestDigest(metaFactory));
         addTest(new org.apache.axiom.ts.om.text.TestGetTextCharactersFromDataHandler(metaFactory));
-        addTest(new org.apache.axiom.ts.om.xop.TestSerialize(metaFactory));
+        addTest(new org.apache.axiom.ts.om.xop.TestSerialize(metaFactory, false));
+        addTest(new org.apache.axiom.ts.om.xop.TestSerialize(metaFactory, true));
         addTest(new org.apache.axiom.ts.om.xop.XOPRoundtripTest(metaFactory));
         Method[] methods = AXIOMXPathTestCase.class.getMethods();
         for (int i=0; i<methods.length; i++) {
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/builder/TestRootPartStreaming.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/builder/TestRootPartStreaming.java
index f4dd620..50afa1a 100644
--- a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/builder/TestRootPartStreaming.java
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/builder/TestRootPartStreaming.java
@@ -49,7 +49,7 @@
         
         // Programmatically create the message
         OMElement orgRoot = factory.createOMElement("root", null);
-        for (int i=0; i<1000; i++) {
+        for (int i=0; i<10000; i++) {
             factory.createOMElement("child", null, orgRoot).setText("Some text content");
         }
         
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/document/TestAddChildWithExistingDocumentElement.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/document/TestAddChildWithExistingDocumentElement.java
new file mode 100644
index 0000000..8e1d159
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/document/TestAddChildWithExistingDocumentElement.java
@@ -0,0 +1,52 @@
+/*
+ * 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.document;
+
+import javax.xml.namespace.QName;
+
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMException;
+import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMMetaFactory;
+import org.apache.axiom.om.OMNode;
+import org.apache.axiom.ts.AxiomTestCase;
+
+/**
+ * Tests that an attempt to use {@link OMContainer#addChild(OMNode)} to add an {@link OMElement} to
+ * an {@link OMDocument} that already has a document element results in an exception.
+ */
+public class TestAddChildWithExistingDocumentElement extends AxiomTestCase {
+    public TestAddChildWithExistingDocumentElement(OMMetaFactory metaFactory) {
+        super(metaFactory);
+    }
+
+    protected void runTest() throws Throwable {
+        OMFactory factory = metaFactory.getOMFactory();
+        OMDocument document = factory.createOMDocument();
+        document.addChild(factory.createOMElement(new QName("root1")));
+        try {
+            document.addChild(factory.createOMElement(new QName("root2")));
+            fail("Expected OMException");
+        } catch (OMException ex) {
+            // Expected
+        }
+    }
+}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestDataSource.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestDataSource.java
new file mode 100644
index 0000000..d842796
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestDataSource.java
@@ -0,0 +1,47 @@
+/*
+ * 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.sourcedelement;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+class CloseTestDataSource extends TestDataSource {
+    private final Set unclosedReaders = new HashSet();
+    
+    CloseTestDataSource(String data) {
+        super(data);
+    }
+
+    public XMLStreamReader getReader() throws XMLStreamException {
+        CloseTestXMLStreamReaderWrapper reader = new CloseTestXMLStreamReaderWrapper(this, super.getReader());
+        unclosedReaders.add(reader);
+        return reader;
+    }
+
+    boolean hasUnclosedReaders() {
+        return !unclosedReaders.isEmpty();
+    }
+    
+    void readerClosed(CloseTestXMLStreamReaderWrapper reader) {
+        unclosedReaders.remove(reader);
+    }
+}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestXMLStreamReaderWrapper.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestXMLStreamReaderWrapper.java
new file mode 100644
index 0000000..7a82261
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/CloseTestXMLStreamReaderWrapper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.sourcedelement;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.util.stax.wrapper.XMLStreamReaderWrapper;
+
+class CloseTestXMLStreamReaderWrapper extends XMLStreamReaderWrapper {
+    private final CloseTestDataSource ds;
+    private boolean closed;
+    
+    CloseTestXMLStreamReaderWrapper(CloseTestDataSource ds, XMLStreamReader parent) {
+        super(parent);
+        this.ds = ds;
+    }
+
+    public void close() throws XMLStreamException {
+        super.close();
+        ds.readerClosed(this);
+        closed = true;
+    }
+
+    public int next() throws XMLStreamException {
+        if (closed) {
+            throw new IllegalStateException();
+        }
+        return super.next();
+    }
+}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/TestCloseOnComplete.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/TestCloseOnComplete.java
new file mode 100644
index 0000000..a5fc0d0
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/sourcedelement/TestCloseOnComplete.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sourcedelement;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.om.OMDataSource;
+import org.apache.axiom.om.OMMetaFactory;
+import org.apache.axiom.om.OMNode;
+import org.apache.axiom.om.OMSourcedElement;
+import org.apache.axiom.ts.AxiomTestCase;
+
+/**
+ * Tests that {@link OMSourcedElement} calls {@link XMLStreamReader#close()} on the
+ * {@link XMLStreamReader} returned by {@link OMDataSource#getReader()} when the element is
+ * completely built.
+ */
+public class TestCloseOnComplete extends AxiomTestCase {
+    public TestCloseOnComplete(OMMetaFactory metaFactory) {
+        super(metaFactory);
+    }
+
+    protected void runTest() throws Throwable {
+        CloseTestDataSource ds = new CloseTestDataSource("<root><a/></root>");
+        OMSourcedElement element = metaFactory.getOMFactory().createOMElement(ds);
+        OMNode child = element.getFirstOMChild();
+        assertFalse(element.isComplete());
+        assertTrue(ds.hasUnclosedReaders());
+        child.getNextOMSibling();
+        assertTrue(element.isComplete());
+        assertFalse(ds.hasUnclosedReaders());
+    }
+}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
index 35f4f67..b6926c8 100644
--- a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
@@ -18,7 +18,6 @@
  */
 package org.apache.axiom.ts.om.xop;
 
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 
@@ -36,8 +35,12 @@
 import org.apache.axiom.ts.AxiomTestCase;
 
 public class TestSerialize extends AxiomTestCase {
-    public TestSerialize(OMMetaFactory metaFactory) {
+    private final boolean base64;
+    
+    public TestSerialize(OMMetaFactory metaFactory, boolean base64) {
         super(metaFactory);
+        this.base64 = base64;
+        addTestProperty("base64", String.valueOf(base64));
     }
 
     protected void runTest() throws Throwable {
@@ -47,14 +50,14 @@
         InputStream inStream = AbstractTestCase.getTestResource(testMessage.getName());
         Attachments attachments = new Attachments(inStream, testMessage.getContentType());
         
-        attachments.getRootPartInputStream();
-
-        String[] contentIDs = attachments.getAllContentIDs();
-        
         OMOutputFormat oof = new OMOutputFormat();
         oof.setDoOptimize(true);
         oof.setMimeBoundary(testMessage.getBoundary());
         oof.setRootContentId(testMessage.getStart());
+        if (base64) {
+            oof.setProperty(OMOutputFormat.USE_CTE_BASE64_FOR_NON_TEXTUAL_ATTACHMENTS, 
+                    Boolean.TRUE);
+        }
         
         // Write out the message
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -65,65 +68,15 @@
         OMElement om = builder.getDocumentElement();
         om.serialize(writer);
         om.close(false);
-        String outNormal = baos.toString();
+        String out = baos.toString();
         
-        assertTrue(outNormal.indexOf("base64") == -1);
-        
-        // Now do it again but use base64 content-type-encoding for 
-        // binary attachments
-        baos = new ByteArrayOutputStream();
-        oof.setProperty(OMOutputFormat.USE_CTE_BASE64_FOR_NON_TEXTUAL_ATTACHMENTS, 
-                        Boolean.TRUE);
-        writer = new MTOMXMLStreamWriter(baos, oof);
-        builder = 
-            OMXMLBuilderFactory.createOMBuilder(metaFactory.getOMFactory(), StAXParserConfiguration.DEFAULT, attachments);
-        om = builder.getDocumentElement();
-        om.serialize(writer);
-        om.close(false);
-        String outBase64 = baos.toString();
-        
-        
-        // Do a quick check to see if the data is base64 and is
-        // writing base64 compliant code.
-        assertTrue(outBase64.indexOf("base64") != -1);
-        assertTrue(outBase64.indexOf("GBgcGBQgHBwcJCQgKDBQNDAsL") != -1);
-        
-        // Now read the data back in
-        InputStream is = new ByteArrayInputStream(outBase64.getBytes());
-        Attachments attachments2 = new Attachments(is, testMessage.getContentType());
-        
-        // Now write it back out with binary...
-        baos = new ByteArrayOutputStream();
-        oof.setProperty(OMOutputFormat.USE_CTE_BASE64_FOR_NON_TEXTUAL_ATTACHMENTS, 
-                        Boolean.FALSE);
-        writer = new MTOMXMLStreamWriter(baos, oof);
-        builder = 
-            OMXMLBuilderFactory.createOMBuilder(metaFactory.getOMFactory(), StAXParserConfiguration.DEFAULT, attachments2);
-        om = builder.getDocumentElement();
-        om.serialize(writer);
-        om.close(false);
-        String outBase64ToNormal = baos.toString();
-        
-        assertTrue(outBase64ToNormal.indexOf("base64") == -1);
-        
-        // Now do it again but use base64 content-type-encoding for 
-        // binary attachments
-        is = new ByteArrayInputStream(outBase64.getBytes());
-        attachments2 = new Attachments(is, testMessage.getContentType());
-        baos = new ByteArrayOutputStream();
-        oof.setProperty(OMOutputFormat.USE_CTE_BASE64_FOR_NON_TEXTUAL_ATTACHMENTS, 
-                        Boolean.TRUE);
-        writer = new MTOMXMLStreamWriter(baos, oof);
-        builder = 
-            OMXMLBuilderFactory.createOMBuilder(metaFactory.getOMFactory(), StAXParserConfiguration.DEFAULT, attachments2);
-        om = builder.getDocumentElement();
-        om.serialize(writer);
-        om.close(false);
-        String outBase64ToBase64 = baos.toString();
-        
-        // Do a quick check to see if the data is base64 and is
-        // writing base64 compliant code.
-        assertTrue(outBase64ToBase64.indexOf("base64") != -1);
-        assertTrue(outBase64ToBase64.indexOf("GBgcGBQgHBwcJCQgKDBQNDAsL") != -1);
+        if (base64) {
+            // Do a quick check to see if the data is base64 and is
+            // writing base64 compliant code.
+            assertTrue(out.indexOf("base64") != -1);
+            assertTrue(out.indexOf("GBgcGBQgHBwcJCQgKDBQNDAsL") != -1);
+        } else {
+            assertTrue(out.indexOf("base64") == -1);
+        }
     }
 }
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/SOAPTestSuiteBuilder.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/SOAPTestSuiteBuilder.java
index 94b4c5e..8045e79 100644
--- a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/SOAPTestSuiteBuilder.java
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/SOAPTestSuiteBuilder.java
@@ -201,6 +201,8 @@
         addTest(new org.apache.axiom.ts.soap.message.TestCloneIncomplete(metaFactory, spec, false));
         addTest(new org.apache.axiom.ts.soap.message.TestGetCharsetEncodingWithParser(metaFactory, spec));
         addTest(new org.apache.axiom.ts.soap.message.TestGetOMFactoryWithParser(metaFactory, spec));
+        addTest(new org.apache.axiom.ts.soap.message.TestSetOMDocumentElement(metaFactory, spec));
+        addTest(new org.apache.axiom.ts.soap.message.TestSetOMDocumentElementNonSOAPEnvelope(metaFactory, spec));
         addTest(new org.apache.axiom.ts.soap.xpath.TestXPathAppliedToSOAPEnvelope(metaFactory, spec, true));
         addTest(new org.apache.axiom.ts.soap.xpath.TestXPathAppliedToSOAPEnvelope(metaFactory, spec, false));
     }
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElement.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElement.java
new file mode 100644
index 0000000..f341c69
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElement.java
@@ -0,0 +1,44 @@
+/*
+ * 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.soap.message;
+
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMMetaFactory;
+import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axiom.soap.SOAPMessage;
+import org.apache.axiom.ts.soap.SOAPSpec;
+import org.apache.axiom.ts.soap.SOAPTestCase;
+
+/**
+ * Tests the behavior of {@link OMDocument#setOMDocumentElement(OMElement)} when used to set a
+ * {@link SOAPEnvelope} as the root element of a {@link SOAPMessage}.
+ */
+public class TestSetOMDocumentElement extends SOAPTestCase {
+    public TestSetOMDocumentElement(OMMetaFactory metaFactory, SOAPSpec spec) {
+        super(metaFactory, spec);
+    }
+
+    protected void runTest() throws Throwable {
+        SOAPMessage message = soapFactory.createSOAPMessage();
+        OMElement envelope = soapFactory.getDefaultEnvelope();
+        message.setOMDocumentElement(envelope);
+        assertSame(envelope, message.getFirstOMChild());
+    }
+}
diff --git a/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElementNonSOAPEnvelope.java b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElementNonSOAPEnvelope.java
new file mode 100644
index 0000000..0b3155e
--- /dev/null
+++ b/modules/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap/message/TestSetOMDocumentElementNonSOAPEnvelope.java
@@ -0,0 +1,52 @@
+/*
+ * 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.soap.message;
+
+import javax.xml.namespace.QName;
+
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMException;
+import org.apache.axiom.om.OMMetaFactory;
+import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axiom.soap.SOAPMessage;
+import org.apache.axiom.ts.soap.SOAPSpec;
+import org.apache.axiom.ts.soap.SOAPTestCase;
+
+/**
+ * Tests the behavior of {@link OMDocument#setOMDocumentElement(OMElement)} when an attempt is made
+ * to set an {@link OMElement} that is not a {@link SOAPEnvelope} as the root element of a
+ * {@link SOAPMessage}. In this case, an exception should be thrown.
+ */
+public class TestSetOMDocumentElementNonSOAPEnvelope extends SOAPTestCase {
+    public TestSetOMDocumentElementNonSOAPEnvelope(OMMetaFactory metaFactory, SOAPSpec spec) {
+        super(metaFactory, spec);
+    }
+
+    protected void runTest() throws Throwable {
+        SOAPMessage message = soapFactory.createSOAPMessage();
+        OMElement element = soapFactory.createOMElement(new QName("test"));
+        try {
+            message.setOMDocumentElement(element);
+            fail("Expected OMException");
+        } catch (OMException ex) {
+            // Expected
+        }
+    }
+}
diff --git a/modules/axiom-testutils/src/main/resources/org/apache/axiom/testutils/conformance/many-attributes.xml b/modules/axiom-testutils/src/main/resources/org/apache/axiom/testutils/conformance/many-attributes.xml
new file mode 100644
index 0000000..5f645e5
--- /dev/null
+++ b/modules/axiom-testutils/src/main/resources/org/apache/axiom/testutils/conformance/many-attributes.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<root>
+    <element1 attr01="test"
+              attr02="test"
+              attr03="test"
+              attr04="test"
+              attr05="test"
+              attr06="test"
+              attr07="test"
+              attr08="test"
+              attr09="test"
+              attr10="test"
+              attr11="test"
+              attr12="test"
+              attr13="test"
+              attr14="test"
+              attr15="test"
+              attr16="test"
+              attr17="test"
+              attr18="test"
+              attr19="test"
+              attr20="test"
+              attr21="test"
+              attr22="test"
+              attr23="test"
+              attr24="test"
+              attr25="test"
+              attr26="test"
+              attr27="test"
+              attr28="test"
+              attr29="test"
+              attr30="test"
+              attr31="test"
+              attr32="test"/>
+    <element2 xmlns:ns01="urn:ns01"
+              xmlns:ns02="urn:ns02"
+              xmlns:ns03="urn:ns03"
+              xmlns:ns04="urn:ns04"
+              xmlns:ns05="urn:ns05"
+              xmlns:ns06="urn:ns06"
+              xmlns:ns07="urn:ns07"
+              xmlns:ns08="urn:ns08"
+              xmlns:ns09="urn:ns09"
+              xmlns:ns10="urn:ns10"
+              xmlns:ns11="urn:ns11"
+              xmlns:ns12="urn:ns12"
+              xmlns:ns13="urn:ns13"
+              xmlns:ns14="urn:ns14"
+              xmlns:ns15="urn:ns15"
+              xmlns:ns16="urn:ns16"
+              xmlns:ns17="urn:ns17"
+              xmlns:ns18="urn:ns18"
+              xmlns:ns19="urn:ns19"
+              xmlns:ns20="urn:ns20"
+              xmlns:ns21="urn:ns21"
+              xmlns:ns22="urn:ns22"
+              xmlns:ns23="urn:ns23"
+              xmlns:ns24="urn:ns24"
+              xmlns:ns25="urn:ns25"
+              xmlns:ns26="urn:ns26"
+              xmlns:ns27="urn:ns27"
+              xmlns:ns28="urn:ns28"
+              xmlns:ns29="urn:ns29"
+              xmlns:ns30="urn:ns30"
+              xmlns:ns31="urn:ns31"
+              xmlns:ns32="urn:ns32"/>
+</root>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index d0c6d4b..98f2dcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -379,7 +379,7 @@
                         <artifactId>stax-api</artifactId>
                     </exclusion>
                 </exclusions>
-        </dependency>
+            </dependency>
         </dependencies>
     </dependencyManagement>
     <properties>
@@ -423,6 +423,7 @@
                         <includes>
                             <include>**/*Test.java</include>
                         </includes>
+                        <argLine>${jacoco.surefireArgLine}</argLine>
                         <systemProperties>
                             <property>
                                 <name>java.io.tmpdir</name>
@@ -516,6 +517,10 @@
                         </goals>
                         <configuration>
                             <rules>
+                                <requireJavaVersion>
+                                    <!-- We require Java 6 for the build, but we enforce Java 5 compatibility using Animal Sniffer -->
+                                    <version>1.6.0</version>
+                                </requireJavaVersion>
                                 <requireNoRepositories>
                                     <message>The POM must not include repository definitions since non Apache repositories threaten the build stability.</message>
                                     <banRepositories>true</banRepositories>
@@ -560,11 +565,33 @@
                 <version>2.3.2</version>
                 <inherited>true</inherited>
                 <configuration>
-                    <source>1.3</source>
+                    <source>1.4</source>
                     <target>1.5</target>
                 </configuration>
             </plugin>
             <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>animal-sniffer-maven-plugin</artifactId>
+                <!-- Note: 1.9 contains a call to a Java 7 specific method (java.nio.CharBuffer.subSequence(II)Ljava/nio/CharBuffer;)
+                           that is triggered when an undefined reference is found. This breaks error reporting on Java 6. -->
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <configuration>
+                            <signature>
+                                <groupId>org.codehaus.mojo.signature</groupId>
+                                <artifactId>java15</artifactId>
+                                <version>1.0</version>
+                            </signature>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
                 <!-- This serves two purposes:
                       (1) we want to generate source JARs for all builds, not just release builds;
                       (2) we need (some of) the source JARs to generate the Javadoc in the apidocs module. -->
@@ -590,16 +617,20 @@
                 <version>${jacoco.version}</version>
                 <executions>
                     <execution>
+                        <id>prepare-agent-for-surefire</id>
                         <goals>
                             <goal>prepare-agent</goal>
                         </goals>
                         <configuration>
-                            <skip>${skipJacoco}</skip>
+                            <propertyName>jacoco.surefireArgLine</propertyName>
                             <!-- Anonymize the session ID (by default it contains the name of the host executing the build) -->
-                            <sessionId>mvn:${project.groupId}:${project.artifactId}:${project.version}</sessionId>
+                            <sessionId>mvn:${project.groupId}:${project.artifactId}:${project.version}:surefire</sessionId>
                         </configuration>
                     </execution>
                 </executions>
+                <configuration>
+                    <skip>${skipJacoco}</skip>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
@@ -712,10 +743,10 @@
         <module>modules/axiom-jaxb</module>
         <module>modules/axiom-c14n</module>
         <module>modules/axiom-tests</module>
-        <module>modules/axiom-osgi-tests</module>
         <module>modules/axiom-integration</module>
         <module>modules/axiom-all</module>
         <module>modules/axiom-samples</module>
+        <module>systests</module>
         <module>devguide</module>
         <module>userguide</module>
         <module>apidocs</module>
diff --git a/systests/jboss-tests/pom.xml b/systests/jboss-tests/pom.xml
new file mode 100644
index 0000000..18ed599
--- /dev/null
+++ b/systests/jboss-tests/pom.xml
@@ -0,0 +1,131 @@
+<?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>systests</artifactId>
+        <version>1.2.15-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>jboss-tests</artifactId>
+    <name>JBoss Tests</name>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>axiom-impl</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.arquillian.junit</groupId>
+            <artifactId>arquillian-junit-container</artifactId>
+            <version>1.0.3.Final</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.as</groupId>
+            <artifactId>jboss-as-arquillian-container-managed</artifactId>
+            <version>7.1.1.Final</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+                <filtering>true</filtering>
+            </testResource>
+        </testResources>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.5</source>
+                    <target>1.5</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <!-- Copy the dependencies that will be included in the WAR deployed
+                             to JBoss. This is necessary because Arquillian's Maven dependency
+                             resolution doesn't work correctly if some of the dependencies are
+                             snapshots from the current reactor. -->
+                        <id>copy-deps</id>
+                        <phase>generate-test-resources</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <includeArtifactIds>axiom-api,axiom-impl,woodstox-core-asl,stax2-api</includeArtifactIds>
+                            <outputDirectory>${project.build.directory}/deps</outputDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>unpack-jboss</id>
+                        <phase>process-test-classes</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.jboss.as</groupId>
+                                    <artifactId>jboss-as-dist</artifactId>
+                                    <version>7.1.1.Final</version>
+                                    <type>zip</type>
+                                    <overWrite>false</overWrite>
+                                    <outputDirectory>target</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>prepare-agent-for-jboss</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            <propertyName>jacoco.jbossArgLine</propertyName>
+                            <sessionId>mvn:${project.groupId}:${project.artifactId}:${project.version}:jboss</sessionId>
+                        </configuration>
+                    </execution>
+                </executions>
+                <configuration>
+                    <skip>${skipJacoco}</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/systests/jboss-tests/src/test/java/org/apache/axiom/systest/jboss/DialectTest.java b/systests/jboss-tests/src/test/java/org/apache/axiom/systest/jboss/DialectTest.java
new file mode 100644
index 0000000..42d9510
--- /dev/null
+++ b/systests/jboss-tests/src/test/java/org/apache/axiom/systest/jboss/DialectTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.systest.jboss;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.io.File;
+import java.io.StringReader;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+
+import org.apache.axiom.om.OMDocType;
+import org.apache.axiom.om.OMDocument;
+import org.apache.axiom.om.OMXMLBuilderFactory;
+import org.apache.axiom.util.stax.dialect.StAXDialectDetector;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(Arquillian.class)
+public class DialectTest {
+    @Deployment
+    public static WebArchive createDeployment() {
+        return ShrinkWrap.create(WebArchive.class, "dialect-test.war")
+                .addAsLibraries(new File("target/deps").listFiles());
+    }
+    
+    /**
+     * Directly tests {@link StAXDialectDetector}.
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testStAXDialectDetector() throws Exception {
+        assertFalse(StAXDialectDetector.getDialect(XMLInputFactory.newInstance()).getName().equals("Unknown"));
+        assertFalse(StAXDialectDetector.getDialect(XMLOutputFactory.newInstance()).getName().equals("Unknown"));
+    }
+    
+    /**
+     * Tests that Axiom is able to read a DOCTYPE declaration. Since accessing the information in
+     * the DOCTYPE declaration is not standardized by the StAX specification, this will fail if the
+     * StAX dialect is not detected correctly.
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testDTD() throws Exception {
+        OMDocument document = OMXMLBuilderFactory.createOMBuilder(new StringReader("<!DOCTYPE root><root/>")).getDocument();
+        OMDocType dtd = (OMDocType)document.getFirstOMChild();
+        assertEquals("root", dtd.getRootName());
+    }
+}
diff --git a/systests/jboss-tests/src/test/resources/arquillian.xml b/systests/jboss-tests/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..06bd581
--- /dev/null
+++ b/systests/jboss-tests/src/test/resources/arquillian.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+    <container qualifier="jbossas-managed" default="true">
+        <configuration>
+            <property name="jbossHome">${project.build.directory}/jboss-as-7.1.1.Final</property>
+            <property name="javaVmArguments">${jacoco.jbossArgLine}</property>
+        </configuration>
+    </container>
+</arquillian>
diff --git a/modules/axiom-osgi-tests/etc/logging.properties b/systests/osgi-tests/etc/logging.properties
similarity index 100%
rename from modules/axiom-osgi-tests/etc/logging.properties
rename to systests/osgi-tests/etc/logging.properties
diff --git a/modules/axiom-osgi-tests/pom.xml b/systests/osgi-tests/pom.xml
similarity index 86%
rename from modules/axiom-osgi-tests/pom.xml
rename to systests/osgi-tests/pom.xml
index 5e6e8c7..e818000 100644
--- a/modules/axiom-osgi-tests/pom.xml
+++ b/systests/osgi-tests/pom.xml
@@ -21,21 +21,13 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.ws.commons.axiom</groupId>
-        <artifactId>axiom</artifactId>
+        <artifactId>systests</artifactId>
         <version>1.2.15-SNAPSHOT</version>
-        <relativePath>../../pom.xml</relativePath>
+        <relativePath>../pom.xml</relativePath>
     </parent>
-    <artifactId>axiom-osgi-tests</artifactId>
+    <artifactId>osgi-tests</artifactId>
     <name>Axiom OSGi Tests</name>
     <packaging>jar</packaging>
-    <!-- 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-osgi-tests</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/webservices/commons/trunk/modules/axiom/modules/axiom-osgi-tests</developerConnection>
-        <url>http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-osgi-tests</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>org.apache.geronimo.specs</groupId>
@@ -194,13 +186,6 @@
                     </systemPropertyVariables>
                 </configuration>
             </plugin>
-            <plugin>
-                <artifactId>maven-site-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                    <skipDeploy>true</skipDeploy>
-                </configuration>
-            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/DummyBean.java b/systests/osgi-tests/src/test/java/org/apache/axiom/test/DummyBean.java
similarity index 100%
rename from modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/DummyBean.java
rename to systests/osgi-tests/src/test/java/org/apache/axiom/test/DummyBean.java
diff --git a/modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/JAXBTest.java b/systests/osgi-tests/src/test/java/org/apache/axiom/test/JAXBTest.java
similarity index 100%
rename from modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/JAXBTest.java
rename to systests/osgi-tests/src/test/java/org/apache/axiom/test/JAXBTest.java
diff --git a/modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/OMAbstractFactoryTest.java b/systests/osgi-tests/src/test/java/org/apache/axiom/test/OMAbstractFactoryTest.java
similarity index 100%
rename from modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/OMAbstractFactoryTest.java
rename to systests/osgi-tests/src/test/java/org/apache/axiom/test/OMAbstractFactoryTest.java
diff --git a/modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/ServiceTest.java b/systests/osgi-tests/src/test/java/org/apache/axiom/test/ServiceTest.java
similarity index 100%
rename from modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/ServiceTest.java
rename to systests/osgi-tests/src/test/java/org/apache/axiom/test/ServiceTest.java
diff --git a/modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/StAXOMBuilderTest.java b/systests/osgi-tests/src/test/java/org/apache/axiom/test/StAXOMBuilderTest.java
similarity index 100%
rename from modules/axiom-osgi-tests/src/test/java/org/apache/axiom/test/StAXOMBuilderTest.java
rename to systests/osgi-tests/src/test/java/org/apache/axiom/test/StAXOMBuilderTest.java
diff --git a/systests/pom.xml b/systests/pom.xml
new file mode 100644
index 0000000..0508fe0
--- /dev/null
+++ b/systests/pom.xml
@@ -0,0 +1,53 @@
+<?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>systests</artifactId>
+    <name>System Tests</name>
+    <packaging>pom</packaging>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-site-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <skipDeploy>true</skipDeploy>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <modules>
+        <module>jboss-tests</module>
+        <module>osgi-tests</module>
+        <module>spring-ws-tests</module>
+    </modules>
+</project>
diff --git a/systests/spring-ws-tests/pom.xml b/systests/spring-ws-tests/pom.xml
new file mode 100644
index 0000000..1e2732b
--- /dev/null
+++ b/systests/spring-ws-tests/pom.xml
@@ -0,0 +1,53 @@
+<?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>systests</artifactId>
+        <version>1.2.15-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>spring-ws-tests</artifactId>
+    <name>Spring WS Tests</name>
+    <description>
+        Tests interoperability with recent Spring Web Services releases.
+    </description>
+    <packaging>jar</packaging>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.ws</groupId>
+            <artifactId>spring-ws-core</artifactId>
+            <version>2.1.2.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>axiom-impl</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageFactoryTest.java b/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageFactoryTest.java
new file mode 100644
index 0000000..e56e984
--- /dev/null
+++ b/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageFactoryTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.systest.springws;
+
+import junit.framework.TestCase;
+
+import org.apache.axiom.soap.SOAPMessage;
+import org.springframework.ws.soap.axiom.AxiomSoapMessage;
+import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
+
+public class AxiomSoapMessageFactoryTest extends TestCase {
+    /**
+     * Regression test for <a href="https://issues.apache.org/jira/browse/AXIOM-444">AXIOM-444</a>.
+     * 
+     * @throws Exception
+     */
+    public void testCreateWebServiceMessage() throws Exception {
+        AxiomSoapMessageFactory mf = new AxiomSoapMessageFactory();
+        mf.afterPropertiesSet();
+        AxiomSoapMessage swsMessage = mf.createWebServiceMessage();
+        SOAPMessage message = swsMessage.getAxiomMessage();
+        // Spring-WS uses SOAPFactory#createSOAPMessage(OMXMLParserWrapper) with a null argument.
+        // We need to make sure that we nevertheless get a SOAPMessage that is in state complete.
+        assertTrue(message.isComplete());
+    }
+}
diff --git a/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageTest.java b/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageTest.java
new file mode 100644
index 0000000..f9e1c0f
--- /dev/null
+++ b/systests/spring-ws-tests/src/test/java/org/apache/axiom/systest/springws/AxiomSoapMessageTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.systest.springws;
+
+import java.util.Iterator;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.axiom.om.OMAbstractFactory;
+import org.apache.axiom.soap.SOAPFactory;
+import org.springframework.ws.soap.SoapHeaderElement;
+import org.springframework.ws.soap.axiom.AxiomSoapMessage;
+import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
+import org.w3c.dom.Document;
+
+public class AxiomSoapMessageTest extends TestCase {
+    /**
+     * Tests that {@link AxiomSoapMessage#setDocument(Document)} works correctly. There have been
+     * issues with that method because Spring-WS instantiates {@link SOAPFactory} implementations
+     * directly instead of using {@link OMAbstractFactory}.
+     * 
+     * @throws Exception
+     */
+    public void testSetDocument() throws Exception {
+        AxiomSoapMessageFactory mf = new AxiomSoapMessageFactory();
+        mf.afterPropertiesSet();
+        AxiomSoapMessage message = mf.createWebServiceMessage();
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setNamespaceAware(true);
+        Document document = dbf.newDocumentBuilder().parse(AxiomSoapMessageTest.class.getResource("soap-message.xml").toString());
+        message.setDocument(document);
+        Iterator it = message.getEnvelope().getHeader().examineAllHeaderElements();
+        assertTrue(it.hasNext());
+        SoapHeaderElement headerElement = (SoapHeaderElement)it.next();
+        assertEquals(new QName("urn:test", "myHeader"), headerElement.getName());
+    }
+}
diff --git a/systests/spring-ws-tests/src/test/resources/org/apache/axiom/systest/springws/soap-message.xml b/systests/spring-ws-tests/src/test/resources/org/apache/axiom/systest/springws/soap-message.xml
new file mode 100644
index 0000000..97d7a2f
--- /dev/null
+++ b/systests/spring-ws-tests/src/test/resources/org/apache/axiom/systest/springws/soap-message.xml
@@ -0,0 +1,9 @@
+<?xml version='1.0'?>
+<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
+    <env:Header>
+        <p:myHeader xmlns:p="urn:test">value</p:myHeader>
+    </env:Header>
+    <env:Body>
+        <p:echo xmlns:p="urn:test">hi!</p:echo>
+    </env:Body>
+</env:Envelope>
\ No newline at end of file