org.apache.axiom.om.impl.builder.SafeXMLStreamReader Maven / Gradle / Ivy
/*
* 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.
*
* 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.
*
* 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.
*
* 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).
*
* 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;
}
}
}