Author: veithen Date: Tue Dec 16 02:39:23 2008 New Revision: 727013 URL: http://svn.apache.org/viewvc?rev=727013&view=rev Log: WSCOMMONS-372: Added a mechanism that prevents Axiom from requesting new events from a parser that has reported a parsing error before. This avoids problems with parsers that are left in an inconsistent state after a parsing error and continue to return (incorrect) events.
Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXBuilder.java Added: 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=727013&view=auto ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java (added) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/SafeXMLStreamReader.java Tue Dec 16 02:39:23 2008 @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.axiom.om.impl.builder; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; + +/** + * XMLStreamReader wrapper that prevents access to the underlying parser + * after the first error occurs. + * <p> + * Usually, code that uses StAX directly just stops processing of an XML document + * once the first parsing error has been reported. However, since Axiom + * uses deferred parsing, and client code accesses the XML infoset using + * an object model, things are more complicated. Indeed, if the XML + * document is not well formed, the corresponding error might be reported + * as a runtime exception by any call to a method of an OM node. + * <p> + * Typically the client code will have some error handling that will intercept + * runtime exceptions and take appropriate action. Very often this error handling + * code might want to access the object model again, for example to log the request that caused the + * failure. This causes no problem except if the runtime exception was caused by a + * parsing error, in which case Axiom would again try to pull events from the parser. + * <p> + * This would lead to a situation where Axiom accesses a parser that has reported a parsing + * error before. While one would expect that after a first error reported by the parser, all + * subsequent invocations of the parser will fail, this is not the case for all parsers + * (at least not in all situations). Instead, the parser might be left in an inconsistent + * state after the error. E.g. WSCOMMONS-372 describes a case where Woodstox + * encounters an error in {...@link XMLStreamReader#getText()} but continues to return + * (incorrect) events afterwards. The explanation for this behaviour might be that + * the situation described here is quite uncommon when StAX is used directly (i.e. not through + * Axiom). + * <p> + * This class provides a simple way to prevent this type of issue by wrapping the underlying + * parser implementation. After the first parsing error occurs, the wrapper prevents any call + * 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 { + private boolean parserError; + + public SafeXMLStreamReader(XMLStreamReader reader) { + super(reader); + } + + private void checkError() throws XMLStreamException { + if (parserError) { + throw new XMLStreamException( + "Trying to read events from a parser that already reported an error before"); + } + } + + public String getElementText() throws XMLStreamException { + try { + return super.getElementText(); + } catch (XMLStreamException ex) { + parserError = true; + throw ex; + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public String getPIData() { + try { + return super.getPIData(); + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public String getText() { + try { + return super.getText(); + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public char[] getTextCharacters() { + try { + return super.getTextCharacters(); + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) + throws XMLStreamException { + checkError(); + try { + return super.getTextCharacters(sourceStart, target, targetStart, length); + } catch (XMLStreamException ex) { + parserError = true; + throw ex; + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public int getTextLength() { + try { + return super.getTextLength(); + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public int getTextStart() { + try { + return super.getTextStart(); + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public boolean hasNext() throws XMLStreamException { + checkError(); + try { + return super.hasNext(); + } catch (XMLStreamException ex) { + parserError = true; + throw ex; + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public int next() throws XMLStreamException { + checkError(); + try { + return super.next(); + } catch (XMLStreamException ex) { + parserError = true; + throw ex; + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } + + public int nextTag() throws XMLStreamException { + checkError(); + try { + return super.nextTag(); + } catch (XMLStreamException ex) { + parserError = true; + throw ex; + } catch (RuntimeException ex) { + parserError = true; + throw ex; + } catch (Error ex) { + parserError = true; + throw ex; + } + } +} Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXBuilder.java URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXBuilder.java?rev=727013&r1=727012&r2=727013&view=diff ============================================================================== --- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXBuilder.java (original) +++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/om/impl/builder/StAXBuilder.java Tue Dec 16 02:39:23 2008 @@ -116,7 +116,6 @@ * @param parser */ protected StAXBuilder(OMFactory ombuilderFactory, XMLStreamReader parser) { - this.parser = parser; omfactory = ombuilderFactory; // The getCharacterEncodingScheme and getEncoding information are @@ -126,9 +125,7 @@ charEncoding = parser.getEncoding(); } - if (parser instanceof BuilderAwareReader) { - ((BuilderAwareReader) parser).setBuilder(this); - } + initParser(parser); } /** @@ -142,13 +139,16 @@ protected StAXBuilder(OMFactory ombuilderFactory, XMLStreamReader parser, String characterEncoding) { - this.parser = parser; omfactory = ombuilderFactory; charEncoding = characterEncoding; - + initParser(parser); + } + + private void initParser(XMLStreamReader parser) { if (parser instanceof BuilderAwareReader) { ((BuilderAwareReader) parser).setBuilder(this); } + this.parser = new SafeXMLStreamReader(parser); } /**