From 5d2e096f06d6cac9ed6ee18ad1cf716a09adc2b0 Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 30 Oct 2008 00:14:15 +0000 Subject: TUSCANY-2629 and TUSCANY-2624 - Enhancments to processor that handles unknown elements git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@709052 13f79535-47bb-0310-9956-ffa450edef68 --- .../processor/TuscanyNamespaceContext.java | 124 +++++++ .../processor/TuscanyXMLStreamReader.java | 112 ++++++ .../processor/ValidatingXMLStreamReader.java | 9 +- .../processor/ValidatingXMLStreamReader.java.orig | 388 +++++++++++++++++++++ 4 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyNamespaceContext.java create mode 100644 branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyXMLStreamReader.java create mode 100644 branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java.orig (limited to 'branches/sca-java-1.3.3/modules/contribution/src') diff --git a/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyNamespaceContext.java b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyNamespaceContext.java new file mode 100644 index 0000000000..8b1e40cee9 --- /dev/null +++ b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyNamespaceContext.java @@ -0,0 +1,124 @@ +package org.apache.tuscany.sca.contribution.processor; + +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Stack; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; + +@SuppressWarnings("unused") +public class TuscanyNamespaceContext implements NamespaceContext { + + private Stack>> context = null; + + public TuscanyNamespaceContext(Stack>> context){ + this.context = context; + } + + public String getNamespaceURI(String prefix) { + if (prefix == null) { + throw new IllegalArgumentException(); + } + return (String) getResult("getNSUri",prefix); + } + + public String getPrefix(String namespaceURI) { + if (namespaceURI == null) { + throw new IllegalArgumentException(); + } + return (String) getResult("getPrefix",namespaceURI); + } + + @SuppressWarnings("unchecked") + public Iterator getPrefixes(String namespaceURI) { + if (namespaceURI == null) { + throw new IllegalArgumentException(); + } + + Iterator iterator = new Itr((Iterator) getResult("getPrefixes",namespaceURI)); + return iterator; + } + + /* + * Generic method to Iterate through the Stack and return required result(s) + */ + private Object getResult(String operation,String arg){ + + ArrayList> contextList = null; + Iterator prefItr = null; + Iterator uriItr = null; + + List list = new ArrayList();; + + String toCompare = null; + + String tempPrefix = null; + String tempUri = null ; + + for(int i = context.size()-1; i>=0;i--){ + contextList = context.get(i); + prefItr = ((ArrayList)contextList.get(0)).iterator(); + uriItr = ((ArrayList)contextList.get(1)).iterator(); + for(int j = 0;uriItr.hasNext();j++){ + tempPrefix = (String) prefItr.next(); + tempUri = (String) uriItr.next(); + if(operation.equalsIgnoreCase("getNSUri")){ + toCompare = tempPrefix; + } + else if(operation.equalsIgnoreCase("getPrefix")){ + toCompare = tempUri; + } + else if(operation.equalsIgnoreCase("getPrefixes")){ + toCompare = tempUri; + } + if(toCompare != null && arg.equalsIgnoreCase(toCompare)){ + if(operation.equalsIgnoreCase("getNSUri")){ + return tempUri; + } + else if(operation.equalsIgnoreCase("getPrefix")){ + return tempPrefix; + } + else if(operation.equalsIgnoreCase("getPrefixes")){ + list.add(tempPrefix); + + } + + } + } + } + + if(operation.equalsIgnoreCase("getPrefixes")){ + return list.iterator(); + } + + return null; + } + + /* + * Custom implementation of the Iterator interface to override the behavior of the remove() method. + * The iterator should not be modifiable and invocation of the remove() method should throw UnsupportedOperationException. + */ + private class Itr implements Iterator{ + Iterator iterator = null; + + Itr(Iterator inputItr){ + this.iterator = inputItr; + } + + public boolean hasNext() { + return this.iterator.hasNext(); + } + + public E next() { + return (E) this.iterator.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } //end of class Itr + + +} //end of Class diff --git a/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyXMLStreamReader.java b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyXMLStreamReader.java new file mode 100644 index 0000000000..7aa6e518f4 --- /dev/null +++ b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/TuscanyXMLStreamReader.java @@ -0,0 +1,112 @@ +package org.apache.tuscany.sca.contribution.processor; +/* + * 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. + */ +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; +import javax.xml.XMLConstants; + +/* + * Custom implementaion of the XMLStreamReader to keep track of the namespace context for each element + */ +public class TuscanyXMLStreamReader extends StreamReaderDelegate implements + XMLStreamReader { + + Stack>> context = new Stack>>(); + + List contextList; + List prefixList; + List uriList; + + public TuscanyXMLStreamReader(XMLStreamReader reader) { + super(reader); + } + + public void pushContext() throws XMLStreamException { + contextList = new ArrayList>(); + prefixList = new ArrayList(); + uriList = new ArrayList(); + int namespaceCount = this.getNamespaceCount(); + if (namespaceCount == 0) { + prefixList.add(null); + uriList.add(null); + } + for (int i = 0; i < namespaceCount; i++) { + prefixList.add(checkString(this.getNamespacePrefix(i))); + uriList.add(this.getNamespaceURI(i)); + } + contextList.add(prefixList); + contextList.add(uriList); + context.push((ArrayList) contextList); + } + + private String checkString(String namespacePrefix) { + if (namespacePrefix == null) { + return XMLConstants.DEFAULT_NS_PREFIX; + } else { + return namespacePrefix; + } + } + + public void popContext() throws XMLStreamException { + context.pop(); + } + + /* + * Overriding the next() method to perform PUSH and POP operations + * for the NamespaceContext for the current element + */ + + @Override + public int next() throws XMLStreamException { + // POP the context if the element ends + if (this.getEventType() == END_ELEMENT) { + popContext(); + } + + //get the next event + int nextEvent = super.next(); + //PUSH the events info onto the Stack + if (nextEvent == START_ELEMENT) { + pushContext(); + } + return nextEvent; + } + + @Override + public int nextTag() throws XMLStreamException { + if (this.getEventType() == START_ELEMENT) { + pushContext(); + } + if (this.getEventType() == END_ELEMENT) { + popContext(); + } + return super.nextTag(); + } + + @Override + public NamespaceContext getNamespaceContext(){ + return new TuscanyNamespaceContext((Stack)context.clone()); + } +} diff --git a/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java index c136c62d33..3251ff37e1 100644 --- a/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java +++ b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java @@ -21,6 +21,7 @@ package org.apache.tuscany.sca.contribution.processor; import java.util.logging.Logger; +import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamConstants; @@ -47,7 +48,8 @@ import org.apache.tuscany.sca.monitor.Problem.Severity; * * @version $Rev$ $Date$ */ -class ValidatingXMLStreamReader extends StreamReaderDelegate implements XMLStreamReader { +class ValidatingXMLStreamReader extends TuscanyXMLStreamReader implements XMLStreamReader { + private static final Logger logger = Logger.getLogger(ValidatingXMLStreamReader.class.getName()); private int level; @@ -260,6 +262,11 @@ class ValidatingXMLStreamReader extends StreamReaderDelegate implements XMLStrea } } + @Override + public NamespaceContext getNamespaceContext(){ + return super.getNamespaceContext(); + } + /** * Handle a start element event. * diff --git a/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java.orig b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java.orig new file mode 100644 index 0000000000..2e86f1b4c5 --- /dev/null +++ b/branches/sca-java-1.3.3/modules/contribution/src/main/java/org/apache/tuscany/sca/contribution/processor/ValidatingXMLStreamReader.java.orig @@ -0,0 +1,388 @@ +/* + * 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.sca.contribution.processor; + +import java.util.logging.Logger; + +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; +import javax.xml.validation.Schema; +import javax.xml.validation.ValidatorHandler; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.apache.tuscany.sca.assembly.builder.impl.ProblemImpl; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; + +/** + * + * A validating XMLStreamReader that reports XMLSchema validation errors. + * + * @version $Rev: 667376 $ $Date: 2008-06-12 23:29:16 -0700 (Thu, 12 Jun 2008) $ + */ +class ValidatingXMLStreamReader extends StreamReaderDelegate implements XMLStreamReader { + private static final Logger logger = Logger.getLogger(ValidatingXMLStreamReader.class.getName()); + + private int level; + private ValidatorHandler handler; + private final Monitor monitor; + + /** + * Constructs a new ValidatingXMLStreamReader. + * + * @param reader + * @param schema + * @throws XMLStreamException + */ + ValidatingXMLStreamReader(XMLStreamReader reader, Schema schema, Monitor monitor) throws XMLStreamException { + super(reader); + this.monitor = monitor; + if (schema == null) { + return; + } + + handler = schema.newValidatorHandler(); + handler.setDocumentLocator(new LocatorAdapter()); + try { + handler.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + } catch (SAXException e) { + XMLStreamException xse = new XMLStreamException(e); + error("XMLStreamException", handler, xse); + throw xse; + } + + // These validation errors are just warnings for us as we want to support + // running from an XML document with XSD validation errors, as long as we can + // get the metadata we need from the document + handler.setErrorHandler(new ErrorHandler() { + private String getMessage(SAXParseException e) { + return "XMLSchema validation problem in: " + e.getSystemId() + ", line: " + e.getLineNumber() + ", column: " + e.getColumnNumber() + "\n" + e.getMessage(); + } + + public void error(SAXParseException exception) throws SAXException { + if (ValidatingXMLStreamReader.this.monitor == null) + logger.warning(getMessage(exception)); + else + ValidatingXMLStreamReader.this.error("SchemaError", ValidatingXMLStreamReader.this.getClass(), exception.getSystemId(), + exception.getLineNumber(), exception.getColumnNumber(), exception.getMessage()); + } + + public void fatalError(SAXParseException exception) throws SAXException { + if (ValidatingXMLStreamReader.this.monitor == null) + logger.warning(getMessage(exception)); + else + ValidatingXMLStreamReader.this.error("SchemaFatalError", ValidatingXMLStreamReader.this.getClass(), exception.getSystemId(), + exception.getLineNumber(), exception.getColumnNumber(), exception.getMessage()); + } + + public void warning(SAXParseException exception) throws SAXException { + if (ValidatingXMLStreamReader.this.monitor == null) + logger.warning(getMessage(exception)); + else + ValidatingXMLStreamReader.this.warning("SchemaWarning", ValidatingXMLStreamReader.this.getClass(), exception.getSystemId(), + exception.getLineNumber(), exception.getColumnNumber(), exception.getMessage()); + } + }); + } + + /** + * Report a warning. + * + * @param problems + * @param message + * @param model + */ + private void warning(String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = new ProblemImpl(this.getClass().getName(), "contribution-validation-messages", Severity.WARNING, model, message, (Object[])messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void error(String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = new ProblemImpl(this.getClass().getName(), "contribution-validation-messages", Severity.ERROR, model, message, (Object[])messageParameters); + monitor.problem(problem); + } + } + + @Override + public int next() throws XMLStreamException { + if (handler == null) { + return super.next(); + } + + int event = super.next(); + try { + switch (event) { + case XMLStreamConstants.START_DOCUMENT: + level++; + handler.startDocument(); + break; + case XMLStreamConstants.START_ELEMENT: + level++; + handleStartElement(); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + handler.processingInstruction(super.getPITarget(), super.getPIData()); + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.CDATA: + case XMLStreamConstants.SPACE: + case XMLStreamConstants.ENTITY_REFERENCE: + handler.characters(super.getTextCharacters(), super.getTextStart(), super.getTextLength()); + break; + case XMLStreamConstants.END_ELEMENT: + handleEndElement(); + level--; + break; + case XMLStreamConstants.END_DOCUMENT: + handler.endDocument(); + break; + } + } catch (SAXException e) { + XMLStreamException xse = new XMLStreamException(e.getMessage(), e); + error("XMLStreamException", handler, xse); + throw xse; + } + return event; + } + + @Override + public int nextTag() throws XMLStreamException { + if (handler == null) { + return super.nextTag(); + } + + for (;;) { + int event = super.getEventType(); + try { + switch (event) { + case XMLStreamConstants.START_DOCUMENT: + level++; + handler.startDocument(); + break; + case XMLStreamConstants.START_ELEMENT: + level++; + handleStartElement(); + return event; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + handler.processingInstruction(super.getPITarget(), super.getPIData()); + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.CDATA: + case XMLStreamConstants.SPACE: + case XMLStreamConstants.ENTITY_REFERENCE: + handler.characters(super.getTextCharacters(), super.getTextStart(), super.getTextLength()); + break; + case XMLStreamConstants.END_ELEMENT: + handleEndElement(); + level--; + return event; + case XMLStreamConstants.END_DOCUMENT: + handler.endDocument(); + return event; + } + } catch (SAXException e) { + XMLStreamException xse = new XMLStreamException(e); + error("XMLStreamException", handler, xse); + throw xse; + } + super.next(); + } + } + + @Override + public String getElementText() throws XMLStreamException { + if (handler == null) { + return super.getElementText(); + } + + if (getEventType() != XMLStreamConstants.START_ELEMENT) { + return super.getElementText(); + } + StringBuffer text = new StringBuffer(); + + for (;;) { + int event = next(); + switch (event) { + case XMLStreamConstants.END_ELEMENT: + return text.toString(); + + case XMLStreamConstants.COMMENT: + case XMLStreamConstants.PROCESSING_INSTRUCTION: + continue; + + case CHARACTERS: + case CDATA: + case SPACE: + case ENTITY_REFERENCE: + text.append(getText()); + break; + + default: + break; + } + } + } + + /** + * Handle a start element event. + * + * @throws SAXException + */ + private void handleStartElement() throws SAXException { + + // send startPrefixMapping events immediately before startElement event + int nsCount = super.getNamespaceCount(); + for (int i = 0; i < nsCount; i++) { + String prefix = super.getNamespacePrefix(i); + if (prefix == null) { // true for default namespace + prefix = ""; + } + handler.startPrefixMapping(prefix, super.getNamespaceURI(i)); + } + + // fire startElement + QName qname = super.getName(); + String prefix = qname.getPrefix(); + String rawname; + if (prefix == null || prefix.length() == 0) { + rawname = qname.getLocalPart(); + } else { + rawname = prefix + ':' + qname.getLocalPart(); + } + Attributes attrs = getAttributes(); + handler.startElement(qname.getNamespaceURI(), qname.getLocalPart(), rawname, attrs); + } + + /** + * Handle an endElement event. + * + * @throws SAXException + */ + private void handleEndElement() throws SAXException { + + // fire endElement + QName qname = super.getName(); + handler.endElement(qname.getNamespaceURI(), qname.getLocalPart(), qname.toString()); + + // send endPrefixMapping events immediately after endElement event + // we send them in the opposite order to that returned but this is not + // actually required by SAX + int nsCount = super.getNamespaceCount(); + for (int i = nsCount - 1; i >= 0; i--) { + String prefix = super.getNamespacePrefix(i); + if (prefix == null) { // true for default namespace + prefix = ""; + } + handler.endPrefixMapping(prefix); + } + } + + /** + * Get the attributes associated with the current START_ELEMENT event. + * + * @return the StAX attributes converted to org.xml.sax.Attributes + */ + private Attributes getAttributes() { + AttributesImpl attrs = new AttributesImpl(); + + // add namespace declarations + for (int i = 0; i < super.getNamespaceCount(); i++) { + String prefix = super.getNamespacePrefix(i); + String uri = super.getNamespaceURI(i); + if (prefix == null) { + attrs.addAttribute("", "", "xmlns", "CDATA", uri); + } else { + attrs.addAttribute("", "", "xmlns:" + prefix, "CDATA", uri); + } + } + + // Regular attributes + for (int i = 0; i < super.getAttributeCount(); i++) { + String uri = super.getAttributeNamespace(i); + if (uri == null) { + uri = ""; + } + String localName = super.getAttributeLocalName(i); + String prefix = super.getAttributePrefix(i); + String qname; + if (prefix == null || prefix.length() == 0) { + qname = localName; + } else { + qname = prefix + ':' + localName; + } + String type = super.getAttributeType(i); + String value = super.getAttributeValue(i); + + attrs.addAttribute(uri, localName, qname, type, value); + } + + return attrs; + } + + /** + * Adapter for mapping Locator information. + */ + private final class LocatorAdapter implements Locator { + + private LocatorAdapter() { + } + + public int getColumnNumber() { + Location location = getLocation(); + return location == null ? 0 : location.getColumnNumber(); + } + + public int getLineNumber() { + Location location = getLocation(); + return location == null ? 0 : location.getLineNumber(); + } + + public String getPublicId() { + Location location = getLocation(); + return location == null ? "" : location.getPublicId(); + } + + public String getSystemId() { + Location location = getLocation(); + return location == null ? "" : location.getSystemId(); + } + } + +} -- cgit v1.2.3