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 2009/08/09 23:51:33 UTC

svn commit: r802616 - in /webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax: AbstractXMLStreamWriter.java dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java dialect/StAXDialect.java

Author: veithen
Date: Sun Aug  9 21:51:33 2009
New Revision: 802616

URL: http://svn.apache.org/viewvc?rev=802616&view=rev
Log:
* Refactored NamespaceContextCorrectingXMLStreamWriterWrapper so that the namespace context handling logic can be reused to build other XMLStreamWriter implementations.
* Added a discussion about another ambiguity in the StAX specs to the documentation of StAXDialect.

Added:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java   (with props)
Modified:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialect.java

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java?rev=802616&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java Sun Aug  9 21:51:33 2009
@@ -0,0 +1,249 @@
+/*
+ * 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;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.axiom.util.namespace.ScopedNamespaceContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Partial implementation of the {@link XMLStreamWriter} interface. It handles namespace bindings,
+ * i.e. the methods related to the namespace context. Subclasses only need to implement write
+ * methods that take a prefix together with the namespace URI argument. All {@link XMLStreamWriter}
+ * methods that have a namespace URI argument, but no prefix argument are implemented by this class.
+ */
+public abstract class AbstractXMLStreamWriter implements XMLStreamWriter {
+    private static final Log log = LogFactory.getLog(AbstractXMLStreamWriter.class);
+    
+    private final ScopedNamespaceContext namespaceContext = new ScopedNamespaceContext();
+    private boolean inEmptyElement;
+
+    public final NamespaceContext getNamespaceContext() {
+        return namespaceContext;
+    }
+
+    public final void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
+        // TODO: not sure yet how to implement this method
+        throw new UnsupportedOperationException();
+    }
+
+    public final String getPrefix(String uri) throws XMLStreamException {
+        return namespaceContext.getPrefix(uri);
+    }
+
+    private void internalSetPrefix(String prefix, String uri) {
+        if (inEmptyElement) {
+            log.warn("The behavior of XMLStreamWriter#setPrefix and " +
+            		"XMLStreamWriter#setDefaultNamespace is undefined when invoked in the " +
+            		"context of an empty element");
+        }
+        namespaceContext.setPrefix(prefix, uri);
+    }
+    
+    public final void setDefaultNamespace(String uri) throws XMLStreamException {
+        internalSetPrefix("", uri);
+    }
+
+    public final void setPrefix(String prefix, String uri) throws XMLStreamException {
+        internalSetPrefix(prefix, uri);
+    }
+
+    public final void writeStartDocument() throws XMLStreamException {
+        doWriteStartDocument();
+    }
+    
+    protected abstract void doWriteStartDocument() throws XMLStreamException;
+
+    public final void writeStartDocument(String encoding, String version) throws XMLStreamException {
+        doWriteStartDocument(encoding, version);
+    }
+
+    protected abstract void doWriteStartDocument(String encoding, String version) throws XMLStreamException;
+
+    public final void writeStartDocument(String version) throws XMLStreamException {
+        doWriteStartDocument(version);
+    }
+
+    protected abstract void doWriteStartDocument(String version) throws XMLStreamException;
+    
+    public final void writeDTD(String dtd) throws XMLStreamException {
+        doWriteDTD(dtd);
+    }
+
+    protected abstract void doWriteDTD(String dtd) throws XMLStreamException;
+    
+    public final void writeEndDocument() throws XMLStreamException {
+        doWriteEndDocument();
+    }
+
+    protected abstract void doWriteEndDocument() throws XMLStreamException;
+    
+    private String internalGetPrefix(String namespaceURI) throws XMLStreamException {
+        String prefix = namespaceContext.getPrefix(namespaceURI);
+        if (prefix == null) {
+            throw new XMLStreamException("Unbound namespace URI '" + namespaceURI + "'");
+        } else {
+            return prefix;
+        }
+    }
+    
+    public final void writeStartElement(String prefix, String localName, String namespaceURI)
+            throws XMLStreamException {
+        doWriteStartElement(prefix, localName, namespaceURI);
+        namespaceContext.startScope();
+        inEmptyElement = false;
+    }
+
+    public final void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+        doWriteStartElement(internalGetPrefix(namespaceURI), namespaceURI, localName);
+        namespaceContext.startScope();
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteStartElement(String prefix, String localName, String namespaceURI)
+            throws XMLStreamException;
+
+    public final void writeStartElement(String localName) throws XMLStreamException {
+        doWriteStartElement(localName);
+        namespaceContext.startScope();
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteStartElement(String localName) throws XMLStreamException;
+
+    public final void writeEndElement() throws XMLStreamException {
+        doWriteEndElement();
+        namespaceContext.endScope();
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteEndElement() throws XMLStreamException;
+
+    public final void writeEmptyElement(String prefix, String localName, String namespaceURI)
+            throws XMLStreamException {
+        doWriteEmptyElement(prefix, localName, namespaceURI);
+        inEmptyElement = true;
+    }
+
+    public final void writeEmptyElement(String namespaceURI, String localName)
+            throws XMLStreamException {
+        doWriteEmptyElement(internalGetPrefix(namespaceURI), namespaceURI, localName);
+        inEmptyElement = true;
+    }
+
+    protected abstract void doWriteEmptyElement(String prefix, String localName, String namespaceURI)
+            throws XMLStreamException;
+
+    public final void writeEmptyElement(String localName) throws XMLStreamException {
+        doWriteEmptyElement(localName);
+        inEmptyElement = true;
+    }
+
+    protected abstract void doWriteEmptyElement(String localName) throws XMLStreamException;
+    
+    public final void writeAttribute(String prefix, String namespaceURI, String localName, String value)
+            throws XMLStreamException {
+        doWriteAttribute(prefix, namespaceURI, localName, value);
+    }
+
+    public final void writeAttribute(String namespaceURI, String localName, String value)
+            throws XMLStreamException {
+        doWriteAttribute(internalGetPrefix(namespaceURI), namespaceURI, localName, value);
+    }
+
+    protected abstract void doWriteAttribute(String prefix, String namespaceURI, String localName,
+            String value) throws XMLStreamException;
+
+    public final void writeAttribute(String localName, String value) throws XMLStreamException {
+        doWriteAttribute(localName, value);
+    }
+    
+    protected abstract void doWriteAttribute(String localName, String value)
+            throws XMLStreamException;
+
+    public final void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
+        doWriteNamespace(prefix, namespaceURI);
+    }
+    
+    protected abstract void doWriteNamespace(String prefix, String namespaceURI)
+            throws XMLStreamException;
+
+    public final void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
+        doWriteDefaultNamespace(namespaceURI);
+    }
+
+    protected abstract void doWriteDefaultNamespace(String namespaceURI) throws XMLStreamException;
+
+    public final void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
+        doWriteCharacters(text, start, len);
+        inEmptyElement = false;
+    }
+    
+    protected abstract void doWriteCharacters(char[] text, int start, int len)
+            throws XMLStreamException;
+
+    public final void writeCharacters(String text) throws XMLStreamException {
+        doWriteCharacters(text);
+        inEmptyElement = false;
+    }
+    
+    protected abstract void doWriteCharacters(String text) throws XMLStreamException;
+
+    public final void writeCData(String data) throws XMLStreamException {
+        doWriteCData(data);
+        inEmptyElement = false;
+    }
+    
+    protected abstract void doWriteCData(String data) throws XMLStreamException;
+
+    public final void writeComment(String data) throws XMLStreamException {
+        doWriteComment(data);
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteComment(String data) throws XMLStreamException;
+
+    public final void writeEntityRef(String name) throws XMLStreamException {
+        doWriteEntityRef(name);
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteEntityRef(String name) throws XMLStreamException;
+
+    public final void writeProcessingInstruction(String target, String data)
+            throws XMLStreamException {
+        doWriteProcessingInstruction(target, data);
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteProcessingInstruction(String target, String data)
+            throws XMLStreamException;
+
+    public final void writeProcessingInstruction(String target) throws XMLStreamException {
+        doWriteProcessingInstruction(target);
+        inEmptyElement = false;
+    }
+
+    protected abstract void doWriteProcessingInstruction(String target) throws XMLStreamException;
+}

Propchange: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/AbstractXMLStreamWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java?rev=802616&r1=802615&r2=802616&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/NamespaceContextCorrectingXMLStreamWriterWrapper.java Sun Aug  9 21:51:33 2009
@@ -23,8 +23,7 @@
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
-import org.apache.axiom.util.namespace.ScopedNamespaceContext;
-import org.apache.axiom.util.stax.wrapper.XMLStreamWriterWrapper;
+import org.apache.axiom.util.stax.AbstractXMLStreamWriter;
 
 /**
  * {@link XMLStreamWriter} wrapper that handles namespace bindings on behalf of the underlying
@@ -67,69 +66,110 @@
  * This implies that if the wrapper is used, these methods will never be called on the underlying
  * writer.
  */
-public class NamespaceContextCorrectingXMLStreamWriterWrapper extends XMLStreamWriterWrapper {
-    private final ScopedNamespaceContext namespaceContext = new ScopedNamespaceContext();
-
+public class NamespaceContextCorrectingXMLStreamWriterWrapper extends AbstractXMLStreamWriter {
+    private final XMLStreamWriter parent;
+    
     public NamespaceContextCorrectingXMLStreamWriterWrapper(XMLStreamWriter parent) {
-        super(parent);
+        this.parent = parent;
     }
 
-    public NamespaceContext getNamespaceContext() {
-        return namespaceContext;
+    protected void doWriteAttribute(String prefix, String namespaceURI, String localName,
+            String value) throws XMLStreamException {
+        parent.writeAttribute(prefix, namespaceURI, localName, value);
     }
 
-    public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
-        // TODO: not sure yet how to implement this method
-        throw new UnsupportedOperationException();
+    protected void doWriteAttribute(String localName, String value) throws XMLStreamException {
+        parent.writeAttribute(localName, value);
     }
 
-    public String getPrefix(String uri) throws XMLStreamException {
-        return namespaceContext.getPrefix(uri);
+    protected void doWriteCData(String data) throws XMLStreamException {
+        parent.writeCData(data);
     }
 
-    public void setDefaultNamespace(String uri) throws XMLStreamException {
-        namespaceContext.setPrefix("", uri);
+    protected void doWriteCharacters(char[] text, int start, int len) throws XMLStreamException {
+        parent.writeCharacters(text, start, len);
     }
 
-    public void setPrefix(String prefix, String uri) throws XMLStreamException {
-        namespaceContext.setPrefix(prefix, uri);
+    protected void doWriteCharacters(String text) throws XMLStreamException {
+        parent.writeCharacters(text);
     }
 
-    private String internalGetPrefix(String namespaceURI) throws XMLStreamException {
-        String prefix = namespaceContext.getPrefix(namespaceURI);
-        if (prefix == null) {
-            throw new XMLStreamException("Unbound namespace URI '" + namespaceURI + "'");
-        } else {
-            return prefix;
-        }
+    protected void doWriteComment(String data) throws XMLStreamException {
+        parent.writeComment(data);
     }
-    
-    public void writeStartElement(String prefix, String localName, String namespaceURI)
+
+    protected void doWriteDefaultNamespace(String namespaceURI) throws XMLStreamException {
+        parent.writeDefaultNamespace(namespaceURI);
+    }
+
+    protected void doWriteDTD(String dtd) throws XMLStreamException {
+        parent.writeDTD(dtd);
+    }
+
+    protected void doWriteEmptyElement(String prefix, String localName, String namespaceURI)
             throws XMLStreamException {
-        super.writeStartElement(prefix, localName, namespaceURI);
-        namespaceContext.startScope();
+        parent.writeEmptyElement(prefix, localName, namespaceURI);
     }
 
-    public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
-        super.writeStartElement(internalGetPrefix(namespaceURI), namespaceURI, localName);
+    protected void doWriteEmptyElement(String localName) throws XMLStreamException {
+        parent.writeEmptyElement(localName);
     }
 
-    public void writeStartElement(String localName) throws XMLStreamException {
-        super.writeStartElement(localName);
-        namespaceContext.startScope();
+    protected void doWriteEndDocument() throws XMLStreamException {
+        parent.writeEndDocument();
     }
 
-    public void writeEndElement() throws XMLStreamException {
-        super.writeEndElement();
-        namespaceContext.endScope();
+    protected void doWriteEndElement() throws XMLStreamException {
+        parent.writeEndElement();
     }
 
-    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
-        super.writeEmptyElement(internalGetPrefix(namespaceURI), namespaceURI, localName);
+    protected void doWriteEntityRef(String name) throws XMLStreamException {
+        parent.writeEntityRef(name);
     }
 
-    public void writeAttribute(String namespaceURI, String localName, String value)
+    protected void doWriteNamespace(String prefix, String namespaceURI) throws XMLStreamException {
+        parent.writeNamespace(prefix, namespaceURI);
+    }
+
+    protected void doWriteProcessingInstruction(String target, String data)
             throws XMLStreamException {
-        super.writeAttribute(internalGetPrefix(namespaceURI), namespaceURI, localName, value);
+        parent.writeProcessingInstruction(target, data);
+    }
+
+    protected void doWriteProcessingInstruction(String target) throws XMLStreamException {
+        parent.writeProcessingInstruction(target);
+    }
+
+    protected void doWriteStartDocument() throws XMLStreamException {
+        parent.writeStartDocument();
+    }
+
+    protected void doWriteStartDocument(String encoding, String version) throws XMLStreamException {
+        parent.writeStartDocument(encoding, version);
+    }
+
+    protected void doWriteStartDocument(String version) throws XMLStreamException {
+        parent.writeStartDocument(version);
+    }
+
+    protected void doWriteStartElement(String prefix, String localName, String namespaceURI)
+            throws XMLStreamException {
+        parent.writeStartElement(prefix, localName, namespaceURI);
+    }
+
+    protected void doWriteStartElement(String localName) throws XMLStreamException {
+        parent.writeStartElement(localName);
+    }
+
+    public void close() throws XMLStreamException {
+        parent.close();
+    }
+
+    public void flush() throws XMLStreamException {
+        parent.flush();
+    }
+
+    public Object getProperty(String name) throws IllegalArgumentException {
+        return parent.getProperty(name);
     }
 }

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialect.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialect.java?rev=802616&r1=802615&r2=802616&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialect.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/dialect/StAXDialect.java Sun Aug  9 21:51:33 2009
@@ -113,6 +113,36 @@
  *   <li>An XML document may contain a namespace declaration such as <tt>xmlns=""</tt>. In this
  *       case, it is not clear if {@link javax.xml.stream.XMLStreamReader#getNamespaceURI(int)}
  *       should return <code>null</code> or an empty string.</li>
+ *   <li>The documentation of {@link javax.xml.stream.XMLStreamWriter#setPrefix(String, String)}
+ *       and {@link javax.xml.stream.XMLStreamWriter#setDefaultNamespace(String)} requires that
+ *       the namespace "is bound in the scope of the current START_ELEMENT / END_ELEMENT pair".
+ *       The meaning of this requirement is clear in the context of an element written using
+ *       the <code>writeStartElement</code> and <code>writeEndElement</code> methods. On the
+ *       other hand, the requirement is ambiguous in the context of an element written using
+ *       <code>writeEmptyElement</code> and there are two competing interpretations:
+ *       <ol>
+ *         <li>Since the element is empty, it doesn't define a nested scope and the namespace
+ *             should be bound in the scope of the enclosing element.</li>
+ *         <li>An invocation of one of the <code>writeEmptyElement</code> methods actually
+ *             doesn't write a complete element because it can be followed by invocations
+ *             of <code>writeAttribute</code>, <code>writeNamespace</code> or
+ *             <code>writeDefaultNamespace</code>. The element is only completed by a
+ *             call to a <code>write</code> method other than the aforementioned methods.
+ *             An element written using <code>writeEmptyElement</code> therefore also
+ *             defines a scope and the namespace should be bound in that scope.</li>
+ *       </ol>
+ *       While the second interpretation seems to be more consistent, it would introduce another
+ *       ambiguity for the following sequence of calls: <code>writeEmptyElement</code>,
+ *       <code>writeAttribute</code>, <code>setPrefix</code>, <code>writeCharacters</code>.
+ *       In this case, it is not clear if the scope of the empty element should end at the call to
+ *       <code>writeAttribute</code> or <code>writeCharacters</code>.
+ *       <p>
+ *       Because of these ambiguities, the dialect implementations don't attempt to normalize the
+ *       behavior of {@link javax.xml.stream.XMLStreamWriter#setPrefix(String, String)}
+ *       and {@link javax.xml.stream.XMLStreamWriter#setDefaultNamespace(String)} in this particular
+ *       context, and their usage in conjunction with <code>writeEmptyElement</code> should be
+ *       avoided.
+ *       </li>
  * </ul>
  */
 public interface StAXDialect {