package org.infinispan.configuration.parsing; import java.util.ArrayDeque; import java.util.Deque; 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; /** * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a> * @author Tristan Tarrant * @since 6.0 */ final class XMLExtendedStreamReaderImpl implements XMLExtendedStreamReader { private final NamespaceMappingParser parser; private final XMLStreamReader streamReader; private final Deque<Context> stack = new ArrayDeque<Context>(); private Schema schema; XMLExtendedStreamReaderImpl(final NamespaceMappingParser parser, final XMLStreamReader streamReader) { this.parser = parser; this.streamReader = streamReader; stack.push(new Context()); } @Override public void handleAny(final ConfigurationBuilderHolder holder) throws XMLStreamException { require(START_ELEMENT, null, null); boolean ok = false; try { final Deque<Context> stack = this.stack; stack.push(new Context()); try { parser.parseElement(this, holder); } finally { stack.pop(); } ok = true; } finally { if (!ok) { safeClose(); } } } @Override public Object getProperty(final String name) throws IllegalArgumentException { return streamReader.getProperty(name); } @Override public int next() throws XMLStreamException { final Context context = stack.getFirst(); if (context.depth > 0) { final int next = streamReader.next(); if (next == END_ELEMENT) { context.depth--; } else if (next == START_ELEMENT) { context.depth++; } return next; } else { try { throw readPastEnd(getLocation()); } finally { safeClose(); } } } @Override public void require(final int type, final String namespaceURI, final String localName) throws XMLStreamException { streamReader.require(type, namespaceURI, localName); } @Override public String getElementText() throws XMLStreamException { return streamReader.getElementText().trim(); } @Override public int nextTag() throws XMLStreamException { final Context context = stack.getFirst(); if (context.depth > 0) { final int next = streamReader.nextTag(); if (next == END_ELEMENT) { context.depth--; } else if (next == START_ELEMENT) { context.depth++; } return next; } else { try { throw readPastEnd(getLocation()); } finally { safeClose(); } } } @Override public boolean hasNext() throws XMLStreamException { return stack.getFirst().depth > 0 && streamReader.hasNext(); } @Override public void close() throws XMLStreamException { throw new UnsupportedOperationException(); } @Override public String getNamespaceURI(final String prefix) { return streamReader.getNamespaceURI(prefix); } @Override public boolean isStartElement() { return streamReader.isStartElement(); } @Override public boolean isEndElement() { return streamReader.isEndElement(); } @Override public boolean isCharacters() { return streamReader.isCharacters(); } @Override public boolean isWhiteSpace() { return streamReader.isWhiteSpace(); } @Override public String getAttributeValue(final String namespaceURI, final String localName) { return streamReader.getAttributeValue(namespaceURI, localName); } @Override public int getAttributeCount() { return streamReader.getAttributeCount(); } @Override public QName getAttributeName(final int index) { return streamReader.getAttributeName(index); } @Override public String getAttributeNamespace(final int index) { return streamReader.getAttributeNamespace(index); } @Override public String getAttributeLocalName(final int index) { return streamReader.getAttributeLocalName(index); } @Override public String getAttributePrefix(final int index) { return streamReader.getAttributePrefix(index); } @Override public String getAttributeType(final int index) { return streamReader.getAttributeType(index); } @Override public String getAttributeValue(final int index) { return streamReader.getAttributeValue(index); } @Override public boolean isAttributeSpecified(final int index) { return streamReader.isAttributeSpecified(index); } @Override public int getNamespaceCount() { return streamReader.getNamespaceCount(); } @Override public String getNamespacePrefix(final int index) { return streamReader.getNamespacePrefix(index); } @Override public String getNamespaceURI(final int index) { return streamReader.getNamespaceURI(index); } @Override public NamespaceContext getNamespaceContext() { return streamReader.getNamespaceContext(); } @Override public int getEventType() { return streamReader.getEventType(); } @Override public String getText() { return streamReader.getText(); } @Override public char[] getTextCharacters() { return streamReader.getTextCharacters(); } @Override public int getTextCharacters(final int sourceStart, final char[] target, final int targetStart, final int length) throws XMLStreamException { return streamReader.getTextCharacters(sourceStart, target, targetStart, length); } @Override public int getTextStart() { return streamReader.getTextStart(); } @Override public int getTextLength() { return streamReader.getTextLength(); } @Override public String getEncoding() { return streamReader.getEncoding(); } @Override public boolean hasText() { return streamReader.hasText(); } @Override public Location getLocation() { return streamReader.getLocation(); } @Override public QName getName() { return streamReader.getName(); } @Override public String getLocalName() { return streamReader.getLocalName(); } @Override public boolean hasName() { return streamReader.hasName(); } @Override public String getNamespaceURI() { return streamReader.getNamespaceURI(); } @Override public String getPrefix() { return streamReader.getPrefix(); } @Override public String getVersion() { return streamReader.getVersion(); } @Override public boolean isStandalone() { return streamReader.isStandalone(); } @Override public boolean standaloneSet() { return streamReader.standaloneSet(); } @Override public String getCharacterEncodingScheme() { return streamReader.getCharacterEncodingScheme(); } @Override public String getPITarget() { return streamReader.getPITarget(); } @Override public String getPIData() { return streamReader.getPIData(); } @Override public String[] getListAttributeValue(int i) { return getAttributeValue(i).split("\\s+"); } @Override public Schema getSchema() { return schema; } @Override public void setSchema(Schema schema) { this.schema = schema; } // private members private static final class Context { int depth = 1; } private void safeClose() { try { streamReader.close(); } catch (Exception e) { // ignore } } private static XMLStreamException readPastEnd(final Location location) { return new XMLStreamException("Attempt to read past end of element", location); } }