You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2008/12/22 16:12:06 UTC
svn commit: r728709 - in /webservices/commons/trunk/modules/axiom/modules:
axiom-api/src/main/java/org/apache/axiom/om/
axiom-api/src/main/java/org/apache/axiom/om/impl/builder/
axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ axiom-dom/src/main/j...
Author: veithen
Date: Mon Dec 22 07:12:06 2008
New Revision: 728709
URL: http://svn.apache.org/viewvc?rev=728709&view=rev
Log:
WSCOMMONS-423: Make sure that in DOOM, Text nodes never appear as children of Document (forbidden by DOM).
Added:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java (with props)
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java (with props)
Modified:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java
webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ParentNode.java
webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/factory/OMDOMFactory.java
webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/DocumentImplTest.java
Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java?rev=728709&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java Mon Dec 22 07:12:06 2008
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axiom.om;
+
+/**
+ * Thrown if an object model operation would lead to a hierarchy that is not allowed in the
+ * given object model implementation.
+ * <p>
+ * If this exception is encountered by a builder when creating an OM node from an event received
+ * by the parser and if the corresponding content can be ignored (i.e. is not semantically
+ * relevant), the builder should ignore the exception and skip the event. An example is whitespace
+ * appearing before or after the root element of a document. This would be represented as an
+ * {@link OMText} node below the {@link OMDocument}. If the OM implementation doesn't allow text
+ * nodes as children of a document (as for example in DOM), it should throw this exception so
+ * that the builder can discard the event.
+ */
+public class OMHierarchyException extends OMException {
+ private static final long serialVersionUID = 8391435427221729190L;
+
+ public OMHierarchyException(String message) {
+ super(message);
+ }
+}
Propchange: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMHierarchyException.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java?rev=728709&r1=728708&r2=728709&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXOMBuilder.java Mon Dec 22 07:12:06 2008
@@ -24,6 +24,7 @@
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMHierarchyException;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
@@ -163,86 +164,96 @@
*/
public int next() throws OMException {
try {
- if (done) {
- throw new OMException();
- }
- int token = parserNext();
- if (!cache) {
- return token;
- }
-
- // The current token should be the same as the
- // one just obtained. This bit of code is used to
- // detect invalid parser state.
- if (doTrace) {
- int currentParserToken = parser.getEventType();
- if (currentParserToken != token) {
-
-
- log.debug("WARNING: The current state of the parser is not equal to the " +
- "state just received from the parser. The current state in the paser is " +
- getStateString(currentParserToken) + " the state just received is " +
- getStateString(token));
-
- /*
- throw new OMException("The current token " + token +
- " does not match the current event " +
- "reported by the parser token. The parser did not update its state correctly. " +
- "The parser is " + parser);
- */
- }
- }
-
- // Now log the current state of the parser
- if (doTrace) {
- logParserState();
- }
-
- switch (token) {
- case XMLStreamConstants.START_ELEMENT:
- elementLevel++;
- lastNode = createNextOMElement();
- break;
- case XMLStreamConstants.START_DOCUMENT:
- // Document has already being created.
-
- document.setXMLVersion(parser.getVersion());
- document.setCharsetEncoding(parser.getEncoding());
- document.setStandalone(parser.isStandalone() ? "yes" : "no");
- break;
- case XMLStreamConstants.CHARACTERS:
- lastNode = createOMText(XMLStreamConstants.CHARACTERS);
- break;
- case XMLStreamConstants.CDATA:
- lastNode = createOMText(XMLStreamConstants.CDATA);
- break;
- case XMLStreamConstants.END_ELEMENT:
- endElement();
- elementLevel--;
- break;
- case XMLStreamConstants.END_DOCUMENT:
- done = true;
- ((OMContainerEx) this.document).setComplete(true);
- break;
- case XMLStreamConstants.SPACE:
- lastNode = createOMText(XMLStreamConstants.SPACE);
- break;
- case XMLStreamConstants.COMMENT:
- lastNode = createComment();
- break;
- case XMLStreamConstants.DTD:
- createDTD();
- break;
- case XMLStreamConstants.PROCESSING_INSTRUCTION:
- lastNode = createPI();
- break;
- case XMLStreamConstants.ENTITY_REFERENCE:
- lastNode = createOMText(XMLStreamConstants.ENTITY_REFERENCE);
- break;
- default :
+ // We need a loop here because we may decide to skip an event
+ while (true) {
+ if (done) {
throw new OMException();
+ }
+ int token = parserNext();
+ if (!cache) {
+ return token;
+ }
+
+ // The current token should be the same as the
+ // one just obtained. This bit of code is used to
+ // detect invalid parser state.
+ if (doTrace) {
+ int currentParserToken = parser.getEventType();
+ if (currentParserToken != token) {
+
+
+ log.debug("WARNING: The current state of the parser is not equal to the " +
+ "state just received from the parser. The current state in the paser is " +
+ getStateString(currentParserToken) + " the state just received is " +
+ getStateString(token));
+
+ /*
+ throw new OMException("The current token " + token +
+ " does not match the current event " +
+ "reported by the parser token. The parser did not update its state correctly. " +
+ "The parser is " + parser);
+ */
+ }
+ }
+
+ // Now log the current state of the parser
+ if (doTrace) {
+ logParserState();
+ }
+
+ switch (token) {
+ case XMLStreamConstants.START_ELEMENT:
+ elementLevel++;
+ lastNode = createNextOMElement();
+ break;
+ case XMLStreamConstants.START_DOCUMENT:
+ // Document has already being created.
+
+ document.setXMLVersion(parser.getVersion());
+ document.setCharsetEncoding(parser.getEncoding());
+ document.setStandalone(parser.isStandalone() ? "yes" : "no");
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ lastNode = createOMText(XMLStreamConstants.CHARACTERS);
+ break;
+ case XMLStreamConstants.CDATA:
+ lastNode = createOMText(XMLStreamConstants.CDATA);
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ endElement();
+ elementLevel--;
+ break;
+ case XMLStreamConstants.END_DOCUMENT:
+ done = true;
+ ((OMContainerEx) this.document).setComplete(true);
+ break;
+ case XMLStreamConstants.SPACE:
+ try {
+ lastNode = createOMText(XMLStreamConstants.SPACE);
+ } catch (OMHierarchyException ex) {
+ // The OM implementation doesn't allow text nodes at the current
+ // position in the tree. Since it is only whitespace, we can safely
+ // skip this event.
+ continue;
+ }
+ break;
+ case XMLStreamConstants.COMMENT:
+ lastNode = createComment();
+ break;
+ case XMLStreamConstants.DTD:
+ createDTD();
+ break;
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ lastNode = createPI();
+ break;
+ case XMLStreamConstants.ENTITY_REFERENCE:
+ lastNode = createOMText(XMLStreamConstants.ENTITY_REFERENCE);
+ break;
+ default :
+ throw new OMException();
+ }
+ return token;
}
- return token;
} catch (OMException e) {
throw e;
} catch (Exception e) {
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ParentNode.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ParentNode.java?rev=728709&r1=728708&r2=728709&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ParentNode.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/ParentNode.java Mon Dec 22 07:12:06 2008
@@ -218,19 +218,28 @@
}
if (this instanceof Document) {
- if (((DocumentImpl) this).documentElement != null
- && !(newDomChild instanceof CommentImpl)) {
- // Throw exception since there cannot be two document elements
- throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
- DOMMessageFormatter.formatMessage(
- DOMMessageFormatter.DOM_DOMAIN,
- "HIERARCHY_REQUEST_ERR", null));
- } else if (newDomChild instanceof ElementImpl) {
+ if (newDomChild instanceof ElementImpl) {
+ if (((DocumentImpl) this).documentElement != null) {
+ // Throw exception since there cannot be two document elements
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
+ DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "HIERARCHY_REQUEST_ERR", null));
+ }
if (newDomChild.parentNode == null) {
newDomChild.parentNode = this;
}
// set the document element
((DocumentImpl) this).documentElement = (ElementImpl) newDomChild;
+ } else if (!(newDomChild instanceof CommentImpl
+ || newDomChild instanceof DocumentFragmentImpl)) {
+ // TODO: we should also check for ProcessingInstruction and DocumentType,
+ // but since we don't have implementations yet, we can leave it
+ // like this for now
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
+ DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "HIERARCHY_REQUEST_ERR", null));
}
}
boolean compositeChild = newDomChild.nextSibling != null;
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/factory/OMDOMFactory.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/factory/OMDOMFactory.java?rev=728709&r1=728708&r2=728709&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/factory/OMDOMFactory.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/factory/OMDOMFactory.java Mon Dec 22 07:12:06 2008
@@ -30,6 +30,7 @@
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMHierarchyException;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMProcessingInstruction;
@@ -241,10 +242,12 @@
* @see org.apache.axiom.om.OMFactory#createOMText( org.apache.axiom.om.OMElement,String)
*/
public OMText createOMText(OMContainer parent, String text) {
- // A text node can also be added as the child of a Document node (at least if
- // it contains whitespace only). Therefore we can't assume that the parent is
- // an element and we need to use getDocumentFromParent instead.
- TextImpl txt = new TextImpl(getDocumentFromParent(parent), text, this);
+ if (parent instanceof DocumentImpl) {
+ throw new OMHierarchyException(
+ "DOM doesn't support text nodes as children of a document");
+ }
+ TextImpl txt = new TextImpl((DocumentImpl)((ElementImpl)parent).getOwnerDocument(),
+ text, this);
parent.addChild(txt);
return txt;
}
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/DocumentImplTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/DocumentImplTest.java?rev=728709&r1=728708&r2=728709&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/DocumentImplTest.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/DocumentImplTest.java Mon Dec 22 07:12:06 2008
@@ -23,6 +23,7 @@
import junit.framework.TestCase;
import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -101,4 +102,44 @@
}
});
}
+
+ public void testAllowedChildren() throws Exception {
+ DOMTestUtil.execute(new DOMTestUtil.Test() {
+ public void execute(DocumentBuilderFactory dbf) throws Exception {
+ Document doc = dbf.newDocumentBuilder().newDocument();
+
+ doc.appendChild(doc.createComment("some comment"));
+
+ // Document Object Model (DOM) Level 3 Core Specification, section 1.1.1
+ // says that text nodes are not allowed as children of a document.
+ try {
+ doc.appendChild(doc.createTextNode(" "));
+ fail("Expected DOMException");
+ } catch (DOMException ex) {
+ assertEquals(DOMException.HIERARCHY_REQUEST_ERR, ex.code);
+ }
+
+ doc.appendChild(doc.createElement("root1"));
+
+ // Multiple document elements are not allowed
+ try {
+ doc.appendChild(doc.createElement("root2"));
+ fail("Expected DOMException");
+ } catch (DOMException ex) {
+ assertEquals(DOMException.HIERARCHY_REQUEST_ERR, ex.code);
+ }
+
+ // A comment after the document element is allowed
+ doc.appendChild(doc.createComment("some comment"));
+
+ // Again, text nodes are not allowed
+ try {
+ doc.appendChild(doc.createTextNode(" "));
+ fail("Expected DOMException");
+ } catch (DOMException ex) {
+ assertEquals(DOMException.HIERARCHY_REQUEST_ERR, ex.code);
+ }
+ }
+ });
+ }
}
Added: webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java?rev=728709&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java Mon Dec 22 07:12:06 2008
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axiom.om.impl.dom.jaxp;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.axiom.om.impl.dom.DOMTestUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
+
+public class DocumentBuilderTest extends TestCase {
+ /**
+ * Test that whitespace around the document element is discarded.
+ * Indeed, DOM doesn't allow text nodes as children of a document and we
+ * need to check that the builder silently discards the corresponding
+ * events received from the parser.
+ *
+ * @throws Exception
+ */
+ public void testWhitespaceAroundDocumentElement() throws Exception {
+ DOMTestUtil.execute(new DOMTestUtil.Test() {
+ public void execute(DocumentBuilderFactory dbf) throws Exception {
+ Document doc = dbf.newDocumentBuilder().parse(new InputSource(new StringReader("<!-- --> <root/> ")));
+ Node child = doc.getFirstChild();
+ do {
+ assertFalse(child instanceof Text);
+ child = child.getNextSibling();
+ } while (child != null);
+ }
+ });
+ }
+}
Propchange: webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/dom/jaxp/DocumentBuilderTest.java
------------------------------------------------------------------------------
svn:eol-style = native