Author: scheu Date: Tue Jan 19 22:46:32 2010 New Revision: 900993 URL: http://svn.apache.org/viewvc?rev=900993&view=rev Log: WSCOMMONS-518 Contributor: Rich Scheuerle Analysis: Doug Larson Summary of Problem: The new XMLStreamReader wrappers and delegates in Axiom prevent consumers from directly accessing the original parser. This has caused regressions for some users. Summary of Solution: The XMLStreamReader wrappers and delegates remain intact. Some of them have been marked with a new marker interface, XMLStreamReaderContainer. New utility methods are added to XMLStreamReaderUtils to allow a consumer to access the original XMLStreamReader.
Tests are added to verify the function. Note that an OMStAXWRapper is not an XMLStreamReaderContainer. An OMStaXWrapper actually wraps a OM tree and adapts it to an XMLStreamReader interface (versus wrapping an actual live parser). Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderContainer.java Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/OMStAXWrapper.java webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderWrapper.java webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java webservices/commons/trunk/modules/axiom/modules/axiom-tests/src/test/java/org/apache/axiom/om/impl/mtom/MTOMStAXSOAPModelBuilderTest.java Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/OMStAXWrapper.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/OMStAXWrapper.java?rev=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/OMStAXWrapper.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/OMStAXWrapper.java Tue Jan 19 22:46:32 2010 @@ -41,6 +41,8 @@ /** * {...@link XMLStreamReader} implementation that generates events from a given Axiom tree. + * This class does intentionally does not implement XMLStreamReaderContainer because + * it does not wrap a parser (it wraps an OM graph). */ public class OMStAXWrapper extends StreamReaderDelegate implements OMXMLStreamReader { private static final Log log = LogFactory.getLog(OMStAXWrapper.class); Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java?rev=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java Tue Jan 19 22:46:32 2010 @@ -23,6 +23,8 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; +import org.apache.axiom.util.stax.wrapper.XMLStreamReaderContainer; + /** * XMLStreamReader wrapper that prevents access to the underlying parser * after the first error occurs. @@ -55,7 +57,7 @@ * to {...@link XMLStreamReader#next()} and similar methods on the underlying parser. * Any attempt to do so will immediately result in an error. */ -public class SafeXMLStreamReader extends StreamReaderDelegate { +public class SafeXMLStreamReader extends StreamReaderDelegate implements XMLStreamReaderContainer { private boolean parserError; public SafeXMLStreamReader(XMLStreamReader reader) { Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java?rev=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java Tue Jan 19 22:46:32 2010 @@ -26,12 +26,19 @@ import org.apache.axiom.attachments.ByteArrayDataSource; import org.apache.axiom.ext.stax.datahandler.DataHandlerReader; +import org.apache.axiom.om.OMAttachmentAccessor; import org.apache.axiom.om.util.Base64; +import org.apache.axiom.util.stax.wrapper.XMLStreamReaderContainer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Contains utility methods to work with {...@link XMLStreamReader} objects. */ public class XMLStreamReaderUtils { + + private static Log log = LogFactory.getLog(XMLStreamReaderUtils.class); + /** * Get the {...@link DataHandlerReader} extension from a given {...@link XMLStreamReader}. * @@ -108,4 +115,60 @@ } return new DataHandler(new ByteArrayDataSource(Base64.decode(base64))); } + + /** + * getOriginalXMLStreamReader + * Searches the wrapper and delegate classes to find the original XMLStreamReader + * This method should only be used when a consumer of Axiom really needs to + * access the original stream reader. + * @param parser XMLStreamReader used by Axiom + * @return original parser + */ + public static XMLStreamReader getOriginalXMLStreamReader(XMLStreamReader parser) { + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug("Entry getOriginalXMLStreamReader: " + clsName); + } + while (parser instanceof XMLStreamReaderContainer) { + parser = ((XMLStreamReaderContainer) parser).getParent(); + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug(" parent: " + clsName); + } + } + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug("Exit getOriginalXMLStreamReader: " + clsName); + } + return parser; + } + + /** + * Searches the wrapper and delegate classes to find an XMLStreamReader + * that implements the OMAttachmentAccessor + * @param parser + * @return XMLStreamREader that implements OMAttachmentAccessor or null + */ + public static XMLStreamReader getOMAttachmentAccessorXMLStreamReader(XMLStreamReader parser) { + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug("Entry getOMAttachmentAccessorXMLStreamReader: " + clsName); + } + while (!(parser instanceof OMAttachmentAccessor) && + (parser instanceof XMLStreamReaderContainer)) { + parser = ((XMLStreamReaderContainer) parser).getParent(); + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug(" parent: " + clsName); + } + } + if (!(parser instanceof OMAttachmentAccessor)) { + parser = null; + } + if (log.isDebugEnabled()) { + String clsName = (parser != null) ? parser.getClass().toString() : "null"; + log.debug("Exit getOMAttachmentAccessorXMLStreamReader: " + clsName); + } + return parser; + } } Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderContainer.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderContainer.java?rev=900993&view=auto ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderContainer.java (added) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderContainer.java Tue Jan 19 22:46:32 2010 @@ -0,0 +1,37 @@ +/* + * 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.wrapper; + +import javax.xml.stream.XMLStreamReader; + +/** + * Marker interface for Axiom XMLStreamReader classes that + * wrap or delegate to another (parent) XMLStreamReader. + * + * The marker interface is necessary so that consumers + * can access the original parser. + * @see XMLStreamReaderUtils + * + * Note that the only the getParent() method is applicable. + * Please do not add a setParent() method since that would + * violate the immutable characteristic of the XMLStreamReaderWrapper + */ +public interface XMLStreamReaderContainer { + XMLStreamReader getParent(); +} Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderWrapper.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderWrapper.java?rev=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderWrapper.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/wrapper/XMLStreamReaderWrapper.java Tue Jan 19 22:46:32 2010 @@ -31,7 +31,7 @@ * similar to {...@link javax.xml.stream.util.StreamReaderDelegate}, with the difference that it is * immutable. */ -public class XMLStreamReaderWrapper implements XMLStreamReader { +public class XMLStreamReaderWrapper implements XMLStreamReader, XMLStreamReaderContainer { private final XMLStreamReader parent; /** @@ -42,6 +42,15 @@ public XMLStreamReaderWrapper(XMLStreamReader parent) { this.parent = parent; } + + /** + * Get Parent + * Note that setParent is intentionally omitted. XMLStreamReaderWrapper is immutable. + * @return XMLStreamReader parent + */ + public XMLStreamReader getParent() { + return parent; + } public void close() throws XMLStreamException { parent.close(); Modified: 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=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPDecodingStreamReader.java Tue Jan 19 22:46:32 2010 @@ -35,6 +35,7 @@ import org.apache.axiom.ext.stax.datahandler.DataHandlerReader; import org.apache.axiom.om.util.StAXUtils; import org.apache.axiom.util.base64.Base64Utils; +import org.apache.axiom.util.stax.wrapper.XMLStreamReaderContainer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,7 +57,8 @@ * {...@link DataHandlerReader#getDataHandlerProvider()}, then the {...@link MimePartProvider} will only * be invoked when {...@link DataHandlerProvider#getDataHandler()} is called. */ -public class XOPDecodingStreamReader extends StreamReaderDelegate implements XMLStreamReader, DataHandlerReader { +public class XOPDecodingStreamReader extends StreamReaderDelegate + implements XMLStreamReader, DataHandlerReader, XMLStreamReaderContainer { 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/)"; Modified: 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=900993&r1=900992&r2=900993&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/xop/XOPEncodingStreamReader.java Tue Jan 19 22:46:32 2010 @@ -33,6 +33,7 @@ import javax.xml.stream.XMLStreamReader; import org.apache.axiom.ext.stax.datahandler.DataHandlerReader; +import org.apache.axiom.util.stax.wrapper.XMLStreamReaderContainer; /** * {...@link XMLStreamReader} wrapper that encodes XOP. It assumes that the underlying reader @@ -52,7 +53,8 @@ * 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 extends XOPEncodingStreamWrapper implements XMLStreamReader { +public class XOPEncodingStreamReader extends XOPEncodingStreamWrapper + implements XMLStreamReader, XMLStreamReaderContainer { /** * Wrapper that adds the XOP namespace to another namespace context. */ @@ -530,4 +532,8 @@ default: return parent.isEndElement(); } } + + public XMLStreamReader getParent() { + return parent; + } } 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=900993&r1=900992&r2=900993&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 Jan 19 22:46:32 2010 @@ -28,10 +28,13 @@ import org.apache.axiom.om.OMOutputFormat; import org.apache.axiom.om.OMText; import org.apache.axiom.om.OMXMLStreamReader; +import org.apache.axiom.om.impl.OMStAXWrapper; +import org.apache.axiom.om.impl.builder.StAXBuilder; import org.apache.axiom.om.impl.traverse.OMDescendantsIterator; import org.apache.axiom.om.util.StAXUtils; import org.apache.axiom.soap.SOAP12Constants; import org.apache.axiom.soap.impl.builder.MTOMStAXSOAPModelBuilder; +import org.apache.axiom.util.stax.XMLStreamReaderUtils; import javax.activation.DataHandler; import javax.xml.namespace.QName; @@ -79,6 +82,7 @@ return createBuilderForTestMTOMMessage().getDocumentElement(); } + private void checkSerialization(OMElement root, boolean optimize) throws Exception { OMOutputFormat format = new OMOutputFormat(); format.setDoOptimize(optimize); @@ -95,6 +99,45 @@ } } + public void testAccessToParser() throws Exception { + OMElement root = createTestMTOMMessage(); + StAXBuilder builder = (StAXBuilder) root.getBuilder(); + // Disable caching so that the reader can be accessed. + builder.setCache(false); + XMLStreamReader reader = (XMLStreamReader) builder.getParser(); + + XMLStreamReader original = XMLStreamReaderUtils.getOriginalXMLStreamReader(reader); + + // The streaming parser is wrapped by a SafeXMLStreamReader and dialect readers. + // Thus the reader and original readers will not be the same. + assertTrue(reader != original); + + // The streaming parser will not have access to the attachments. Thus this will + // return null + XMLStreamReader attachmentAccessor = + XMLStreamReaderUtils.getOMAttachmentAccessorXMLStreamReader(reader); + + assertTrue(attachmentAccessor == null); + + } + + public void testAccessToCachedParser() throws Exception { + OMElement root = createTestMTOMMessage(); + XMLStreamReader reader = root.getXMLStreamReader(true); + + XMLStreamReader original = XMLStreamReaderUtils.getOriginalXMLStreamReader(reader); + + // The caching parser will be an OMStaXWrapper. + assertTrue(original instanceof OMStAXWrapper); + + XMLStreamReader attachmentAccessor = + XMLStreamReaderUtils.getOMAttachmentAccessorXMLStreamReader(reader); + + // Thus the attachmentAccessor should also be the OMStaXWrapper + assertTrue(attachmentAccessor instanceof OMStAXWrapper); + + } + public void testCreateOMElement() throws Exception { OMElement root = createTestMTOMMessage(); OMElement body = (OMElement) root.getFirstOMChild();