blob: a0da5d2609d93b657ba6b3a7af2dd1cd4dded978 [file] [log] [blame]
/**
*
* 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.tuscany.sdo.util.resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.XMLConstants;
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;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
/**
* This special purpose XMLStreamReader is used to produce a StAX event stream corresponding to a list of events
* recorded earlier. The recorded events are generated by the inner class RecordedEventXMLStreamReader.Tag,
* which records the events in either of 2 ways:
*
* 1) in conjunction with class SDOXMLLoadImpl, it records events corresponding to the SAX events being
* handled by the SDOXMLLoadImpl when loading XML using SDOXMLResourceImpl.
* 2) when Tag.record() is called (see class ChangeSummaryStreamDeserializer), it walks through and records
* the StAX events produced by another XMLStreamReader.
*
* This class is used by the SDO StAX-based ChangeSummaryType-property loader, class
* ChangeSummaryStreamDeserializer, which is inoked by and uses (for loading deleted object XML fragments)
* the SAX-based loader class XMLResourceImpl.
*/
public abstract class RecordedEventXMLStreamReader implements XMLStreamReader {
static private class Event {
int type;
public NamespaceContext nameSpaceContext;
Location location;
protected final void initialize(XMLStreamReader reader) {
nameSpaceContext = reader.getNamespaceContext();
location = reader.getLocation();
}
protected final void location(final Locator locator) {
location = new Location() {
public int getCharacterOffset() {
return -1;
}
public int getColumnNumber() {
return locator.getColumnNumber();
}
public int getLineNumber() {
return locator.getLineNumber();
}
public String getPublicId() {
return locator.getPublicId();
}
public String getSystemId() {
return locator.getSystemId();
}
};
}
}
static class ValueEvent extends Event {
final String value;
protected ValueEvent(String v) {
value = v;
}
}
static protected class Reference extends ValueEvent {
final String target;
protected Reference(String name, String data) {
super(data);
target = name;
}
}
static protected final class AttributeEvent extends Reference {
final QName name;
final String nameSpace, prefix;
int attributes;
final boolean specified;
protected AttributeEvent(XMLStreamReader reader) {
super(reader.getAttributeType(0), reader.getAttributeValue(0));
attributes = reader.getAttributeCount();
name = reader.getAttributeName(0);
nameSpace = reader.getAttributeNamespace(0);
prefix = reader.getAttributePrefix(0);
specified = reader.isAttributeSpecified(0);
}
}
static protected final class NameSpaceEvent extends Reference {
int nameSpaces;
protected NameSpaceEvent(XMLStreamReader reader) {
super(reader.getNamespacePrefix(0), reader.getNamespaceURI(0));
nameSpaces = reader.getNamespaceCount();
}
}
static protected String prefix(String qName, String nameSpace) {
int delimiter = qName.indexOf(':');
if (delimiter != -1)
return qName.substring(0, delimiter);
if (nameSpace.length() != 0)
return XMLConstants.DEFAULT_NS_PREFIX;
// if (nameSpaceContext.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX) != null || xsdHelper.getGlobalProperty(null, name, element) == null)
return null;
}
static class EndElement extends Event {
List nameSpaces/* = null */;
public final QName name;
public final String nameSpace;
final String prefix;
protected EndElement(XMLStreamReader reader) {
name = reader.getName();
nameSpace = reader.getNamespaceURI();
prefix = reader.getPrefix();
int count = reader.getNamespaceCount();
if (count == 0)
return;
nameSpaces = new ArrayList(count);
int index = 0;
do
Tag.bind(reader.getNamespacePrefix(index), reader.getNamespaceURI(index), nameSpaces);
while (++index != count);
}
protected EndElement(String uri, String local, String p, Locator locator) {
if (p == null) {
name = new QName(uri, local, XMLConstants.DEFAULT_NS_PREFIX);
nameSpace = null;
} else {
name = new QName(uri, local, p);
nameSpace = uri;
}
prefix = p;
location(locator);
}
}
static class NameSpace {
final String prefix, uri;
protected NameSpace(String p, String nameSpace) {
prefix = p;
uri = nameSpace;
}
}
static final class Attribute extends NameSpace {
final String type, value;
final QName qName;
boolean specified/* = false */;
protected Attribute(String t, String v, QName name, String prefix, String nameSpace) {
super(prefix, nameSpace);
type = t;
value = v;
qName = name;
}
}
static final class AttributeList /* implements Attributes */{// TODO exclude XMLConstants.XMLNS_ATTRIBUTE
final List attributes;
protected AttributeList(int size) {
attributes = new ArrayList(size);
}
/*
* @param uri Never null
*/
public final int getIndex(String uri, String localName) {
for (int index = getLength(); index != 0;)
if (getLocalName(--index).equals(localName) && uri.equals(getURI(index)))
return index;
return -1;
}
public final int getLength() {
return attributes.size();
}
protected final Attribute attribute(int index) {
return (Attribute) attributes.get(index);
}
public final String getLocalName(int index) {
return attribute(index).qName.getLocalPart();
}
public final String getType(int index) {
return attribute(index).type;
}
/*public String getType(String uri, String localName) {
int index = getIndex(uri, localName);
return index == -1 ? null: getType(index);
} */
public final String getURI(int index) {
return attribute(index).uri;
}
public final String getValue(int index) {
return attribute(index).value;
}
/*
* @param uri Never null
*/
public final String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
return index == -1 ? null : getValue(index);
}
}
static protected class StartElement extends EndElement {
final AttributeList attributes;
protected StartElement(XMLStreamReader reader) {
super(reader);
int count = reader.getAttributeCount();
if (count == 0)
attributes = null;
else {
attributes = new AttributeList(count);
int index = 0;
do {
Attribute attribute = new Attribute(reader.getAttributeType(index), reader.getAttributeValue(index), reader
.getAttributeName(index), reader.getAttributePrefix(index), reader.getAttributeNamespace(index));
attribute.specified = reader.isAttributeSpecified(index);
attributes.attributes.add(attribute);
} while (++index != count);
}
}
protected StartElement(String nameSpace, String local, String prefix, Attributes attributeArray, Locator locator, List bindings,
final NamespaceContext context) {
super(nameSpace, local, prefix, locator);
nameSpaces = bindings;
nameSpaceContext = bindings == null || bindings.isEmpty() ? context : new NamespaceContext() {
public String getNamespaceURI(String prefix) {
for (int index = nameSpaces.size(); index != 0;) {
NameSpace binding = (NameSpace) nameSpaces.get(--index);
if (binding.prefix.equals(prefix))
return binding.uri;
}
return context.getNamespaceURI(prefix);
}
public String getPrefix(String namespaceURI) {
for (int index = nameSpaces.size(); index != 0;) {
NameSpace binding = (NameSpace) nameSpaces.get(--index);
if (binding.uri.equals(namespaceURI))
return binding.prefix;
}
return context.getPrefix(namespaceURI);
}
public Iterator getPrefixes(final String namespaceURI) {
final Iterator iterator = context.getPrefixes(namespaceURI);
return new Iterator() {
Iterator bindings = nameSpaces.iterator();
NameSpace binding/* = null */;
protected final boolean prefix() {
while (bindings.hasNext()) {
binding = (NameSpace) bindings.next();
if (binding.uri.equals(namespaceURI))
return true;
}
bindings = null;
return false;
}
public boolean hasNext() {
return bindings != null && prefix() || iterator.hasNext();
}
protected NameSpace nameSpace;
public Object next() {
if (bindings == null || binding == null && !prefix())
return iterator.next();
nameSpace = binding;
binding = null;
return nameSpace.prefix;
}
public void remove() {
if (bindings == null)
iterator.remove();
else
nameSpaces.remove(nameSpace);
}
};
}
};
int count = attributeArray.getLength();
if (count == 0)
attributes = null;
else {
attributes = new AttributeList(count);
int index = 0;
do {
QName name;
nameSpace = attributeArray.getURI(index);
local = attributeArray.getLocalName(index);
prefix = prefix(attributeArray.getQName(index), nameSpace);
if (prefix == null) {
name = new QName(nameSpace, local, XMLConstants.DEFAULT_NS_PREFIX);
nameSpace = null;
} else
name = new QName(nameSpace, local, prefix);
attributes.attributes.add(new Attribute(attributeArray.getType(index), attributeArray.getValue(index), name, prefix, nameSpace));
} while (++index != count);
}
}
}
static public class Tag extends StartElement {
public Tag(XMLStreamReader reader) {
super(reader);
initialize(reader);
}
public List events/* = null */; // may be empty
protected final void events() {
events = new ArrayList();
}
public Tag(String nameSpace, String local, String prefix, Attributes attributes, Locator locator, NamespaceContext context, List bindings) {
super(nameSpace, local, prefix, attributes, locator, bindings, context);
events();
}
static public void bind(String prefix, String nameSpace, Collection nameSpaces) {
nameSpaces.add(new NameSpace(prefix, nameSpace));
}
protected int nest/* = 0 */;
public final void start(String nameSpace, String local, String qName, Attributes attributes, Locator locator, List bindings) {
Event event;
for (int index = events.size();/* true */;) {
if (index == 0) {
event = this;
break;
}
event = (Event) events.get(--index);
if (event.type != END_ELEMENT)
break;
siblings: for (int nest = 0;/* true */;)
switch (((Event) events.get(--index)).type) {
case START_ELEMENT:
if (nest == 0)
break siblings;
--nest;
break;
case END_ELEMENT:
++nest;
}
}
Event start = new StartElement(nameSpace, local, prefix(qName, nameSpace), attributes, locator, bindings, event.nameSpaceContext);
start.type = START_ELEMENT;
events.add(start);
++nest;
}
protected final void add (Event event)
{
int index = events.size();
event.nameSpaceContext = index == 0 ? nameSpaceContext : ((Event) events.get(--index)).nameSpaceContext;
events.add(event);
}
public final void text(int type, String value, Locator locator) {
Event event = new ValueEvent(value);
event.type = type;
event.location(locator);
//int index = events.size();
add(event);
}
public final boolean end(String nameSpace, String local, String qName, Locator locator) {
Event end = new EndElement(nameSpace, local, prefix(qName, nameSpace), locator);
end.type = END_ELEMENT;
add(end);
if (nest == 0)
return true;
--nest;
return false;
}
public final XMLStreamReader play(final XMLResource resource) {
return new RecordedEventXMLStreamReader(this) {
public void close() {
}
public String getCharacterEncodingScheme() {
return null; // TODO
}
public String getEncoding() {
return resource.getEncoding();
}
public Object getProperty(String property) {
return null; // TODO javax.xml.stream.notations & javax.xml.stream.entities for DTD
}
public String getVersion() {
return resource.getXMLVersion();
}
public boolean isStandalone() {
return false; // TODO
}
public boolean standaloneSet() {
return false; // TODO
}
};
}
protected final void add(Event event, int type, XMLStreamReader reader) {
event.type = type;
event.initialize(reader);
events.add(event);
}
public final boolean record(XMLStreamReader reader) throws XMLStreamException {
events();
for (int nest = 0; reader.hasNext();) {
Event event;
int type = reader.next();
switch (type) {
case CHARACTERS:
case CDATA:
case COMMENT:
case SPACE:
case DTD:
event = new ValueEvent(reader.getText());
break;
case ENTITY_REFERENCE:
event = new Reference(reader.getLocalName(), reader.getText());
break;
case PROCESSING_INSTRUCTION:
event = new Reference(reader.getPITarget(), reader.getPIData());
break;
case ATTRIBUTE:
event = new AttributeEvent(reader);
break;
case NAMESPACE:
event = new NameSpaceEvent(reader);
break;
case START_ELEMENT:
++nest;
event = new StartElement(reader);
break;
case END_ELEMENT:
add(new EndElement(reader), type, reader);
if (nest == 0)
return false;
--nest;
continue;
case END_DOCUMENT:
return true; // report error?
default: // new type
event = new Event();
}
add(event, type, reader);
}
return true; // report error?
}
public final XMLStreamReader play(final XMLStreamReader reader) {
return new RecordedEventXMLStreamReader(this) {
public void close() throws XMLStreamException {
reader.close();
}
public String getCharacterEncodingScheme() {
return reader.getCharacterEncodingScheme();
}
public String getEncoding() {
return reader.getEncoding();
}
public Object getProperty(String property) {
return reader.getProperty(property); // TODO javax.xml.stream.notations & javax.xml.stream.entities for DTD
}
public String getVersion() {
return reader.getVersion();
}
public boolean isStandalone() {
return reader.isStandalone();
}
public boolean standaloneSet() {
return reader.standaloneSet();
}
};
}
}
Event event;
final List events;
final int size;
protected RecordedEventXMLStreamReader(Tag tag) {
event = tag;
tag.type = START_ELEMENT;
events = tag.events;
size = events.size();
}
public int getAttributeCount() {
switch (getEventType()) {
case START_ELEMENT:
AttributeList attributes = ((StartElement) event).attributes;
return attributes == null ? 0 : attributes.getLength();
case ATTRIBUTE:
return ((AttributeEvent) event).attributes;
}
throw new IllegalStateException("Neither START_ELEMENT nor ATTRIBUTE");
}
protected final AttributeList attributes() {
if (getEventType() == START_ELEMENT)
return ((StartElement) event).attributes;
throw new IllegalStateException("Neither START_ELEMENT nor ATTRIBUTE");
}
public String getAttributeLocalName(int index) {
return attributes().getLocalName(index);
}
static Attribute attribute(AttributeList attributes, int index) {
return (Attribute) attributes.attributes.get(index);
}
public QName getAttributeName(int index) {
return getEventType() == ATTRIBUTE ? ((AttributeEvent) event).name : attribute(attributes(), index).qName;
}
public String getAttributeNamespace(int index) {
return getEventType() == ATTRIBUTE ? ((AttributeEvent) event).nameSpace : attributes().getURI(index);
}
public String getAttributePrefix(int index) {
return getEventType() == ATTRIBUTE ? ((AttributeEvent) event).prefix : attribute(attributes(), index).prefix;
}
public String getAttributeType(int index) {
return getEventType() == ATTRIBUTE ? ((Reference) event).target : attributes().getType(index);
}
public String getAttributeValue(int index) {
return getEventType() == ATTRIBUTE ? ((ValueEvent) event).value : attributes().getValue(index);
}
public boolean isAttributeSpecified(int index) {
if (getEventType() == ATTRIBUTE)
return ((AttributeEvent) event).specified;
AttributeList attributes = attributes();
return attribute(attributes, index).specified;
}
public String getAttributeValue(String nameSpace, String name) {
if (getEventType() == ATTRIBUTE) {
AttributeEvent attribute = (AttributeEvent) event;
return !attribute.name.getLocalPart().equals(name) ? null : nameSpace == null ? (attribute.nameSpace == null ? attribute.value : null)
: nameSpace.equals(attribute.nameSpace) ? attribute.value : null;
}
AttributeList attributes = attributes();
return attributes == null ? null : attributes.getValue(nameSpace == null ? "" : nameSpace, name);
}
protected StringBuffer buffer/* = null */;
public String getElementText() {
if (buffer != null)
buffer.delete(0, buffer.length());
for (;;)
switch (next()) {
case END_ELEMENT:
return buffer == null ? null : buffer.toString();
default:
if (buffer == null)
buffer = new StringBuffer();
buffer.append(getText());
case PROCESSING_INSTRUCTION:
case COMMENT:
}
}
public final int getEventType() {
return event.type;
}
public String getLocalName() {
if (getEventType() == ENTITY_REFERENCE)
return ((Reference) event).target;
if (event instanceof EndElement)
return ((EndElement) event).name.getLocalPart();
throw new IllegalStateException("Neither START_ELEMENT, END_ELEMENT nor ENTITY_REFERENCE");
}
public final Location getLocation() {
return event.location;
}
public QName getName() {
if (hasName())
return ((EndElement) event).name;
throw new IllegalStateException("Neither START_ELEMENT nor END_ELEMENT");
}
public final NamespaceContext getNamespaceContext() {
return event.nameSpaceContext;
}
public int getNamespaceCount() {
if (getEventType() == NAMESPACE)
return ((NameSpaceEvent) event).nameSpaces;
if (!(event instanceof EndElement))
throw new IllegalStateException("Neither START_ELEMENT, END_ELEMENT nor NAMESPACE");
Collection nameSpaces = ((EndElement) event).nameSpaces;
return nameSpaces == null ? 0 : nameSpaces.size();
}
protected final NameSpace getNameSpace(int index) {
if (event instanceof EndElement)
return (NameSpace) ((EndElement) event).nameSpaces.get(index);
throw new IllegalStateException("Neither START_ELEMENT, END_ELEMENT nor NAMESPACE");
}
public String getNamespacePrefix(int index) {
return getEventType() == NAMESPACE ? ((Reference) event).target : getNameSpace(index).prefix;
}
public final String getNamespaceURI() {
switch (getEventType()) {
case ATTRIBUTE:
return ((AttributeEvent) event).nameSpace;
case NAMESPACE:
return ((ValueEvent) event).value;
}
return event instanceof EndElement ? ((EndElement) event).nameSpace : null;
}
public String getNamespaceURI(String prefix) {
return getNamespaceContext().getNamespaceURI(prefix);
}
public String getNamespaceURI(int index) {
return getEventType() == NAMESPACE ? ((ValueEvent) event).value : getNameSpace(index).uri;
}
public String getPIData() {
return getEventType() == PROCESSING_INSTRUCTION ? ((ValueEvent) event).value : null;
}
public String getPITarget() {
return getEventType() == PROCESSING_INSTRUCTION ? ((Reference) event).target : null;
}
public String getPrefix() {
switch (getEventType()) {
case ATTRIBUTE:
return ((AttributeEvent) event).prefix;
case NAMESPACE:
return ((Reference) event).target;
}
return event instanceof EndElement ? ((EndElement) event).prefix : null;
}
public final String getText() {
if (hasText())
return ((ValueEvent) event).value;
throw new IllegalStateException("Neither CHARACTERS, CDATA, COMMENT, SPACE, ENTITY_REFERENCE nor DTD");
}
public final char[] getTextCharacters() {
switch (getEventType()) {
case CHARACTERS:
case CDATA:
case COMMENT:
case SPACE:
return ((ValueEvent) event).value.toCharArray();
}
throw new IllegalStateException("Neither CHARACTERS, CDATA, COMMENT nor SPACE");
}
public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) {
char[] source = getTextCharacters();
if (sourceStart > source.length)
throw new IndexOutOfBoundsException("source start > source length");
int sourceLen = source.length - sourceStart;
if (length > sourceLen)
length = sourceLen;
System.arraycopy(source, sourceStart, target, targetStart, length);
return sourceLen;
}
public int getTextLength() {
return getTextCharacters().length;
}
public int getTextStart() {
return 0;
}
public final boolean hasName() {
return event instanceof EndElement;
}
protected int next/* = 0 */;
public final boolean hasNext() {
return next != size;
}
public final boolean hasText() {
switch (getEventType()) {
case CHARACTERS:
case CDATA:
case COMMENT:
case SPACE:
case ENTITY_REFERENCE:
case DTD:
return true;
}
return false;
}
public boolean isCharacters() {
switch (getEventType()) {
case CHARACTERS:
case CDATA:
case SPACE:
return true;
}
return false;
}
public boolean isEndElement() {
return getEventType() == END_ELEMENT;
}
public boolean isStartElement() {
return getEventType() == START_ELEMENT;
}
protected final boolean areWhiteSpace() {
String text = getText();
for (int index = text.length(); index != 0;)
if (!Character.isWhitespace(text.charAt(--index)))
return false;
return true;
}
public boolean isWhiteSpace() {
switch (getEventType()) {
case CHARACTERS:
case CDATA:
return areWhiteSpace();
case SPACE:
return true;
}
return false;
}
public final int next() {
if (!hasNext())
throw new NoSuchElementException();
event = (Event) events.get(next++);
return event.type;
}
protected final void throwXMLStreamException(String message) throws XMLStreamException {
throw new XMLStreamException(message, getLocation());
}
public int nextTag() throws XMLStreamException {
for (;;) {
int type = next();
switch (type) {
case CHARACTERS:
case CDATA:
if (!areWhiteSpace())
break;
case SPACE:
case PROCESSING_INSTRUCTION:
case COMMENT:
continue;
case START_ELEMENT:
case END_ELEMENT:
return type;
}
throwXMLStreamException("expected start or end tag");
}
}
public void require(int type, String nameSpace, String name) throws XMLStreamException {
if (getEventType() != type)
throwXMLStreamException("type not matched");
if (nameSpace != null && !nameSpace.equals(getNamespaceURI()))
throwXMLStreamException("Name Space not matched");
if (name != null
&& !(getEventType() == ATTRIBUTE ? name.equals(((AttributeEvent) event).name.getLocalPart()) : event instanceof EndElement
&& name.equals(((EndElement) event).name.getLocalPart())))
throwXMLStreamException("name not matched");
}
}