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/07/12 02:54:06 UTC

svn commit: r793253 [1/2] - in /webservices/commons/trunk/modules/axiom/modules/axiom-api: ./ src/main/java/org/apache/axiom/util/stax/xop/ src/test/java/org/apache/axiom/om/ src/test/java/org/apache/axiom/util/stax/xop/ src/test/resources/mtom/

Author: veithen
Date: Sun Jul 12 00:54:05 2009
New Revision: 793253

URL: http://svn.apache.org/viewvc?rev=793253&view=rev
Log:
Added XOP encoding/decoding XMLStreamReader wrappers that will be used to solve WSCOMMONS-485 and WSCOMMONS-488.

Added:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/ContentIDGenerator.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/MimePartProvider.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPConstants.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/package.html   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/OMAttachmentAccessorMimePartProvider.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReaderTest.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReaderTest.java   (with props)
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/resources/mtom/MTOMAttachmentStream_inlined.xml   (with props)
Modified:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/pom.xml
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/om/TestConstants.java

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/pom.xml
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/pom.xml?rev=793253&r1=793252&r2=793253&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/pom.xml (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/pom.xml Sun Jul 12 00:54:05 2009
@@ -183,6 +183,12 @@
                     <includes>
                         <include>**/*Test.java</include>
                     </includes>
+                    <systemProperties>
+                        <property>
+                            <name>java.awt.headless</name>
+                            <value>true</value>
+                        </property>
+                    </systemProperties>
                 </configuration>
             </plugin>
         </plugins>

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/ContentIDGenerator.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/ContentIDGenerator.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/ContentIDGenerator.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/ContentIDGenerator.java Sun Jul 12 00:54:05 2009
@@ -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.util.stax.xop;
+
+/**
+ * Content ID generator interface. Implementations of this interface are used by
+ * {@link XOPEncodingStreamReader} to generate content IDs for use in <tt>xop:Include</tt>
+ * elements.
+ */
+public interface ContentIDGenerator {
+    /**
+     * Generate a content ID.
+     * 
+     * @param existingContentID
+     *            An existing content ID for the {@link javax.activation.DataHandler} being
+     *            processed, as returned by
+     *            {@link org.apache.axiom.ext.stax.datahandler.DataHandlerReader#getContentID()},
+     *            or <code>null</code> if no existing content ID is known. The implementation is
+     *            free to use this information or not.
+     * @return the content ID; may not be <code>null</code>
+     */
+    String generateContentID(String existingContentID);
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/MimePartProvider.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/MimePartProvider.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/MimePartProvider.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/MimePartProvider.java Sun Jul 12 00:54:05 2009
@@ -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.util.stax.xop;
+
+import javax.activation.DataHandler;
+import javax.xml.stream.XMLStreamException;
+
+/**
+ * Interface used by {@link XOPDecodingStreamReader} to load MIME parts referenced by
+ * <tt>xop:Include</tt> elements.
+ */
+public interface MimePartProvider {
+    /**
+     * Get the {@link DataHandler} for the MIME part identified by a given content ID.
+     * 
+     * @param contentID the content ID
+     * @return the {@link DataHandler} for the MIME part identified by the content ID; may not
+     *         be <code>null</code>
+     * @throws XMLStreamException if the MIME part was not found or if an error occurred while
+     *         loading the part
+     */
+    DataHandler getMimePart(String contentID) throws XMLStreamException;
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPConstants.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPConstants.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPConstants.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPConstants.java Sun Jul 12 00:54:05 2009
@@ -0,0 +1,35 @@
+/*
+ * 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.xop;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Interface defining constants used by {@link XOPDecodingStreamReader} and
+ * {@link XOPEncodingStreamReader}.
+ * <p>
+ * For internal use only.
+ */
+interface XOPConstants {
+    String INCLUDE = "Include";
+    String NAMESPACE_URI = "http://www.w3.org/2004/08/xop/include";
+    String DEFAULT_PREFIX = "xop";
+    QName INCLUDE_QNAME = new QName(NAMESPACE_URI, INCLUDE, DEFAULT_PREFIX);
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java Sun Jul 12 00:54:05 2009
@@ -0,0 +1,538 @@
+/*
+ * 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.xop;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import javax.activation.DataHandler;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.ext.stax.datahandler.DataHandlerProvider;
+import org.apache.axiom.ext.stax.datahandler.DataHandlerReader;
+import org.apache.axiom.om.util.StAXUtils;
+import org.apache.axiom.om.util.TextHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * {@link XMLStreamReader} wrapper that decodes XOP. It uses the extension defined by
+ * {@link DataHandlerReader} to expose the {@link DataHandler} objects referenced by
+ * <tt>xop:Include</tt> elements encountered in the underlying stream. If the consumer uses
+ * {@link #getText()}, {@link #getTextCharacters()},
+ * {@link #getTextCharacters(int, char[], int, int)} or {@link #getElementText()} when an
+ * <tt>xop:Include</tt> element is present in the underlying stream, then the decoder will produce
+ * a base64 representation of the data.
+ * <p>
+ * Note that this class only implements infoset transformation, but doesn't handle MIME processing.
+ * A {@link MimePartProvider} implementation must be provided to the constructor of this class. This
+ * object will be used to load MIME parts referenced by <tt>xop:Include</tt> elements encountered
+ * in the underlying stream.
+ * <p>
+ * This class supports deferred loading of MIME parts: If the consumer uses
+ * {@link DataHandlerReader#getDataHandlerProvider()}, then the {@link MimePartProvider} will only
+ * be invoked when {@link DataHandlerProvider#getDataHandler()} is called.
+ */
+public class XOPDecodingStreamReader implements XMLStreamReader, DataHandlerReader {
+    private static final String SOLE_CHILD_MSG =
+            "Expected xop:Include as the sole child of an element information item (see section " +
+            "3.2 of http://www.w3.org/TR/xop10/)";
+    
+    private static class DataHandlerProviderImpl implements DataHandlerProvider {
+        private final MimePartProvider mimePartProvider;
+        private final String contentID;
+        
+        public DataHandlerProviderImpl(MimePartProvider mimePartProvider, String contentID) {
+            this.mimePartProvider = mimePartProvider;
+            this.contentID = contentID;
+        }
+
+        public String getContentID() {
+            return contentID;
+        }
+
+        public DataHandler getDataHandler() throws XMLStreamException {
+            return mimePartProvider.getMimePart(contentID);
+        }
+    }
+    
+    private static final Log log = LogFactory.getLog(XOPDecodingStreamReader.class);
+    
+    private final XMLStreamReader parent;
+    private final MimePartProvider mimePartProvider;
+    private DataHandlerProviderImpl dh;
+    private String base64;
+
+    /**
+     * Constructor.
+     * 
+     * @param parent
+     *            the XML stream to decode
+     * @param mimePartProvider
+     *            An implementation of the {@link MimePartProvider} interface that will be used to
+     *            load the {@link DataHandler} objects for MIME parts referenced by
+     *            <tt>xop:Include</tt> element information items encountered in the underlying
+     *            stream.
+     */
+    public XOPDecodingStreamReader(XMLStreamReader parent, MimePartProvider mimePartProvider) {
+        this.parent = parent;
+        this.mimePartProvider = mimePartProvider;
+    }
+
+    private void resetDataHandler() {
+        dh = null;
+        base64 = null;
+    }
+    
+    /**
+     * Process an <tt>xop:Include</tt> event and return the content ID.
+     * <p>
+     * Precondition: The parent reader is on the START_ELEMENT event for the <tt>xop:Include</tt>
+     * element. Note that the method doesn't check this condition.
+     * <p>
+     * Postcondition: The parent reader is on the event following the END_ELEMENT event for the
+     * <tt>xop:Include</tt> element, i.e. the parent reader is on the END_ELEMENT event of the
+     * element enclosing the <tt>xop:Include</tt> element.
+     * 
+     * @return the content ID the <tt>xop:Include</tt> refers to
+     * 
+     * @throws XMLStreamException
+     */
+    private String processXopInclude() throws XMLStreamException {
+        if (parent.getAttributeCount() != 1 ||
+                !parent.getAttributeLocalName(0).equals("href")) {
+            throw new XMLStreamException("Expected xop:Include element information item with " +
+                    "a (single) href attribute");
+        }
+        String href = parent.getAttributeValue(0);
+        if (!href.startsWith("cid:")) {
+            throw new XMLStreamException("Expected href attribute containing a URL in the " +
+                    "cid scheme");
+        }
+        String contentID;
+        try {
+            // URIs should always be decoded using UTF-8. On the other hand, since non ASCII
+            // characters are not allowed in content IDs, we can simply decode using ASCII
+            // (which is a subset of UTF-8)
+            contentID = URLDecoder.decode(href.substring(4), "ascii");
+        } catch (UnsupportedEncodingException ex) {
+            // We should never get here
+            throw new XMLStreamException(ex);
+        }
+        if (parent.next() != END_ELEMENT) {
+            throw new XMLStreamException(
+                    "Expected xop:Include element information item to be empty");
+        }
+        // Also consume the END_ELEMENT event of the xop:Include element. There are
+        // two reasons for this:
+        //  - It allows us to validate that the message conforms to the XOP specs.
+        //  - It makes it easier to implement the getNamespaceContext method.
+        if (parent.next() != END_ELEMENT) {
+            throw new XMLStreamException(SOLE_CHILD_MSG);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("Encountered xop:Include for content ID '" + contentID + "'");
+        }
+        return contentID;
+    }
+    
+    public int next() throws XMLStreamException {
+        boolean wasStartElement;
+        int event;
+        if (dh != null) {
+            resetDataHandler();
+            // We already advanced to the next event after the xop:Include (see below), so there
+            // is no call to parent.next() here
+            event = END_ELEMENT;
+            wasStartElement = false;
+        } else {
+            wasStartElement = parent.getEventType() == START_ELEMENT;
+            event = parent.next();
+        }
+        if (event == START_ELEMENT
+                && parent.getLocalName().equals(XOPConstants.INCLUDE)
+                && parent.getNamespaceURI().equals(XOPConstants.NAMESPACE_URI)) {
+            if (!wasStartElement) {
+                throw new XMLStreamException(SOLE_CHILD_MSG);
+            }
+            dh = new DataHandlerProviderImpl(mimePartProvider, processXopInclude());
+            return CHARACTERS;
+        } else {
+            return event;
+        }
+    }
+
+    public int getEventType() {
+        return dh == null ? parent.getEventType() : CHARACTERS;
+    }
+
+    public int nextTag() throws XMLStreamException {
+        if (dh != null) {
+            resetDataHandler();
+            // We already advanced to the next event after the xop:Include (see the implementation
+            // of the next() method) and we now that it is an END_ELEMENT event.
+            return END_ELEMENT;
+        } else {
+            return parent.nextTag();
+        }
+    }
+
+    public Object getProperty(String name) throws IllegalArgumentException {
+        if (DataHandlerReader.PROPERTY.equals(name)) {
+            return this;
+        } else {
+            return parent.getProperty(name);
+        }
+    }
+
+    public void close() throws XMLStreamException {
+        parent.close();
+    }
+
+    public int getAttributeCount() {
+        return parent.getAttributeCount();
+    }
+
+    public String getAttributeLocalName(int index) {
+        return parent.getAttributeLocalName(index);
+    }
+
+    public QName getAttributeName(int index) {
+        return parent.getAttributeName(index);
+    }
+
+    public String getAttributeNamespace(int index) {
+        return parent.getAttributeNamespace(index);
+    }
+
+    public String getAttributePrefix(int index) {
+        return parent.getAttributePrefix(index);
+    }
+
+    public String getAttributeType(int index) {
+        return parent.getAttributeType(index);
+    }
+
+    public String getAttributeValue(int index) {
+        return parent.getAttributeValue(index);
+    }
+
+    public boolean isAttributeSpecified(int index) {
+        return parent.isAttributeSpecified(index);
+    }
+
+    public String getAttributeValue(String namespaceURI, String localName) {
+        return parent.getAttributeValue(namespaceURI, localName);
+    }
+
+    public String getCharacterEncodingScheme() {
+        return parent.getCharacterEncodingScheme();
+    }
+
+    public String getElementText() throws XMLStreamException {
+        if (parent.getEventType() != START_ELEMENT) {
+            throw new XMLStreamException("The current event is not a START_ELEMENT event");
+        }
+        int event = parent.next();
+        // Note that an xop:Include must be the first child of the element
+        if (event == START_ELEMENT
+                && parent.getLocalName().equals(XOPConstants.INCLUDE)
+                && parent.getNamespaceURI().equals(XOPConstants.NAMESPACE_URI)) {
+            return toBase64(mimePartProvider.getMimePart(processXopInclude()));
+        } else {
+            String text = null;
+            StringBuffer buffer = null;
+            while (event != END_ELEMENT) {
+                switch (event) {
+                    case CHARACTERS:
+                    case CDATA:
+                    case SPACE:
+                    case ENTITY_REFERENCE:
+                        if (text == null && buffer == null) {
+                            text = parent.getText();
+                        } else {
+                            String thisText = parent.getText();
+                            if (buffer == null) {
+                                buffer = new StringBuffer(text.length() + thisText.length());
+                                buffer.append(text);
+                            }
+                            buffer.append(thisText);
+                        }
+                        break;
+                    case PROCESSING_INSTRUCTION:
+                    case COMMENT:
+                        // Skip this event
+                        break;
+                    default:
+                        throw new XMLStreamException("Unexpected event " +
+                                StAXUtils.getEventTypeString(event) +
+                                " while reading element text");
+                }
+                event = parent.next();
+            }
+            if (buffer != null) {
+                return buffer.toString();
+            } else if (text != null) {
+                return text;
+            } else {
+                return "";
+            }
+        }
+    }
+
+    public String getEncoding() {
+        return parent.getEncoding();
+    }
+
+    public String getPrefix() {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getPrefix();
+        }
+    }
+
+    public String getNamespaceURI() {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getNamespaceURI();
+        }
+    }
+
+    public String getLocalName() {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getLocalName();
+        }
+    }
+
+    public QName getName() {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getName();
+        }
+    }
+
+    public Location getLocation() {
+        return parent.getLocation();
+    }
+
+    // Attention!
+    public NamespaceContext getNamespaceContext() {
+        return parent.getNamespaceContext();
+    }
+
+    public String getNamespaceURI(String prefix) {
+        String uri = parent.getNamespaceURI(prefix);
+        if ("xop".equals(prefix) && uri != null) {
+            System.out.println(prefix + " -> " + uri);
+        }
+        return uri;
+    }
+
+    public int getNamespaceCount() {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getNamespaceCount();
+        }
+    }
+
+    public String getNamespacePrefix(int index) {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getNamespacePrefix(index);
+        }
+    }
+
+    public String getNamespaceURI(int index) {
+        if (dh != null) {
+            throw new IllegalStateException();
+        } else {
+            return parent.getNamespaceURI(index);
+        }
+    }
+
+    public String getPIData() {
+        return parent.getPIData();
+    }
+
+    public String getPITarget() {
+        return parent.getPITarget();
+    }
+
+    private static String toBase64(DataHandler dh) throws XMLStreamException {
+        try {
+            InputStream in = dh.getInputStream();
+            try {
+                // TODO: we should also move the base64 stuff to org.apache.axiom.util
+                return TextHelper.toString(in);
+            } finally {
+                in.close();
+            }
+        } catch (IOException ex) {
+            throw new XMLStreamException("Exception when encoding data handler as base64", ex);
+        }
+    }
+    
+    private String toBase64() throws XMLStreamException {
+        if (base64 == null) {
+            base64 = toBase64(dh.getDataHandler());
+        }
+        return base64;
+    }
+    
+    public String getText() {
+        if (dh != null) {
+            try {
+                return toBase64();
+            } catch (XMLStreamException ex) {
+                throw new RuntimeException(ex);
+            }
+        } else {
+            return parent.getText();
+        }
+    }
+
+    public char[] getTextCharacters() {
+        if (dh != null) {
+            try {
+                return toBase64().toCharArray();
+            } catch (XMLStreamException ex) {
+                throw new RuntimeException(ex);
+            }
+        } else {
+            return parent.getTextCharacters();
+        }
+    }
+
+    public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+            throws XMLStreamException {
+        if (dh != null) {
+            String text = toBase64();
+            int copied = Math.min(length, text.length()-sourceStart);
+            text.getChars(sourceStart, sourceStart + copied, target, targetStart);
+            return copied;
+        } else {
+            return parent.getTextCharacters(sourceStart, target, targetStart, length);
+        }
+    }
+
+    public int getTextLength() {
+        if (dh != null) {
+            try {
+                return toBase64().length();
+            } catch (XMLStreamException ex) {
+                throw new RuntimeException(ex);
+            }
+        } else {
+            return parent.getTextLength();
+        }
+    }
+
+    public int getTextStart() {
+        if (dh != null) {
+            return 0;
+        } else {
+            return parent.getTextStart();
+        }
+    }
+
+    public String getVersion() {
+        return parent.getVersion();
+    }
+
+    public boolean hasNext() throws XMLStreamException {
+        return parent.hasNext();
+    }
+
+    public boolean isStandalone() {
+        return parent.isStandalone();
+    }
+
+    public boolean standaloneSet() {
+        return parent.standaloneSet();
+    }
+
+    public boolean hasText() {
+        return dh != null || parent.hasText();
+    }
+
+    public boolean isCharacters() {
+        return dh != null || parent.isCharacters();
+    }
+
+    public boolean isStartElement() {
+        return dh == null && parent.isStartElement();
+    }
+
+    public boolean isEndElement() {
+        return dh == null && parent.isEndElement();
+    }
+
+    public boolean hasName() {
+        return dh == null && parent.hasName();
+    }
+
+    public boolean isWhiteSpace() {
+        return dh == null && parent.isWhiteSpace();
+    }
+
+    public void require(int type, String namespaceURI, String localName)
+            throws XMLStreamException {
+        if (dh != null) {
+            if (type != CHARACTERS) {
+                throw new XMLStreamException("Expected CHARACTERS event");
+            }
+        } else {
+            parent.require(type, namespaceURI, localName);
+        }
+    }
+
+    public boolean isBinary() {
+        return dh != null;
+    }
+
+    public boolean isDeferred() {
+        return true;
+    }
+    
+    public String getContentID() {
+        return dh.getContentID();
+    }
+
+    public DataHandler getDataHandler() throws XMLStreamException{
+        return dh.getDataHandler();
+    }
+
+    public DataHandlerProvider getDataHandlerProvider() {
+        return dh;
+    }
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java Sun Jul 12 00:54:05 2009
@@ -0,0 +1,536 @@
+/*
+ * 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.xop;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.activation.DataHandler;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.ext.stax.datahandler.DataHandlerProvider;
+import org.apache.axiom.ext.stax.datahandler.DataHandlerReader;
+
+/**
+ * {@link XMLStreamReader} wrapper that encodes XOP. It assumes that the underlying reader
+ * implements the extension defined by {@link DataHandlerReader} so that it can identify the
+ * information items to optimize (by looking for
+ * {@link javax.xml.stream.XMLStreamConstants#CHARACTERS} events for which
+ * {@link DataHandlerReader#isBinary()} returns <code>true</code>). The {@link DataHandler}
+ * objects for the parts referenced by <tt>xop:Include</tt> element information items produced by
+ * an instance of this class can be retrieved using the {@link #getDataHandler(String)} method.
+ * <p>
+ * Note that the primary purpose of this class is not to serialize an XML infoset to an XOP package
+ * (this is better done using a specialized {@link javax.xml.stream.XMLStreamWriter}
+ * implementation), but rather to optimize interaction (by exchanging {@link DataHandler} objects
+ * instead of base64 encoded representations) with databinding frameworks that understand XOP, but
+ * that are not aware of the {@link DataHandlerReader} extension.
+ * <p>
+ * This class defers loading of {@link DataHandler} objects until {@link #getDataHandler(String)} is
+ * called, except if this is not supported by the underlying stream.
+ */
+public class XOPEncodingStreamReader implements XMLStreamReader {
+    /**
+     * Wrapper that adds the XOP namespace to another namespace context.
+     */
+    private static class NamespaceContextWrapper implements NamespaceContext {
+        private static final List xopPrefixList = Arrays.asList(new String[] {
+                XOPConstants.DEFAULT_PREFIX });
+        
+        private final NamespaceContext parent;
+
+        public NamespaceContextWrapper(NamespaceContext parent) {
+            this.parent = parent;
+        }
+
+        public String getNamespaceURI(String prefix) {
+            return XOPConstants.DEFAULT_PREFIX.equals(prefix)
+                    ? XOPConstants.NAMESPACE_URI
+                    : parent.getNamespaceURI(prefix);
+        }
+
+        public String getPrefix(String namespaceURI) {
+            return XOPConstants.NAMESPACE_URI.equals(namespaceURI)
+                    ? XOPConstants.DEFAULT_PREFIX
+                    : parent.getPrefix(namespaceURI);
+        }
+
+        public Iterator getPrefixes(String namespaceURI) {
+            Iterator prefixes = parent.getPrefixes(namespaceURI);
+            if (XOPConstants.NAMESPACE_URI.equals(namespaceURI)) {
+                if (!prefixes.hasNext()) {
+                    return xopPrefixList.iterator();
+                } else {
+                    // This case is very unusual
+                    List prefixList = new ArrayList();
+                    do {
+                        prefixList.add(prefixes.next());
+                    } while (prefixes.hasNext());
+                    prefixList.add(XOPConstants.DEFAULT_PREFIX);
+                    return prefixList.iterator();
+                }
+            } else {
+                return prefixes;
+            }
+        }
+    }
+    
+    private static final int STATE_PASS_THROUGH = 0;
+    private static final int STATE_XOP_INCLUDE_START_ELEMENT = 1;
+    private static final int STATE_XOP_INCLUDE_END_ELEMENT = 2;
+    
+    private final XMLStreamReader parent;
+    private final ContentIDGenerator contentIDGenerator;
+    private final DataHandlerReader dataHandlerReader;
+    private int state = STATE_PASS_THROUGH;
+    private String currentContentID;
+    private Map dataHandlerObjects = new HashMap();
+
+    /**
+     * Constructor.
+     * 
+     * @param parent
+     *            The XML stream to encode. The reader must implement the extension defined by
+     *            {@link DataHandlerReader}.
+     * @param contentIDGenerator
+     *            used to generate content IDs for the binary content exposed as
+     *            <tt>xop:Include</tt> element information items
+     * 
+     * @throws IllegalArgumentException
+     *             if the provided {@link XMLStreamReader} doesn't implement the extension defined
+     *             by {@link DataHandlerReader}
+     */
+    public XOPEncodingStreamReader(XMLStreamReader parent, ContentIDGenerator contentIDGenerator) {
+        this.parent = parent;
+        this.contentIDGenerator = contentIDGenerator;
+        DataHandlerReader dataHandlerReader;
+        try {
+            dataHandlerReader = (DataHandlerReader)parent.getProperty(DataHandlerReader.PROPERTY);
+        } catch (IllegalArgumentException ex) {
+            dataHandlerReader = null;
+        }
+        if (dataHandlerReader == null) {
+            throw new IllegalArgumentException("The supplied XMLStreamReader doesn't implement the DataHandlerReader extension");
+        }
+        this.dataHandlerReader = dataHandlerReader;
+    }
+
+    /**
+     * Get the data handler for a given content ID.
+     * 
+     * @param contentID a content ID previously returned by an <tt>xop:Include</tt> element
+     *                  produced by this reader
+     * @return the corresponding data handler
+     * @throws XMLStreamException if an error occurred while loading the data handler
+     */
+    public DataHandler getDataHandler(String contentID) throws XMLStreamException {
+        Object dataHandlerObject = dataHandlerObjects.get(contentID);
+        if (dataHandlerObject instanceof DataHandler) {
+            return (DataHandler)dataHandlerObject;
+        } else {
+            return ((DataHandlerProvider)dataHandlerObject).getDataHandler();
+        }
+    }
+    
+    public int next() throws XMLStreamException {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                state = STATE_XOP_INCLUDE_END_ELEMENT;
+                return END_ELEMENT;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                state = STATE_PASS_THROUGH;
+                currentContentID = null;
+                // Fall through
+            default:
+                int event = parent.next();
+                if (event == CHARACTERS && dataHandlerReader.isBinary()) {
+                    String contentID = dataHandlerReader.getContentID();
+                    contentID = contentIDGenerator.generateContentID(contentID);
+                    Object dataHandlerObject = dataHandlerReader.isDeferred()
+                            ? (Object)dataHandlerReader.getDataHandlerProvider()
+                            : (Object)dataHandlerReader.getDataHandler();
+                    dataHandlerObjects.put(contentID, dataHandlerObject);
+                    currentContentID = contentID;
+                    state = STATE_XOP_INCLUDE_START_ELEMENT;
+                    return START_ELEMENT;
+                } else {
+                    return event;
+                }
+        }
+    }
+
+    public boolean hasNext() throws XMLStreamException {
+        return state == STATE_PASS_THROUGH ? parent.hasNext() : true;
+    }
+
+    public int nextTag() throws XMLStreamException {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                state = STATE_XOP_INCLUDE_END_ELEMENT;
+                return END_ELEMENT;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                currentContentID = null;
+                // Fall through
+            default:
+                return parent.nextTag();
+        }
+    }
+
+    public void require(int type, String namespaceURI, String localName) throws XMLStreamException {
+        if (state == STATE_PASS_THROUGH) {
+            parent.require(type, namespaceURI, localName);
+        } else {
+            if (state == STATE_XOP_INCLUDE_START_ELEMENT && type != START_ELEMENT
+                    || state == STATE_XOP_INCLUDE_END_ELEMENT && type != END_ELEMENT
+                    || namespaceURI != null && !namespaceURI.equals(XOPConstants.NAMESPACE_URI)
+                    || localName != null && !localName.equals(XOPConstants.INCLUDE)) {
+                throw new XMLStreamException();
+            }
+        }
+    }
+
+    public Location getLocation() {
+        return parent.getLocation();
+    }
+
+    public void close() throws XMLStreamException {
+        parent.close();
+    }
+
+    public Object getProperty(String name) throws IllegalArgumentException {
+        return parent.getProperty(name);
+    }
+
+    public String getEncoding() {
+        return parent.getEncoding();
+    }
+
+    public String getCharacterEncodingScheme() {
+        return parent.getCharacterEncodingScheme();
+    }
+
+    public String getVersion() {
+        return parent.getVersion();
+    }
+
+    public boolean isStandalone() {
+        return parent.isStandalone();
+    }
+
+    public boolean standaloneSet() {
+        return parent.standaloneSet();
+    }
+
+    public String getPIData() {
+        return parent.getPIData();
+    }
+
+    public String getPITarget() {
+        return parent.getPITarget();
+    }
+
+    public int getAttributeCount() {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                return 1;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeCount();
+        }
+    }
+
+    public String getAttributeLocalName(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return "href";
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeLocalName(index);
+        }
+    }
+
+    public QName getAttributeName(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return new QName("href");
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeName(index);
+        }
+    }
+
+    public String getAttributeNamespace(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return null;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeNamespace(index);
+        }
+    }
+
+    public String getAttributePrefix(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return null;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributePrefix(index);
+        }
+    }
+
+    public String getAttributeType(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return "CDATA";
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeType(index);
+        }
+    }
+
+    public String getAttributeValue(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                // We don't use full URL encoding here, because this might cause
+                // interoperability issues. The specs (RFC 2111 and 2392) are not very clear
+                // on which characters should be URL encoded, but one can consider that '%'
+                // is the only really unsafe character.
+                return "cid:" + currentContentID.replaceAll("%", "%25");
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeValue(index);
+        }
+    }
+
+    public boolean isAttributeSpecified(int index) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (index != 0) {
+                    throw new IllegalArgumentException();
+                }
+                return true;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.isAttributeSpecified(index);
+        }
+    }
+
+    public String getAttributeValue(String namespaceURI, String localName) {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                if (namespaceURI == null && localName.equals("href")) {
+                    return "cid:" + currentContentID;
+                } else {
+                    return null;
+                }
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getAttributeValue(namespaceURI, localName);
+        }
+    }
+
+    public String getElementText() throws XMLStreamException {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                state = STATE_XOP_INCLUDE_END_ELEMENT;
+                return "";
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                throw new IllegalStateException();
+            default:
+                return parent.getElementText();
+        }
+    }
+
+    public int getEventType() {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT:
+                return START_ELEMENT;
+            case STATE_XOP_INCLUDE_END_ELEMENT:
+                return END_ELEMENT;
+            default:
+                return parent.getEventType();
+        }
+    }
+
+    public String getNamespaceURI() {
+        return state == STATE_PASS_THROUGH ? parent.getNamespaceURI() : XOPConstants.NAMESPACE_URI;
+    }
+
+    public String getLocalName() {
+        return state == STATE_PASS_THROUGH ? parent.getLocalName() : XOPConstants.INCLUDE;
+    }
+
+    public String getPrefix() {
+        return state == STATE_PASS_THROUGH ? parent.getPrefix() : XOPConstants.DEFAULT_PREFIX;
+    }
+
+    public QName getName() {
+        return state == STATE_PASS_THROUGH ? parent.getName() : XOPConstants.INCLUDE_QNAME;
+    }
+
+    public NamespaceContext getNamespaceContext() {
+        NamespaceContext ctx = parent.getNamespaceContext();
+        if (state != STATE_PASS_THROUGH) {
+            ctx = new NamespaceContextWrapper(ctx);
+        }
+        return ctx;
+    }
+
+    public String getNamespaceURI(String prefix) {
+        if (state != STATE_PASS_THROUGH && XOPConstants.DEFAULT_PREFIX.equals(prefix)) {
+            return XOPConstants.NAMESPACE_URI;
+        } else {
+            return parent.getNamespaceURI(prefix);
+        }
+    }
+
+    public int getNamespaceCount() {
+        return state == STATE_PASS_THROUGH ? parent.getNamespaceCount() : 1;
+    }
+
+    public String getNamespacePrefix(int index) {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getNamespacePrefix(index);
+        } else if (index != 0) {
+            throw new IllegalArgumentException();
+        } else {
+            return XOPConstants.DEFAULT_PREFIX;
+        }
+    }
+    
+    public String getNamespaceURI(int index) {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getNamespaceURI(index);
+        } else if (index != 0) {
+            throw new IllegalArgumentException();
+        } else {
+            return XOPConstants.NAMESPACE_URI;
+        }
+    }
+
+    public String getText() {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getText();
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public int getTextStart() {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getTextStart();
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public int getTextLength() {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getTextLength();
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public char[] getTextCharacters() {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getTextCharacters();
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+            throws XMLStreamException {
+        if (state == STATE_PASS_THROUGH) {
+            return parent.getTextCharacters(sourceStart, target, targetStart, length);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public boolean hasName() {
+        return state == STATE_PASS_THROUGH ? parent.hasName() : true;
+    }
+
+    public boolean hasText() {
+        return state == STATE_PASS_THROUGH ? parent.hasText() : false;
+    }
+
+    public boolean isCharacters() {
+        return state == STATE_PASS_THROUGH ? parent.isCharacters() : false;
+    }
+
+    public boolean isWhiteSpace() {
+        return state == STATE_PASS_THROUGH ? parent.isWhiteSpace() : false;
+    }
+
+    public boolean isStartElement() {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT: return true;
+            case STATE_XOP_INCLUDE_END_ELEMENT: return false;
+            default: return parent.isStartElement();
+        }
+    }
+
+    public boolean isEndElement() {
+        switch (state) {
+            case STATE_XOP_INCLUDE_START_ELEMENT: return false;
+            case STATE_XOP_INCLUDE_END_ELEMENT: return true;
+            default: return parent.isEndElement();
+        }
+    }
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/package.html
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/package.html?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/package.html (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/package.html Sun Jul 12 00:54:05 2009
@@ -0,0 +1,5 @@
+<html>
+<body>
+Contains classes to encode and decode XOP infosets.
+</body>
+</html>
\ No newline at end of file

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

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/om/TestConstants.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/om/TestConstants.java?rev=793253&r1=793252&r2=793253&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/om/TestConstants.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/om/TestConstants.java Sun Jul 12 00:54:05 2009
@@ -46,6 +46,7 @@
                         "start-info=\"application/soap+xml\"; " +
                         "charset=UTF-8;" +
                         "action=\"mtomSample\"";
+    public static final String MTOM_MESSAGE_INLINED = "mtom/MTOMAttachmentStream_inlined.xml";
     
     
     private TestConstants() {

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/OMAttachmentAccessorMimePartProvider.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/OMAttachmentAccessorMimePartProvider.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/OMAttachmentAccessorMimePartProvider.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/OMAttachmentAccessorMimePartProvider.java Sun Jul 12 00:54:05 2009
@@ -0,0 +1,45 @@
+/*
+ * 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.xop;
+
+import javax.activation.DataHandler;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.axiom.om.OMAttachmentAccessor;
+
+/**
+ * Adapts an {@link OMAttachmentAccessor} instance to the {@link MimePartProvider} interface.
+ */
+public class OMAttachmentAccessorMimePartProvider implements MimePartProvider {
+    private final OMAttachmentAccessor attachments;
+
+    public OMAttachmentAccessorMimePartProvider(OMAttachmentAccessor attachments) {
+        this.attachments = attachments;
+    }
+
+    public DataHandler getMimePart(String contentID) throws XMLStreamException {
+        DataHandler dh = attachments.getDataHandler(contentID);
+        if (dh == null) {
+            throw new XMLStreamException("No attachment found for content ID '" + contentID + "'");
+        } else {
+            return dh;
+        }
+    }
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReaderTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReaderTest.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReaderTest.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReaderTest.java Sun Jul 12 00:54:05 2009
@@ -0,0 +1,63 @@
+/*
+ * 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.xop;
+
+import java.io.ByteArrayInputStream;
+
+import javax.imageio.ImageIO;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.attachments.Attachments;
+import org.apache.axiom.om.AbstractTestCase;
+import org.apache.axiom.om.TestConstants;
+import org.apache.axiom.om.util.Base64;
+import org.apache.axiom.om.util.StAXUtils;
+import org.apache.axiom.util.stax.XMLStreamReaderComparator;
+
+public class XOPDecodingStreamReaderTest extends AbstractTestCase {
+    private XMLStreamReader getXOPDecodingStreamReader() throws Exception {
+        Attachments attachments = new Attachments(getTestResource(TestConstants.MTOM_MESSAGE),
+                TestConstants.MTOM_MESSAGE_CONTENT_TYPE);
+        return new XOPDecodingStreamReader(
+                StAXUtils.createXMLStreamReader(attachments.getSOAPPartInputStream()),
+                new OMAttachmentAccessorMimePartProvider(attachments));
+    }
+    
+    public void testCompareToInlined() throws Exception {
+        XMLStreamReader expected = StAXUtils.createXMLStreamReader(
+                getTestResource(TestConstants.MTOM_MESSAGE_INLINED));
+        XMLStreamReader actual = getXOPDecodingStreamReader();
+        XMLStreamReaderComparator comparator = new XMLStreamReaderComparator(expected, actual);
+        comparator.addPrefix("xop");
+        comparator.compare();
+    }
+    
+    public void testGetElementText() throws Exception {
+        XMLStreamReader reader = getXOPDecodingStreamReader();
+        while (!reader.isStartElement() || !reader.getLocalName().equals("image1")) {
+            reader.next();
+        }
+        String base64 = reader.getElementText();
+        byte[] data = Base64.decode(base64);
+        // The data is actually a JPEG image. Try to decode it to check that the data is not
+        // corrupted.
+        ImageIO.read(new ByteArrayInputStream(data));
+    }
+}

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

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReaderTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReaderTest.java?rev=793253&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReaderTest.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReaderTest.java Sun Jul 12 00:54:05 2009
@@ -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.util.stax.xop;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.axiom.attachments.Attachments;
+import org.apache.axiom.om.AbstractTestCase;
+import org.apache.axiom.om.TestConstants;
+import org.apache.axiom.om.util.StAXUtils;
+import org.apache.axiom.util.stax.XMLStreamReaderComparator;
+import org.apache.axiom.util.stax.xop.ContentIDGenerator;
+import org.apache.axiom.util.stax.xop.XOPDecodingStreamReader;
+import org.apache.axiom.util.stax.xop.XOPEncodingStreamReader;
+
+public class XOPEncodingStreamReaderTest extends AbstractTestCase {
+    private static ContentIDGenerator contentIDGenerator = new ContentIDGenerator() {
+        public String generateContentID(String existingContentID) {
+            if (existingContentID == null) {
+                fail();
+            }
+            return existingContentID;
+        }
+    };
+    
+    public void test() throws Exception {
+        Attachments[] attachments = new Attachments[2];
+        XMLStreamReader[] soapPartReader = new XMLStreamReader[2];
+        for (int i=0; i<2; i++) {
+            attachments[i] = new Attachments(getTestResource(TestConstants.MTOM_MESSAGE),
+                    TestConstants.MTOM_MESSAGE_CONTENT_TYPE);
+            soapPartReader[i] = StAXUtils.createXMLStreamReader(attachments[i].getSOAPPartInputStream());
+        }
+        XMLStreamReader actual = new XOPEncodingStreamReader(new XOPDecodingStreamReader(soapPartReader[1], new OMAttachmentAccessorMimePartProvider(attachments[1])), contentIDGenerator);
+        new XMLStreamReaderComparator(soapPartReader[0], actual).compare();
+    }
+
+}

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