You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by rf...@apache.org on 2008/12/10 20:37:27 UTC

svn commit: r725398 [3/4] - in /tuscany/java/sca/modules/common-xml: ./ META-INF/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/tuscany/ src/main/java/org/apache/tuscany/sca/ src/main/java/org/apach...

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java Wed Dec 10 11:37:25 2008
@@ -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;
+
+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;
+    }
+
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLFragmentStreamReaderImpl.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java Wed Dec 10 11:37:25 2008
@@ -0,0 +1,287 @@
+/*
+ * 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 javax.xml.namespace.NamespaceContext;
+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;
+
+    /**
+     * 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 writerPrefix;
+        for (int i = 0; i < count; i++) {
+            prefix = reader.getAttributePrefix(i);
+            namespaceName = reader.getAttributeNamespace(i);
+            /*
+             * 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 (namespaceName == null) {
+                namespaceName = "";
+            }
+
+            writerPrefix = writer.getPrefix(namespaceName);
+
+            if (!"".equals(namespaceName)) {
+                // prefix has already being declared but this particular
+                // attrib has a
+                // no prefix attached. So use the prefix provided by the
+                // writer
+                if (writerPrefix != null && (prefix == null || prefix.equals(""))) {
+                    writer.writeAttribute(writerPrefix, namespaceName, reader.getAttributeLocalName(i), reader
+                        .getAttributeValue(i));
+
+                    // writer prefix is available but different from the
+                    // current
+                    // prefix of the attrib. We should be declaring the new
+                    // prefix
+                    // as a namespace declaration
+                } else if (prefix != null && !"".equals(prefix) && !prefix.equals(writerPrefix)) {
+                    writer.writeNamespace(prefix, namespaceName);
+                    writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader
+                        .getAttributeValue(i));
+
+                    // 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
+                } else if (prefix == null || prefix.equals("")) {
+                    prefix = generateUniquePrefix(writer.getNamespaceContext());
+                    writer.writeNamespace(prefix, namespaceName);
+                    writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader
+                        .getAttributeValue(i));
+                } else {
+                    writer.writeAttribute(prefix, namespaceName, reader.getAttributeLocalName(i), reader
+                        .getAttributeValue(i));
+                }
+            } else {
+                // empty namespace is equal to no namespace!
+                writer.writeAttribute(reader.getAttributeLocalName(i), reader.getAttributeValue(i));
+            }
+
+        }
+    }
+
+    /**
+     * 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 {
+        String prefix = reader.getPrefix();
+        String nameSpaceName = reader.getNamespaceURI();
+        if (nameSpaceName != null) {
+            String writerPrefix = writer.getPrefix(nameSpaceName);
+            if (writerPrefix != null) {
+                writer.writeStartElement(nameSpaceName, reader.getLocalName());
+            } else {
+                if (prefix != null) {
+                    writer.writeStartElement(prefix, reader.getLocalName(), nameSpaceName);
+                    writer.writeNamespace(prefix, nameSpaceName);
+                    // writer.setPrefix(prefix, nameSpaceName);
+                } else {
+                    // [rfeng] We need to set default NS 1st before calling writeStateElement
+                    writer.setDefaultNamespace(nameSpaceName);
+                    writer.writeStartElement(nameSpaceName, reader.getLocalName());
+                    writer.writeDefaultNamespace(nameSpaceName);
+                }
+            }
+        } else {
+            writer.writeStartElement(reader.getLocalName());
+        }
+
+        // add the namespaces
+        int count = reader.getNamespaceCount();
+        String namespacePrefix;
+        for (int i = 0; i < count; i++) {
+            namespacePrefix = reader.getNamespacePrefix(i);
+            // [rfeng] The following is commented out to allow to default ns
+            // if (namespacePrefix != null && namespacePrefix.length() == 0) {
+            // continue;
+            // }
+
+            serializeNamespace(namespacePrefix, reader.getNamespaceURI(i), writer);
+        }
+
+        // add attributes
+        serializeAttributes(reader, writer);
+
+    }
+
+    /**
+     * 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 {
+        String prefix1 = writer.getPrefix(uri);
+        if (prefix1 == null) {
+            writer.writeNamespace(prefix, uri);
+            // writer.setPrefix(prefix, uri);
+        }
+    }
+
+    /**
+     * 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());
+    }
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamSerializer.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java Wed Dec 10 11:37:25 2008
@@ -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;
+
+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);
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XMLStreamable.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java Wed Dec 10 11:37:25 2008
@@ -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;
+
+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();
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNode.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java Wed Dec 10 11:37:25 2008
@@ -0,0 +1,355 @@
+/*
+ * 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.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+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;
+        }
+    }
+
+    private static 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();
+        }
+    }
+
+    /**
+     * 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);
+        }
+
+    }
+
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlNodeIterator.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java (added)
+++ tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java Wed Dec 10 11:37:25 2008
@@ -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;
+
+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;
+    }
+
+}

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderImpl.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java (added)
+++ tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java Wed Dec 10 11:37:25 2008
@@ -0,0 +1,49 @@
+/*
+ * 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 static org.junit.Assert.assertNotNull;
+
+import javax.xml.stream.XMLStreamReader;
+
+import org.custommonkey.xmlunit.XMLAssert;
+import org.junit.Test;
+
+/**
+ * Test Case for StAXHelper
+ *
+ * @version $Rev$ $Date$
+ */
+public class StAXHelperTestCase {
+    private static final String XML =
+        "<a:foo xmlns:a='http://a' name='foo'><bar name='bar'>" 
+            + "<doo a:name='doo' xmlns:a='http://doo'/>"
+            + "</bar></a:foo>";
+
+    @Test
+    public void testHelper() throws Exception {
+        XMLStreamReader reader = StAXHelper.createXMLStreamReader(XML);
+        String xml = StAXHelper.save(reader);
+        XMLAssert.assertXMLEqual(XML, xml);
+        reader = StAXHelper.createXMLStreamReader(xml);
+        assertNotNull(reader);
+    }
+
+}

