Author: scheu Date: Tue May 13 05:56:37 2008 New Revision: 655845 URL: http://svn.apache.org/viewvc?rev=655845&view=rev Log: WSCOMMONS-344 Contributor:Rich Scheuerle Discovered By: Huiran Wang The OMStAXWrapper code is upgraded to support the delivery of MTOM attachments as XOP:Include elements. See the discussion in the JIRA
Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMXMLStreamReader.java Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/soap/impl/builder/MTOMStAXSOAPModelBuilder.java webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DOMStAXWrapper.java webservices/commons/trunk/modules/axiom/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMStAXWrapper.java webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMXMLStreamReader.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMXMLStreamReader.java?rev=655845&view=auto ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMXMLStreamReader.java (added) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/OMXMLStreamReader.java Tue May 13 05:56:37 2008 @@ -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.om; + +import javax.xml.stream.XMLStreamReader; + +/** + * Objects returned by OMElement.getXMLStreamReader may implement this interface + */ +/** + * @author scheu + * + */ +public interface OMXMLStreamReader extends XMLStreamReader, OMAttachmentAccessor { + + /** + * By default, an OMText item that has an MTOM datahandler + * will be rendered as a inlined text event. + * @return true if inlined as TEXT, false if XOP_INCLUDE is used + */ + public boolean isInlineMTOM(); + + /** + * @param value set to true if inlining of text is desired (default) + * throw OMException if not the value is not supported. + */ + public void setInlineMTOM(boolean value); + +} Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/soap/impl/builder/MTOMStAXSOAPModelBuilder.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/soap/impl/builder/MTOMStAXSOAPModelBuilder.java?rev=655845&r1=655844&r2=655845&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/soap/impl/builder/MTOMStAXSOAPModelBuilder.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/soap/impl/builder/MTOMStAXSOAPModelBuilder.java Tue May 13 05:56:37 2008 @@ -101,11 +101,15 @@ */ public DataHandler getDataHandler(String blobContentID) throws OMException { DataHandler dataHandler = attachments.getDataHandler(blobContentID); + /* The getDataHandler javadoc indicates that null indicate that the datahandler + * was not found + * if (dataHandler == null) { throw new OMException( "Referenced Attachment not found in the MIME Message. ContentID:" + blobContentID); } + */ return dataHandler; } } Modified: webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DOMStAXWrapper.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DOMStAXWrapper.java?rev=655845&r1=655844&r2=655845&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DOMStAXWrapper.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-dom/src/main/java/org/apache/axiom/om/impl/dom/DOMStAXWrapper.java Tue May 13 05:56:37 2008 @@ -19,20 +19,24 @@ package org.apache.axiom.om.impl.dom; +import org.apache.axiom.om.OMAttachmentAccessor; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMComment; import org.apache.axiom.om.OMConstants; import org.apache.axiom.om.OMDocument; import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.OMException; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.OMNode; import org.apache.axiom.om.OMText; import org.apache.axiom.om.OMXMLParserWrapper; +import org.apache.axiom.om.OMXMLStreamReader; import org.apache.axiom.om.impl.EmptyOMLocation; import org.apache.axiom.om.impl.builder.StAXBuilder; import org.apache.axiom.om.impl.exception.OMStreamingException; import org.w3c.dom.Attr; +import javax.activation.DataHandler; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; @@ -49,7 +53,7 @@ * Note - This class also implements the streaming constants interface to get access to the StAX * constants. */ -public class DOMStAXWrapper implements XMLStreamReader, XMLStreamConstants { +public class DOMStAXWrapper implements OMXMLStreamReader, XMLStreamConstants { /** Field navigator */ private DOMNavigator navigator; @@ -117,6 +121,13 @@ private OMNode lastNode = null; private boolean needToThrowEndDocument = false; + + /** + * If true then TEXT events are constructed for the MTOM attachment + * If false, an <xop:Include href="cid:xxxxx"/> event is constructed and + * the consumer must call getDataHandler(cid) to access the datahandler. + */ + private boolean inlineMTOM = true; /** * Method setAllowSwitching. @@ -266,7 +277,8 @@ * @see javax.xml.stream.XMLStreamReader#hasText() */ public boolean hasText() { - return ((currentEvent == CHARACTERS) || (currentEvent == DTD) + return ((currentEvent == CHARACTERS) || (currentEvent == DTD) + || (currentEvent == CDATA) || (currentEvent == ENTITY_REFERENCE) || (currentEvent == COMMENT) || (currentEvent == SPACE)); } @@ -1208,4 +1220,24 @@ public void setParser(XMLStreamReader parser) { this.parser = parser; } + + public DataHandler getDataHandler(String blobcid) { + DataHandler dh = null; + if (builder != null && + builder instanceof OMAttachmentAccessor) { + dh = ((OMAttachmentAccessor) builder).getDataHandler(blobcid); + } + return dh; + } + + public boolean isInlineMTOM() { + return inlineMTOM; + + } + + public void setInlineMTOM(boolean value) { + if (value == true) { + throw new OMException("setInlineMTOM(true) is not supported"); + } + } } Modified: webservices/commons/trunk/modules/axiom/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMStAXWrapper.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMStAXWrapper.java?rev=655845&r1=655844&r2=655845&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMStAXWrapper.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-impl/src/main/java/org/apache/axiom/om/impl/llom/OMStAXWrapper.java Tue May 13 05:56:37 2008 @@ -45,6 +45,7 @@ import org.apache.axiom.om.OMSourcedElement; import org.apache.axiom.om.OMText; import org.apache.axiom.om.OMXMLParserWrapper; +import org.apache.axiom.om.OMXMLStreamReader; import org.apache.axiom.om.impl.EmptyOMLocation; import org.apache.axiom.om.impl.builder.StAXBuilder; import org.apache.axiom.om.impl.exception.OMStreamingException; @@ -57,7 +58,7 @@ * constants */ public class OMStAXWrapper - implements XMLStreamReader, XMLStreamConstants, OMAttachmentAccessor { + implements OMXMLStreamReader, XMLStreamConstants { private static final Log log = LogFactory.getLog(OMStAXWrapper.class); private static boolean DEBUG_ENABLED = log.isDebugEnabled(); @@ -91,6 +92,14 @@ private static final short COMPLETED = 2; private static final short SWITCHED = 3; private static final short DOCUMENT_COMPLETE = 4; + + + // Variables used to build an xop:include representation + private final static QName XOP_INCLUDE = + new QName("http://www.w3.org/2004/08/xop/include", "Include", "xop"); + private OMElement xopInclude = null; + private OMText xopIncludeText = null; + private boolean xopIncludeStart = false; /** Field state */ @@ -113,7 +122,7 @@ boolean namespaceURIInterning = false; /** Field elementStack */ - private Stack elementStack = null; + private Stack nodeStack = null; // keeps the next event. The parser actually keeps one step ahead to // detect the end of navigation. (at the end of the stream the navigator @@ -137,6 +146,13 @@ private boolean needToThrowEndDocument = false; + /** + * If true then TEXT events are constructed for the MTOM attachment + * If false, an <xop:Include href="cid:xxxxx"/> event is constructed and + * the consumer must call getDataHandler(cid) to access the datahandler. + */ + private boolean inlineMTOM = true; + /** * Method setAllowSwitching. * @@ -239,7 +255,7 @@ } else { if ((currentEvent == START_ELEMENT) || (currentEvent == END_ELEMENT)) { - OMNamespace ns = ((OMElement) lastNode).getNamespace(); + OMNamespace ns = ((OMElement) getNode()).getNamespace(); returnStr = (ns == null) ? null : ns.getPrefix(); @@ -260,7 +276,7 @@ if ((currentEvent == START_ELEMENT) || (currentEvent == END_ELEMENT) || (currentEvent == NAMESPACE)) { - OMNamespace ns = ((OMElement) lastNode).getNamespace(); + OMNamespace ns = ((OMElement) getNode()).getNamespace(); returnStr = (ns == null) ? null : ns.getNamespaceURI(); @@ -303,7 +319,7 @@ if ((currentEvent == START_ELEMENT) || (currentEvent == END_ELEMENT) || (currentEvent == ENTITY_REFERENCE)) { - returnStr = ((OMElement) lastNode).getLocalName(); + returnStr = ((OMElement) getNode()).getLocalName(); } } return returnStr; @@ -320,7 +336,7 @@ } else { if ((currentEvent == START_ELEMENT) || (currentEvent == END_ELEMENT)) { - returnName = getQName((OMElement) lastNode); + returnName = getQName((OMElement) getNode()); } } return returnName; @@ -346,7 +362,7 @@ if (parser != null) { returnLength = parser.getTextLength(); } else { - OMText textNode = (OMText) lastNode; + OMText textNode = (OMText) getNode(); returnLength = textNode.getText().length(); } return returnLength; @@ -386,7 +402,7 @@ } } else { if (hasText()) { - OMText textNode = (OMText) lastNode; + OMText textNode = (OMText) getNode(); String str = textNode.getText(); str.getChars(i, i + i2, chars, i1); } @@ -404,7 +420,7 @@ returnArray = parser.getTextCharacters(); } else { if (hasText()) { - OMText textNode = (OMText) lastNode; + OMText textNode = (OMText) getNode(); String str = textNode.getText(); returnArray = str.toCharArray(); } @@ -422,10 +438,10 @@ returnString = parser.getText(); } else { if (hasText()) { - if (lastNode instanceof OMText) { - returnString = ((OMText) lastNode).getText(); - } else if (lastNode instanceof OMComment) { - returnString = ((OMComment) lastNode).getValue(); + if (getNode() instanceof OMText) { + returnString = ((OMText) getNode()).getText(); + } else if (getNode() instanceof OMComment) { + returnString = ((OMComment) getNode()).getValue(); } } } @@ -456,7 +472,7 @@ if (isStartElement() || isEndElement() || (currentEvent == NAMESPACE)) { OMNamespace ns = (OMNamespace) getItemFromIterator( - ((OMElement) lastNode).getAllDeclaredNamespaces(), i); + ((OMElement) getNode()).getAllDeclaredNamespaces(), i); returnString = (ns == null) ? null : ns.getNamespaceURI(); @@ -490,7 +506,7 @@ if (isStartElement() || isEndElement() || (currentEvent == NAMESPACE)) { OMNamespace ns = (OMNamespace) getItemFromIterator( - ((OMElement) lastNode).getAllDeclaredNamespaces(), i); + ((OMElement) getNode()).getAllDeclaredNamespaces(), i); returnString = (ns == null) ? null : ns.getPrefix(); @@ -512,7 +528,7 @@ || (currentEvent == NAMESPACE)) { returnCount = getCount( - ((OMElement) lastNode).getAllDeclaredNamespaces()); + ((OMElement) getNode()).getAllDeclaredNamespaces()); } } return returnCount; @@ -550,7 +566,7 @@ returnString = parser.getAttributeValue(i); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMAttribute attrib = getAttribute((OMElement) lastNode, i); + OMAttribute attrib = getAttribute((OMElement) getNode(), i); if (attrib != null) { returnString = attrib.getAttributeValue(); } @@ -574,7 +590,7 @@ } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMAttribute attrib = getAttribute((OMElement) lastNode, i); + OMAttribute attrib = getAttribute((OMElement) getNode(), i); if (attrib != null) { returnString = attrib.getAttributeType(); } @@ -599,7 +615,7 @@ returnString = parser.getAttributePrefix(i); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMAttribute attrib = getAttribute((OMElement) lastNode, i); + OMAttribute attrib = getAttribute((OMElement) getNode(), i); if (attrib != null) { OMNamespace nameSpace = attrib.getNamespace(); if (nameSpace != null) { @@ -625,7 +641,7 @@ returnString = parser.getAttributeLocalName(i); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMAttribute attrib = getAttribute((OMElement) lastNode, i); + OMAttribute attrib = getAttribute((OMElement) getNode(), i); if (attrib != null) { returnString = attrib.getLocalName(); } @@ -648,7 +664,7 @@ returnString = parser.getAttributeNamespace(i); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMAttribute attrib = getAttribute((OMElement) lastNode, i); + OMAttribute attrib = getAttribute((OMElement) getNode(), i); if (attrib != null) { OMNamespace nameSpace = attrib.getNamespace(); if (nameSpace != null) { @@ -674,7 +690,7 @@ returnQName = parser.getAttributeName(i); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - returnQName = getAttribute((OMElement) lastNode, i).getQName(); + returnQName = getAttribute((OMElement) getNode(), i).getQName(); } else { throw new IllegalStateException( "attribute count accessed in illegal event!"); @@ -693,7 +709,7 @@ returnCount = parser.getAttributeCount(); } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { - OMElement elt = (OMElement) lastNode; + OMElement elt = (OMElement) getNode(); returnCount = getCount(elt.getAllAttributes()); } else { throw new IllegalStateException( @@ -720,7 +736,7 @@ } else { if (isStartElement() || (currentEvent == ATTRIBUTE)) { QName qname = new QName(s, s1); - OMAttribute attrib = ((OMElement) lastNode).getAttribute(qname); + OMAttribute attrib = ((OMElement) getNode()).getAttribute(qname); if (attrib != null) { returnString = attrib.getAttributeValue(); } @@ -981,6 +997,7 @@ updateCompleteStatus(); break; case NAVIGABLE: + currentEvent = generateEvents(currentNode); updateCompleteStatus(); updateLastNode(); @@ -1009,14 +1026,14 @@ return Boolean.TRUE; } if (OMConstants.IS_BINARY.equals(s)) { - if (lastNode instanceof OMText) { - OMText text = (OMText) lastNode; + if (getNode() instanceof OMText) { + OMText text = (OMText) getNode(); return new Boolean(text.isBinary()); } return Boolean.FALSE; } else if (OMConstants.DATA_HANDLER.equals(s)) { - if (lastNode instanceof OMText) { - OMText text = (OMText) lastNode; + if (getNode() instanceof OMText) { + OMText text = (OMText) getNode(); if (text.isBinary()) return text.getDataHandler(); } @@ -1055,6 +1072,15 @@ * @throws XMLStreamException */ private void updateLastNode() throws XMLStreamException { + // Detect XOP:Include element and don't advance if processing + // the end tag. + if (xopInclude != null && + xopIncludeText == currentNode && + xopIncludeStart) { + lastNode = xopIncludeText; + return; + } + lastNode = currentNode; currentNode = nextNode; try { @@ -1139,7 +1165,12 @@ if (state==SWITCHED){ return parser.getNamespaceContext(); } - return new NamespaceContextImpl(getAllNamespaces(lastNode)); + Map m = getAllNamespaces(getNode()); + if (getNode() != lastNode) { + // Handle situation involving substituted node. + m.putAll(getAllNamespaces(lastNode)); + } + return new NamespaceContextImpl(m); } /** @@ -1241,7 +1272,7 @@ returnEvent = generateElementEvents(element); break; case OMNode.TEXT_NODE: - returnEvent = generateTextEvents(); + returnEvent = generateTextEvents(node); break; case OMNode.COMMENT_NODE: returnEvent = generateCommentEvents(); @@ -1262,15 +1293,15 @@ * @return Returns int. */ private int generateElementEvents(OMElement elt) { - if (elementStack == null) { - elementStack = new Stack(); + if (nodeStack == null) { + nodeStack = new Stack(); } int returnValue = START_ELEMENT; - if (!elementStack.isEmpty() && elementStack.peek().equals(elt)) { + if (!nodeStack.isEmpty() && nodeStack.peek().equals(elt)) { returnValue = END_ELEMENT; - elementStack.pop(); + nodeStack.pop(); } else { - elementStack.push(elt); + nodeStack.push(elt); } return returnValue; } @@ -1280,9 +1311,52 @@ * * @return Returns int. */ - private int generateTextEvents() { + private int generateTextEvents(OMNode node) { + if (!isInlineMTOM()) { + // If this is an optimized MTOM text node + // then simulate an XOP_INCLUDE element. + if (node instanceof OMText) { + OMText text = (OMText) node; + if (text.isOptimized()) { + + if (nodeStack == null) { + nodeStack = new Stack(); + } + + if (!nodeStack.isEmpty() && nodeStack.peek().equals(text)) { + // Process the end tag of the XOP:Include + nodeStack.pop(); + xopIncludeStart = false; + return END_ELEMENT; + } else { + + // Create an XOPInclude element to represent this node + xopIncludeText = text; + xopInclude = node.getOMFactory().createOMElement(XOP_INCLUDE); + String cid = text.getContentID(); + xopInclude.addAttribute("href", "cid:" + cid, null); + xopIncludeStart = true; + nodeStack.push(text); + return START_ELEMENT; + } + } + } + } return CHARACTERS; } + + /** + * @return the node to use for the current event + */ + private OMNode getNode() { + // This method returns the node used to construct + // the current event (lastNode). + // In some cases a new node is substitued (i.e. an XOPInclude element) + if (lastNode == xopIncludeText) { + return xopInclude; + } + return lastNode; + } /** * Method generateCommentEvents @@ -1395,7 +1469,7 @@ this.parser = parser; } - private Map getAllNamespaces(Object contextNode) { + private Map getAllNamespaces(OMNode contextNode) { if (!(contextNode instanceof OMContainer && contextNode instanceof OMElement)) { return new HashMap(); @@ -1472,10 +1546,32 @@ public DataHandler getDataHandler(String blobcid) { DataHandler dh = null; + // The datahandler may be part of the attachments map of the builder if (builder != null && builder instanceof OMAttachmentAccessor) { dh = ((OMAttachmentAccessor) builder).getDataHandler(blobcid); + } + + // Or the datahandler might be part of the current optimized text node + if (dh == null && + lastNode != null && + lastNode instanceof OMText) { + OMText text = (OMText) lastNode; + if (text.isOptimized() && + blobcid.equals("cid:" + text.getContentID())) { + dh = (DataHandler) text.getDataHandler(); + } } + return dh; } + + public boolean isInlineMTOM() { + return inlineMTOM; + + } + + public void setInlineMTOM(boolean value) { + inlineMTOM = value; + } } Modified: webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java?rev=655845&r1=655844&r2=655845&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java Tue May 13 05:56:37 2008 @@ -21,14 +21,17 @@ import org.apache.axiom.attachments.Attachments; import org.apache.axiom.om.AbstractTestCase; +import org.apache.axiom.om.OMAttachmentAccessor; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMOutputFormat; import org.apache.axiom.om.OMText; import org.apache.axiom.om.OMXMLParserWrapper; +import org.apache.axiom.om.OMXMLStreamReader; import org.apache.axiom.soap.SOAP12Constants; import org.apache.axiom.soap.impl.builder.MTOMStAXSOAPModelBuilder; import javax.activation.DataHandler; +import javax.xml.namespace.QName; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; @@ -44,6 +47,9 @@ public class MTOMStAXSOAPModelBuilderTest extends AbstractTestCase { + private final static QName XOP_INCLUDE = + new QName("http://www.w3.org/2004/08/xop/include", "Include"); + /** @param testName */ public MTOMStAXSOAPModelBuilderTest(String testName) { super(testName); @@ -113,6 +119,7 @@ assertTrue(msg.indexOf("Content-ID: <cid:-1609420109260943731>") > 0); } + public void testCreateAndSerializeInlined() throws Exception { String contentTypeString = "multipart/Related; charset=\"UTF-8\"; type=\"application/xop+xml\"; boundary=\"----=_AxIs2_Def_boundary_=42214532\"; start=\"SOAPPart\""; @@ -172,6 +179,54 @@ System.out.println(root.toString()); } + public void testCreateAndXMLStreamReader() throws Exception { + String contentTypeString = + "multipart/Related; charset=\"UTF-8\"; type=\"application/xop+xml\"; boundary=\"----=_AxIs2_Def_boundary_=42214532\"; start=\"SOAPPart\""; + String inFileName = "mtom/MTOMBuilderTestIn.txt"; + InputStream inStream = new FileInputStream(getTestResourceFile(inFileName)); + Attachments attachments = new Attachments(inStream, contentTypeString); + XMLStreamReader reader = XMLInputFactory.newInstance() + .createXMLStreamReader(new BufferedReader(new InputStreamReader(attachments + .getSOAPPartInputStream()))); + OMXMLParserWrapper builder = new MTOMStAXSOAPModelBuilder(reader, attachments, + SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI); + OMElement root = builder.getDocumentElement(); + + // Build tree + root.build(); + + // Use tree as input to XMLStreamReader + OMXMLStreamReader xmlStreamReader = (OMXMLStreamReader) root.getXMLStreamReader(); + + // Issue XOP:Include events for optimized MTOM text nodes + xmlStreamReader.setInlineMTOM(false); + + DataHandler dh = null; + while(xmlStreamReader.hasNext() && dh == null) { + xmlStreamReader.next(); + if (xmlStreamReader.isStartElement()) { + QName qName =xmlStreamReader.getName(); + if (XOP_INCLUDE.equals(qName)) { + String hrefValue = xmlStreamReader.getAttributeValue("", "href"); + if (hrefValue != null) { + dh =((OMAttachmentAccessor)xmlStreamReader).getDataHandler(hrefValue); + } + } + } + } + assertTrue(dh != null); + + // Make sure next event is an an XOP_Include END element + xmlStreamReader.next(); + assertTrue(xmlStreamReader.isEndElement()); + assertTrue(XOP_INCLUDE.equals(xmlStreamReader.getName())); + + // Make sure the next event is the end tag of name + xmlStreamReader.next(); + assertTrue(xmlStreamReader.isEndElement()); + assertTrue("name".equals(xmlStreamReader.getLocalName())); + } + private byte[] append(byte[] a, byte[] b) { byte[] z = new byte[a.length + b.length]; System.arraycopy(a, 0, z, 0, a.length);