summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main')
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/XMLDocumentHelper.java153
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java231
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java244
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/sax/SAXHelper.java79
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java573
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/StAX2SAXAdapter.java256
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java368
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXMLStreamReader.java36
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXmlNodeImpl.java150
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DelegatingNamespaceContext.java310
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValueArrayStreamReader.java404
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValuePairStreamReader.java348
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamedProperty.java59
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamespaceContextImpl.java124
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NilElementStreamReader.java279
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/SimpleXmlNodeImpl.java112
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/WrappingXMLStreamReader.java100
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLDocumentStreamReader.java482
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReader.java53
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReaderImpl.java858
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLStreamable.java37
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNode.java69
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNodeIterator.java258
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderImpl.java531
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XMLCharHelper.java613
-rw-r--r--sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XPathHelper.java169
26 files changed, 6896 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/XMLDocumentHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/XMLDocumentHelper.java
new file mode 100644
index 0000000000..3bc24f8939
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/XMLDocumentHelper.java
@@ -0,0 +1,153 @@
+/*
+ * 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.common.xml;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.xml.sax.InputSource;
+
+/**
+ * @version $Rev$ $Date$]
+ * @tuscany.spi.extension.asclient
+ */
+public class XMLDocumentHelper {
+ protected static final int BUFFER_SIZE = 256;
+
+ /**
+ * Detect the XML encoding of the document
+ *
+ * @param is The input stream
+ * @return The encoding
+ * @throws IOException
+ */
+ public static String getEncoding(InputStream is) throws IOException {
+ if (!is.markSupported())
+ is = new BufferedInputStream(is);
+
+ byte[] buffer = readBuffer(is);
+ return getXMLEncoding(buffer);
+ }
+
+ /**
+ * Searches the array of bytes to determine the XML encoding.
+ */
+ protected static String getXMLEncoding(byte[] bytes) {
+ String javaEncoding = null;
+
+ if (bytes.length >= 4) {
+ if (((bytes[0] == -2) && (bytes[1] == -1)) || ((bytes[0] == 0) && (bytes[1] == 60)))
+ javaEncoding = "UnicodeBig";
+ else if (((bytes[0] == -1) && (bytes[1] == -2)) || ((bytes[0] == 60) && (bytes[1] == 0)))
+ javaEncoding = "UnicodeLittle";
+ else if ((bytes[0] == -17) && (bytes[1] == -69) && (bytes[2] == -65))
+ javaEncoding = "UTF8";
+ }
+
+ String header = null;
+
+ try {
+ if (javaEncoding != null)
+ header = new String(bytes, 0, bytes.length, javaEncoding);
+ else
+ header = new String(bytes, 0, bytes.length);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+
+ if (!header.startsWith("<?xml"))
+ return "UTF-8";
+
+ int endOfXMLPI = header.indexOf("?>");
+ int encodingIndex = header.indexOf("encoding", 6);
+
+ if ((encodingIndex == -1) || (encodingIndex > endOfXMLPI))
+ return "UTF-8";
+
+ int firstQuoteIndex = header.indexOf("\"", encodingIndex);
+ int lastQuoteIndex;
+
+ if ((firstQuoteIndex == -1) || (firstQuoteIndex > endOfXMLPI)) {
+ firstQuoteIndex = header.indexOf("'", encodingIndex);
+ lastQuoteIndex = header.indexOf("'", firstQuoteIndex + 1);
+ } else
+ lastQuoteIndex = header.indexOf("\"", firstQuoteIndex + 1);
+
+ return header.substring(firstQuoteIndex + 1, lastQuoteIndex);
+ }
+
+ protected static byte[] readBuffer(InputStream is) throws IOException {
+ if (is.available() == 0) {
+ return new byte[0];
+ }
+
+ byte[] buffer = new byte[BUFFER_SIZE];
+ is.mark(BUFFER_SIZE);
+ int bytesRead = is.read(buffer, 0, BUFFER_SIZE);
+ int totalBytesRead = bytesRead;
+
+ while (bytesRead != -1 && (totalBytesRead < BUFFER_SIZE)) {
+ bytesRead = is.read(buffer, totalBytesRead, BUFFER_SIZE - totalBytesRead);
+
+ if (bytesRead != -1)
+ totalBytesRead += bytesRead;
+ }
+
+ if (totalBytesRead < BUFFER_SIZE) {
+ byte[] smallerBuffer = new byte[totalBytesRead];
+ System.arraycopy(buffer, 0, smallerBuffer, 0, totalBytesRead);
+ smallerBuffer = buffer;
+ }
+
+ is.reset();
+ return buffer;
+ }
+
+ public static InputSource getInputSource(URL url) throws IOException {
+ InputStream is = openStream(url);
+ return getInputSource(url, is);
+ }
+
+ private static InputStream openStream(URL url) throws IOException {
+ URLConnection connection = url.openConnection();
+ if (connection instanceof JarURLConnection) {
+ // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041014
+ connection.setUseCaches(false);
+ }
+ InputStream is = connection.getInputStream();
+ return is;
+ }
+
+ public static InputSource getInputSource(URL url, InputStream is) throws IOException {
+ // is = new BufferedInputStream(is);
+ // String encoding = getEncoding(is);
+ InputSource inputSource = new InputSource(is);
+ // inputSource.setEncoding(encoding);
+ // [rfeng] Make sure we set the system id as it will be used as the base URI for nested import/include
+ inputSource.setSystemId(url.toString());
+ return inputSource;
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
new file mode 100644
index 0000000000..304275beb7
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java
@@ -0,0 +1,231 @@
+/*
+ * 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.common.xml.dom;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.tuscany.sca.common.xml.dom.impl.SAX2DOMAdapter;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * Helper for DOM
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public class DOMHelper {
+ private DocumentBuilderFactory documentBuilderFactory;
+ private TransformerFactory transformerFactory;
+
+ public static DOMHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilities.getUtility(DOMHelper.class);
+ }
+
+ public DOMHelper(ExtensionPointRegistry registry) {
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ documentBuilderFactory = factories.getFactory(DocumentBuilderFactory.class);
+ documentBuilderFactory.setNamespaceAware(true);
+ transformerFactory = factories.getFactory(TransformerFactory.class);
+ }
+
+ /**
+ * @param documentBuilderFactory
+ * @param transformerFactory
+ */
+ public DOMHelper(DocumentBuilderFactory documentBuilderFactory, TransformerFactory transformerFactory) {
+ super();
+ this.documentBuilderFactory = documentBuilderFactory;
+ this.transformerFactory = transformerFactory;
+ }
+
+ public Document newDocument() {
+ return newDocumentBuilder().newDocument();
+
+ }
+
+ public DocumentBuilder newDocumentBuilder() {
+ try {
+ return documentBuilderFactory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public Document load(String xmlString) throws IOException, SAXException {
+ DocumentBuilder builder = newDocumentBuilder();
+ InputSource is = new InputSource(new StringReader(xmlString));
+ return builder.parse(is);
+ }
+
+ public Document load(Source source) {
+ Transformer transformer = newTransformer();
+ DOMResult result = new DOMResult(newDocument());
+ try {
+ transformer.transform(source, result);
+ } catch (TransformerException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return (Document)result.getNode();
+ }
+
+ public NodeContentHandler createContentHandler(Node root) {
+ if (root == null) {
+ root = newDocument();
+ }
+ return new SAX2DOMAdapter(root);
+ }
+
+ public String saveAsString(Node node) {
+ Transformer transformer = newTransformer();
+ StringWriter sw = new StringWriter();
+ StreamResult result = new StreamResult(sw);
+ try {
+ transformer.transform(new DOMSource(node), result);
+ } catch (TransformerException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return result.getWriter().toString();
+ }
+
+ private Transformer newTransformer() {
+ Transformer transformer = null;
+ try {
+ transformer = transformerFactory.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return transformer;
+ }
+
+ public void saveAsSAX(Node node, ContentHandler contentHandler) {
+ Transformer transformer = newTransformer();
+ SAXResult result = new SAXResult(contentHandler);
+ try {
+ transformer.transform(new DOMSource(node), result);
+ } catch (TransformerException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static QName getQName(Node node) {
+ String ns = node.getNamespaceURI();
+ String prefix = node.getPrefix();
+ String localName = node.getLocalName();
+ if (localName == null) {
+ localName = node.getNodeName();
+ }
+ if (ns == null) {
+ ns = "";
+ }
+ if (prefix == null) {
+ prefix = "";
+ }
+ return new QName(ns, localName, prefix);
+ }
+
+ public static Element createElement(Document document, QName name) {
+ String prefix = name.getPrefix();
+ String qname =
+ (prefix != null && prefix.length() > 0) ? prefix + ":" + name.getLocalPart() : name.getLocalPart();
+ return document.createElementNS(name.getNamespaceURI(), qname);
+ }
+
+ /**
+ * Wrap an element as a DOM document
+ * @param node
+ * @return
+ */
+ public static Document promote(Node node) {
+ if (node instanceof Document) {
+ return (Document)node;
+ }
+ Element element = (Element)node;
+ Document doc = element.getOwnerDocument();
+ if (doc.getDocumentElement() == element) {
+ return doc;
+ }
+ doc = (Document)element.getOwnerDocument().cloneNode(false);
+ Element schema = (Element)doc.importNode(element, true);
+ doc.appendChild(schema);
+ Node parent = element.getParentNode();
+ while (parent instanceof Element) {
+ Element root = (Element)parent;
+ NamedNodeMap nodeMap = root.getAttributes();
+ for (int i = 0; i < nodeMap.getLength(); i++) {
+ Attr attr = (Attr)nodeMap.item(i);
+ String name = attr.getName();
+ if ("xmlns".equals(name) || name.startsWith("xmlns:")) {
+ if (schema.getAttributeNode(name) == null) {
+ schema.setAttributeNodeNS((Attr)doc.importNode(attr, true));
+ }
+ }
+ }
+ parent = parent.getParentNode();
+ }
+ return doc;
+ }
+
+ public static String getPrefix(Element element, String namespace) {
+ if (element.isDefaultNamespace(namespace)) {
+ return XMLConstants.DEFAULT_NS_PREFIX;
+ }
+ return element.lookupPrefix(namespace);
+ }
+
+ public static String getNamespaceURI(Element element, String prefix) {
+ if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
+ prefix = null;
+ }
+ return element.lookupNamespaceURI(prefix);
+ }
+
+ public static interface NodeContentHandler extends ContentHandler, LexicalHandler {
+ Node getNode();
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java
new file mode 100644
index 0000000000..11d692c81e
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.common.xml.dom.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper;
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper.NodeContentHandler;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * SAX2DOM adapter
+ *
+ * @version $Rev$ $Date$
+ */
+public class SAX2DOMAdapter implements DOMHelper.NodeContentHandler {
+ public static final String EMPTYSTRING = "";
+ public static final String XML_PREFIX = "xml";
+ public static final String XMLNS_PREFIX = "xmlns";
+ public static final String XMLNS_STRING = "xmlns:";
+ public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
+
+ private Node root;
+
+ private Document document;
+
+ private Node nextSibling;
+
+ private Stack<Node> nodeStk = new Stack<Node>();
+
+ private List<String> namespaceDecls;
+
+ private Node lastSibling;
+
+ public SAX2DOMAdapter(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ DOMHelper domHelper = utilities.getUtility(DOMHelper.class);
+ this.document = domHelper.newDocument();
+ this.root = document;
+ }
+
+ public SAX2DOMAdapter(Node root, Node nextSibling) {
+ this.root = root;
+ if (root instanceof Document) {
+ this.document = (Document)root;
+ } else if (root != null) {
+ this.document = root.getOwnerDocument();
+ }
+
+ this.nextSibling = nextSibling;
+ }
+
+ public SAX2DOMAdapter(Node root) {
+ this(root, null);
+ }
+
+ public Node getNode() {
+ return root;
+ }
+
+ public void characters(char[] ch, int start, int length) {
+ final Node last = nodeStk.peek();
+
+ // No text nodes can be children of root (DOM006 exception)
+ if (last != document) {
+ final String text = new String(ch, start, length);
+ if (lastSibling != null && lastSibling.getNodeType() == Node.TEXT_NODE) {
+ ((Text)lastSibling).appendData(text);
+ } else if (last == root && nextSibling != null) {
+ lastSibling = last.insertBefore(document.createTextNode(text), nextSibling);
+ } else {
+ lastSibling = last.appendChild(document.createTextNode(text));
+ }
+
+ }
+ }
+
+ public void startDocument() {
+ nodeStk.push(root);
+ }
+
+ public void endDocument() {
+ nodeStk.pop();
+ }
+
+ public void startElement(String namespace, String localName, String qName, Attributes attrs) {
+ final Element tmp = document.createElementNS(namespace, qName);
+
+ // Add namespace declarations first
+ if (namespaceDecls != null) {
+ final int nDecls = namespaceDecls.size();
+ for (int i = 0; i < nDecls; i++) {
+ final String prefix = namespaceDecls.get(i++);
+
+ if (prefix == null || prefix.equals(EMPTYSTRING)) {
+ tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX, namespaceDecls.get(i));
+ } else {
+ tmp.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix, namespaceDecls.get(i));
+ }
+ }
+ namespaceDecls.clear();
+ }
+
+ // Add attributes to element
+ final int nattrs = attrs.getLength();
+ for (int i = 0; i < nattrs; i++) {
+ if (attrs.getLocalName(i) == null) {
+ tmp.setAttribute(attrs.getQName(i), attrs.getValue(i));
+ } else {
+ tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i), attrs.getValue(i));
+ }
+ }
+
+ // Append this new node onto current stack node
+ Node last = nodeStk.peek();
+
+ // If the SAX2DOM is created with a non-null next sibling node,
+ // insert the result nodes before the next sibling under the root.
+ if (last == root && nextSibling != null) {
+ last.insertBefore(tmp, nextSibling);
+ } else {
+ last.appendChild(tmp);
+ }
+
+ // Push this node onto stack
+ nodeStk.push(tmp);
+ lastSibling = null;
+ }
+
+ public void endElement(String namespace, String localName, String qName) {
+ nodeStk.pop();
+ lastSibling = null;
+ }
+
+ public void startPrefixMapping(String prefix, String uri) {
+ if (namespaceDecls == null) {
+ namespaceDecls = new ArrayList<String>(2);
+ }
+ namespaceDecls.add(prefix);
+ namespaceDecls.add(uri);
+ }
+
+ public void endPrefixMapping(String prefix) {
+ // do nothing
+ }
+
+ /**
+ * This class is only used internally so this method should never be called.
+ */
+ public void ignorableWhitespace(char[] ch, int start, int length) {
+ }
+
+ /**
+ * adds processing instruction node to DOM.
+ */
+ public void processingInstruction(String target, String data) {
+ final Node last = nodeStk.peek();
+ ProcessingInstruction pi = document.createProcessingInstruction(target, data);
+ if (pi != null) {
+ if (last == root && nextSibling != null) {
+ last.insertBefore(pi, nextSibling);
+ } else {
+ last.appendChild(pi);
+ }
+
+ lastSibling = pi;
+ }
+ }
+
+ /**
+ * This class is only used internally so this method should never be called.
+ */
+ public void setDocumentLocator(Locator locator) {
+ }
+
+ /**
+ * This class is only used internally so this method should never be called.
+ */
+ public void skippedEntity(String name) {
+ }
+
+ /**
+ * Lexical Handler method to create comment node in DOM tree.
+ */
+ public void comment(char[] ch, int start, int length) {
+ final Node last = nodeStk.peek();
+ Comment comment = document.createComment(new String(ch, start, length));
+ if (comment != null) {
+ if (last == root && nextSibling != null) {
+ last.insertBefore(comment, nextSibling);
+ } else {
+ last.appendChild(comment);
+ }
+
+ lastSibling = comment;
+ }
+ }
+
+ // Lexical Handler methods- not implemented
+ public void startCDATA() {
+ }
+
+ public void endCDATA() {
+ }
+
+ public void startEntity(java.lang.String name) {
+ }
+
+ public void endDTD() {
+ }
+
+ public void endEntity(String name) {
+ }
+
+ public void startDTD(String name, String publicId, String systemId) throws SAXException {
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/sax/SAXHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/sax/SAXHelper.java
new file mode 100644
index 0000000000..dd22912b17
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/sax/SAXHelper.java
@@ -0,0 +1,79 @@
+/*
+ * 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.common.xml.sax;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Helper class for SAX parsing
+ */
+public class SAXHelper {
+ private final SAXParserFactory saxParserFactory;
+
+ /**
+ * @param saxParserFactory
+ */
+ public SAXHelper(SAXParserFactory saxParserFactory) {
+ super();
+ this.saxParserFactory = saxParserFactory;
+ }
+
+ public SAXHelper(ExtensionPointRegistry registry) {
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ saxParserFactory = factories.getFactory(SAXParserFactory.class);
+ saxParserFactory.setNamespaceAware(true);
+ }
+
+ public SAXHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilities.getUtility(SAXHelper.class);
+ }
+
+ public SAXParser newSAXParser() throws SAXException {
+ try {
+ return saxParserFactory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public XMLReader newXMLReader() throws SAXException {
+ return newSAXParser().getXMLReader();
+ }
+
+ public void parse(String xmlString, ContentHandler handler) throws SAXException, IOException {
+ XMLReader reader = newXMLReader();
+ reader.setContentHandler(handler);
+ reader.parse(new InputSource(new StringReader(xmlString)));
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java
new file mode 100644
index 0000000000..d7c85f01b5
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/StAXHelper.java
@@ -0,0 +1,573 @@
+/*
+ * 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.common.xml.stax;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.StreamFilter;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper;
+import org.apache.tuscany.sca.common.xml.stax.impl.StAX2SAXAdapter;
+import org.apache.tuscany.sca.common.xml.stax.impl.XMLStreamSerializer;
+import org.apache.tuscany.sca.common.xml.stax.reader.DOMXMLStreamReader;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Helper class for StAX
+ * @tuscany.spi.extension.asclient
+ */
+public class StAXHelper {
+ private final XMLInputFactory inputFactory;
+ private final XMLOutputFactory outputFactory;
+ private final DOMHelper domHelper;
+
+ public StAXHelper(ExtensionPointRegistry registry) {
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ factories.getFactory(XMLInputFactory.class);
+ inputFactory = factories.getFactory(XMLInputFactory.class);
+ outputFactory = factories.getFactory(XMLOutputFactory.class);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ domHelper = utilities.getUtility(DOMHelper.class);
+ }
+
+ public static StAXHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilities.getUtility(StAXHelper.class);
+ }
+
+ /**
+ * @param inputFactory
+ * @param outputFactory
+ * @param domHelper
+ */
+ public StAXHelper(XMLInputFactory inputFactory, XMLOutputFactory outputFactory, DOMHelper domHelper) {
+ super();
+ this.inputFactory = inputFactory;
+ this.outputFactory = outputFactory;
+ if (outputFactory != null) {
+ this.outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
+ }
+ this.domHelper = domHelper;
+ }
+
+ public XMLStreamReader createXMLStreamReader(InputStream inputStream) throws XMLStreamException {
+ return inputFactory.createXMLStreamReader(inputStream);
+ }
+
+ public XMLStreamReader createXMLStreamReader(Reader reader) throws XMLStreamException {
+ return inputFactory.createXMLStreamReader(reader);
+ }
+
+ public XMLStreamReader createXMLStreamReader(Source source) throws XMLStreamException {
+ return inputFactory.createXMLStreamReader(source);
+ }
+
+ public XMLStreamReader createXMLStreamReader(Node node) throws XMLStreamException {
+ /*
+ // DOMSource is not supported by the XMLInputFactory from JDK 6
+ DOMSource source = new DOMSource(node);
+ return createXMLStreamReader(source);
+ */
+ return new DOMXMLStreamReader(node);
+ }
+
+ public XMLStreamReader createXMLStreamReader(String string) throws XMLStreamException {
+ StringReader reader = new StringReader(string);
+ return createXMLStreamReader(reader);
+ }
+
+ private static InputStream openStream(URL url) throws IOException {
+ URLConnection connection = url.openConnection();
+ if (connection instanceof JarURLConnection) {
+ // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041014
+ connection.setUseCaches(false);
+ }
+ InputStream is = connection.getInputStream();
+ return is;
+ }
+
+ public XMLStreamReader createXMLStreamReader(URL url) throws XMLStreamException {
+ try {
+ // Set up a StreamSource from the url, since this has an associated URL that
+ // can be used by the parser to find references to other files such as DTDs
+ StreamSource scdlSource = new StreamSource( openStream(url), url.toString() );
+ return inputFactory.createXMLStreamReader(scdlSource);
+ } catch (IOException e) {
+ throw new XMLStreamException(e);
+ }
+ }
+
+ public String saveAsString(XMLStreamReader reader) throws XMLStreamException {
+ StringWriter writer = new StringWriter();
+ save(reader, writer);
+ return writer.toString();
+ }
+
+ public void save(XMLStreamReader reader, OutputStream outputStream) throws XMLStreamException {
+ XMLStreamWriter streamWriter = createXMLStreamWriter(outputStream);
+ save(reader, streamWriter);
+ }
+
+ public XMLStreamWriter createXMLStreamWriter(OutputStream outputStream) throws XMLStreamException {
+ return outputFactory.createXMLStreamWriter(outputStream);
+ }
+
+ public void save(XMLStreamReader reader, Writer writer) throws XMLStreamException {
+ XMLStreamWriter streamWriter = createXMLStreamWriter(writer);
+ save(reader, streamWriter);
+ }
+
+ public XMLStreamWriter createXMLStreamWriter(Writer writer) throws XMLStreamException {
+ return outputFactory.createXMLStreamWriter(writer);
+ }
+
+ public Node saveAsNode(XMLStreamReader reader) throws XMLStreamException {
+ // woodstox 3.2.4 fails due to http://jira.codehaus.org/browse/WSTX-144
+ // this issue has been fixed in woodstox 3.2.9
+ // We can use the commented code once we move to woodstox 3.2.9
+ /*
+ XMLStreamSerializer serializer = new XMLStreamSerializer();
+ Document document = domHelper.newDocument();
+ DOMResult result = new DOMResult(document);
+ XMLStreamWriter streamWriter = createXMLStreamWriter(result);
+ serializer.serialize(reader, streamWriter);
+ streamWriter.flush();
+ return result.getNode();
+ */
+ Document root = domHelper.newDocument();
+ ContentHandler handler = domHelper.createContentHandler(root);
+ try {
+ saveAsSAX(reader, handler);
+ } catch (SAXException e) {
+ throw new XMLStreamException(e);
+ }
+ return root;
+ }
+
+ public XMLStreamWriter createXMLStreamWriter(Result result) throws XMLStreamException {
+ return outputFactory.createXMLStreamWriter(result);
+ }
+
+ public void save(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces());
+ serializer.serialize(reader, writer);
+ writer.flush();
+ }
+
+ public void saveAsSAX(XMLStreamReader reader, ContentHandler contentHandler) throws XMLStreamException,
+ SAXException {
+ new StAX2SAXAdapter(false).parse(reader, contentHandler);
+ }
+
+ /**
+ * @param url
+ * @param element
+ * @param attribute
+ * @param rootOnly
+ * @return
+ * @throws IOException
+ * @throws XMLStreamException
+ */
+ public String readAttribute(URL url, QName element, String attribute) throws IOException, XMLStreamException {
+ if (attribute == null) {
+ attribute = "targetNamespace";
+ }
+ XMLStreamReader reader = createXMLStreamReader(url);
+ try {
+ return readAttributeFromRoot(reader, element, attribute);
+ } finally {
+ reader.close();
+ }
+ }
+
+ public List<String> readAttributes(URL url, QName element, String attribute) throws IOException, XMLStreamException {
+ if (attribute == null) {
+ attribute = "targetNamespace";
+ }
+ XMLStreamReader reader = createXMLStreamReader(url);
+ try {
+ Attribute attr = new Attribute(element, attribute);
+ return readAttributes(reader, attr)[0].getValues();
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Returns the boolean value of an attribute.
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static Boolean getAttributeAsBoolean(XMLStreamReader reader, String name) {
+ String value = reader.getAttributeValue(null, name);
+ if (value == null) {
+ return null;
+ }
+ return Boolean.valueOf(value);
+ }
+
+ /**
+ * Returns the QName value of an attribute.
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static QName getAttributeAsQName(XMLStreamReader reader, String name) {
+ String qname = reader.getAttributeValue(null, name);
+ return getValueAsQName(reader, qname);
+ }
+
+ /**
+ * Returns the value of an attribute as a list of QNames.
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static List<QName> getAttributeAsQNames(XMLStreamReader reader, String name) {
+ String value = reader.getAttributeValue(null, name);
+ if (value != null) {
+ List<QName> qnames = new ArrayList<QName>();
+ for (StringTokenizer tokens = new StringTokenizer(value); tokens.hasMoreTokens();) {
+ qnames.add(getValueAsQName(reader, tokens.nextToken()));
+ }
+ return qnames;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Returns a QName from a string.
+ * @param reader
+ * @param value
+ * @return
+ */
+ public static QName getValueAsQName(XMLStreamReader reader, String value) {
+ if (value != null) {
+ int index = value.indexOf(':');
+ String prefix = index == -1 ? "" : value.substring(0, index);
+ String localName = index == -1 ? value : value.substring(index + 1);
+ String ns = reader.getNamespaceContext().getNamespaceURI(prefix);
+ if (ns == null) {
+ ns = "";
+ }
+ return new QName(ns, localName, prefix);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the string value of an attribute.
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static String getAttributeAsString(XMLStreamReader reader, String name) {
+ return reader.getAttributeValue(null, name);
+ }
+
+ /**
+ * TUSCANY-242
+ *
+ * Returns the URI value of an attribute as a string and first applies the
+ * URI whitespace processing as defined in section 4.3.6 of XML Schema Part2: Datatypes
+ * [http://www.w3.org/TR/xmlschema-2/#rf-facets]. anyURI is defined with the following
+ * XSD:
+ * <xs:simpleType name="anyURI" id="anyURI">
+ * <xs:restriction base="xs:anySimpleType">
+ * <xs:whiteSpace value="collapse" fixed="true" id="anyURI.whiteSpace"/>
+ * </xs:restriction>
+ * </xs:simpleType>
+ *
+ * The <xs:whiteSpace value="collapse"/> constraining facet is defined as follows
+ *
+ * replace
+ * All occurrences of #x9 (tab), #xA (line feed) and #xD (carriage return) are replaced with #x20 (space)
+ * collapse
+ * After the processing implied by replace, contiguous sequences of #x20's are collapsed to a single #x20,
+ * and leading and trailing #x20's are removed
+ *
+ * It seems that the StAX parser does apply this rule so we do it here.
+ *
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static String getAttributeAsURIString(XMLStreamReader reader, String name) {
+ // get the basic string value
+ String uri = reader.getAttributeValue(null, name);
+
+ // apply the "collapse" rule
+ if (uri != null){
+ // turn tabs, line feeds and carriage returns into spaces
+ uri = uri.replace('\t', ' ');
+ uri = uri.replace('\n', ' ');
+ uri = uri.replace('\r', ' ');
+
+ // remote leading and trailing spaces. Other whitespace
+ // has already been converted to spaces above
+ uri = uri.trim();
+
+ // collapse any contiguous spaces into a single space
+ StringBuilder sb= new StringBuilder(uri.length());
+ boolean spaceFound= false;
+ for(int i=0; i< uri.length(); ++i){
+ char c= uri.charAt(i);
+ if(c == ' '){
+ if(!spaceFound){
+ sb.append(c);
+ spaceFound = true;
+ } else {
+ // collapse the space by ignoring it
+ }
+ }else{
+ sb.append(c);
+ spaceFound= false;
+ }
+ }
+ uri = sb.toString();
+ }
+
+ return uri;
+ }
+
+ /**
+ * Returns the value of xsi:type attribute
+ * @param reader The XML stream reader
+ * @return The QName of the type, if the attribute is not present, null is
+ * returned.
+ */
+ public static QName getXSIType(XMLStreamReader reader) {
+ String qname = reader.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type");
+ return getValueAsQName(reader, qname);
+ }
+
+ /**
+ * Test if an attribute is explicitly set
+ * @param reader
+ * @param name
+ * @return
+ */
+ public static boolean isAttributePresent(XMLStreamReader reader, String name) {
+ return reader.getAttributeValue(null, name) != null;
+ }
+
+ /**
+ * Advance the stream to the next END_ELEMENT event skipping any nested
+ * content.
+ * @param reader the reader to advance
+ * @throws XMLStreamException if there was a problem reading the stream
+ */
+ public static void skipToEndElement(XMLStreamReader reader) throws XMLStreamException {
+ int depth = 0;
+ while (reader.hasNext()) {
+ int event = reader.next();
+ if (event == XMLStreamConstants.START_ELEMENT) {
+ depth++;
+ } else if (event == XMLStreamConstants.END_ELEMENT) {
+ if (depth == 0) {
+ return;
+ }
+ depth--;
+ }
+ }
+ }
+
+ private Attribute[] readAttributes(XMLStreamReader reader, AttributeFilter filter) throws XMLStreamException {
+ XMLStreamReader newReader = inputFactory.createFilteredReader(reader, filter);
+ while (filter.proceed() && newReader.hasNext()) {
+ newReader.next();
+ }
+ return filter.attributes;
+ }
+
+ public Attribute[] readAttributes(URL url, Attribute... attributes) throws XMLStreamException {
+ XMLStreamReader reader = createXMLStreamReader(url);
+ try {
+ return readAttributes(reader, attributes);
+ } finally {
+ reader.close();
+ }
+ }
+
+ public Attribute[] readAttributes(XMLStreamReader reader, Attribute... attributes) throws XMLStreamException {
+ return readAttributes(reader, new AttributeFilter(false, attributes));
+ }
+
+ private String readAttributeFromRoot(XMLStreamReader reader, Attribute filter) throws XMLStreamException {
+ Attribute[] attrs = readAttributes(reader, new AttributeFilter(true, filter));
+ List<String> values = attrs[0].getValues();
+ if (values.isEmpty()) {
+ return null;
+ } else {
+ return values.get(0);
+ }
+ }
+
+ public String readAttributeFromRoot(XMLStreamReader reader, QName element, String attributeName)
+ throws XMLStreamException {
+ Attribute filter = new Attribute(element, attributeName);
+ return readAttributeFromRoot(reader, filter);
+ }
+
+ /**
+ *
+ * @tuscany.spi.extension.asclient
+ *
+ */
+ public static class Attribute {
+ private QName element;
+ private String name;
+ private List<String> values = new ArrayList<String>();
+
+ /**
+ * @param element
+ * @param name
+ */
+ public Attribute(QName element, String name) {
+ super();
+ this.element = element;
+ this.name = name;
+ }
+
+ public List<String> getValues() {
+ return values;
+ }
+
+ }
+
+ private static class AttributeFilter implements StreamFilter {
+ private boolean proceed = true;
+ private Attribute[] attributes;
+ private boolean rootOnly;
+
+ /**
+ * @param rootOnly
+ */
+ public AttributeFilter(boolean rootOnly, Attribute... attributes) {
+ super();
+ this.rootOnly = rootOnly;
+ this.attributes = attributes;
+ }
+
+ public boolean accept(XMLStreamReader reader) {
+ if (attributes == null || attributes.length == 0) {
+ proceed = false;
+ return true;
+ }
+ if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
+ QName name = reader.getName();
+ for (Attribute attr : attributes) {
+ if (attr.element.equals(name)) {
+ attr.values.add(reader.getAttributeValue(null, attr.name));
+ }
+ }
+ if (rootOnly) {
+ proceed = false;
+ }
+ }
+ return true;
+ }
+
+ public boolean proceed() {
+ return proceed;
+ }
+
+ }
+
+ public XMLInputFactory getInputFactory() {
+ return inputFactory;
+ }
+
+ private boolean isReparingNamespaces() {
+ if (outputFactory == null) {
+ return Boolean.TRUE;
+ }
+ return outputFactory.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES) == Boolean.TRUE;
+ }
+
+ public XMLOutputFactory getOutputFactory() {
+ return outputFactory;
+ }
+
+ public String writeAttribute(XMLStreamWriter writer, QName name, String value) throws XMLStreamException {
+ return writeAttribute(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI(), value);
+ }
+
+ public String writeAttribute(XMLStreamWriter writer,
+ String prefix,
+ String localName,
+ String namespaceURI,
+ String value) throws XMLStreamException {
+ if (value == null) {
+ return null;
+ }
+ XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces());
+ return serializer.writeAttribute(writer, prefix, localName, namespaceURI, value);
+ }
+
+ public void writeStartElement(XMLStreamWriter writer, QName name) throws XMLStreamException {
+ writeStartElement(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI());
+ }
+
+ public void writeStartElement(XMLStreamWriter writer, String prefix, String localName, String namespaceURI)
+ throws XMLStreamException {
+ XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces());
+ serializer.writeStartElement(writer, prefix, localName, namespaceURI);
+ }
+
+ public String writeNamespace(XMLStreamWriter writer, String prefix, String namespaceURI) throws XMLStreamException {
+ XMLStreamSerializer serializer = new XMLStreamSerializer(isReparingNamespaces());
+ return serializer.writeNamespace(writer, prefix, namespaceURI);
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/StAX2SAXAdapter.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/StAX2SAXAdapter.java
new file mode 100644
index 0000000000..df0fc069b6
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/StAX2SAXAdapter.java
@@ -0,0 +1,256 @@
+/*
+ * 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.common.xml.stax.impl;
+
+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 org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Adapter that converts from StAX to SAX event streams. Currently the following
+ * SAX events are not generated:
+ * <ul>
+ * <li>ignorableWhitespace</li>
+ * <li>skippedEntity</li>
+ * <ul>
+ * Also the following StAX events are not mapped:
+ * <ul>
+ * <li>CDATA</li>
+ * <li>COMMENT</li>
+ * <li>DTD</li>
+ * <li>ENTITY_DECLARATION</li>
+ * <li>ENTITY_REFERENCE</li>
+ * <li>NOTATION_DECLARATION</li>
+ * <li>SPACE</li>
+ * </ul>
+ * StAX ATTRIBUTE events are ignored but the equivalent attributes (derived from
+ * the START_ELEMENT event) are supplied in the SAX startElement event's
+ * Attributes parameter. If the adaptor is configured to pass namespace prefixes
+ * then namespace information will also be included in the Attributes; StAX
+ * NAMESPACE events are ignored. <p/> Another issue is namespace processing. If
+ * the reader is positioned at a sub-node, we cannot capture all the in-scope
+ * namespace bindings. Therefore we cannot re-create a proper SAX event stream
+ * from a StAX parser. <p/> For example <p/> &lt;a:root xmlns:a="foo"
+ * xmlns:b="bar"&gt;&lt;b:sub&gt;a:foo&lt;/b:sub&gt;&lt;/a:root&gt; <p/> And if
+ * you are handed a parser at &lt;b:sub&gt;, then your SAX events should look
+ * like: <p/> &lt;b:sub xmlns:a="foo" xmlns:b="bar"&gt;a:foo&lt;/b:sub&gt; <p/>
+ * not: <p/> &lt;b:sub&gt;a:foo&lt;/b:sub&gt; <p/> <p/> Proposal: we change the
+ * receiver of SAX events (SDOXMLResourceImpl) so that it uses NamespaceContext
+ * to resolve prefix (as opposed to record start/endPrefixMappings and use it
+ * for resolution.)
+ *
+ * @version $Rev$ $Date$
+ */
+public class StAX2SAXAdapter {
+ private final boolean namespacePrefixes;
+
+ /**
+ * Construct a new StAX to SAX adapter that will convert a StAX event stream
+ * into a SAX event stream.
+ *
+ * @param namespacePrefixes whether xmlns attributes should be included in
+ * startElement events;
+ */
+ public StAX2SAXAdapter(boolean namespacePrefixes) {
+ this.namespacePrefixes = namespacePrefixes;
+ }
+
+ /**
+ * Pull events from the StAX stream and dispatch to the SAX ContentHandler.
+ * The StAX stream would typically be located on a START_DOCUMENT or
+ * START_ELEMENT event and when this method returns it will be located on
+ * the associated END_DOCUMENT or END_ELEMENT event. Behaviour with other
+ * start events is undefined.
+ *
+ * @param reader StAX event source to read
+ * @param handler SAX ContentHandler for processing events
+ * @throws XMLStreamException if there was a problem reading the stream
+ * @throws SAXException passed through from the ContentHandler
+ */
+ public void parse(XMLStreamReader reader, ContentHandler handler) throws XMLStreamException, SAXException {
+ handler.setDocumentLocator(new LocatorAdaptor(reader.getLocation()));
+
+ // remembers the nest level of elements to know when we are done
+ int level = 0;
+ int event = reader.getEventType();
+ while (true) {
+ switch (event) {
+ case XMLStreamConstants.START_DOCUMENT:
+ level++;
+ handler.startDocument();
+ break;
+ case XMLStreamConstants.START_ELEMENT:
+ level++;
+ handleStartElement(reader, handler);
+ break;
+ case XMLStreamConstants.PROCESSING_INSTRUCTION:
+ handler.processingInstruction(reader.getPITarget(), reader.getPIData());
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ handler.characters(reader.getTextCharacters(), reader.getTextStart(), reader
+ .getTextLength());
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ handleEndElement(reader, handler);
+ level--;
+ if (level == 0) {
+ return;
+ }
+ break;
+ case XMLStreamConstants.END_DOCUMENT:
+ handler.endDocument();
+ return;
+ /*
+ * uncomment to handle all events rather than just mapped
+ * ones // StAX events that are not mapped to SAX case
+ * XMLStreamConstants.COMMENT: case
+ * XMLStreamConstants.SPACE: case
+ * XMLStreamConstants.ENTITY_REFERENCE: case
+ * XMLStreamConstants.DTD: case XMLStreamConstants.CDATA:
+ * case XMLStreamConstants.NOTATION_DECLARATION: case
+ * XMLStreamConstants.ENTITY_DECLARATION: break; // StAX
+ * events handled in START_ELEMENT case
+ * XMLStreamConstants.ATTRIBUTE: case
+ * XMLStreamConstants.NAMESPACE: break; default: throw new
+ * AssertionError("Unknown StAX event: " + event);
+ */
+ }
+ event = reader.next();
+ }
+ }
+
+ private void handleStartElement(XMLStreamReader reader, ContentHandler handler) throws SAXException {
+ // send startPrefixMapping events immediately before startElement event
+ int nsCount = reader.getNamespaceCount();
+ for (int i = 0; i < nsCount; i++) {
+ String prefix = reader.getNamespacePrefix(i);
+ if (prefix == null) { // true for default namespace
+ prefix = "";
+ }
+ handler.startPrefixMapping(prefix, reader.getNamespaceURI(i));
+ }
+
+ // fire startElement
+ QName qname = reader.getName();
+ String prefix = qname.getPrefix();
+ String rawname;
+ if (prefix == null || prefix.length() == 0) {
+ rawname = qname.getLocalPart();
+ } else {
+ rawname = prefix + ':' + qname.getLocalPart();
+ }
+ Attributes attrs = getAttributes(reader);
+ handler.startElement(qname.getNamespaceURI(), qname.getLocalPart(), rawname, attrs);
+ }
+
+ private static void handleEndElement(XMLStreamReader reader, ContentHandler handler) throws SAXException {
+ // fire endElement
+ QName qname = reader.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 = reader.getNamespaceCount();
+ for (int i = nsCount - 1; i >= 0; i--) {
+ String prefix = reader.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(XMLStreamReader reader) {
+ assert reader.getEventType() == XMLStreamConstants.START_ELEMENT;
+
+ AttributesImpl attrs = new AttributesImpl();
+
+ // add namespace declarations if required
+ if (namespacePrefixes) {
+ for (int i = 0; i < reader.getNamespaceCount(); i++) {
+ String prefix = reader.getNamespacePrefix(i);
+ String uri = reader.getNamespaceURI(i);
+ attrs.addAttribute(null, prefix, "xmlns:" + prefix, "CDATA", uri);
+ }
+ }
+
+ // Regular attributes
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ String uri = reader.getAttributeNamespace(i);
+ if (uri == null) {
+ uri = "";
+ }
+ String localName = reader.getAttributeLocalName(i);
+ String prefix = reader.getAttributePrefix(i);
+ String qname;
+ if (prefix == null || prefix.length() == 0) {
+ qname = localName;
+ } else {
+ qname = prefix + ':' + localName;
+ }
+ String type = reader.getAttributeType(i);
+ String value = reader.getAttributeValue(i);
+
+ attrs.addAttribute(uri, localName, qname, type, value);
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Adaptor for mapping Locator information.
+ */
+ private static final class LocatorAdaptor implements Locator {
+ private final Location location;
+
+ private LocatorAdaptor(Location location) {
+ this.location = location;
+ }
+
+ public int getColumnNumber() {
+ return location == null ? 0 : location.getColumnNumber();
+ }
+
+ public int getLineNumber() {
+ return location == null ? 0 : location.getLineNumber();
+ }
+
+ public String getPublicId() {
+ return location == null ? "" : location.getPublicId();
+ }
+
+ public String getSystemId() {
+ return location == null ? "" : location.getSystemId();
+ }
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java
new file mode 100644
index 0000000000..883199e4dd
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/impl/XMLStreamSerializer.java
@@ -0,0 +1,368 @@
+/*
+ * 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.common.xml.stax.impl;
+
+import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX;
+import static javax.xml.XMLConstants.NULL_NS_URI;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * The XMLStreamSerializer pulls events from the XMLStreamReader and dumps into the XMLStreamWriter
+ *
+ * @version $Rev$ $Date$
+ */
+public class XMLStreamSerializer implements XMLStreamConstants {
+ public static final String NAMESPACE_PREFIX = "ns";
+ private static int namespaceSuffix;
+
+ /*
+ * The behavior of the Serializer is such that it returns when it encounters the starting element for the second
+ * time. The depth variable tracks the depth of the Serializer and tells it when to return. Note that it is assumed
+ * that this Serialization starts on an Element.
+ */
+
+ /**
+ * Field depth
+ */
+ private int depth;
+
+ /**
+ * A flag to tell if the writer has javax.xml.stream.isRepairingNamespaces set to true
+ */
+ private boolean isRepairingNamespaces = true;
+
+ /**
+ * @param isRepairingNamespaces
+ */
+ public XMLStreamSerializer(boolean isRepairingNamespaces) {
+ super();
+ this.isRepairingNamespaces = isRepairingNamespaces;
+ }
+
+ public XMLStreamSerializer() {
+ this(true);
+ }
+
+ /**
+ * Generates a unique namespace prefix that is not in the scope of the NamespaceContext
+ *
+ * @param nsCtxt
+ * @return string
+ */
+ private String generateUniquePrefix(NamespaceContext nsCtxt) {
+ String prefix = NAMESPACE_PREFIX + namespaceSuffix++;
+ // null should be returned if the prefix is not bound!
+ while (nsCtxt.getNamespaceURI(prefix) != null) {
+ prefix = NAMESPACE_PREFIX + namespaceSuffix++;
+ }
+
+ return prefix;
+ }
+
+ /**
+ * Method serialize.
+ *
+ * @param node
+ * @param writer
+ * @throws XMLStreamException
+ */
+ public void serialize(XMLStreamReader node, XMLStreamWriter writer) throws XMLStreamException {
+ serializeNode(node, writer);
+ }
+
+ /**
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeAttributes(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ int count = reader.getAttributeCount();
+ String prefix;
+ String namespaceName;
+ String localName;
+ String value;
+ for (int i = 0; i < count; i++) {
+ prefix = reader.getAttributePrefix(i);
+ namespaceName = reader.getAttributeNamespace(i);
+ localName = reader.getAttributeLocalName(i);
+ value = reader.getAttributeValue(i);
+
+ writeAttribute(writer, prefix, localName, namespaceName, value);
+
+ }
+ }
+
+ public void writeAttribute(XMLStreamWriter writer, QName name, String value) throws XMLStreamException {
+ writeAttribute(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI(), value);
+ }
+
+ public String writeAttribute(XMLStreamWriter writer,
+ String prefix,
+ String localName,
+ String namespaceURI,
+ String value) throws XMLStreamException {
+ String writerPrefix;
+ /*
+ * Due to parser implementations returning null as the namespace URI (for the empty namespace) we need to
+ * make sure that we deal with a namespace name that is not null. The best way to work around this issue is
+ * to set the namespace URI to "" if it is null
+ */
+ if (namespaceURI == null) {
+ namespaceURI = NULL_NS_URI;
+ }
+
+ if (prefix == null) {
+ prefix = DEFAULT_NS_PREFIX;
+ }
+
+ if (isRepairingNamespaces) {
+ writer.writeAttribute(prefix, namespaceURI, localName, value);
+ return writer.getPrefix(namespaceURI);
+ }
+
+ writerPrefix = writer.getPrefix(namespaceURI);
+
+ if (!NULL_NS_URI.equals(namespaceURI)) {
+ if (writerPrefix != null && isDefaultNSPrefix(prefix)) {
+ // prefix has already being declared but this particular attrib has a
+ // no prefix attached. So use the prefix provided by the writer
+
+ writer.writeAttribute(writerPrefix, namespaceURI, localName, value);
+ return writerPrefix;
+
+ } else if (!isDefaultNSPrefix(prefix) && !prefix.equals(writerPrefix)) {
+ // writer prefix is available but different from the current
+ // prefix of the attrib. We should be declaring the new prefix
+ // as a namespace declaration
+
+ writer.writeNamespace(prefix, namespaceURI);
+ writer.writeAttribute(prefix, namespaceURI, localName, value);
+ return prefix;
+
+ } else if (isDefaultNSPrefix(prefix)) {
+ // prefix is null (or empty), but the namespace name is valid! it has not
+ // being written previously also. So we need to generate a prefix here
+
+ prefix = generateUniquePrefix(writer.getNamespaceContext());
+ writer.writeNamespace(prefix, namespaceURI);
+ writer.writeAttribute(prefix, namespaceURI, localName, value);
+ return prefix;
+ } else {
+ writer.writeAttribute(prefix, namespaceURI, localName, value);
+ return prefix;
+ }
+ } else {
+ // empty namespace is equal to no namespace!
+ writer.writeAttribute(localName, value);
+ return prefix;
+ }
+ }
+
+ private boolean isDefaultNSPrefix(String prefix) {
+ return (prefix == null || prefix.equals(DEFAULT_NS_PREFIX));
+ }
+
+ /**
+ * Method serializeCData.
+ *
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeCData(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeCData(reader.getText());
+ }
+
+ /**
+ * Method serializeComment.
+ *
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeComment(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeComment(reader.getText());
+ }
+
+ /**
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeElement(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ writeStartElement(writer, reader.getName());
+
+ // add the namespaces
+ int count = reader.getNamespaceCount();
+ String namespacePrefix;
+ for (int i = 0; i < count; i++) {
+ namespacePrefix = reader.getNamespacePrefix(i);
+ serializeNamespace(namespacePrefix, reader.getNamespaceURI(i), writer);
+ }
+
+ // add attributes
+ serializeAttributes(reader, writer);
+
+ }
+
+ public void writeStartElement(XMLStreamWriter writer, QName name) throws XMLStreamException {
+ writeStartElement(writer, name.getPrefix(), name.getLocalPart(), name.getNamespaceURI());
+ }
+
+ public void writeStartElement(XMLStreamWriter writer, String prefix, String localName, String namespaceURI)
+ throws XMLStreamException {
+
+ if (namespaceURI == null) {
+ namespaceURI = NULL_NS_URI;
+ }
+ if (prefix == null) {
+ prefix = DEFAULT_NS_PREFIX;
+ }
+
+ if (isRepairingNamespaces) {
+ writer.writeStartElement(prefix, localName, namespaceURI);
+ return;
+ }
+
+ String writerPrefix = writer.getPrefix(namespaceURI);
+ if (writerPrefix != null) {
+ // Namespace is bound
+ writer.writeStartElement(writerPrefix, localName, namespaceURI);
+ } else {
+ // Namespace is not bound
+ if (NULL_NS_URI.equals(namespaceURI)) {
+ writer.writeStartElement(localName);
+ String defaultNS = writer.getNamespaceContext().getNamespaceURI(DEFAULT_NS_PREFIX);
+ if (defaultNS != null && !NULL_NS_URI.equals(defaultNS)) {
+ writer.writeNamespace(prefix, namespaceURI);
+ }
+ } else {
+ writer.writeStartElement(prefix, localName, namespaceURI);
+ // writeNamespace() will call setPrefix()
+ writer.writeNamespace(prefix, namespaceURI);
+ }
+ }
+ }
+
+ /**
+ * Method serializeEndElement.
+ *
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeEndElement(XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeEndElement();
+ }
+
+ /**
+ * Method serializeNamespace.
+ *
+ * @param prefix
+ * @param uri
+ * @param writer
+ * @throws XMLStreamException
+ */
+ private void serializeNamespace(String prefix, String uri, XMLStreamWriter writer) throws XMLStreamException {
+ writeNamespace(writer, prefix, uri);
+ }
+
+ public String writeNamespace(XMLStreamWriter writer, String prefix, String uri) throws XMLStreamException {
+ if (uri == null) {
+ uri = NULL_NS_URI;
+ }
+ String prefix1 = writer.getPrefix(uri);
+ if (prefix1 == null) {
+ if (prefix == null) {
+ prefix = DEFAULT_NS_PREFIX;
+ }
+ if (DEFAULT_NS_PREFIX.equals(prefix) && !XMLConstants.NULL_NS_URI.equals(uri)) {
+ String ns = writer.getNamespaceContext().getNamespaceURI(prefix);
+ if (ns != null) {
+ prefix = generateUniquePrefix(writer.getNamespaceContext());
+ }
+ }
+ writer.writeNamespace(prefix, uri);
+ return prefix;
+ } else {
+ return prefix1;
+ }
+ }
+
+ /**
+ * Method serializeNode.
+ *
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeNode(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ while (true) {
+ int event = reader.getEventType();
+ if (event == START_ELEMENT) {
+ serializeElement(reader, writer);
+ depth++;
+ } else if (event == ATTRIBUTE) {
+ serializeAttributes(reader, writer);
+ } else if (event == CHARACTERS) {
+ serializeText(reader, writer);
+ } else if (event == COMMENT) {
+ serializeComment(reader, writer);
+ } else if (event == CDATA) {
+ serializeCData(reader, writer);
+ } else if (event == END_ELEMENT) {
+ serializeEndElement(writer);
+ depth--;
+ } else if (event == START_DOCUMENT) {
+ depth++; // if a start document is found then increment
+ writer.writeStartDocument();
+ // the depth
+ } else if (event == END_DOCUMENT) {
+ if (depth != 0) {
+ depth--; // for the end document - reduce the depth
+ }
+ writer.writeEndDocument();
+ }
+ if (depth == 0) {
+ break;
+ }
+ if (reader.hasNext()) {
+ reader.next();
+ } else {
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param reader
+ * @param writer
+ * @throws XMLStreamException
+ */
+ protected void serializeText(XMLStreamReader reader, XMLStreamWriter writer) throws XMLStreamException {
+ writer.writeCharacters(reader.getText());
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXMLStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXMLStreamReader.java
new file mode 100644
index 0000000000..b0224b6ca5
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXMLStreamReader.java
@@ -0,0 +1,36 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import org.w3c.dom.Node;
+
+public class DOMXMLStreamReader extends XmlTreeStreamReaderImpl {
+
+ public DOMXMLStreamReader(Node node) {
+ super(new DOMXmlNodeImpl(node));
+ switch (node.getNodeType()) {
+ case Node.DOCUMENT_NODE:
+ break;
+ case Node.ELEMENT_NODE:
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal node type: " + node);
+ }
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXmlNodeImpl.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXmlNodeImpl.java
new file mode 100644
index 0000000000..faa56701ad
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DOMXmlNodeImpl.java
@@ -0,0 +1,150 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class DOMXmlNodeImpl implements XmlNode {
+ private Node node;
+ private Map<String, String> namespaces;
+ private Type type;
+
+ /**
+ * @param element
+ */
+ public DOMXmlNodeImpl(Node element) {
+ super();
+ if (element.getNodeType() == Node.DOCUMENT_NODE) {
+ this.node = ((Document)element).getDocumentElement();
+ } else {
+ this.node = element;
+ }
+ switch (node.getNodeType()) {
+ case Node.CDATA_SECTION_NODE:
+ this.type = Type.CHARACTERS;
+ break;
+ case Node.ELEMENT_NODE:
+ this.type = Type.ELEMENT;
+ break;
+ case Node.TEXT_NODE:
+ this.type = Type.CHARACTERS;
+ break;
+ }
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#attributes()
+ */
+ public List<XmlNode> attributes() {
+ if (type != Type.ELEMENT) {
+ return null;
+ }
+ NamedNodeMap attrs = node.getAttributes();
+ List<XmlNode> xmlAttrs = new ArrayList<XmlNode>();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr)attrs.item(i);
+ if (!attr.getName().equals("xmlns") && !attr.getName().startsWith("xmlns:")) {
+ xmlAttrs.add(new SimpleXmlNodeImpl(getQName(attr), attr.getValue(), XmlNode.Type.ATTRIBUTE));
+ }
+ }
+ return xmlAttrs;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#children()
+ */
+ public Iterator<XmlNode> children() {
+ if (type != Type.ELEMENT) {
+ return null;
+ }
+ NodeList nodes = node.getChildNodes();
+ List<XmlNode> xmlNodes = new ArrayList<XmlNode>();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node child = (Node)nodes.item(i);
+ int nodeType = child.getNodeType();
+ if (nodeType == Node.ELEMENT_NODE || nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) {
+ xmlNodes.add(new DOMXmlNodeImpl(child));
+ }
+ }
+ return xmlNodes.iterator();
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#getName()
+ */
+ public QName getName() {
+ return getQName(node);
+ }
+
+ private static QName getQName(Node node) {
+ return DOMHelper.getQName(node);
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#getValue()
+ */
+ public String getValue() {
+ return node.getNodeValue();
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#namespaces()
+ */
+ public Map<String, String> namespaces() {
+ if (type != Type.ELEMENT) {
+ return null;
+ }
+ if (namespaces == null) {
+ namespaces = new HashMap<String, String>();
+ NamedNodeMap attrs = node.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr)attrs.item(i);
+ if ("xmlns".equals(attr.getPrefix())) {
+ namespaces.put(attr.getLocalName(), attr.getValue());
+ }
+ if ("xmlns".equals(attr.getName())) {
+ namespaces.put("", attr.getValue());
+ }
+ }
+ }
+ return namespaces;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DelegatingNamespaceContext.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DelegatingNamespaceContext.java
new file mode 100644
index 0000000000..8f136df7df
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/DelegatingNamespaceContext.java
@@ -0,0 +1,310 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.NamespaceContext;
+
+public class DelegatingNamespaceContext implements NamespaceContext {
+ private static int count;
+
+ private class WrappingIterator implements Iterator {
+
+ private Iterator containedIterator;
+
+ public WrappingIterator(Iterator containedIterator) {
+ this.containedIterator = containedIterator;
+ }
+
+ public Iterator getContainedIterator() {
+ return containedIterator;
+ }
+
+ public boolean hasNext() {
+ return containedIterator.hasNext();
+ }
+
+ public Object next() {
+ return containedIterator.next();
+ }
+
+ /**
+ * As per the contract on the API of Namespace context the returned iterator should be immutable
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setContainedIterator(Iterator containedIterator) {
+ this.containedIterator = containedIterator;
+ }
+ }
+
+ private NamespaceContext parentNsContext;
+
+ private FastStack<String> prefixStack = new FastStack<String>();
+
+ // Keep two ArrayLists for the prefixes and namespaces. They should be in
+ // sync
+ // since the index of the entry will be used to relate them
+ // use the minimum initial capacity to let things handle memory better
+
+ private FastStack<String> uriStack = new FastStack<String>();
+
+ /**
+ * Generates a unique namespace prefix that is not in the scope of the NamespaceContext
+ *
+ * @return string
+ */
+ public String generateUniquePrefix() {
+ String prefix = "p" + count++;
+ // null should be returned if the prefix is not bound!
+ while (getNamespaceURI(prefix) != null) {
+ prefix = "p" + count++;
+ }
+
+ return prefix;
+ }
+
+ public String getNamespaceURI(String prefix) {
+ // do the corrections as per the Javadoc
+ int index = prefixStack.search(prefix);
+ if (index != -1) {
+ return uriStack.get(index);
+ }
+ if (parentNsContext != null) {
+ return parentNsContext.getPrefix(prefix);
+ }
+ return null;
+ }
+
+ public NamespaceContext getParentNsContext() {
+ return parentNsContext;
+ }
+
+ public String getPrefix(String uri) {
+ // do the corrections as per the Javadoc
+ int index = uriStack.search(uri);
+ if (index != -1) {
+ return prefixStack.get(index);
+ }
+
+ if (parentNsContext != null) {
+ return parentNsContext.getPrefix(uri);
+ }
+ return null;
+ }
+
+ public Iterator getPrefixes(String uri) {
+ // create an ArrayList that contains the relevant prefixes
+ String[] uris = uriStack.toArray(new String[uriStack.size()]);
+ List<String> tempList = new ArrayList<String>();
+ for (int i = uris.length - 1; i >= 0; i--) {
+ if (uris[i].equals(uri)) {
+ tempList.add(prefixStack.get(i));
+ // we assume that array conversion preserves the order
+ }
+ }
+ // by now all the relevant prefixes are collected
+ // make a new iterator and provide a wrapper iterator to
+ // obey the contract on the API
+ return new WrappingIterator(tempList.iterator());
+ }
+
+ /**
+ * Pop a namespace
+ */
+ public void popNamespace() {
+ prefixStack.pop();
+ uriStack.pop();
+ }
+
+ /**
+ * Register a namespace in this context
+ *
+ * @param prefix
+ * @param uri
+ */
+ public void pushNamespace(String prefix, String uri) {
+ prefixStack.push(prefix);
+ uriStack.push(uri);
+
+ }
+
+ public void setParentNsContext(NamespaceContext parentNsContext) {
+ this.parentNsContext = parentNsContext;
+ }
+
+ /**
+ * An implementation of the {@link java.util.Stack} API that is based on an <code>ArrayList</code> instead of a
+ * <code>Vector</code>, so it is not synchronized to protect against multi-threaded access. The implementation is
+ * therefore operates faster in environments where you do not need to worry about multiple thread contention.
+ * <p>
+ * The removal order of an <code>ArrayStack</code> is based on insertion order: The most recently added element is
+ * removed first. The iteration order is <i>not</i> the same as the removal order. The iterator returns elements
+ * from the bottom up, whereas the {@link #remove()} method removes them from the top down.
+ * <p>
+ * Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
+ */
+ public static class FastStack<T> extends ArrayList<T> {
+
+ /** Ensure Serialization compatibility */
+ private static final long serialVersionUID = 2130079159931574599L;
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code>. The initial size is controlled by <code>ArrayList</code>
+ * and is currently 10.
+ */
+ public FastStack() {
+ super();
+ }
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code> with an initial size.
+ *
+ * @param initialSize the initial size to use
+ * @throws IllegalArgumentException if the specified initial size is negative
+ */
+ public FastStack(int initialSize) {
+ super(initialSize);
+ }
+
+ /**
+ * Return <code>true</code> if this stack is currently empty.
+ * <p>
+ * This method exists for compatibility with <code>java.util.Stack</code>. New users of this class should use
+ * <code>isEmpty</code> instead.
+ *
+ * @return true if the stack is currently empty
+ */
+ public boolean empty() {
+ return isEmpty();
+ }
+
+ /**
+ * Returns the top item off of this stack without removing it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T peek() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(n - 1);
+ }
+ }
+
+ /**
+ * Returns the n'th item down (zero-relative) from the top of this stack without removing it.
+ *
+ * @param n the number of items down to go
+ * @return the n'th item on the stack, zero relative
+ * @throws EmptyStackException if there are not enough items on the stack to satisfy this request
+ */
+ public T peek(int n) throws EmptyStackException {
+ int m = (size() - n) - 1;
+ if (m < 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(m);
+ }
+ }
+
+ /**
+ * Pops the top item off of this stack and return it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T pop() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return remove(n - 1);
+ }
+ }
+
+ /**
+ * Pushes a new item onto the top of this stack. The pushed item is also returned. This is equivalent to calling
+ * <code>add</code>.
+ *
+ * @param item the item to be added
+ * @return the item just pushed
+ */
+ public Object push(T item) {
+ add(item);
+ return item;
+ }
+
+ /**
+ * Returns the top-most index for the object in the stack
+ *
+ * @param object the object to be searched for
+ * @return top-most index, or -1 if not found
+ */
+ public int search(T object) {
+ int i = size() - 1; // Current index
+ while (i >= 0) {
+ T current = get(i);
+ if ((object == null && current == null) || (object != null && object.equals(current))) {
+ return i;
+ }
+ i--;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the element on the top of the stack.
+ *
+ * @return the element on the top of the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T get() {
+ int size = size();
+ if (size == 0) {
+ throw new EmptyStackException();
+ }
+ return get(size - 1);
+ }
+
+ /**
+ * Removes the element on the top of the stack.
+ *
+ * @return the removed element
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T remove() {
+ int size = size();
+ if (size == 0) {
+ throw new EmptyStackException();
+ }
+ return remove(size - 1);
+ }
+
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValueArrayStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValueArrayStreamReader.java
new file mode 100644
index 0000000000..ec3b6e083b
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValueArrayStreamReader.java
@@ -0,0 +1,404 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+
+public class NameValueArrayStreamReader implements XMLFragmentStreamReader {
+
+ private static final int START_ELEMENT_STATE = 0;
+ private static final int TEXT_STATE = 1;
+ private static final int END_ELEMENT_STATE = 2;
+ private static final int FINAL_END_ELEMENT_STATE = 3;
+ private static final int START_ELEMENT_STATE_WITH_NULL = 4;
+
+ private DelegatingNamespaceContext namespaceContext = new DelegatingNamespaceContext();
+ // the index of the array
+ private int arrayIndex;
+
+ private QName name;
+ private String[] values;
+
+ // start element is the default state
+ private int state = START_ELEMENT_STATE;
+
+ public NameValueArrayStreamReader(QName name, String[] values) {
+ this.name = name;
+ this.values = values;
+ }
+
+ public void setParentNamespaceContext(NamespaceContext nsContext) {
+ this.namespaceContext.setParentNsContext(nsContext);
+ }
+
+ public void init() {
+ // TODO what if the QName namespace has not been declared
+ }
+
+ public Object getProperty(String string) throws IllegalArgumentException {
+ return null;
+ }
+
+ /**
+ * @throws XMLStreamException
+ */
+ public int next() throws XMLStreamException {
+ switch (state) {
+ case START_ELEMENT_STATE:
+ if (values.length > 0) {
+ state = TEXT_STATE;
+ return CHARACTERS;
+ } else {
+ state = FINAL_END_ELEMENT_STATE;
+ return END_ELEMENT;
+ }
+
+ case START_ELEMENT_STATE_WITH_NULL:
+ if (arrayIndex == (values.length - 1)) {
+ state = FINAL_END_ELEMENT_STATE;
+ } else {
+ state = END_ELEMENT_STATE;
+ }
+ return END_ELEMENT;
+ case FINAL_END_ELEMENT_STATE:
+ // oops, not supposed to happen!
+ throw new XMLStreamException("end already reached!");
+ case END_ELEMENT_STATE:
+ // we've to have more values since this is not the
+ // last value
+ // increment the counter
+ arrayIndex++;
+ if (values[arrayIndex] == null) {
+ state = START_ELEMENT_STATE_WITH_NULL;
+ } else {
+ state = START_ELEMENT_STATE;
+ }
+ return START_ELEMENT;
+ case TEXT_STATE:
+ if (arrayIndex == (values.length - 1)) {
+ state = FINAL_END_ELEMENT_STATE;
+ return END_ELEMENT;
+ } else {
+ state = END_ELEMENT_STATE;
+ return END_ELEMENT;
+ }
+
+ default:
+ throw new XMLStreamException("unknown event type!");
+ }
+ }
+
+ public void require(int i, String string, String string1) throws XMLStreamException {
+ // nothing done here
+ }
+
+ public String getElementText() throws XMLStreamException {
+ return null; // not implemented
+ }
+
+ public int nextTag() throws XMLStreamException {
+ return 0; // not implemented
+ }
+
+ public String getAttributeValue(String string, String string1) {
+ if (state == TEXT_STATE) {
+ // TODO something
+ return null;
+ } else {
+ return null;
+ }
+
+ }
+
+ public int getAttributeCount() {
+ if (state == START_ELEMENT_STATE_WITH_NULL) {
+ return 1;
+ }
+ if (state == START_ELEMENT_STATE) {
+ return 0;
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public QName getAttributeName(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && i == 0) {
+ return NIL_QNAME;
+ }
+ if (state == START_ELEMENT_STATE) {
+ return null;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeNamespace(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && i == 0) {
+ return NIL_QNAME.getNamespaceURI();
+ }
+ if (state == START_ELEMENT_STATE) {
+ return null;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeLocalName(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && i == 0) {
+ return NIL_QNAME.getLocalPart();
+ }
+ if (state == START_ELEMENT_STATE) {
+ return null;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributePrefix(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && i == 0) {
+ return NIL_QNAME.getPrefix();
+ }
+ if (state == START_ELEMENT_STATE) {
+ return null;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeType(int i) {
+ return null; // not implemented
+ }
+
+ public String getAttributeValue(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && i == 0) {
+ return NIL_VALUE_TRUE;
+ }
+ if (state == START_ELEMENT_STATE) {
+ return null;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ return false; // not supported
+ }
+
+ public int getNamespaceCount() {
+ if (state == START_ELEMENT_STATE_WITH_NULL && isXsiNamespacePresent()) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+ }
+
+ public String getNamespacePrefix(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && isXsiNamespacePresent() && i == 0) {
+ return NIL_QNAME.getPrefix();
+ } else {
+ return null;
+ }
+ }
+
+ public String getNamespaceURI(int i) {
+ if (state == START_ELEMENT_STATE_WITH_NULL && isXsiNamespacePresent() && i == 0) {
+ return NIL_QNAME.getNamespaceURI();
+ } else {
+ return null;
+ }
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return this.namespaceContext;
+ }
+
+ public boolean isDone() {
+ return state == FINAL_END_ELEMENT_STATE;
+ }
+
+ public int getEventType() {
+ switch (state) {
+ case START_ELEMENT_STATE:
+ return START_ELEMENT;
+ case END_ELEMENT_STATE:
+ return END_ELEMENT;
+ case TEXT_STATE:
+ return CHARACTERS;
+ case FINAL_END_ELEMENT_STATE:
+ return END_ELEMENT;
+ default:
+ throw new UnsupportedOperationException();
+ // we've no idea what this is!!!!!
+ }
+
+ }
+
+ public String getText() {
+ if (state == TEXT_STATE) {
+ return values[arrayIndex];
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public char[] getTextCharacters() {
+ if (state == TEXT_STATE) {
+ return values[arrayIndex].toCharArray();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ // not implemented
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTextStart() {
+ if (state == TEXT_STATE) {
+ return 0;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextLength() {
+ if (state == TEXT_STATE) {
+ return values[arrayIndex].length();
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public String getEncoding() {
+ return null;
+ }
+
+ public boolean hasText() {
+ return state == TEXT_STATE;
+ }
+
+ public Location getLocation() {
+ return null; // not supported
+ }
+
+ public QName getName() {
+ if (state != TEXT_STATE) {
+ return name;
+ } else {
+ return null;
+ }
+ }
+
+ public String getLocalName() {
+ if (state != TEXT_STATE) {
+ return name.getLocalPart();
+ } else {
+ return null;
+ }
+ }
+
+ public boolean hasName() {
+ return state != TEXT_STATE;
+
+ }
+
+ public String getNamespaceURI() {
+ if (state != TEXT_STATE) {
+ return name.getNamespaceURI();
+ } else {
+ return null;
+ }
+
+ }
+
+ public String getPrefix() {
+ if (state != TEXT_STATE) {
+ return name.getPrefix();
+ } else {
+ return null;
+ }
+ }
+
+ public String getVersion() {
+ return null; // TODO 1.0 ?
+ }
+
+ public boolean isStandalone() {
+ return false;
+ }
+
+ public boolean standaloneSet() {
+ return false;
+ }
+
+ public String getCharacterEncodingScheme() {
+ return null;
+ }
+
+ public String getPITarget() {
+ return null;
+ }
+
+ public String getPIData() {
+ return null;
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ return state != FINAL_END_ELEMENT_STATE;
+ }
+
+ public void close() throws XMLStreamException {
+ // Do nothing - we've nothing to free here
+ }
+
+ public String getNamespaceURI(String prefix) {
+ return namespaceContext.getNamespaceURI(prefix);
+ }
+
+ public boolean isStartElement() {
+ return state == START_ELEMENT_STATE;
+ }
+
+ public boolean isEndElement() {
+ return state == END_ELEMENT_STATE;
+ }
+
+ public boolean isCharacters() {
+ return state == TEXT_STATE;
+ }
+
+ public boolean isWhiteSpace() {
+ return false; // no whitespaces here
+ }
+
+ /**
+ * Test whether the xsi namespace is present
+ */
+ private boolean isXsiNamespacePresent() {
+ return namespaceContext.getNamespaceURI(NIL_QNAME.getPrefix()) != null;
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValuePairStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValuePairStreamReader.java
new file mode 100644
index 0000000000..4abf9b3dcf
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NameValuePairStreamReader.java
@@ -0,0 +1,348 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+
+
+public class NameValuePairStreamReader implements XMLFragmentStreamReader {
+
+ private static final int START_ELEMENT_STATE = 0;
+ private static final int TEXT_STATE = 1;
+ private static final int END_ELEMENT_STATE = 2;
+
+ private DelegatingNamespaceContext namespaceContext = new DelegatingNamespaceContext();
+
+ private QName name;
+ private String value;
+
+ private int state = START_ELEMENT_STATE;
+ // initiate at the start element state
+
+ // keeps track whether the namespace is declared
+ // false by default
+ private boolean nsDeclared;
+
+ public NameValuePairStreamReader(QName name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public Object getProperty(String key) throws IllegalArgumentException {
+ return null;
+ }
+
+ public int next() throws XMLStreamException {
+ // no need to handle null here. it should have been handled
+ // already
+ switch (state) {
+ case START_ELEMENT_STATE:
+ state = TEXT_STATE;
+ return CHARACTERS;
+ case END_ELEMENT_STATE:
+ // oops, not supposed to happen!
+ throw new XMLStreamException("end already reached!");
+ case TEXT_STATE:
+ state = END_ELEMENT_STATE;
+ return END_ELEMENT;
+ default:
+ throw new XMLStreamException("unknown event type!");
+ }
+ }
+
+ public void require(int i, String string, String string1) throws XMLStreamException {
+ // not implemented
+ }
+
+ public String getElementText() throws XMLStreamException {
+ if (state == START_ELEMENT) {
+ // move to the end state and return the value
+ state = END_ELEMENT_STATE;
+ return value;
+ } else {
+ throw new XMLStreamException();
+ }
+
+ }
+
+ public int nextTag() throws XMLStreamException {
+ return 0; // TODO
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ return state != END_ELEMENT_STATE;
+ }
+
+ public void close() throws XMLStreamException {
+ // Do nothing - we've nothing to free here
+ }
+
+ public String getNamespaceURI(String prefix) {
+ return namespaceContext.getNamespaceURI(prefix);
+ }
+
+ public boolean isStartElement() {
+ return state == START_ELEMENT_STATE;
+ }
+
+ public boolean isEndElement() {
+ return state == END_ELEMENT_STATE;
+ }
+
+ public boolean isCharacters() {
+ return state == TEXT_STATE;
+ }
+
+ public boolean isWhiteSpace() {
+ return false; // no whitespaces here
+ }
+
+ public String getAttributeValue(String string, String string1) {
+ return null;
+ }
+
+ public int getAttributeCount() {
+ return 0;
+ }
+
+ public QName getAttributeName(int i) {
+ return null;
+ }
+
+ public String getAttributeNamespace(int i) {
+ return null;
+ }
+
+ public String getAttributeLocalName(int i) {
+ return null;
+ }
+
+ public String getAttributePrefix(int i) {
+ return null;
+ }
+
+ public String getAttributeType(int i) {
+ return null;
+ }
+
+ public String getAttributeValue(int i) {
+ return null;
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ return false; // no attributes here
+ }
+
+ public int getNamespaceCount() {
+ return nsDeclared ? 1 : 0;
+ }
+
+ public String getNamespacePrefix(int i) {
+ return (nsDeclared && i == 0) ? name.getPrefix() : null;
+ }
+
+ public String getNamespaceURI(int i) {
+ return (nsDeclared && i == 0) ? name.getNamespaceURI() : null;
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return this.namespaceContext;
+ }
+
+ public int getEventType() {
+ switch (state) {
+ case START_ELEMENT_STATE:
+ return START_ELEMENT;
+ case END_ELEMENT_STATE:
+ return END_ELEMENT;
+ case TEXT_STATE:
+ return CHARACTERS;
+ default:
+ throw new UnsupportedOperationException();
+ // we've no idea what this is!!!!!
+ }
+
+ }
+
+ public String getText() {
+ if (state == TEXT_STATE) {
+ return value;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public char[] getTextCharacters() {
+ if (state == TEXT_STATE) {
+ return value.toCharArray();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ // not implemented
+ throw new UnsupportedOperationException();
+ }
+
+ public int getTextStart() {
+ if (state == TEXT_STATE) {
+ return 0;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextLength() {
+ if (state == TEXT_STATE) {
+ return value.length();
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public String getEncoding() {
+ return null;
+ }
+
+ public boolean hasText() {
+ return state == TEXT_STATE;
+ }
+
+ public Location getLocation() {
+ return new Location() {
+ public int getLineNumber() {
+ return 0;
+ }
+
+ public int getColumnNumber() {
+ return 0;
+ }
+
+ public int getCharacterOffset() {
+ return 0;
+ }
+
+ public String getPublicId() {
+ return null;
+ }
+
+ public String getSystemId() {
+ return null;
+ }
+ };
+ }
+
+ public QName getName() {
+ if (state != TEXT_STATE) {
+ return name;
+ } else {
+ return null;
+ }
+ }
+
+ public String getLocalName() {
+ if (state != TEXT_STATE) {
+ return name.getLocalPart();
+ } else {
+ return null;
+ }
+ }
+
+ public boolean hasName() {
+ return state != TEXT_STATE;
+
+ }
+
+ public String getNamespaceURI() {
+ if (state != TEXT_STATE) {
+ return name.getNamespaceURI();
+ } else {
+ return null;
+ }
+
+ }
+
+ public String getPrefix() {
+ if (state != TEXT_STATE) {
+ return name.getPrefix();
+ } else {
+ return null;
+ }
+ }
+
+ public String getVersion() {
+ return null; // TODO 1.0 ?
+ }
+
+ public boolean isStandalone() {
+ return false;
+ }
+
+ public boolean standaloneSet() {
+ return false;
+ }
+
+ public String getCharacterEncodingScheme() {
+ return null;
+ }
+
+ public String getPITarget() {
+ return null;
+ }
+
+ public String getPIData() {
+ return null;
+ }
+
+ public boolean isDone() {
+ return state == END_ELEMENT_STATE;
+ }
+
+ public void setParentNamespaceContext(NamespaceContext nsContext) {
+ this.namespaceContext.setParentNsContext(nsContext);
+ }
+
+ public void init() {
+ // just add the current elements namespace and prefix to the this
+ // elements nscontext
+ addToNsMap(name.getPrefix(), name.getNamespaceURI());
+
+ }
+
+ /**
+ * @param prefix
+ * @param uri
+ */
+ private void addToNsMap(String prefix, String uri) {
+ // TODO - need to fix this up to cater for cases where
+ // namespaces are having no prefixes
+ if (!uri.equals(namespaceContext.getNamespaceURI(prefix))) {
+ // this namespace is not there. Need to declare it
+ namespaceContext.pushNamespace(prefix, uri);
+ nsDeclared = true;
+ }
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamedProperty.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamedProperty.java
new file mode 100644
index 0000000000..dc5954f541
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamedProperty.java
@@ -0,0 +1,59 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+/**
+ * A named property
+ *
+ * @version $Rev$ $Date$
+ */
+public class NamedProperty implements Map.Entry<QName, Object> {
+ private QName key;
+
+ private Object value;
+
+ public NamedProperty(QName key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public NamedProperty(String key, Object value) {
+ this.key = new QName(key);
+ this.value = value;
+ }
+
+ public QName getKey() {
+ return key;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object setValue(Object value) {
+ Object v = this.value;
+ this.value = value;
+ return v;
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamespaceContextImpl.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamespaceContextImpl.java
new file mode 100644
index 0000000000..d88f298a6c
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NamespaceContextImpl.java
@@ -0,0 +1,124 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.NamespaceContext;
+
+public class NamespaceContextImpl implements NamespaceContext {
+ private NamespaceContext parent;
+ private Map<String, String> map = new HashMap<String, String>();
+
+ /**
+ * @param parent
+ */
+ public NamespaceContextImpl(NamespaceContext parent) {
+ super();
+ this.parent = parent;
+ if (parent == null) {
+ map.put("xml", "http://www.w3.org/XML/1998/namespace");
+ map.put("xmlns", "http://www.w3.org/2000/xmlns/");
+ }
+ }
+
+ public String getNamespaceURI(String prefix) {
+ if (prefix == null) {
+ throw new IllegalArgumentException("Prefix is null");
+ }
+
+ String ns = (String)map.get(prefix);
+ if (ns != null) {
+ return ns;
+ }
+ if (parent != null) {
+ return parent.getNamespaceURI(prefix);
+ }
+ return null;
+ }
+
+ public String getPrefix(String nsURI) {
+ if (nsURI == null)
+ throw new IllegalArgumentException("Namespace is null");
+ for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, String> entry = i.next();
+ if (entry.getValue().equals(nsURI)) {
+ return entry.getKey();
+ }
+ }
+ if (parent != null) {
+ return parent.getPrefix(nsURI);
+ }
+ return null;
+ }
+
+ public Iterator getPrefixes(String nsURI) {
+ List<String> prefixList = new ArrayList<String>();
+ for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String, String> entry = i.next();
+ if (entry.getValue().equals(nsURI)) {
+ prefixList.add(entry.getKey());
+ }
+ }
+ final Iterator<String> currentIterator = prefixList.iterator();
+ final Iterator parentIterator = parent == null ? null : parent.getPrefixes(nsURI);
+ return new Iterator() {
+
+ public boolean hasNext() {
+ return currentIterator.hasNext() || (parentIterator != null && parentIterator.hasNext());
+ }
+
+ public Object next() {
+ if (!hasNext()) {
+ throw new IllegalStateException("End of iterator has reached");
+ }
+ return currentIterator.hasNext() ? currentIterator.next() : parentIterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+
+ }
+
+ public void register(String prefix, String ns) {
+ map.put(prefix, ns);
+ }
+
+ public NamespaceContext getParent() {
+ return parent;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(map.toString());
+ if (parent != null) {
+ sb.append("\nParent: ");
+ sb.append(parent);
+ }
+ return sb.toString();
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NilElementStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NilElementStreamReader.java
new file mode 100644
index 0000000000..cee70f64df
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/NilElementStreamReader.java
@@ -0,0 +1,279 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+public class NilElementStreamReader implements XMLFragmentStreamReader {
+
+ private static final int END_ELEMENT_STATE = 2;
+
+ private static final int START_ELEMENT_STATE = 1;
+ private int currentState = START_ELEMENT;
+
+ private QName elementQName;
+
+ public NilElementStreamReader(QName elementQName) {
+ this.elementQName = elementQName;
+ }
+
+ public void setParentNamespaceContext(NamespaceContext nsContext) {
+ // NOOP
+ }
+
+ public void close() throws XMLStreamException {
+ // do nothing
+ }
+
+ public int getAttributeCount() {
+ return 1;
+ }
+
+ public String getAttributeLocalName(int i) {
+ return (i == 0) ? NIL_QNAME.getLocalPart() : null;
+ }
+
+ public QName getAttributeName(int i) {
+ return (i == 0) ? NIL_QNAME : null;
+ }
+
+ public String getAttributeNamespace(int i) {
+ return (i == 0) ? NIL_QNAME.getNamespaceURI() : null;
+ }
+
+ public String getAttributePrefix(int i) {
+ return (i == 0) ? NIL_QNAME.getPrefix() : null;
+ }
+
+ public String getAttributeType(int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getAttributeValue(int i) {
+ return (i == 0) ? NIL_VALUE_TRUE : null;
+ }
+
+ public String getAttributeValue(String string, String string1) {
+ if (string == null && NIL_QNAME.getLocalPart().equals(string1)) {
+ return NIL_VALUE_TRUE;
+ }
+ return null;
+ }
+
+ public String getCharacterEncodingScheme() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getElementText() throws XMLStreamException {
+ return null;
+ }
+
+ public String getEncoding() {
+ return null;
+ }
+
+ public int getEventType() {
+ int returnEvent = START_DOCUMENT;
+ switch (currentState) {
+ case START_ELEMENT_STATE:
+ returnEvent = START_ELEMENT;
+ break;
+ case END_ELEMENT_STATE:
+ returnEvent = END_ELEMENT;
+ break;
+ }
+ return returnEvent;
+ }
+
+ public String getLocalName() {
+ return elementQName.getLocalPart();
+ }
+
+ public Location getLocation() {
+ return new Location() {
+ public int getCharacterOffset() {
+ return 0;
+ }
+
+ public int getColumnNumber() {
+ return 0;
+ }
+
+ public int getLineNumber() {
+ return 0;
+ }
+
+ public String getPublicId() {
+ return null;
+ }
+
+ public String getSystemId() {
+ return null;
+ }
+ };
+ }
+
+ public QName getName() {
+ return elementQName;
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getNamespaceCount() {
+ return 0;
+ }
+
+ public String getNamespacePrefix(int i) {
+ return null;
+ }
+
+ public String getNamespaceURI() {
+ return elementQName.getNamespaceURI();
+ }
+
+ public String getNamespaceURI(int i) {
+ return null;
+ }
+
+ public String getNamespaceURI(String string) {
+ if (elementQName.getPrefix() != null && elementQName.getPrefix().equals(string)) {
+ return elementQName.getNamespaceURI();
+ } else {
+ return null;
+ }
+ }
+
+ public String getPIData() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPITarget() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPrefix() {
+ return elementQName.getPrefix();
+ }
+
+ public Object getProperty(String key) throws IllegalArgumentException {
+ // since optimization is a global property
+ // we've to implement it everywhere
+ return null;
+ }
+
+ public String getText() {
+ return null;
+ }
+
+ public char[] getTextCharacters() {
+ return new char[0];
+ }
+
+ public int getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ return 0;
+ }
+
+ public int getTextLength() {
+ return 0;
+ }
+
+ public int getTextStart() {
+ return 0;
+ }
+
+ public String getVersion() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasName() {
+ return true;
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ return currentState != END_ELEMENT_STATE;
+
+ }
+
+ public boolean hasText() {
+ return false;
+ }
+
+ public void init() {
+ // NOOP
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ return i == 0;
+ }
+
+ public boolean isCharacters() {
+ return false;
+ }
+
+ public boolean isDone() {
+ return currentState == END_ELEMENT_STATE;
+ }
+
+ public boolean isEndElement() {
+ return currentState == END_ELEMENT_STATE;
+ }
+
+ public boolean isStandalone() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isStartElement() {
+ return currentState == START_ELEMENT_STATE;
+ }
+
+ public boolean isWhiteSpace() {
+ return false;
+ }
+
+ public int next() throws XMLStreamException {
+ int returnEvent = START_DOCUMENT;
+ switch (currentState) {
+ case START_ELEMENT_STATE:
+ currentState = END_ELEMENT_STATE;
+ returnEvent = END_ELEMENT;
+ break;
+ case END_ELEMENT_STATE:
+ throw new XMLStreamException("parser completed!");
+
+ }
+ return returnEvent;
+ }
+
+ public int nextTag() throws XMLStreamException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void require(int i, String string, String string1) throws XMLStreamException {
+ // nothing
+ }
+
+ public boolean standaloneSet() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/SimpleXmlNodeImpl.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/SimpleXmlNodeImpl.java
new file mode 100644
index 0000000000..30f388543c
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/SimpleXmlNodeImpl.java
@@ -0,0 +1,112 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class SimpleXmlNodeImpl implements XmlNode {
+ private static final String XSI_PREFIX = "xsi";
+ private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
+ private static final QName XSI_NIL = new QName(XSI_NS, "nil", XSI_PREFIX);
+ private static final Map<String, String> NS_MAP = new HashMap<String, String>();
+ static {
+ NS_MAP.put(XSI_PREFIX, XSI_NS);
+ }
+
+ protected Type type;
+ protected QName name;
+ protected Object value;
+
+ public SimpleXmlNodeImpl(QName name, Object value) {
+ this(name, value, name != null ? Type.ELEMENT : Type.CHARACTERS);
+ }
+
+ public SimpleXmlNodeImpl(QName name, Object value, Type type) {
+ super();
+ this.type = type;
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#attributes()
+ */
+ public List<XmlNode> attributes() {
+ if (type == Type.ELEMENT && value == null) {
+ // Nil element
+ XmlNode attr = new SimpleXmlNodeImpl(XSI_NIL, "true");
+ return Arrays.asList(attr);
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#children()
+ */
+ public Iterator<XmlNode> children() {
+ if (type == Type.ELEMENT && value != null) {
+ // Nil element
+ XmlNode node = new SimpleXmlNodeImpl(null, value);
+ return Arrays.asList(node).iterator();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#getName()
+ */
+ public QName getName() {
+ return name;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#getValue()
+ */
+ public String getValue() {
+ return value == null ? null : String.valueOf(value);
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.common.xml.stax.reader.databinding.xml.XmlNode#namespaces()
+ */
+ public Map<String, String> namespaces() {
+ if (type == Type.ELEMENT && value == null) {
+ return NS_MAP;
+ }
+ return null;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/WrappingXMLStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/WrappingXMLStreamReader.java
new file mode 100644
index 0000000000..896f4b5b71
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/WrappingXMLStreamReader.java
@@ -0,0 +1,100 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.util.StreamReaderDelegate;
+
+public class WrappingXMLStreamReader extends StreamReaderDelegate implements XMLFragmentStreamReader {
+
+ private boolean done;
+ private int level;
+
+ public WrappingXMLStreamReader(XMLStreamReader realReader) throws XMLStreamException {
+ super(realReader);
+ if (realReader == null) {
+ throw new UnsupportedOperationException("Reader cannot be null");
+ }
+
+ if (realReader instanceof XMLFragmentStreamReader) {
+ ((XMLFragmentStreamReader)realReader).init();
+ }
+
+ if (realReader.getEventType() == START_DOCUMENT) {
+ // Position to the 1st element
+ realReader.nextTag();
+ }
+ if (realReader.getEventType() != START_ELEMENT) {
+ throw new IllegalStateException("The reader is not positioned at START_DOCUMENT or START_ELEMENT");
+ }
+ this.done = false;
+ this.level = 1;
+ }
+
+ @Override
+ public boolean hasNext() throws XMLStreamException {
+ return !done && super.hasNext();
+ }
+
+ @Override
+ public int next() throws XMLStreamException {
+ if (!hasNext()) {
+ throw new IllegalStateException("No more events");
+ }
+ int event = super.next();
+ if (!super.hasNext()) {
+ done = true;
+ }
+ if (event == START_ELEMENT) {
+ level++;
+ } else if (event == END_ELEMENT) {
+ level--;
+ if (level == 0) {
+ done = true;
+ }
+ }
+ return event;
+ }
+
+ @Override
+ public int nextTag() throws XMLStreamException {
+ int event = 0;
+ while (true) {
+ event = next();
+ if (event == START_ELEMENT || event == END_ELEMENT) {
+ return event;
+ }
+ }
+ }
+
+ public void setParentNamespaceContext(NamespaceContext nsContext) {
+ // nothing to do here
+ }
+
+ public void init() {
+ // Nothing to do here
+ }
+
+ public boolean isDone() {
+ return done;
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLDocumentStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLDocumentStreamReader.java
new file mode 100644
index 0000000000..a020a8a61e
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLDocumentStreamReader.java
@@ -0,0 +1,482 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.NoSuchElementException;
+
+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;
+
+/**
+ * This class is derived from Apache Axis2 class
+ * org.apache.axis2.util.StreamWrapper</a>. It's used wrap a XMLStreamReader to
+ * create a XMLStreamReader representing a document and it will produce
+ * START_DOCUMENT, END_DOCUMENT events.
+ *
+ * @version $Rev$ $Date$
+ */
+public class XMLDocumentStreamReader implements XMLStreamReader {
+ private static final int STATE_COMPLETE_AT_NEXT = 2; // The wrapper
+ // will produce
+ // END_DOCUMENT
+
+ private static final int STATE_COMPLETED = 3; // Done
+
+ private static final int STATE_INIT = 0; // The wrapper will produce
+ // START_DOCUMENT
+
+ private static final int STATE_SWITCHED = 1; // The real reader will
+ // produce events
+
+ private XMLStreamReader realReader;
+ private boolean fragment;
+ private int level = 1;
+
+ private int state = STATE_INIT;
+
+ public XMLDocumentStreamReader(XMLStreamReader realReader) {
+ if (realReader == null) {
+ throw new UnsupportedOperationException("Reader cannot be null");
+ }
+
+ this.realReader = realReader;
+
+ if (realReader instanceof XMLFragmentStreamReader) {
+ ((XMLFragmentStreamReader)realReader).init();
+ }
+
+ // If the real reader is positioned at START_DOCUMENT, always use
+ // the real reader
+ if (realReader.getEventType() == START_DOCUMENT) {
+ fragment = false;
+ state = STATE_SWITCHED;
+ }
+ }
+
+ public void close() throws XMLStreamException {
+ realReader.close();
+ }
+
+ public int getAttributeCount() {
+ if (isDelegating()) {
+ return realReader.getAttributeCount();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeLocalName(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributeLocalName(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public QName getAttributeName(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributeName(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeNamespace(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributeNamespace(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributePrefix(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributePrefix(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeType(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributeType(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeValue(int i) {
+ if (isDelegating()) {
+ return realReader.getAttributeValue(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeValue(String s, String s1) {
+ if (isDelegating()) {
+ return realReader.getAttributeValue(s, s1);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getCharacterEncodingScheme() {
+ return realReader.getCharacterEncodingScheme();
+ }
+
+ public String getElementText() throws XMLStreamException {
+ if (isDelegating()) {
+ return realReader.getElementText();
+ } else {
+ throw new XMLStreamException();
+ }
+ }
+
+ public String getEncoding() {
+ return realReader.getEncoding();
+ }
+
+ public int getEventType() {
+ int event = -1;
+ switch (state) {
+ case STATE_SWITCHED:
+ case STATE_COMPLETE_AT_NEXT:
+ event = realReader.getEventType();
+ break;
+ case STATE_INIT:
+ event = START_DOCUMENT;
+ break;
+ case STATE_COMPLETED:
+ event = END_DOCUMENT;
+ break;
+ }
+ return event;
+ }
+
+ public String getLocalName() {
+ if (isDelegating()) {
+ return realReader.getLocalName();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public Location getLocation() {
+ if (isDelegating()) {
+ return realReader.getLocation();
+ } else {
+ return null;
+ }
+ }
+
+ public QName getName() {
+ if (isDelegating()) {
+ return realReader.getName();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return realReader.getNamespaceContext();
+ }
+
+ public int getNamespaceCount() {
+ if (isDelegating()) {
+ return realReader.getNamespaceCount();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getNamespacePrefix(int i) {
+ if (isDelegating()) {
+ return realReader.getNamespacePrefix(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getNamespaceURI() {
+ if (isDelegating()) {
+ return realReader.getNamespaceURI();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getNamespaceURI(int i) {
+ if (isDelegating()) {
+ return realReader.getNamespaceURI(i);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getNamespaceURI(String s) {
+ if (isDelegating()) {
+ return realReader.getNamespaceURI(s);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getPIData() {
+ if (isDelegating()) {
+ return realReader.getPIData();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getPITarget() {
+ if (isDelegating()) {
+ return realReader.getPITarget();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getPrefix() {
+ if (isDelegating()) {
+ return realReader.getPrefix();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public Object getProperty(String s) throws IllegalArgumentException {
+ if (isDelegating()) {
+ return realReader.getProperty(s);
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public String getText() {
+ if (isDelegating()) {
+ return realReader.getText();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public char[] getTextCharacters() {
+ if (isDelegating()) {
+ return realReader.getTextCharacters();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ if (isDelegating()) {
+ return realReader.getTextCharacters(i, chars, i1, i2);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextLength() {
+ if (isDelegating()) {
+ return realReader.getTextLength();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextStart() {
+ if (isDelegating()) {
+ return realReader.getTextStart();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getVersion() {
+ if (isDelegating()) {
+ return realReader.getVersion();
+ } else {
+ return null;
+ }
+ }
+
+ public boolean hasName() {
+ if (isDelegating()) {
+ return realReader.hasName();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean hasNext() throws XMLStreamException {
+ if (state == STATE_COMPLETE_AT_NEXT) {
+ return true;
+ } else if (state == STATE_COMPLETED) {
+ return false;
+ } else if (state == STATE_SWITCHED) {
+ return realReader.hasNext();
+ } else {
+ return true;
+ }
+ }
+
+ public boolean hasText() {
+ if (isDelegating()) {
+ return realReader.hasText();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ if (isDelegating()) {
+ return realReader.isAttributeSpecified(i);
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isCharacters() {
+ if (isDelegating()) {
+ return realReader.isCharacters();
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isDelegating() {
+ return state == STATE_SWITCHED || state == STATE_COMPLETE_AT_NEXT;
+ }
+
+ public boolean isEndElement() {
+ if (isDelegating()) {
+ return realReader.isEndElement();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isStandalone() {
+ if (isDelegating()) {
+ return realReader.isStandalone();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isStartElement() {
+ if (isDelegating()) {
+ return realReader.isStartElement();
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isWhiteSpace() {
+ if (isDelegating()) {
+ return realReader.isWhiteSpace();
+ } else {
+ return false;
+ }
+ }
+
+ public int next() throws XMLStreamException {
+ int returnEvent;
+
+ switch (state) {
+ case STATE_SWITCHED:
+ returnEvent = realReader.next();
+ if (returnEvent == END_DOCUMENT) {
+ state = STATE_COMPLETED;
+ } else if (!realReader.hasNext()) {
+ state = STATE_COMPLETE_AT_NEXT;
+ }
+ if (fragment && returnEvent == END_ELEMENT) {
+ level--;
+ if (level == 0) {
+ // We are now at the end of the top-level element in the fragment
+ state = STATE_COMPLETE_AT_NEXT;
+ }
+ }
+ if (fragment && returnEvent == START_ELEMENT) {
+ level++;
+ }
+ break;
+ case STATE_INIT:
+ state = STATE_SWITCHED;
+ returnEvent = realReader.getEventType();
+ if (returnEvent == START_ELEMENT) {
+ // The real reader is positioned at the top-level element in the fragment
+ level = 0;
+ fragment = true;
+ }
+ break;
+ case STATE_COMPLETE_AT_NEXT:
+ state = STATE_COMPLETED;
+ returnEvent = END_DOCUMENT;
+ break;
+ case STATE_COMPLETED:
+ // oops - no way we can go beyond this
+ throw new NoSuchElementException("End of stream has reached.");
+ default:
+ throw new UnsupportedOperationException();
+ }
+
+ return returnEvent;
+ }
+
+ public int nextTag() throws XMLStreamException {
+ if (isDelegating()) {
+ int returnEvent = realReader.nextTag();
+ if (fragment && returnEvent == END_ELEMENT) {
+ level--;
+ if (level == 0) {
+ // We are now at the end of the top-level element in the fragment
+ state = STATE_COMPLETE_AT_NEXT;
+ }
+ }
+ if (fragment && returnEvent == START_ELEMENT) {
+ level++;
+ }
+ return returnEvent;
+ } else {
+ throw new XMLStreamException();
+ }
+ }
+
+ public void require(int i, String s, String s1) throws XMLStreamException {
+ if (isDelegating()) {
+ realReader.require(i, s, s1);
+ }
+ }
+
+ public boolean standaloneSet() {
+ if (isDelegating()) {
+ return realReader.standaloneSet();
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReader.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReader.java
new file mode 100644
index 0000000000..95ede0a840
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReader.java
@@ -0,0 +1,53 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
+public interface XMLFragmentStreamReader extends XMLStreamReader {
+ QName NIL_QNAME = new QName("http://www.w3.org/2001/XMLSchema-instance", "nil", "xsi");
+ String NIL_VALUE_TRUE = "true";
+
+ /**
+ * this will help to handle Text within the current element. user should
+ * pass the element text to the property list as this ELEMENT_TEXT as the
+ * key. This key deliberately has a space in it so that it is not a valid
+ * XML name
+ */
+ String ELEMENT_TEXT = "Element Text";
+
+ /**
+ * Extra method to query the state of the pullparser
+ */
+ boolean isDone();
+
+ /**
+ * add the parent namespace context to this parser
+ */
+ void setParentNamespaceContext(NamespaceContext nsContext);
+
+ /**
+ * Initiate the parser - this will do whatever the needed tasks to initiate
+ * the parser and must be called before attempting any specific parsing
+ * using this parser
+ */
+ void init();
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReaderImpl.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReaderImpl.java
new file mode 100644
index 0000000000..4fd70bea67
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLFragmentStreamReaderImpl.java
@@ -0,0 +1,858 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+
+
+/**
+ * This is the new implementation of the XMLFramentStreamReader. The approach
+ * here is simple When the pull parser needs to generate events for a particular
+ * name-value(s) pair it always hands over (delegates) the task to another pull
+ * parser which knows how to deal with it The common types of name value pairs
+ * we'll come across are
+ * <ul>
+ * <li> String name/QName name - String value
+ * <li> String name/QName name - String[] value
+ * <li> QName name/String name - XMLStreamReader value
+ * <li> QName name/String name - XMLStreamable value
+ * <li> QName name/String name - Java bean
+ * <li> QName name/String name - Datahandler
+ *
+ * </ul>
+ * <p/> As for the attributes, these are the possible combinations in the array
+ * <ul>
+ * <li> String name/QName name - String value
+ * </ul>
+ * Note that certain array methods have been deliberately removed to avoid
+ * complications. The generated code will take the trouble to lay the elements
+ * of the array in the correct order <p/> <p/> Hence there will be a parser impl
+ * that knows how to handle these types, and this parent parser will always
+ * delegate these tasks to the child pullparasers in effect this is one huge
+ * state machine that has only a few states and delegates things down to the
+ * child parsers whenever possible <p/>
+ *
+ * @version $Rev$ $Date$
+ */
+public class XMLFragmentStreamReaderImpl implements XMLFragmentStreamReader {
+
+ private static final int DELEGATED_STATE = 2;
+ private static final int END_ELEMENT_STATE = 1;
+ // states for this pullparser - it can only have four states
+ private static final int START_ELEMENT_STATE = 0;
+ private static final int TEXT_STATE = 3;
+
+ protected NamedProperty[] attributes;
+
+ // reference to the child reader
+ protected XMLFragmentStreamReader childReader;
+ // current property index
+ // initialized at zero
+ protected int index;
+ protected Map<String, String> declaredNamespaceMap = new HashMap<String, String>();
+ protected QName elementQName;
+
+ // we always create a new namespace context
+ protected DelegatingNamespaceContext namespaceContext = new DelegatingNamespaceContext();
+
+ protected NamedProperty[] elements;
+
+ // integer field that keeps the state of this
+ // parser.
+ protected int state = START_ELEMENT_STATE;
+
+ /*
+ * we need to pass in a namespace context since when delegated, we've no
+ * idea of the current namespace context. So it needs to be passed on here!
+ */
+ public XMLFragmentStreamReaderImpl(QName elementQName, NamedProperty[] elements, NamedProperty[] attributes) {
+ // validate the lengths, since both the arrays are supposed
+ // to have
+ this.elements = elements == null ? new NamedProperty[0] : elements;
+ this.elementQName = elementQName;
+ this.attributes = attributes == null ? new NamedProperty[0] : attributes;
+ }
+
+ protected XMLFragmentStreamReaderImpl(QName elementQName) {
+ this.elementQName = elementQName;
+ }
+
+ /**
+ * add the namespace context
+ */
+
+ public void setParentNamespaceContext(NamespaceContext nsContext) {
+ // register the namespace context passed in to this
+ this.namespaceContext.setParentNsContext(nsContext);
+
+ }
+
+ protected NamedProperty[] getElements() {
+ return elements;
+ }
+
+ protected NamedProperty[] getAttributes() {
+ return attributes;
+ }
+
+ protected QName[] getNamespaces() {
+ return new QName[0];
+ }
+
+ /**
+ * @param prefix
+ * @param uri
+ */
+ protected void addToNsMap(String prefix, String uri) {
+ if (!uri.equals(namespaceContext.getNamespaceURI(prefix))) {
+ namespaceContext.pushNamespace(prefix, uri);
+ declaredNamespaceMap.put(prefix, uri);
+ }
+ }
+
+ public void close() throws XMLStreamException {
+ // do nothing here - we have no resources to free
+ }
+
+ public int getAttributeCount() {
+ return (state == DELEGATED_STATE) ? childReader.getAttributeCount() : (state == START_ELEMENT_STATE
+ ? getAttributes().length : 0);
+ }
+
+ public String getAttributeLocalName(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getAttributeLocalName(i);
+ } else if (state == START_ELEMENT_STATE) {
+ QName name = getAttributeName(i);
+ if (name == null) {
+ return null;
+ } else {
+ return name.getLocalPart();
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * @param i
+ */
+ public QName getAttributeName(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getAttributeName(i);
+ } else if (state == START_ELEMENT_STATE) {
+ if ((i >= (getAttributes().length)) || i < 0) { // out of range
+ return null;
+ } else {
+ // get the attribute pointer
+ QName attribPointer = getAttributes()[i].getKey();
+ // case one - attrib name is null
+ // this should be the pointer to the OMAttribute then
+ if (attribPointer == null) {
+ throw new UnsupportedOperationException();
+ } else if (attribPointer instanceof QName) {
+ return attribPointer;
+ } else {
+ return null;
+ }
+ }
+ } else {
+ throw new IllegalStateException(); // as per the API contract
+ }
+
+ }
+
+ public String getAttributeNamespace(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getAttributeNamespace(i);
+ } else if (state == START_ELEMENT_STATE) {
+ QName name = getAttributeName(i);
+ if (name == null) {
+ return null;
+ } else {
+ return name.getNamespaceURI();
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributePrefix(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getAttributePrefix(i);
+ } else if (state == START_ELEMENT_STATE) {
+ QName name = getAttributeName(i);
+ if (name == null) {
+ return null;
+ } else {
+ return name.getPrefix();
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getAttributeType(int i) {
+ return null; // not supported
+ }
+
+ public String getAttributeValue(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getAttributeValue(i);
+ } else if (state == START_ELEMENT_STATE) {
+ if ((i >= (getAttributes().length)) || i < 0) { // out of range
+ return null;
+ } else {
+ // get the attribute pointer
+ QName attribPointer = getAttributes()[i].getKey();
+ Object omAttribObj = getAttributes()[i].getValue();
+ // case one - attrib name is null
+ // this should be the pointer to the OMAttribute then
+ if (attribPointer == null) {
+ throw new UnsupportedOperationException();
+ } else if (attribPointer instanceof QName) {
+ return (String)omAttribObj;
+ } else {
+ return null;
+ }
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public String getAttributeValue(String nsUri, String localName) {
+
+ int attribCount = getAttributeCount();
+ String returnValue = null;
+ QName attribQualifiedName;
+ for (int i = 0; i < attribCount; i++) {
+ attribQualifiedName = getAttributeName(i);
+ if (nsUri == null) {
+ if (localName.equals(attribQualifiedName.getLocalPart())) {
+ returnValue = getAttributeValue(i);
+ break;
+ }
+ } else {
+ if (localName.equals(attribQualifiedName.getLocalPart()) && nsUri.equals(attribQualifiedName
+ .getNamespaceURI())) {
+ returnValue = getAttributeValue(i);
+ break;
+ }
+ }
+
+ }
+
+ return returnValue;
+ }
+
+ public String getCharacterEncodingScheme() {
+ return null; // TODO - should we return something for this ?
+ }
+
+ /**
+ * TODO implement the right contract for this
+ *
+ * @throws XMLStreamException
+ */
+ public String getElementText() throws XMLStreamException {
+ if (state == DELEGATED_STATE) {
+ return childReader.getElementText();
+ } else {
+ return null;
+ }
+
+ }
+
+ // /////////////////////////////////////////////////////////////////////////
+ // / attribute handling
+ // /////////////////////////////////////////////////////////////////////////
+
+ public String getEncoding() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getEncoding();
+ } else {
+ // we've no idea what the encoding is going to be in this case
+ // perhaps we ought to return some constant here, which the user
+ // might
+ // have access to change!
+ return null;
+ }
+ }
+
+ public int getEventType() {
+ if (state == START_ELEMENT_STATE) {
+ return START_ELEMENT;
+ } else if (state == END_ELEMENT_STATE) {
+ return END_ELEMENT;
+ } else if (state == TEXT_STATE) {
+ return CHARACTERS;
+ } else { // this is the delegated state
+ return childReader.getEventType();
+ }
+ }
+
+ public String getLocalName() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getLocalName();
+ } else if (state != TEXT_STATE) {
+ return elementQName.getLocalPart();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ */
+ public Location getLocation() {
+ // return a default location
+ return new Location() {
+ public int getCharacterOffset() {
+ return 0;
+ }
+
+ public int getColumnNumber() {
+ return 0;
+ }
+
+ public int getLineNumber() {
+ return 0;
+ }
+
+ public String getPublicId() {
+ return null;
+ }
+
+ public String getSystemId() {
+ return null;
+ }
+ };
+ }
+
+ public QName getName() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getName();
+ } else if (state != TEXT_STATE) {
+ return elementQName;
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getNamespaceContext();
+ } else {
+ return namespaceContext;
+ }
+
+ }
+
+ public int getNamespaceCount() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getNamespaceCount();
+ } else {
+ return declaredNamespaceMap.size();
+ }
+ }
+
+ /**
+ * @param i
+ */
+ public String getNamespacePrefix(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getNamespacePrefix(i);
+ } else if (state != TEXT_STATE) {
+ // order the prefixes
+ String[] prefixes = makePrefixArray();
+ if ((i >= prefixes.length) || (i < 0)) {
+ return null;
+ } else {
+ return prefixes[i];
+ }
+
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public String getNamespaceURI() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getNamespaceURI();
+ } else if (state == TEXT_STATE) {
+ return null;
+ } else {
+ return elementQName.getNamespaceURI();
+ }
+ }
+
+ // /////////////////////////////////////////////////////////////////////////
+ // //////////// end of attribute handling
+ // /////////////////////////////////////////////////////////////////////////
+
+ // //////////////////////////////////////////////////////////////////////////
+ // //////////// namespace handling
+ // //////////////////////////////////////////////////////////////////////////
+
+ public String getNamespaceURI(int i) {
+ if (state == DELEGATED_STATE) {
+ return childReader.getNamespaceURI(i);
+ } else if (state != TEXT_STATE) {
+ String namespacePrefix = getNamespacePrefix(i);
+ return namespacePrefix == null ? null : (String)declaredNamespaceMap.get(namespacePrefix);
+ } else {
+ throw new IllegalStateException();
+ }
+
+ }
+
+ public String getNamespaceURI(String prefix) {
+ return namespaceContext.getNamespaceURI(prefix);
+ }
+
+ public String getPIData() {
+ throw new UnsupportedOperationException("Yet to be implemented !!");
+ }
+
+ public String getPITarget() {
+ throw new UnsupportedOperationException("Yet to be implemented !!");
+ }
+
+ public String getPrefix() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getPrefix();
+ } else if (state == TEXT_STATE) {
+ return null;
+ } else {
+ String prefix = elementQName.getPrefix();
+ return "".equals(prefix) ? null : prefix;
+ }
+ }
+
+ // /////////////////////////////////////////////////////////////////////////
+ // /////// end of namespace handling
+ // /////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @param key
+ * @throws IllegalArgumentException
+ */
+ public Object getProperty(String key) throws IllegalArgumentException {
+ if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
+ return null;
+ } else if (state == TEXT_STATE) {
+ return null;
+ } else if (state == DELEGATED_STATE) {
+ return childReader.getProperty(key);
+ } else {
+ return null;
+ }
+
+ }
+
+ public String getText() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getText();
+ } else if (state == TEXT_STATE) {
+ return (String)getElements()[index - 1].getValue();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public char[] getTextCharacters() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getTextCharacters();
+ } else if (state == TEXT_STATE) {
+ return getElements()[index - 1].getValue() == null ? new char[0] : ((String)getElements()[index - 1]
+ .getValue()).toCharArray();
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ private int copy(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 getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ if (state == DELEGATED_STATE) {
+ return childReader.getTextCharacters(i, chars, i1, i2);
+ } else if (state == TEXT_STATE) {
+ return copy(i, chars, i1, i2);
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextLength() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getTextLength();
+ } else if (state == TEXT_STATE) {
+ return getTextCharacters().length;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public int getTextStart() {
+ if (state == DELEGATED_STATE) {
+ return childReader.getTextStart();
+ } else if (state == TEXT_STATE) {
+ return 0; // assume text always starts at 0
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ public String getVersion() {
+ return null;
+ }
+
+ public boolean hasName() {
+ // since this parser always has a name, the hasName
+ // has to return true if we are still navigating this element
+ // if not we should ask the child reader for it.
+ if (state == DELEGATED_STATE) {
+ return childReader.hasName();
+ } else {
+ return state != TEXT_STATE;
+ }
+ }
+
+ /**
+ * @throws XMLStreamException
+ */
+ public boolean hasNext() throws XMLStreamException {
+ if (state == DELEGATED_STATE) {
+ if (childReader.isDone()) {
+ // the child reader is done. We shouldn't be getting the
+ // hasNext result from the child pullparser then
+ return true;
+ } else {
+ return childReader.hasNext();
+ }
+ } else {
+ return state == START_ELEMENT_STATE || state == TEXT_STATE;
+
+ }
+ }
+
+ /**
+ * check the validity of this implementation
+ */
+ public boolean hasText() {
+ if (state == DELEGATED_STATE) {
+ return childReader.hasText();
+ } else {
+ return state == TEXT_STATE;
+ }
+
+ }
+
+ /**
+ * we need to split out the calling to the populate namespaces separately
+ * since this needs to be done *after* setting the parent namespace context.
+ * We cannot assume it will happen at construction!
+ */
+ public void init() {
+ // here we have an extra issue to attend to. we need to look at the
+ // prefixes and URIs (the combination) and populate a HashMap of
+ // namespaces. The HashMap of namespaces will be used to serve the
+ // namespace context
+
+ populateNamespaceContext();
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ return false; // not supported
+ }
+
+ public boolean isCharacters() {
+ if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
+ return false;
+ }
+ return childReader.isCharacters();
+ }
+
+ /**
+ * are we done ?
+ */
+ public boolean isDone() {
+ return state == END_ELEMENT_STATE;
+ }
+
+ public boolean isEndElement() {
+ if (state == START_ELEMENT_STATE) {
+ return false;
+ } else if (state == END_ELEMENT_STATE) {
+ return true;
+ }
+ return childReader.isEndElement();
+ }
+
+ public boolean isStandalone() {
+ return true;
+ }
+
+ public boolean isStartElement() {
+ if (state == START_ELEMENT_STATE) {
+ return true;
+ } else if (state == END_ELEMENT_STATE) {
+ return false;
+ }
+ return childReader.isStartElement();
+ }
+
+ public boolean isWhiteSpace() {
+ if (state == START_ELEMENT_STATE || state == END_ELEMENT_STATE) {
+ return false;
+ }
+ return childReader.isWhiteSpace();
+ }
+
+ /**
+ * Get the prefix list from the HashTable and take that into an array
+ */
+ private String[] makePrefixArray() {
+ String[] prefixes = declaredNamespaceMap.keySet().toArray(new String[declaredNamespaceMap.size()]);
+ Arrays.sort(prefixes);
+ return prefixes;
+ }
+
+ /**
+ * By far this should be the most important method in this class this method
+ * changes the state of the parser
+ */
+ public int next() throws XMLStreamException {
+ int returnEvent = -1; // invalid state is the default state
+ switch (state) {
+ case START_ELEMENT_STATE:
+ // current element is start element. We should be looking at the
+ // property list and making a pullparser for the property value
+ if (getElements() == null || getElements().length == 0) {
+ // no properties - move to the end element state
+ // straight away
+ state = END_ELEMENT_STATE;
+ returnEvent = END_ELEMENT;
+ } else {
+ // there are properties. now we should delegate this task to
+ // a
+ // child reader depending on the property type
+ returnEvent = processProperties();
+
+ }
+ break;
+ case END_ELEMENT_STATE:
+ // we've reached the end element already. If the user tries to
+ // push
+ // further ahead then it is an exception
+ throw new XMLStreamException("Trying to go beyond the end of the pullparser");
+
+ case DELEGATED_STATE:
+ if (childReader.isDone()) {
+ // we've reached the end!
+ if (index > (getElements().length - 1)) {
+ state = END_ELEMENT_STATE;
+ returnEvent = END_ELEMENT;
+ } else {
+ returnEvent = processProperties();
+ }
+ } else {
+ returnEvent = childReader.next();
+ }
+ break;
+
+ case TEXT_STATE:
+ // if there are any more event we should be delegating to
+ // processProperties. if not we just return an end element
+ if (index > (getElements().length - 1)) {
+ state = END_ELEMENT_STATE;
+ returnEvent = END_ELEMENT;
+ } else {
+ returnEvent = processProperties();
+ }
+ break;
+ }
+ return returnEvent;
+ }
+
+ // /////////////////////////////////////////////////////////////////////////
+ // / Other utility methods
+ // ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * TODO implement this
+ *
+ * @throws XMLStreamException
+ */
+ public int nextTag() throws XMLStreamException {
+ return 0;
+ }
+
+ /**
+ * Populates a namespace context
+ */
+ private void populateNamespaceContext() {
+
+ // first add the current element namespace to the namespace context
+ // declare it if not found
+ addToNsMap(elementQName.getPrefix(), elementQName.getNamespaceURI());
+
+ for (QName n : getNamespaces()) {
+ addToNsMap(n.getPrefix(), n.getNamespaceURI());
+ }
+
+ // traverse through the attributes and populate the namespace context
+ // the attrib list can be of many combinations
+ // the valid combinations are
+ // String - String
+ // QName - QName
+ // null - OMAttribute
+
+ for (int i = 0; i < getAttributes().length; i++) { // jump in two
+ QName attrQName = getAttributes()[i].getKey();
+ if (!"".equals(attrQName.getNamespaceURI())) {
+ addToNsMap(attrQName.getPrefix(), attrQName.getNamespaceURI());
+ }
+ }
+ }
+
+ /**
+ * A convenient method to reuse the properties
+ *
+ * @return event to be thrown
+ * @throws XMLStreamException
+ */
+ private int processProperties() throws XMLStreamException {
+ // move to the next property depending on the current property
+ // index
+ QName propertyQName = getElements()[index].getKey();
+ boolean textFound = false;
+ if (propertyQName == null) {
+ throw new XMLStreamException("property key cannot be null!");
+ } else if (ELEMENT_TEXT.equals(propertyQName.getLocalPart())) {
+ // propPointer being a String has a special case
+ // that is it can be a the special constant ELEMENT_TEXT that
+ // says this text event
+ textFound = true;
+ }
+
+ // OK! we got the key. Now look at the value
+ Object propertyValue = getElements()[index].getValue();
+ // cater for the special case now
+ if (textFound) {
+ // no delegation here - make the parser null and immediately
+ // return with the event characters
+ childReader = null;
+ state = TEXT_STATE;
+ ++index;
+ return CHARACTERS;
+ } else if (propertyValue == null) {
+ // if the value is null we delegate the work to a nullable
+ // parser
+ childReader = new NilElementStreamReader(propertyQName);
+ childReader.setParentNamespaceContext(this.namespaceContext);
+ childReader.init();
+ } else if (propertyValue instanceof String) {
+ // strings are handled by the NameValuePairStreamReader
+ childReader = new NameValuePairStreamReader(propertyQName, (String)propertyValue);
+ childReader.setParentNamespaceContext(this.namespaceContext);
+ childReader.init();
+ } else if (propertyValue instanceof String[]) {
+ // string[] are handled by the NameValueArrayStreamReader
+ // if the array is empty - skip it
+ if (((String[])propertyValue).length == 0) {
+ // advance the index
+ ++index;
+ return processProperties();
+ } else {
+ childReader = new NameValueArrayStreamReader(propertyQName, (String[])propertyValue);
+ childReader.setParentNamespaceContext(this.namespaceContext);
+ childReader.init();
+ }
+
+ } else if (propertyValue instanceof XMLStreamable) {
+ // ADBbean has it's own method to get a reader
+ XMLStreamReader reader = ((XMLStreamable)propertyValue).getXMLStreamReader(propertyQName);
+ // we know for sure that this is an ADB XMLStreamreader.
+ // However we need to make sure that it is compatible
+ if (reader instanceof XMLFragmentStreamReader) {
+ childReader = (XMLFragmentStreamReader)reader;
+ childReader.setParentNamespaceContext(this.namespaceContext);
+ childReader.init();
+ } else {
+ // wrap it to make compatible
+ childReader = new WrappingXMLStreamReader(reader);
+ }
+ } else if (propertyValue instanceof XMLStreamReader) {
+ XMLStreamReader reader = (XMLStreamReader)propertyValue;
+ if (reader instanceof XMLFragmentStreamReader) {
+ childReader = (XMLFragmentStreamReader)reader;
+ childReader.setParentNamespaceContext(this.namespaceContext);
+ childReader.init();
+ } else {
+ // wrap it to make compatible
+ childReader = new WrappingXMLStreamReader(reader);
+ }
+
+ } else {
+ // all special possibilities has been tried! Let's treat
+ // the thing as a bean and try generating events from it
+ throw new UnsupportedOperationException("Property type is not supported");
+ // we cannot register the namespace context here
+ }
+
+ // set the state here
+ state = DELEGATED_STATE;
+ // we are done with the delegation
+ // increment the property index
+ ++index;
+ return childReader.getEventType();
+ }
+
+ public void require(int i, String string, String string1) throws XMLStreamException {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean standaloneSet() {
+ return true;
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLStreamable.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLStreamable.java
new file mode 100644
index 0000000000..f433753f96
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XMLStreamable.java
@@ -0,0 +1,37 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ * An interface represents data that can be read using StAX streaming
+ *
+ * @version $Rev$ $Date$
+ */
+public interface XMLStreamable {
+ /**
+ * Get the XMLStreamReader for StAX processing
+ *
+ * @param rootElementName the name of the element to be generated
+ * @return Returns a pull parser.
+ */
+ XMLStreamReader getXMLStreamReader(QName rootElementName);
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNode.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNode.java
new file mode 100644
index 0000000000..9e39f58b31
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNode.java
@@ -0,0 +1,69 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface XmlNode {
+ enum Type {ELEMENT, ATTRIBUTE, CHARACTERS, READER};
+ /**
+ * Returns the children of the receiver as an <code>Iterator</code>.
+ */
+ Iterator<XmlNode> children();
+
+ /**
+ * Returns the attributes of the element as an <code>List</code>. Namespace declarations
+ * should be excluded.
+ *
+ * @return
+ */
+ List<XmlNode> attributes();
+
+ /**
+ * Returns a map of prefix to namespace URI
+ * @return
+ */
+ Map<String, String> namespaces();
+
+ /**
+ * Return the QName of the element. If it's for a text node, the name is null.
+ * @return
+ */
+ QName getName();
+
+ /**
+ * Return the text value of the leaf element
+ * @return
+ */
+ <T> T getValue();
+
+ /**
+ * Return the type of the XML node
+ * @return
+ */
+ Type getType();
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNodeIterator.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNodeIterator.java
new file mode 100644
index 0000000000..e0eba9a35d
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlNodeIterator.java
@@ -0,0 +1,258 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.NamespaceContext;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class XmlNodeIterator implements Iterator<XmlNode> {
+ public static final int START = 0;
+ public static final int END = 1;
+
+ protected FastStack<ElementHolder> stack;
+ protected int state;
+ protected NamespaceContextImpl nsContext;
+
+ public XmlNodeIterator(XmlNode rootNode) {
+ super();
+ List<XmlNode> v = new ArrayList<XmlNode>(1);
+ v.add(rootNode);
+ stack = new FastStack<ElementHolder>();
+ Iterator<XmlNode> i = v.iterator();
+ stack.push(new ElementHolder(null, i));
+ this.state = START;
+ this.nsContext = new NamespaceContextImpl(null);
+ }
+
+ public boolean hasNext() {
+ return !(stack.empty() || (state == END && stack.peek().parent == null));
+ }
+
+ public XmlNode next() {
+ this.state = START;
+ ElementHolder element = stack.peek();
+ Iterator<XmlNode> it = element.children;
+ if (it == null || (!it.hasNext())) {
+ // End of the children, return END event of parent
+ stack.pop();
+ this.state = END;
+ this.nsContext = (NamespaceContextImpl)nsContext.getParent();
+ return element.parent;
+ }
+ XmlNode node = it.next();
+ stack.push(new ElementHolder(node, node.children()));
+ this.nsContext = new NamespaceContextImpl(this.nsContext);
+ populateNamespaces(node);
+ return node;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ return nsContext;
+ }
+
+ private void populateNamespaces(XmlNode element) {
+ if (element.getName() != null) {
+ if (element.namespaces() != null) {
+ for (Map.Entry<String, String> e : element.namespaces().entrySet()) {
+ nsContext.register(e.getKey(), e.getValue());
+ }
+ }
+ }
+ }
+
+ private static class ElementHolder {
+ private XmlNode parent;
+ private Iterator<XmlNode> children;
+
+ public ElementHolder(XmlNode parent, Iterator<XmlNode> children) {
+ this.parent = parent;
+ this.children = children;
+ }
+ }
+
+ /**
+ * An implementation of the {@link java.util.Stack} API that is based on an <code>ArrayList</code> instead of a
+ * <code>Vector</code>, so it is not synchronized to protect against multi-threaded access. The implementation is
+ * therefore operates faster in environments where you do not need to worry about multiple thread contention.
+ * <p>
+ * The removal order of an <code>ArrayStack</code> is based on insertion order: The most recently added element is
+ * removed first. The iteration order is <i>not</i> the same as the removal order. The iterator returns elements
+ * from the bottom up, whereas the {@link #remove()} method removes them from the top down.
+ * <p>
+ * Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
+ */
+ public static class FastStack<T> extends ArrayList<T> {
+
+ /** Ensure Serialization compatibility */
+ private static final long serialVersionUID = 2130079159931574599L;
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code>. The initial size is controlled by <code>ArrayList</code>
+ * and is currently 10.
+ */
+ public FastStack() {
+ super();
+ }
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code> with an initial size.
+ *
+ * @param initialSize the initial size to use
+ * @throws IllegalArgumentException if the specified initial size is negative
+ */
+ public FastStack(int initialSize) {
+ super(initialSize);
+ }
+
+ /**
+ * Return <code>true</code> if this stack is currently empty.
+ * <p>
+ * This method exists for compatibility with <code>java.util.Stack</code>. New users of this class should use
+ * <code>isEmpty</code> instead.
+ *
+ * @return true if the stack is currently empty
+ */
+ public boolean empty() {
+ return isEmpty();
+ }
+
+ /**
+ * Returns the top item off of this stack without removing it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T peek() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(n - 1);
+ }
+ }
+
+ /**
+ * Returns the n'th item down (zero-relative) from the top of this stack without removing it.
+ *
+ * @param n the number of items down to go
+ * @return the n'th item on the stack, zero relative
+ * @throws EmptyStackException if there are not enough items on the stack to satisfy this request
+ */
+ public T peek(int n) throws EmptyStackException {
+ int m = (size() - n) - 1;
+ if (m < 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(m);
+ }
+ }
+
+ /**
+ * Pops the top item off of this stack and return it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T pop() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return remove(n - 1);
+ }
+ }
+
+ /**
+ * Pushes a new item onto the top of this stack. The pushed item is also returned. This is equivalent to calling
+ * <code>add</code>.
+ *
+ * @param item the item to be added
+ * @return the item just pushed
+ */
+ public Object push(T item) {
+ add(item);
+ return item;
+ }
+
+ /**
+ * Returns the top-most index for the object in the stack
+ *
+ * @param object the object to be searched for
+ * @return top-most index, or -1 if not found
+ */
+ public int search(T object) {
+ int i = size() - 1; // Current index
+ while (i >= 0) {
+ T current = get(i);
+ if ((object == null && current == null) || (object != null && object.equals(current))) {
+ return i;
+ }
+ i--;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the element on the top of the stack.
+ *
+ * @return the element on the top of the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T get() {
+ int size = size();
+ if (size == 0) {
+ throw new EmptyStackException();
+ }
+ return get(size - 1);
+ }
+
+ /**
+ * Removes the element on the top of the stack.
+ *
+ * @return the removed element
+ * @throws EmptyStackException if the stack is empty
+ */
+ public T remove() {
+ int size = size();
+ if (size == 0) {
+ throw new EmptyStackException();
+ }
+ return remove(size - 1);
+ }
+
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderImpl.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderImpl.java
new file mode 100644
index 0000000000..3c4c1bdb06
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/reader/XmlTreeStreamReaderImpl.java
@@ -0,0 +1,531 @@
+/*
+ * 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.common.xml.stax.reader;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+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;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class XmlTreeStreamReaderImpl implements XMLStreamReader {
+
+ protected int state;
+ protected XmlNodeIterator iterator;
+ protected XmlNode current;
+
+ protected XMLStreamReader reader;
+
+ /*
+ * we need to pass in a namespace context since when delegated, we've no
+ * idea of the current namespace context. So it needs to be passed on here!
+ */
+ public XmlTreeStreamReaderImpl(XmlNode root) {
+ this.iterator = new XmlNodeIterator(root);
+ this.current = null;
+ this.state = START_DOCUMENT;
+ this.reader = null;
+ }
+
+ public void close() throws XMLStreamException {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+
+ private void checkElementState() {
+ if (getEventType() != START_ELEMENT && getEventType() != END_ELEMENT) {
+ throw new IllegalStateException();
+ }
+ }
+
+ private List<XmlNode> getAttributes() {
+ if (current != null && current.attributes() != null) {
+ return current.attributes();
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ public int getAttributeCount() {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeCount();
+ }
+ return getAttributes().size();
+ }
+
+ public String getAttributeLocalName(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeLocalName(i);
+ }
+ return getAttributes().get(i).getName().getLocalPart();
+ }
+
+ /**
+ * @param i
+ */
+ public QName getAttributeName(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeName(i);
+ }
+ return getAttributes().get(i).getName();
+ }
+
+ public String getAttributeNamespace(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeNamespace(i);
+ }
+ return getAttributes().get(i).getName().getNamespaceURI();
+ }
+
+ public String getAttributePrefix(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributePrefix(i);
+ }
+ return getAttributes().get(i).getName().getPrefix();
+ }
+
+ public String getAttributeType(int i) {
+ if (reader != null) {
+ return reader.getAttributeType(i);
+ }
+ return null; // not supported
+ }
+
+ public String getAttributeValue(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeValue(i);
+ }
+ return getAttributes().get(i).getValue();
+ }
+
+ public String getAttributeValue(String nsUri, String localName) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getAttributeValue(nsUri, localName);
+ }
+ int count = getAttributeCount();
+ String value = null;
+ QName attrQName;
+ for (int i = 0; i < count; i++) {
+ attrQName = getAttributeName(i);
+ if (nsUri == null) {
+ if (localName.equals(attrQName.getLocalPart())) {
+ value = getAttributeValue(i);
+ break;
+ }
+ } else {
+ if (localName.equals(attrQName.getLocalPart()) && nsUri.equals(attrQName.getNamespaceURI())) {
+ value = getAttributeValue(i);
+ break;
+ }
+ }
+
+ }
+
+ return value;
+ }
+
+ public String getCharacterEncodingScheme() {
+ if (reader != null) {
+ return reader.getCharacterEncodingScheme();
+ }
+ return "UTF-8";
+ }
+
+ public String getElementText() throws XMLStreamException {
+ checkElementState();
+ if (reader != null) {
+ return reader.getElementText();
+ }
+ return current.getValue();
+ }
+
+ public String getEncoding() {
+ if (reader != null) {
+ return reader.getEncoding();
+ }
+ return "UTF-8";
+ }
+
+ public int getEventType() {
+ return state;
+ }
+
+ public String getLocalName() {
+ checkElementState();
+ if (reader != null) {
+ return reader.getLocalName();
+ }
+ return current.getName().getLocalPart();
+ }
+
+ /**
+ */
+ public Location getLocation() {
+ if (reader != null) {
+ return reader.getLocation();
+ }
+ // return a default location
+ return new Location() {
+ public int getCharacterOffset() {
+ return 0;
+ }
+
+ public int getColumnNumber() {
+ return 0;
+ }
+
+ public int getLineNumber() {
+ return 0;
+ }
+
+ public String getPublicId() {
+ return null;
+ }
+
+ public String getSystemId() {
+ return null;
+ }
+ };
+ }
+
+ public QName getName() {
+ checkElementState();
+ if (reader != null) {
+ return reader.getName();
+ }
+ return current.getName();
+ }
+
+ public NamespaceContext getNamespaceContext() {
+ if (reader != null) {
+ return reader.getNamespaceContext();
+ }
+ return iterator.getNamespaceContext();
+ }
+
+ private Map<String, String> getNamespaces() {
+ if (current != null && current.namespaces() != null) {
+ return current.namespaces();
+ } else {
+ return Collections.emptyMap();
+ }
+ }
+
+ public int getNamespaceCount() {
+ checkElementState();
+ if (reader != null) {
+ return reader.getNamespaceCount();
+ }
+ return getNamespaces().size();
+ }
+
+ /**
+ * @param i
+ */
+ public String getNamespacePrefix(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getNamespacePrefix(i);
+ }
+ return new ArrayList<Map.Entry<String, String>>(getNamespaces().entrySet()).get(i).getKey();
+ }
+
+ public String getNamespaceURI() {
+ checkElementState();
+ if (reader != null) {
+ return reader.getNamespaceURI();
+ }
+ return current.getName().getNamespaceURI();
+ }
+
+ public String getNamespaceURI(int i) {
+ checkElementState();
+ if (reader != null) {
+ return reader.getNamespaceURI(i);
+ }
+ return new ArrayList<Map.Entry<String, String>>(getNamespaces().entrySet()).get(i).getValue();
+ }
+
+ public String getNamespaceURI(String prefix) {
+ if (reader != null) {
+ return reader.getNamespaceURI(prefix);
+ }
+ return getNamespaceContext().getNamespaceURI(prefix);
+ }
+
+ public String getPIData() {
+ if (reader != null) {
+ return reader.getPIData();
+ }
+ throw new UnsupportedOperationException("Yet to be implemented !!");
+ }
+
+ public String getPITarget() {
+ if (reader != null) {
+ return reader.getPITarget();
+ }
+ throw new UnsupportedOperationException("Yet to be implemented !!");
+ }
+
+ public String getPrefix() {
+ if (reader != null) {
+ return reader.getPrefix();
+ }
+ if (state == START_ELEMENT || state == END_ELEMENT) {
+ String prefix = current.getName().getPrefix();
+ return "".equals(prefix) ? null : prefix;
+ } else if (state == START_DOCUMENT) {
+ return null;
+ } else {
+ throw new IllegalStateException("State==" + state);
+ }
+ }
+
+ /**
+ * @param key
+ * @throws IllegalArgumentException
+ */
+ public Object getProperty(String key) throws IllegalArgumentException {
+ if (reader != null) {
+ return reader.getProperty(key);
+ }
+ return null;
+ }
+
+ public String getText() {
+ if (reader != null) {
+ return reader.getText();
+ }
+ return current.getValue();
+ }
+
+ public char[] getTextCharacters() {
+ if (reader != null) {
+ return reader.getTextCharacters();
+ }
+ String value = current.getValue();
+ return value == null ? new char[0] : value.toCharArray();
+ }
+
+ private int copy(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 getTextCharacters(int i, char[] chars, int i1, int i2) throws XMLStreamException {
+ if (reader != null) {
+ return reader.getTextCharacters(i, chars, i1, i2);
+ }
+ return copy(i, chars, i1, i2);
+ }
+
+ public int getTextLength() {
+ if (reader != null) {
+ return reader.getTextLength();
+ }
+ return getTextCharacters().length;
+ }
+
+ public int getTextStart() {
+ if (reader != null) {
+ return reader.getTextStart();
+ }
+ return 0;
+ }
+
+ public String getVersion() {
+ return "1.0";
+ }
+
+ public boolean hasName() {
+ if (reader != null) {
+ return reader.hasName();
+ }
+ return current.getName() != null;
+ }
+
+ /**
+ * @throws XMLStreamException
+ */
+ public boolean hasNext() throws XMLStreamException {
+ return iterator.hasNext() || state != END_DOCUMENT || (reader != null && reader.hasNext());
+ }
+
+ public boolean hasText() {
+ if (reader != null) {
+ return reader.hasText();
+ }
+ return current.getType() == XmlNode.Type.CHARACTERS;
+ }
+
+ public boolean isAttributeSpecified(int i) {
+ if (reader != null) {
+ return reader.isAttributeSpecified(i);
+ }
+ return false; // not supported
+ }
+
+ public boolean isCharacters() {
+ if (reader != null) {
+ return reader.isCharacters();
+ }
+ return current.getType() == XmlNode.Type.CHARACTERS;
+ }
+
+ public boolean isEndElement() {
+ if (reader != null) {
+ return reader.isEndElement();
+ }
+ return getEventType() == END_ELEMENT;
+ }
+
+ public boolean isStandalone() {
+ return true;
+ }
+
+ public boolean isStartElement() {
+ if (reader != null) {
+ return reader.isStartElement();
+ }
+ return getEventType() == START_ELEMENT;
+ }
+
+ public boolean isWhiteSpace() {
+ if (reader != null) {
+ return reader.isWhiteSpace();
+ }
+ return false;
+ }
+
+ /**
+ * By far this should be the most important method in this class this method
+ * changes the state of the parser
+ */
+ public int next() throws XMLStreamException {
+ if (!hasNext()) {
+ throw new IllegalStateException("No more events");
+ }
+ if (reader != null) {
+ if (!reader.hasNext()) {
+ this.reader = null;
+ } else {
+ // Go to the delegation mode
+ state = reader.next();
+ return state;
+ }
+ }
+ if (!iterator.hasNext()) {
+ state = END_DOCUMENT;
+ current = null;
+ return state;
+ }
+ current = iterator.next();
+ XmlNode.Type type = current.getType();
+
+ int itState = iterator.getState();
+ if (itState == XmlNodeIterator.END) {
+ if (type == XmlNode.Type.ELEMENT) {
+ state = END_ELEMENT;
+ } else {
+ // Ignore the pop
+ state = next();
+ }
+ }
+ if (itState == XmlNodeIterator.START) {
+ if (type == XmlNode.Type.ELEMENT) {
+ state = START_ELEMENT;
+ } else if (type == XmlNode.Type.CHARACTERS) {
+ state = CHARACTERS;
+ } else if (type == XmlNode.Type.READER) {
+ XMLStreamReader value = current.getValue();
+ this.reader = new WrappingXMLStreamReader(value);
+ state = reader.getEventType();
+ return state;
+ }
+ }
+ return state;
+ }
+
+ /**
+ * TODO implement this
+ *
+ * @throws XMLStreamException
+ */
+ public int nextTag() throws XMLStreamException {
+ while (true) {
+ int event = next();
+ if (event == START_ELEMENT || event == END_ELEMENT) {
+ return event;
+ }
+ }
+ }
+
+ public void require(int i, String ns, String localPart) throws XMLStreamException {
+ if (reader != null) {
+ reader.require(i, ns, localPart);
+ return;
+ }
+ int event = getEventType();
+ if (event != i) {
+ throw new IllegalStateException("Event type is " + event + " (!=" + i + ")");
+ }
+ QName name = getName();
+ String ns1 = name.getNamespaceURI();
+ String localName1 = name.getLocalPart();
+
+ if (ns != null && !ns.equals(ns1)) {
+ throw new IllegalStateException("Namespace URI is " + ns1 + " (!=" + ns + ")");
+ }
+
+ if (localPart != null && !localPart.equals(localName1)) {
+ throw new IllegalStateException("Local name is " + localName1 + " (!=" + localPart + ")");
+ }
+
+ }
+
+ public boolean standaloneSet() {
+ return true;
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XMLCharHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XMLCharHelper.java
new file mode 100644
index 0000000000..ea659ce344
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XMLCharHelper.java
@@ -0,0 +1,613 @@
+/*
+ * 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.common.xml.xpath;
+
+/**
+ * This class defines the basic XML character properties. The data
+ * in this class can be used to verify that a character is a valid
+ * XML character or if the character is a space, name start, or name
+ * character.
+ * <p/>
+ * A series of convenience methods are supplied to ease the burden
+ * of the developer. Because inlining the checks can improve per
+ * character performance, the tables of character properties are
+ * public. Using the character as an index into the <code>CHARS</code>
+ * array and applying the appropriate mask flag (e.g.
+ * <code>MASK_VALID</code>), yields the same results as calling the
+ * convenience methods. There is one exception: check the comments
+ * for the <code>isValid</code> method for details.
+ */
+public class XMLCharHelper {
+
+ //
+ // Constants
+ //
+
+ /**
+ * Character flags.
+ */
+ private static final byte[] CHARS = new byte[1 << 16];
+
+ /**
+ * Valid character mask.
+ */
+ public static final int MASK_VALID = 0x01;
+
+ /**
+ * Space character mask.
+ */
+ public static final int MASK_SPACE = 0x02;
+
+ /**
+ * Name start character mask.
+ */
+ public static final int MASK_NAME_START = 0x04;
+
+ /**
+ * Name character mask.
+ */
+ public static final int MASK_NAME = 0x08;
+
+ /**
+ * Pubid character mask.
+ */
+ public static final int MASK_PUBID = 0x10;
+
+ /**
+ * Content character mask. Special characters are those that can
+ * be considered the start of markup, such as '&lt;' and '&amp;'.
+ * The various newline characters are considered special as well.
+ * All other valid XML characters can be considered content.
+ * <p/>
+ * This is an optimization for the inner loop of character scanning.
+ */
+ public static final int MASK_CONTENT = 0x20;
+
+ /**
+ * NCName start character mask.
+ */
+ public static final int MASK_NCNAME_START = 0x40;
+
+ /**
+ * NCName character mask.
+ */
+ public static final int MASK_NCNAME = 0x80;
+
+ //
+ // Static initialization
+ //
+
+ static {
+
+ //
+ // [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] |
+ // [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ //
+
+ int charRange[] = {0x0009, 0x000A, 0x000D, 0x000D, 0x0020, 0xD7FF, 0xE000, 0xFFFD,};
+
+ //
+ // [3] S ::= (#x20 | #x9 | #xD | #xA)+
+ //
+
+ int spaceChar[] = {0x0020, 0x0009, 0x000D, 0x000A,};
+
+ //
+ // [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ // CombiningChar | Extender
+ //
+
+ int nameChar[] = {0x002D, 0x002E, // '-' and '.'
+ };
+
+ //
+ // [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ //
+
+ int nameStartChar[] = {0x003A, 0x005F, // ':' and '_'
+ };
+
+ //
+ // [13] PubidChar ::= #x20 | 0xD | 0xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
+ //
+
+ int pubidChar[] = {0x000A, 0x000D, 0x0020, 0x0021, 0x0023, 0x0024, 0x0025, 0x003D, 0x005F};
+
+ int pubidRange[] = {0x0027, 0x003B, 0x003F, 0x005A, 0x0061, 0x007A};
+
+ //
+ // [84] Letter ::= BaseChar | Ideographic
+ //
+
+ int letterRange[] =
+ {
+ // BaseChar
+ 0x0041, 0x005A, 0x0061, 0x007A, 0x00C0, 0x00D6, 0x00D8, 0x00F6, 0x00F8, 0x0131, 0x0134, 0x013E, 0x0141,
+ 0x0148, 0x014A, 0x017E, 0x0180, 0x01C3, 0x01CD, 0x01F0, 0x01F4, 0x01F5, 0x01FA, 0x0217, 0x0250, 0x02A8,
+ 0x02BB, 0x02C1, 0x0388, 0x038A, 0x038E, 0x03A1, 0x03A3, 0x03CE, 0x03D0, 0x03D6, 0x03E2, 0x03F3, 0x0401,
+ 0x040C, 0x040E, 0x044F, 0x0451, 0x045C, 0x045E, 0x0481, 0x0490, 0x04C4, 0x04C7, 0x04C8, 0x04CB, 0x04CC,
+ 0x04D0, 0x04EB, 0x04EE, 0x04F5, 0x04F8, 0x04F9, 0x0531, 0x0556, 0x0561, 0x0586, 0x05D0, 0x05EA, 0x05F0,
+ 0x05F2, 0x0621, 0x063A, 0x0641, 0x064A, 0x0671, 0x06B7, 0x06BA, 0x06BE, 0x06C0, 0x06CE, 0x06D0, 0x06D3,
+ 0x06E5, 0x06E6, 0x0905, 0x0939, 0x0958, 0x0961, 0x0985, 0x098C, 0x098F, 0x0990, 0x0993, 0x09A8, 0x09AA,
+ 0x09B0, 0x09B6, 0x09B9, 0x09DC, 0x09DD, 0x09DF, 0x09E1, 0x09F0, 0x09F1, 0x0A05, 0x0A0A, 0x0A0F, 0x0A10,
+ 0x0A13, 0x0A28, 0x0A2A, 0x0A30, 0x0A32, 0x0A33, 0x0A35, 0x0A36, 0x0A38, 0x0A39, 0x0A59, 0x0A5C, 0x0A72,
+ 0x0A74, 0x0A85, 0x0A8B, 0x0A8F, 0x0A91, 0x0A93, 0x0AA8, 0x0AAA, 0x0AB0, 0x0AB2, 0x0AB3, 0x0AB5, 0x0AB9,
+ 0x0B05, 0x0B0C, 0x0B0F, 0x0B10, 0x0B13, 0x0B28, 0x0B2A, 0x0B30, 0x0B32, 0x0B33, 0x0B36, 0x0B39, 0x0B5C,
+ 0x0B5D, 0x0B5F, 0x0B61, 0x0B85, 0x0B8A, 0x0B8E, 0x0B90, 0x0B92, 0x0B95, 0x0B99, 0x0B9A, 0x0B9E, 0x0B9F,
+ 0x0BA3, 0x0BA4, 0x0BA8, 0x0BAA, 0x0BAE, 0x0BB5, 0x0BB7, 0x0BB9, 0x0C05, 0x0C0C, 0x0C0E, 0x0C10, 0x0C12,
+ 0x0C28, 0x0C2A, 0x0C33, 0x0C35, 0x0C39, 0x0C60, 0x0C61, 0x0C85, 0x0C8C, 0x0C8E, 0x0C90, 0x0C92, 0x0CA8,
+ 0x0CAA, 0x0CB3, 0x0CB5, 0x0CB9, 0x0CE0, 0x0CE1, 0x0D05, 0x0D0C, 0x0D0E, 0x0D10, 0x0D12, 0x0D28, 0x0D2A,
+ 0x0D39, 0x0D60, 0x0D61, 0x0E01, 0x0E2E, 0x0E32, 0x0E33, 0x0E40, 0x0E45, 0x0E81, 0x0E82, 0x0E87, 0x0E88,
+ 0x0E94, 0x0E97, 0x0E99, 0x0E9F, 0x0EA1, 0x0EA3, 0x0EAA, 0x0EAB, 0x0EAD, 0x0EAE, 0x0EB2, 0x0EB3, 0x0EC0,
+ 0x0EC4, 0x0F40, 0x0F47, 0x0F49, 0x0F69, 0x10A0, 0x10C5, 0x10D0, 0x10F6, 0x1102, 0x1103, 0x1105, 0x1107,
+ 0x110B, 0x110C, 0x110E, 0x1112, 0x1154, 0x1155, 0x115F, 0x1161, 0x116D, 0x116E, 0x1172, 0x1173, 0x11AE,
+ 0x11AF, 0x11B7, 0x11B8, 0x11BC, 0x11C2, 0x1E00, 0x1E9B, 0x1EA0, 0x1EF9, 0x1F00, 0x1F15, 0x1F18, 0x1F1D,
+ 0x1F20, 0x1F45, 0x1F48, 0x1F4D, 0x1F50, 0x1F57, 0x1F5F, 0x1F7D, 0x1F80, 0x1FB4, 0x1FB6, 0x1FBC, 0x1FC2,
+ 0x1FC4, 0x1FC6, 0x1FCC, 0x1FD0, 0x1FD3, 0x1FD6, 0x1FDB, 0x1FE0, 0x1FEC, 0x1FF2, 0x1FF4, 0x1FF6, 0x1FFC,
+ 0x212A, 0x212B, 0x2180, 0x2182, 0x3041, 0x3094, 0x30A1, 0x30FA, 0x3105, 0x312C, 0xAC00, 0xD7A3,
+ // Ideographic
+ 0x3021, 0x3029, 0x4E00, 0x9FA5,};
+ int letterChar[] =
+ {
+ // BaseChar
+ 0x0386, 0x038C, 0x03DA, 0x03DC, 0x03DE, 0x03E0, 0x0559, 0x06D5, 0x093D, 0x09B2, 0x0A5E, 0x0A8D, 0x0ABD,
+ 0x0AE0, 0x0B3D, 0x0B9C, 0x0CDE, 0x0E30, 0x0E84, 0x0E8A, 0x0E8D, 0x0EA5, 0x0EA7, 0x0EB0, 0x0EBD, 0x1100,
+ 0x1109, 0x113C, 0x113E, 0x1140, 0x114C, 0x114E, 0x1150, 0x1159, 0x1163, 0x1165, 0x1167, 0x1169, 0x1175,
+ 0x119E, 0x11A8, 0x11AB, 0x11BA, 0x11EB, 0x11F0, 0x11F9, 0x1F59, 0x1F5B, 0x1F5D, 0x1FBE, 0x2126, 0x212E,
+ // Ideographic
+ 0x3007,};
+
+ //
+ // [87] CombiningChar ::= ...
+ //
+
+ int combiningCharRange[] =
+ {0x0300, 0x0345, 0x0360, 0x0361, 0x0483, 0x0486, 0x0591, 0x05A1, 0x05A3, 0x05B9, 0x05BB, 0x05BD, 0x05C1,
+ 0x05C2, 0x064B, 0x0652, 0x06D6, 0x06DC, 0x06DD, 0x06DF, 0x06E0, 0x06E4, 0x06E7, 0x06E8, 0x06EA, 0x06ED,
+ 0x0901, 0x0903, 0x093E, 0x094C, 0x0951, 0x0954, 0x0962, 0x0963, 0x0981, 0x0983, 0x09C0, 0x09C4, 0x09C7,
+ 0x09C8, 0x09CB, 0x09CD, 0x09E2, 0x09E3, 0x0A40, 0x0A42, 0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71,
+ 0x0A81, 0x0A83, 0x0ABE, 0x0AC5, 0x0AC7, 0x0AC9, 0x0ACB, 0x0ACD, 0x0B01, 0x0B03, 0x0B3E, 0x0B43, 0x0B47,
+ 0x0B48, 0x0B4B, 0x0B4D, 0x0B56, 0x0B57, 0x0B82, 0x0B83, 0x0BBE, 0x0BC2, 0x0BC6, 0x0BC8, 0x0BCA, 0x0BCD,
+ 0x0C01, 0x0C03, 0x0C3E, 0x0C44, 0x0C46, 0x0C48, 0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0C82, 0x0C83, 0x0CBE,
+ 0x0CC4, 0x0CC6, 0x0CC8, 0x0CCA, 0x0CCD, 0x0CD5, 0x0CD6, 0x0D02, 0x0D03, 0x0D3E, 0x0D43, 0x0D46, 0x0D48,
+ 0x0D4A, 0x0D4D, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18,
+ 0x0F19, 0x0F71, 0x0F84, 0x0F86, 0x0F8B, 0x0F90, 0x0F95, 0x0F99, 0x0FAD, 0x0FB1, 0x0FB7, 0x20D0, 0x20DC,
+ 0x302A, 0x302F,};
+
+ int combiningCharChar[] =
+ {0x05BF, 0x05C4, 0x0670, 0x093C, 0x094D, 0x09BC, 0x09BE, 0x09BF, 0x09D7, 0x0A02, 0x0A3C, 0x0A3E, 0x0A3F,
+ 0x0ABC, 0x0B3C, 0x0BD7, 0x0D57, 0x0E31, 0x0EB1, 0x0F35, 0x0F37, 0x0F39, 0x0F3E, 0x0F3F, 0x0F97, 0x0FB9,
+ 0x20E1, 0x3099, 0x309A,};
+
+ //
+ // [88] Digit ::= ...
+ //
+
+ int digitRange[] =
+ {0x0030, 0x0039, 0x0660, 0x0669, 0x06F0, 0x06F9, 0x0966, 0x096F, 0x09E6, 0x09EF, 0x0A66, 0x0A6F, 0x0AE6,
+ 0x0AEF, 0x0B66, 0x0B6F, 0x0BE7, 0x0BEF, 0x0C66, 0x0C6F, 0x0CE6, 0x0CEF, 0x0D66, 0x0D6F, 0x0E50, 0x0E59,
+ 0x0ED0, 0x0ED9, 0x0F20, 0x0F29,};
+
+ //
+ // [89] Extender ::= ...
+ //
+
+ int extenderRange[] = {0x3031, 0x3035, 0x309D, 0x309E, 0x30FC, 0x30FE,};
+
+ int extenderChar[] = {0x00B7, 0x02D0, 0x02D1, 0x0387, 0x0640, 0x0E46, 0x0EC6, 0x3005,};
+
+ //
+ // SpecialChar ::= '<', '&', '\n', '\r', ']'
+ //
+
+ int specialChar[] = {'<', '&', '\n', '\r', ']',};
+
+ //
+ // Initialize
+ //
+
+ // set valid characters
+ for (int i = 0; i < charRange.length; i += 2) {
+ for (int j = charRange[i]; j <= charRange[i + 1]; j++) {
+ CHARS[j] |= MASK_VALID | MASK_CONTENT;
+ }
+ }
+
+ // remove special characters
+ for (int i = 0; i < specialChar.length; i++) {
+ CHARS[specialChar[i]] = (byte)(CHARS[specialChar[i]] & ~MASK_CONTENT);
+ }
+
+ // set space characters
+ for (int i = 0; i < spaceChar.length; i++) {
+ CHARS[spaceChar[i]] |= MASK_SPACE;
+ }
+
+ // set name start characters
+ for (int i = 0; i < nameStartChar.length; i++) {
+ CHARS[nameStartChar[i]] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME;
+ }
+ for (int i = 0; i < letterRange.length; i += 2) {
+ for (int j = letterRange[i]; j <= letterRange[i + 1]; j++) {
+ CHARS[j] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME;
+ }
+ }
+ for (int i = 0; i < letterChar.length; i++) {
+ CHARS[letterChar[i]] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME;
+ }
+
+ // set name characters
+ for (int i = 0; i < nameChar.length; i++) {
+ CHARS[nameChar[i]] |= MASK_NAME | MASK_NCNAME;
+ }
+ for (int i = 0; i < digitRange.length; i += 2) {
+ for (int j = digitRange[i]; j <= digitRange[i + 1]; j++) {
+ CHARS[j] |= MASK_NAME | MASK_NCNAME;
+ }
+ }
+ for (int i = 0; i < combiningCharRange.length; i += 2) {
+ for (int j = combiningCharRange[i]; j <= combiningCharRange[i + 1]; j++) {
+ CHARS[j] |= MASK_NAME | MASK_NCNAME;
+ }
+ }
+ for (int i = 0; i < combiningCharChar.length; i++) {
+ CHARS[combiningCharChar[i]] |= MASK_NAME | MASK_NCNAME;
+ }
+ for (int i = 0; i < extenderRange.length; i += 2) {
+ for (int j = extenderRange[i]; j <= extenderRange[i + 1]; j++) {
+ CHARS[j] |= MASK_NAME | MASK_NCNAME;
+ }
+ }
+ for (int i = 0; i < extenderChar.length; i++) {
+ CHARS[extenderChar[i]] |= MASK_NAME | MASK_NCNAME;
+ }
+
+ // remove ':' from allowable MASK_NCNAME_START and MASK_NCNAME chars
+ CHARS[':'] &= ~(MASK_NCNAME_START | MASK_NCNAME);
+
+ // set Pubid characters
+ for (int i = 0; i < pubidChar.length; i++) {
+ CHARS[pubidChar[i]] |= MASK_PUBID;
+ }
+ for (int i = 0; i < pubidRange.length; i += 2) {
+ for (int j = pubidRange[i]; j <= pubidRange[i + 1]; j++) {
+ CHARS[j] |= MASK_PUBID;
+ }
+ }
+
+ } // <clinit>()
+
+ //
+ // Public static methods
+ //
+
+ /**
+ * Returns true if the specified character is a supplemental character.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isSupplemental(int c) {
+ return (c >= 0x10000 && c <= 0x10FFFF);
+ }
+
+ /**
+ * Returns true the supplemental character corresponding to the given
+ * surrogates.
+ *
+ * @param h The high surrogate.
+ * @param l The low surrogate.
+ */
+ public static int supplemental(char h, char l) {
+ return (h - 0xD800) * 0x400 + (l - 0xDC00) + 0x10000;
+ }
+
+ /**
+ * Returns the high surrogate of a supplemental character
+ *
+ * @param c The supplemental character to "split".
+ */
+ public static char highSurrogate(int c) {
+ return (char)(((c - 0x00010000) >> 10) + 0xD800);
+ }
+
+ /**
+ * Returns the low surrogate of a supplemental character
+ *
+ * @param c The supplemental character to "split".
+ */
+ public static char lowSurrogate(int c) {
+ return (char)(((c - 0x00010000) & 0x3FF) + 0xDC00);
+ }
+
+ /**
+ * Returns whether the given character is a high surrogate
+ *
+ * @param c The character to check.
+ */
+ public static boolean isHighSurrogate(int c) {
+ return (0xD800 <= c && c <= 0xDBFF);
+ }
+
+ /**
+ * Returns whether the given character is a low surrogate
+ *
+ * @param c The character to check.
+ */
+ public static boolean isLowSurrogate(int c) {
+ return (0xDC00 <= c && c <= 0xDFFF);
+ }
+
+ /**
+ * Returns true if the specified character is valid. This method
+ * also checks the surrogate character range from 0x10000 to 0x10FFFF.
+ * <p/>
+ * If the program chooses to apply the mask directly to the
+ * <code>CHARS</code> array, then they are responsible for checking
+ * the surrogate character range.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isValid(int c) {
+ return (c < 0x10000 && (CHARS[c] & MASK_VALID) != 0) || (0x10000 <= c && c <= 0x10FFFF);
+ } // isValid(int):boolean
+
+ /**
+ * Returns true if the specified character is invalid.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isInvalid(int c) {
+ return !isValid(c);
+ } // isInvalid(int):boolean
+
+ /**
+ * Returns true if the specified character can be considered content.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isContent(int c) {
+ return (c < 0x10000 && (CHARS[c] & MASK_CONTENT) != 0) || (0x10000 <= c && c <= 0x10FFFF);
+ } // isContent(int):boolean
+
+ /**
+ * Returns true if the specified character can be considered markup.
+ * Markup characters include '&lt;', '&amp;', and '%'.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isMarkup(int c) {
+ return c == '<' || c == '&' || c == '%';
+ } // isMarkup(int):boolean
+
+ /**
+ * Returns true if the specified character is a space character
+ * as defined by production [3] in the XML 1.0 specification.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isSpace(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_SPACE) != 0;
+ } // isSpace(int):boolean
+
+ /**
+ * Returns true if the specified character is a space character
+ * as amdended in the XML 1.1 specification.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isXML11Space(int c) {
+ return (c < 0x10000 && (CHARS[c] & MASK_SPACE) != 0) || c == 0x85 || c == 0x2028;
+ } // isXML11Space(int):boolean
+
+ /**
+ * Returns true if the specified character is a valid name start
+ * character as defined by production [5] in the XML 1.0
+ * specification.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isNameStart(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0;
+ } // isNameStart(int):boolean
+
+ /**
+ * Returns true if the specified character is a valid name
+ * character as defined by production [4] in the XML 1.0
+ * specification.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isName(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0;
+ } // isName(int):boolean
+
+ /**
+ * Returns true if the specified character is a valid NCName start
+ * character as defined by production [4] in Namespaces in XML
+ * recommendation.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isNCNameStart(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_NCNAME_START) != 0;
+ } // isNCNameStart(int):boolean
+
+ /**
+ * Returns true if the specified character is a valid NCName
+ * character as defined by production [5] in Namespaces in XML
+ * recommendation.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isNCName(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_NCNAME) != 0;
+ } // isNCName(int):boolean
+
+ /**
+ * Returns true if the specified character is a valid Pubid
+ * character as defined by production [13] in the XML 1.0
+ * specification.
+ *
+ * @param c The character to check.
+ */
+ public static boolean isPubid(int c) {
+ return c < 0x10000 && (CHARS[c] & MASK_PUBID) != 0;
+ } // isPubid(int):boolean
+
+ /*
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ */
+ /**
+ * Check to see if a string is a valid Name according to [5]
+ * in the XML 1.0 Recommendation
+ *
+ * @param name string to check
+ * @return true if name is a valid Name
+ */
+ public static boolean isValidName(String name) {
+ if (name.length() == 0) {
+ return false;
+ }
+ char ch = name.charAt(0);
+ if (!isNameStart(ch)) {
+ return false;
+ }
+ for (int i = 1; i < name.length(); i++) {
+ ch = name.charAt(i);
+ if (!isName(ch)) {
+ return false;
+ }
+ }
+ return true;
+ } // isValidName(String):boolean
+
+ /*
+ * from the namespace rec
+ * [4] NCName ::= (Letter | '_') (NCNameChar)*
+ */
+ /**
+ * Check to see if a string is a valid NCName according to [4]
+ * from the XML Namespaces 1.0 Recommendation
+ *
+ * @param ncName string to check
+ * @return true if name is a valid NCName
+ */
+ public static boolean isValidNCName(String ncName) {
+ if (ncName.length() == 0) {
+ return false;
+ }
+ char ch = ncName.charAt(0);
+ if (!isNCNameStart(ch)) {
+ return false;
+ }
+ for (int i = 1; i < ncName.length(); i++) {
+ ch = ncName.charAt(i);
+ if (!isNCName(ch)) {
+ return false;
+ }
+ }
+ return true;
+ } // isValidNCName(String):boolean
+
+ /*
+ * [7] Nmtoken ::= (NameChar)+
+ */
+ /**
+ * Check to see if a string is a valid Nmtoken according to [7]
+ * in the XML 1.0 Recommendation
+ *
+ * @param nmtoken string to check
+ * @return true if nmtoken is a valid Nmtoken
+ */
+ public static boolean isValidNmtoken(String nmtoken) {
+ if (nmtoken.length() == 0) {
+ return false;
+ }
+ for (int i = 0; i < nmtoken.length(); i++) {
+ char ch = nmtoken.charAt(i);
+ if (!isName(ch)) {
+ return false;
+ }
+ }
+ return true;
+ } // isValidName(String):boolean
+
+ // encodings
+
+ /**
+ * Returns true if the encoding name is a valid IANA encoding.
+ * This method does not verify that there is a decoder available
+ * for this encoding, only that the characters are valid for an
+ * IANA encoding name.
+ *
+ * @param ianaEncoding The IANA encoding name.
+ */
+ public static boolean isValidIANAEncoding(String ianaEncoding) {
+ if (ianaEncoding != null) {
+ int length = ianaEncoding.length();
+ if (length > 0) {
+ char c = ianaEncoding.charAt(0);
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ for (int i = 1; i < length; i++) {
+ c = ianaEncoding.charAt(i);
+ if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')
+ && (c < '0' || c > '9')
+ && c != '.'
+ && c != '_'
+ && c != '-') {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ } // isValidIANAEncoding(String):boolean
+
+ /**
+ * Returns true if the encoding name is a valid Java encoding.
+ * This method does not verify that there is a decoder available
+ * for this encoding, only that the characters are valid for an
+ * Java encoding name.
+ *
+ * @param javaEncoding The Java encoding name.
+ */
+ public static boolean isValidJavaEncoding(String javaEncoding) {
+ if (javaEncoding != null) {
+ int length = javaEncoding.length();
+ if (length > 0) {
+ for (int i = 1; i < length; i++) {
+ char c = javaEncoding.charAt(i);
+ if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')
+ && (c < '0' || c > '9')
+ && c != '.'
+ && c != '_'
+ && c != '-') {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ } // isValidIANAEncoding(String):boolean
+
+} // class XMLChar
diff --git a/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XPathHelper.java b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XPathHelper.java
new file mode 100644
index 0000000000..d364aa199f
--- /dev/null
+++ b/sca-java-2.x/branches/2.0-Beta2/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/xpath/XPathHelper.java
@@ -0,0 +1,169 @@
+/*
+ * 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.common.xml.xpath;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.tuscany.sca.common.xml.stax.reader.NamespaceContextImpl;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+
+/**
+ * Helper for XPath operations
+ */
+public class XPathHelper {
+ private XPathFactory factory;
+
+ /**
+ * @param factory
+ */
+ public XPathHelper(XPathFactory factory) {
+ super();
+ this.factory = factory;
+ }
+
+ public XPathHelper(ExtensionPointRegistry registry) {
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ this.factory = factories.getFactory(XPathFactory.class);
+ }
+
+ public static XPathHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilities.getUtility(XPathHelper.class);
+ }
+
+ public XPath newXPath() {
+ return factory.newXPath();
+ }
+
+ public XPathExpression compile(NamespaceContext context, String expression) throws XPathExpressionException {
+ XPath path = newXPath();
+ context = getNamespaceContext(expression, context);
+ return compile(path, context, expression);
+ }
+
+ public XPathExpression compile(XPath path, NamespaceContext context, String expression)
+ throws XPathExpressionException {
+ path.setNamespaceContext(context);
+ return path.compile(expression);
+ }
+
+ /**
+ * Take a snapshot of the given namespace context based on the prefixes found in the expression.
+ * In StAX, the prefix/namespace mapping in the namespace context can change as the event moves
+ * @param expression
+ * @param context
+ * @return
+ */
+ public NamespaceContext getNamespaceContext(String expression, NamespaceContext context) {
+ NamespaceContextImpl nsContext = new NamespaceContextImpl(null);
+
+ boolean found = false;
+ for (String prefix : getPrefixes(expression)) {
+ String namespace = context.getNamespaceURI(prefix);
+ if (namespace != null && !XMLConstants.NULL_NS_URI.equals(namespace)) {
+ nsContext.register(prefix, namespace);
+ if ( (namespace.equals("http://docs.oasis-open.org/ns/opencsa/sca/200912")) && !prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))
+ found = true;
+ }
+ }
+
+ if(!found) {
+ nsContext.register("__sca", "http://docs.oasis-open.org/ns/opencsa/sca/200912");
+ }
+ return nsContext;
+ }
+
+ /**
+ * Registers a prefix in an existing NamespaceContext
+ * @param prefix
+ * @param namespace
+ * @param context
+ */
+ public void registerPrefix(String prefix, String namespace, NamespaceContext context) {
+ NamespaceContextImpl nsContext = (NamespaceContextImpl) context;
+ nsContext.register(prefix, namespace);
+ }
+
+ /**
+ * Parse the XPath expression to collect all the prefixes for namespaces
+ * @param expression
+ * @return A collection of prefixes
+ */
+ private Collection<String> getPrefixes(String expression) {
+ Collection<String> prefixes = new HashSet<String>();
+ prefixes.add(XMLConstants.DEFAULT_NS_PREFIX);
+ Pattern pattern = Pattern.compile("([a-zA-Z.]+):([a-zA-Z.]+)");
+ Matcher matcher = pattern.matcher(expression);
+ while (matcher.find()) {
+ String prefix = extractNCName(matcher.group(1), true);
+ String local = extractNCName(matcher.group(2), false);
+ if (prefix != null && local != null) {
+ prefixes.add(prefix);
+ }
+ }
+ return prefixes;
+ }
+
+ private String extractNCName(String str, boolean reverse) {
+ if (str.length() < 1) {
+ return null;
+ }
+ if (!reverse) {
+ if (!XMLCharHelper.isNCNameStart(str.charAt(0))) {
+ return null;
+ }
+ int i = 0, j = str.length();
+ // Find the last non-NCName char
+ for (; i < j; i++) {
+ if (!XMLCharHelper.isNCName(str.charAt(i))) {
+ break;
+ }
+ }
+ return str.substring(0, i);
+ } else {
+ int j = str.length() - 1;
+ // Find the first non-NCName char
+ for (; j >= 0; j--) {
+ if (!XMLCharHelper.isNCName(str.charAt(j))) {
+ break;
+ }
+ }
+ // j is before the first char of the prefix
+ if (j != (str.length() - 1) && XMLCharHelper.isNCNameStart(str.charAt(j + 1))) {
+ return str.substring(j + 1);
+ } else {
+ return null;
+ }
+ }
+ }
+
+}