Propchange: tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/StAXHelperTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderTestCase.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderTestCase.java?rev=725398&view=auto
==============================================================================
--- tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderTestCase.java (added)
+++ tuscany/java/sca/modules/common-xml/src/test/java/org/apache/tuscany/sca/common/xml/stax/XmlTreeStreamReaderTestCase.java Wed Dec 10 11:37:25 2008
@@ -0,0 +1,204 @@
+/*
+ * 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.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+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;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.custommonkey.xmlunit.XMLAssert;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class XmlTreeStreamReaderTestCase {
+    private static final String IPO_XML =
+        "<?xml version=\"1.0\"?>" + "<ipo:purchaseOrder"
+            + "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+            + "  xmlns:ipo=\"http://www.example.com/IPO\""
+            + "  xsi:schemaLocation=\"http://www.example.com/IPO ipo.xsd\""
+            + "  orderDate=\"1999-12-01\">"
+            + "  <shipTo exportCode=\"1\" xsi:type=\"ipo:UKAddress\">"
+            + "    <name>Helen Zoe</name>"
+            + "    <street>47 Eden Street</street>"
+            + "    <city>Cambridge</city>"
+            + "    <postcode>CB1 1JR</postcode>"
+            + "  </shipTo>"
+            + "  <billTo xsi:type=\"ipo:USAddress\">"
+            + "    <name>Robert Smith</name>"
+            + "    <street>8 Oak Avenue</street>"
+            + "    <city>Old Town</city>"
+            + "    <state>PA</state>"
+            + "    <zip>95819</zip>"
+            + "  </billTo>"
+            + "  <items>"
+            + "    <item partNum=\"833-AA\">"
+            + "      <productName>Lapis necklace</productName>"
+            + "      <quantity>1</quantity>"
+            + "      <USPrice>99.95</USPrice>"
+            + "      <ipo:comment>Want this for the holidays</ipo:comment>"
+            + "      <shipDate>1999-12-05</shipDate>"
+            + "    </item>"
+            + "  </items>"
+            + "</ipo:purchaseOrder>";
+
+    private static final String XML_RESULT =
+        "<?xml version='1.0' encoding='UTF-8'?>" + "<p1:e1 xmlns:p1=\"http://ns\">"
+            + "<p2:e11 xmlns:p2=\"http://ns1\">MyText</p2:e11>"
+            + "<p1:e12><p1:e121 /></p1:e12>"
+            + "<ipo:purchaseOrder xmlns:ipo=\"http://www.example.com/IPO\" "
+            + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+            + "xsi:schemaLocation=\"http://www.example.com/IPO ipo.xsd\" orderDate=\"1999-12-01\">  "
+            + "<shipTo exportCode=\"1\" xsi:type=\"ipo:UKAddress\">    "
+            + "<name>Helen Zoe</name>    <street>47 Eden Street</street>    "
+            + "<city>Cambridge</city>    <postcode>CB1 1JR</postcode>  </shipTo>  "
+            + "<billTo xsi:type=\"ipo:USAddress\">    <name>Robert Smith</name>    "
+            + "<street>8 Oak Avenue</street>    <city>Old Town</city>    <state>PA</state>    "
+            + "<zip>95819</zip>  </billTo>  <items>    <item partNum=\"833-AA\">      "
+            + "<productName>Lapis necklace</productName>      <quantity>1</quantity>      "
+            + "<USPrice>99.95</USPrice>      <ipo:comment>Want this for the holidays</ipo:comment>      "
+            + "<shipDate>1999-12-05</shipDate>    </item>  </items></ipo:purchaseOrder></p1:e1>";
+    private XmlNodeImpl root;
+
+    @Before
+    public void setUp() throws Exception {
+        root = new XmlNodeImpl();
+        root.name = new QName("http://ns", "e1", "p1");
+
+        XmlNodeImpl e11 = new XmlNodeImpl();
+        e11.name = new QName("http://ns1", "e11", "p2");
+
+        XmlNodeImpl e12 = new XmlNodeImpl();
+        e12.name = new QName("http://ns", "e12");
+
+        root.children.add(e11);
+        root.children.add(e12);
+
+        XmlNodeImpl e121 = new XmlNodeImpl();
+        e121.name = new QName("http://ns", "e121");
+        e12.children.add(e121);
+
+        XmlNodeImpl e111 = new XmlNodeImpl();
+        e111.value = "MyText";
+        e11.children.add(e111);
+
+        XmlNodeImpl e13 = new XmlNodeImpl();
+        e13.value = XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(IPO_XML));
+        root.children.add(e13);
+
+    }
+
+    @Test
+    public void testIterator() {
+        List<QName> elements = new ArrayList<QName>();
+        XmlNodeIterator i = new XmlNodeIterator(root);
+        for (; i.hasNext();) {
+            XmlNode e = i.next();
+            elements.add(e.getName());
+        }
+        // System.out.println(elements);
+        QName[] names =
+            {new QName("http://ns", "e1"), new QName("http://ns1", "e11"), null, null, new QName("http://ns1", "e11"),
+             new QName("http://ns", "e12"), new QName("http://ns", "e121"), new QName("http://ns", "e121"),
+             new QName("http://ns", "e12"), null, null, new QName("http://ns", "e1")};
+        Assert.assertEquals(Arrays.asList(names), elements);
+    }
+
+    @Test
+    public void testReader() throws Exception {
+        XmlTreeStreamReaderImpl reader = new XmlTreeStreamReaderImpl(root);
+        XMLStreamSerializer serializer = new XMLStreamSerializer();
+        StringWriter sw = new StringWriter();
+        XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(sw);
+        serializer.serialize(reader, writer);
+        String xml = sw.toString();
+        XMLAssert.assertXMLEqual(XML_RESULT, xml);
+    }
+
+    private static class XmlNodeImpl implements XmlNode {
+        private List<XmlNode> children = new ArrayList<XmlNode>();
+        private List<XmlNode> attrs = new ArrayList<XmlNode>();
+        private Map<String, String> namespaces = new HashMap<String, String>();
+        private QName name;
+        private Object value = "123";
+
+        /**
+         * @see org.apache.tuscany.sca.databinding.xml.XmlNode#attributes()
+         */
+        public List<XmlNode> attributes() {
+            return attrs;
+        }
+
+        /**
+         * @see org.apache.tuscany.sca.databinding.xml.XmlNode#children()
+         */
+        public Iterator<XmlNode> children() {
+            return children.iterator();
+        }
+
+        /**
+         * @see org.apache.tuscany.sca.databinding.xml.XmlNode#getName()
+         */
+        public QName getName() {
+            return name;
+        }
+
+        /**
+         * @see org.apache.tuscany.sca.databinding.xml.XmlNode#getValue()
+         */
+        public <T> T getValue() {
+            return (T)value;
+        }
+
+        /**
+         * @see org.apache.tuscany.sca.databinding.xml.XmlNode#namespaces()
+         */
+        public Map<String, String> namespaces() {
+            return namespaces;
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(name);
+        }
+
+        public Type getType() {
+            if (value instanceof XMLStreamReader) {
+                return Type.READER;
+            }
+            return name == null ? Type.CHARACTERS : Type.ELEMENT;
+        }
+
+    }
+}