/*******************************************************************************
* Copyright (c) 1998, 2009 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* mmacivor - September 14/2009 - 2.0 - Initial implementation
******************************************************************************/
package org.eclipse.persistence.internal.oxm.record;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.Comment;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.ProcessingInstruction;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.eclipse.persistence.oxm.XMLConstants;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.ext.LexicalHandler;
/**
* Convert and XMLEventReader into SAX events.
*/
public class XMLEventReaderReader extends XMLReader {
private ContentHandler contentHandler;
private LexicalHandler lexicalHandler;
private ErrorHandler errorHandler;
private int depth = 0;
//Required because the EndElement fails to properly won't give the list of namespaces going out of
//scope in some STAX implementations
private HashMap<Integer, ArrayList<Namespace>> namespaces;
public XMLEventReaderReader() {
this.namespaces = new HashMap<Integer, ArrayList<Namespace>>();
}
@Override
public ContentHandler getContentHandler() {
return contentHandler;
}
@Override
public void setContentHandler(ContentHandler aContentHandler) {
this.contentHandler = aContentHandler;
}
@Override
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@Override
public void setErrorHandler(ErrorHandler anErrorHandler) {
this.errorHandler = anErrorHandler;
}
@Override
public void setProperty (String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
if(name.equals("http://xml.org/sax/properties/lexical-handler")) {
lexicalHandler = (LexicalHandler)value;
}
}
@Override
public void parse(InputSource input) throws SAXException {
if(input instanceof XMLEventReaderInputSource) {
XMLEventReader xmlEventReader = ((XMLEventReaderInputSource) input).getXmlEventReader();
parse(xmlEventReader);
}
}
@Override
public void parse(InputSource input, SAXUnmarshallerHandler saxUnmarshallerHandler) throws SAXException {
if(input instanceof XMLEventReaderInputSource) {
XMLEventReader xmlEventReader = ((XMLEventReaderInputSource) input).getXmlEventReader();
//saxUnmarshallerHandler.setUnmarshalNamespaceResolver(new UnmarshalNamespaceContext(xmlEventReader));
parse(xmlEventReader);
}
}
public void parse(String systemId) throws SAXException {}
private void parse(XMLEventReader xmlEventReader) throws SAXException {
try {
getContentHandler().startDocument();
XMLEvent firstEvent = xmlEventReader.nextEvent();
parseEvent(firstEvent);
while(depth > 0 && xmlEventReader.hasNext()) {
XMLEvent xmlEvent = (XMLEvent)xmlEventReader.nextEvent();
parseEvent(xmlEvent);
}
getContentHandler().endDocument();
} catch(XMLStreamException ex) {
throw new RuntimeException(ex);
}
}
private void parseEvent(XMLEvent xmlEvent) throws SAXException {
if(null == getContentHandler()) {
return;
}
switch (xmlEvent.getEventType()) {
case XMLEvent.ATTRIBUTE: {
break;
}
case XMLEvent.CDATA: {
Characters characters = xmlEvent.asCharacters();
if(null == lexicalHandler) {
getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
} else {
lexicalHandler.startCDATA();
getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
lexicalHandler.endCDATA();
}
break;
}
case XMLEvent.CHARACTERS: {
Characters characters = xmlEvent.asCharacters();
getContentHandler().characters(characters.getData().toCharArray(), 0, characters.getData().length());
break;
}
case XMLEvent.COMMENT: {
if(null != lexicalHandler) {
Comment comment = (Comment)xmlEvent;
lexicalHandler.comment(comment.getText().toCharArray(), 0, comment.getText().length());
}
break;
}
case XMLEvent.DTD: {
break;
}
case XMLEvent.END_DOCUMENT: {
depth--;
return;
}
case XMLEvent.END_ELEMENT: {
ArrayList declaredNs = this.namespaces.get(new Integer(depth));
depth--;
EndElement endElement = xmlEvent.asEndElement();
QName name = endElement.getName();
String prefix = endElement.getName().getPrefix();
if(null == prefix || prefix.length() == 0) {
getContentHandler().endElement(name.getNamespaceURI(), name.getLocalPart(), name.getLocalPart());
} else {
getContentHandler().endElement(name.getNamespaceURI(), name.getLocalPart(), prefix + XMLConstants.COLON + name.getLocalPart());
}
if(declaredNs != null) {
Iterator iter = declaredNs.iterator();
while(iter.hasNext()) {
Namespace next = (Namespace)iter.next();
getContentHandler().endPrefixMapping(next.getPrefix());
}
}
break;
}
case XMLEvent.ENTITY_DECLARATION: {
break;
}
case XMLEvent.ENTITY_REFERENCE: {
break;
}
case XMLEvent.NAMESPACE: {
break;
}
case XMLEvent.NOTATION_DECLARATION: {
break;
}
case XMLEvent.PROCESSING_INSTRUCTION: {
ProcessingInstruction pi = (ProcessingInstruction)xmlEvent;
getContentHandler().processingInstruction(pi.getTarget(), pi.getData());
break;
}
case XMLEvent.SPACE: {
char[] characters = xmlEvent.asCharacters().getData().toCharArray();
getContentHandler().characters(characters, 0, characters.length);
break;
}
case XMLEvent.START_DOCUMENT: {
depth++;
break;
}
case XMLEvent.START_ELEMENT: {
depth++;
StartElement startElement = xmlEvent.asStartElement();
Iterator namespaces = startElement.getNamespaces();
ArrayList<Namespace> declaredNs = null;
if(namespaces.hasNext()) {
declaredNs = new ArrayList<Namespace>();
}
while(namespaces.hasNext()) {
Namespace next = (Namespace)namespaces.next();
getContentHandler().startPrefixMapping(next.getPrefix(), next.getNamespaceURI());
declaredNs.add(next);
}
if(declaredNs != null) {
this.namespaces.put(new Integer(depth), declaredNs);
}
QName qName = startElement.getName();
String prefix = qName.getPrefix();
if(null == prefix || prefix.length() == 0) {
getContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalPart(), qName.getLocalPart(), new IndexedAttributeList(startElement.getAttributes(), startElement.getNamespaces()));
} else {
getContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalPart(), prefix + XMLConstants.COLON + qName.getLocalPart(), new IndexedAttributeList(startElement.getAttributes(), startElement.getNamespaces()));
}
break;
}
}
}
private static class IndexedAttributeList implements Attributes {
private List<Attribute> attributes;
public IndexedAttributeList(Iterator attrs, Iterator namespaces) {
this.attributes = new ArrayList<Attribute>();
while(namespaces.hasNext()) {
Namespace next = (Namespace)namespaces.next();
String uri = XMLConstants.XMLNS_URL;
String localName = next.getPrefix();
String qName;
if(null == localName || localName.length() == 0) {
localName = XMLConstants.XMLNS;
qName = XMLConstants.XMLNS;
} else {
qName = XMLConstants.XMLNS + XMLConstants.COLON + localName;
}
String value = next.getNamespaceURI();
attributes.add(new Attribute(uri, localName, qName, value));
}
while(attrs.hasNext()) {
javax.xml.stream.events.Attribute next = (javax.xml.stream.events.Attribute)attrs.next();
String uri = next.getName().getNamespaceURI();
String localName = next.getName().getLocalPart();
String prefix = next.getName().getPrefix();
String qName;
if(null == prefix || prefix.length() == 0) {
qName = localName;
} else {
qName = prefix + XMLConstants.COLON + localName;
}
String value = next.getValue();
attributes.add(new Attribute(uri, localName, qName, value));
}
}
public int getIndex(String qName) {
if(null == qName) {
return -1;
}
int index = 0;
for(Attribute attribute : attributes) {
if(qName.equals(attribute.getName())) {
return index;
}
index++;
}
return -1;
}
public int getIndex(String uri, String localName) {
if(null == localName) {
return -1;
}
int index = 0;
for(Attribute attribute : attributes) {
QName testQName = new QName(uri, localName);
if(attribute.getQName().equals(testQName)) {
return index;
}
index++;
}
return -1;
}
public int getLength() {
return attributes.size();
}
public String getLocalName(int index) {
return attributes.get(index).getQName().getLocalPart();
}
public String getQName(int index) {
return attributes.get(index).getName();
}
public String getType(int index) {
return XMLConstants.CDATA;
}
public String getType(String name) {
return XMLConstants.CDATA;
}
public String getType(String uri, String localName) {
return XMLConstants.CDATA;
}
public String getURI(int index) {
return attributes.get(index).getQName().getNamespaceURI();
}
public String getValue(int index) {
return attributes.get(index).getValue();
}
public String getValue(String qName) {
int index = getIndex(qName);
if(-1 == index) {
return null;
}
return attributes.get(index).getValue();
}
public String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
if(-1 == index) {
return null;
}
return attributes.get(index).getValue();
}
}
private static class Attribute {
private QName qName;
private String name;
private String value;
public Attribute(String uri, String localName, String name, String value) {
this.qName = new QName(uri, localName);
this.name = name;
this.value = value;
}
public QName getQName() {
return qName;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
}
}