You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by dk...@apache.org on 2014/09/17 17:32:46 UTC

svn commit: r1625632 [3/9] - in /webservices/xmlschema/trunk: ./ xmlschema-walker/ xmlschema-walker/src/ xmlschema-walker/src/main/ xmlschema-walker/src/main/java/ xmlschema-walker/src/main/java/org/ xmlschema-walker/src/main/java/org/apache/ xmlschema...

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathManager.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathManager.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathManager.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathManager.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,300 @@
+/**
+ * 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.ws.commons.schema.docpath;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * Factory for creating {@link XmlSchemaPathNode}s. This allows for recycling
+ * and abstracts away the complexity of walking through an XML Schema.
+ */
+final class XmlSchemaPathManager<U, V> {
+
+    private ArrayList<XmlSchemaPathNode<U, V>> unusedPathNodes;
+    private ArrayList<XmlSchemaDocumentNode<U>> unusedDocNodes;
+
+    /**
+     * Constructs the document path node factory.
+     */
+    XmlSchemaPathManager() {
+        unusedPathNodes = new ArrayList<XmlSchemaPathNode<U, V>>();
+        unusedDocNodes = new ArrayList<XmlSchemaDocumentNode<U>>();
+    }
+
+    XmlSchemaPathNode<U, V> createStartPathNode(XmlSchemaPathNode.Direction direction,
+                                                XmlSchemaStateMachineNode state) {
+
+        return createPathNode(direction, null, state);
+    }
+
+    XmlSchemaPathNode<U, V> addParentSiblingOrContentNodeToPath(XmlSchemaPathNode<U, V> startNode,
+                                                                XmlSchemaPathNode.Direction direction) {
+
+        XmlSchemaDocumentNode<U> position = startNode.getDocumentNode();
+
+        switch (direction) {
+        case PARENT:
+            if (position != null) {
+                position = position.getParent();
+            }
+        case SIBLING:
+        case CONTENT:
+            if (position == null) {
+                throw new IllegalStateException(
+                                                "When calling addParentSiblingOrContentNodeToPath(), the "
+                                                    + "startNode's document node (and its parent) cannot be null.");
+            }
+            break;
+        default:
+            throw new IllegalStateException("This method cannot be called if following a child.  Use "
+                                            + "addChildNodeToPath(startNode, direction, stateIndex).");
+        }
+
+        XmlSchemaPathNode<U, V> node = null;
+        if (!unusedPathNodes.isEmpty()) {
+            node = unusedPathNodes.remove(unusedPathNodes.size() - 1);
+            node.update(direction, startNode, position);
+        } else {
+            node = new XmlSchemaPathNode<U, V>(direction, startNode, position);
+        }
+
+        if (direction.equals(XmlSchemaPathNode.Direction.SIBLING)) {
+            node.setIteration(position.getIteration() + 1);
+        } else {
+            node.setIteration(position.getIteration());
+        }
+
+        return node;
+    }
+
+    XmlSchemaPathNode<U, V> addChildNodeToPath(XmlSchemaPathNode<U, V> startNode, int branchIndex) {
+
+        final XmlSchemaStateMachineNode stateMachine = startNode.getStateMachineNode();
+
+        if (stateMachine.getPossibleNextStates() == null) {
+            throw new IllegalStateException("Cannot follow the branch index; no possible next states.");
+
+        } else if (stateMachine.getPossibleNextStates().size() <= branchIndex) {
+            throw new IllegalArgumentException("Cannot follow the branch index; branch " + branchIndex
+                                               + " was requested when there are only "
+                                               + stateMachine.getPossibleNextStates().size()
+                                               + " branches to follow.");
+        }
+
+        final XmlSchemaPathNode<U, V> next = createPathNode(XmlSchemaPathNode.Direction.CHILD,
+                                                            startNode,
+                                                            stateMachine.getPossibleNextStates()
+                                                                .get(branchIndex));
+
+        final XmlSchemaDocumentNode<U> docNode = startNode.getDocumentNode();
+
+        if ((startNode.getDocumentNode() != null) && (docNode.getChildren(startNode.getIteration()) != null)
+            && docNode.getChildren().containsKey(branchIndex)) {
+
+            next.setDocumentNode(docNode.getChildren(startNode.getIteration()).get(branchIndex));
+            next.setIteration(next.getDocIteration() + 1);
+
+        } else {
+            next.setIteration(1);
+        }
+
+        return next;
+    }
+
+    /**
+     * Recyles the provided {@link XmlSchemaPathNode} and all of the nodes that
+     * follow it. Unlinks from its previous node.
+     */
+    void recyclePathNode(XmlSchemaPathNode<U, V> toRecycle) {
+        if (toRecycle.getPrevious() != null) {
+            toRecycle.getPrevious().setNextNode(-1, null);
+            toRecycle.setPreviousNode(null);
+        }
+
+        if (toRecycle.getNext() != null) {
+            recyclePathNode(toRecycle.getNext());
+        }
+
+        unusedPathNodes.add(toRecycle);
+    }
+
+    XmlSchemaPathNode<U, V> clone(XmlSchemaPathNode<U, V> original) {
+        final XmlSchemaPathNode<U, V> clone = createPathNode(original.getDirection(), original.getPrevious(),
+                                                             original.getStateMachineNode());
+
+        clone.setIteration(original.getIteration());
+
+        if (original.getDocumentNode() != null) {
+            clone.setDocumentNode(original.getDocumentNode());
+        }
+
+        return clone;
+    }
+
+    /**
+     * Follows the path starting at <code>startNode</code>, creating
+     * {@link XmlSchemaDocumentNode}s and linking them along the way.
+     *
+     * @param startNode The node to start building the tree from.
+     */
+    void followPath(XmlSchemaPathNode<U, V> startNode) {
+        if (startNode.getDocumentNode() == null) {
+            if (!startNode.getDirection().equals(XmlSchemaPathNode.Direction.CHILD)) {
+
+                throw new IllegalStateException(
+                                                "The startNode may only have a null XmlSchemaDocumentNode if it "
+                                                    + "represents the root node, and likewise its only valid "
+                                                    + "direction is CHILD, not " + startNode.getDirection());
+            }
+
+            // startNode is the root node.
+            XmlSchemaDocumentNode<U> rootDoc = createDocumentNode(null, startNode.getStateMachineNode());
+            startNode.setDocumentNode(rootDoc);
+            rootDoc.addVisitor(startNode);
+        }
+
+        XmlSchemaPathNode<U, V> prev = startNode;
+        XmlSchemaPathNode<U, V> iter = prev.getNext();
+        while (iter != null) {
+            if (iter.getDocumentNode() == null) {
+                if (!iter.getDirection().equals(XmlSchemaPathNode.Direction.CHILD)) {
+                    throw new IllegalStateException(
+                                                    "XmlSchemaPathNode has a direction of "
+                                                        + iter.getDirection()
+                                                        + " but it does not have an XmlSchemaDocumentNode to represent"
+                                                        + " its state machine (" + iter.getStateMachineNode()
+                                                        + ").");
+                }
+
+                final XmlSchemaDocumentNode<U> newDocNode = createDocumentNode(prev.getDocumentNode(),
+                                                                               iter.getStateMachineNode());
+
+                iter.setDocumentNode(newDocNode);
+
+                final Map<Integer, XmlSchemaDocumentNode<U>> siblings = prev.getDocumentNode().getChildren();
+
+                if (prev.getIndexOfNextNodeState() < 0) {
+                    throw new IllegalStateException(
+                                                    "Creating a new document node for a node represented by "
+                                                        + iter.getStateMachineNode()
+                                                        + " but its previous state does not know how to reach me.");
+                }
+
+                siblings.put(prev.getIndexOfNextNodeState(), iter.getDocumentNode());
+            }
+
+            switch (iter.getDirection()) {
+            case CHILD:
+            case SIBLING:
+                iter.getDocumentNode().addVisitor(iter);
+                break;
+            default:
+            }
+
+            if (iter.getIteration() != iter.getDocIteration()) {
+                throw new IllegalStateException("The current path node (representing "
+                                                + iter.getStateMachineNode() + ") has an iteration of "
+                                                + iter.getIteration()
+                                                + ", which does not match the document node iteration of "
+                                                + iter.getDocIteration() + '.');
+            }
+
+            prev = iter;
+            iter = iter.getNext();
+        }
+    }
+
+    void unfollowPath(XmlSchemaPathNode<U, V> startNode) {
+        // Walk to the end and work backwards, recycling as we go.
+        XmlSchemaPathNode<U, V> iter = startNode;
+        XmlSchemaPathNode<U, V> prev = null;
+
+        while (iter != null) {
+            prev = iter;
+            iter = iter.getNext();
+        }
+
+        while (prev != startNode) {
+            iter = prev;
+            prev = iter.getPrevious();
+
+            if (iter.getDocumentNode() != null) {
+                iter.getDocumentNode().removeVisitor(iter);
+                if (iter.getDocIteration() == 0) {
+                    recycleDocumentNode(iter.getDocumentNode());
+                }
+            }
+            recyclePathNode(iter);
+        }
+    }
+
+    void clear() {
+        unusedPathNodes.clear();
+        unusedDocNodes.clear();
+    }
+
+    private XmlSchemaPathNode<U, V> createPathNode(XmlSchemaPathNode.Direction direction,
+                                                   XmlSchemaPathNode<U, V> previous,
+                                                   XmlSchemaStateMachineNode state) {
+
+        if (!unusedPathNodes.isEmpty()) {
+            XmlSchemaPathNode<U, V> node = unusedPathNodes.remove(unusedPathNodes.size() - 1);
+            node.update(direction, previous, state);
+            return node;
+        } else {
+            return new XmlSchemaPathNode<U, V>(direction, previous, state);
+        }
+    }
+
+    private XmlSchemaDocumentNode<U> createDocumentNode(XmlSchemaDocumentNode<U> parent,
+                                                        XmlSchemaStateMachineNode state) {
+
+        if (!unusedDocNodes.isEmpty()) {
+            XmlSchemaDocumentNode<U> node = unusedDocNodes.remove(unusedDocNodes.size() - 1);
+            node.set(parent, state);
+            return node;
+        } else {
+            return new XmlSchemaDocumentNode<U>(parent, state);
+        }
+    }
+
+    void recycleDocumentNode(XmlSchemaDocumentNode<U> node) {
+        if (node.getParent() != null) {
+            final Map<Integer, XmlSchemaDocumentNode<U>> siblings = node.getParent().getChildren();
+
+            for (Map.Entry<Integer, XmlSchemaDocumentNode<U>> sibling : siblings.entrySet()) {
+
+                if (sibling.getValue() == node) {
+                    siblings.remove(sibling.getKey());
+                    break;
+                }
+            }
+
+            if (node.getChildren() != null) {
+                for (Map.Entry<Integer, XmlSchemaDocumentNode<U>> child : node.getChildren().entrySet()) {
+                    recycleDocumentNode(child.getValue());
+                }
+            }
+        }
+
+        unusedDocNodes.add(node);
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathNode.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathNode.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathNode.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathNode.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,304 @@
+/**
+ * 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.ws.commons.schema.docpath;
+
+/**
+ * This represents a node in the path when walking an XML or Avro document. As
+ * {@link XmlSchemaPathFinder} walks through an XML document, it builds
+ * <code>XmlSchemaPathNode</code>s representing the path walked, and
+ * {@link XmlSchemaDocumentNode}s representing where the XML document's elements
+ * fall in the XML Schema's sequences, choices, and all groups.
+ */
+public final class XmlSchemaPathNode<U, V> {
+
+    private Direction direction;
+    private XmlSchemaDocumentNode<U> documentNode;
+    private XmlSchemaStateMachineNode stateMachineNode;
+    private int nextNodeStateIndex;
+    private int iterationNum;
+    private V userDefinedContent;
+
+    private XmlSchemaPathNode<U, V> prevNode;
+    private XmlSchemaPathNode<U, V> nextNode;
+
+    /**
+     * Represents a path's direction. Paths may go in four directions:
+     * <ul>
+     * <li>
+     * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#CHILD}
+     * : The path moves from the current node in the tree (an element or group)
+     * to one of its children.
+     * <li>
+     * <li>
+     * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#PARENT}
+     * : The path moves from the current node in the tree to its parent. If
+     * moving to the parent of an element, this closes the tag.</li>
+     * <li>
+     * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#SIBLING}
+     * : This initiates a new occurrence of the current (wildcard) element or
+     * group. If creating a sibling (wildcard) element, this closes the tag of
+     * the existing element and opens a new one of the same name.</li>
+     * <li>
+     * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#CONTENT}
+     * : This represents content inside an element (not children tags). This
+     * will either be the simple content of a simple element, or the text
+     * contained inside a mixed element. Mixed content may occur as either a
+     * direct child of the owning element, or inside one of the owning element's
+     * child groups.</li>
+     * </ul>
+     */
+    public enum Direction {
+        PARENT(2), CHILD(0), CONTENT(3), SIBLING(1);
+
+        // CHILD < SIBLING < PARENT < CONTENT when comparing possible schema
+        // paths.
+        Direction(int rank) {
+            this.rank = rank;
+        }
+
+        int getRank() {
+            return rank;
+        }
+
+        final int rank;
+    }
+
+    XmlSchemaPathNode(Direction dir, XmlSchemaPathNode<U, V> previous, XmlSchemaDocumentNode<U> node) {
+
+        update(dir, previous, node);
+    }
+
+    XmlSchemaPathNode(Direction dir, XmlSchemaPathNode<U, V> previous, XmlSchemaStateMachineNode stateMachine) {
+
+        update(dir, previous, stateMachine);
+    }
+
+    /**
+     * Retrieves the {@link XmlSchemaDocumentNode} this
+     * <code>XmlSchemaPathNode</code> is visiting.
+     */
+    public XmlSchemaDocumentNode<U> getDocumentNode() {
+        return documentNode;
+    }
+
+    /**
+     * Retrieves the {@link XmlSchemaStateMachineNode} representing the XML
+     * Schema that this <code>XmlSchemaPathNode</code> is visiting. This is
+     * equivalent to calling
+     * <code>getDocumentNode().getStateMachineNode()</code>.
+     */
+    public XmlSchemaStateMachineNode getStateMachineNode() {
+        return stateMachineNode;
+    }
+
+    /**
+     * The direction this path travels.
+     */
+    public Direction getDirection() {
+        return direction;
+    }
+
+    /**
+     * The iteration through the underlying {@link XmlSchemaDocumentNode}. If
+     * the path traverses the same <code>XmlSchemaDocumentNode</code> twice,
+     * {@link XmlSchemaDocumentNode#getIteration()} will return two, and one
+     * {@link #getIteration()} will return one, while the other will return two.
+     */
+    public int getIteration() {
+        return iterationNum;
+    }
+
+    /**
+     * Shortcut for calling <code>getStateMachineNode().getMinOccurs()</code>.
+     *
+     * @see XmlSchemaStateMachineNode#getMinOccurs()
+     */
+    public long getMinOccurs() {
+        return stateMachineNode.getMinOccurs();
+    }
+
+    /**
+     * Shortcut for calling <code>getStateMachineNode().getMaxOccurs()</code>.
+     *
+     * @see XmlSchemaStateMachineNode#getMaxOccurs()
+     */
+    public long getMaxOccurs() {
+        return stateMachineNode.getMaxOccurs();
+    }
+
+    /**
+     * Shortcut for calling <code>getDocumentNode().getIteration()</code>.
+     *
+     * @see XmlSchemaDocumentNode#getIteration()
+     */
+    public int getDocIteration() {
+        if (documentNode == null) {
+            return 0;
+        } else {
+            return documentNode.getIteration();
+        }
+    }
+
+    /**
+     * The previous node in the path, or <code>null</code> if at the beginning
+     * of the path.
+     */
+    public XmlSchemaPathNode<U, V> getPrevious() {
+        return prevNode;
+    }
+
+    /**
+     * The next node in the path, or <code>null</code> if at the end of the
+     * path.
+     */
+    public XmlSchemaPathNode<U, V> getNext() {
+        return nextNode;
+    }
+
+    int getIndexOfNextNodeState() {
+        return nextNodeStateIndex;
+    }
+
+    int getDocSequencePosition() {
+        if (documentNode == null) {
+            return 0;
+        } else {
+            return documentNode.getSequencePosition();
+        }
+    }
+
+    void setIteration(int newIteration) {
+        if (newIteration < 1) {
+            throw new IllegalArgumentException("The new iteration must be at least one, not " + newIteration
+                                               + '.');
+
+        } else if (stateMachineNode.getMaxOccurs() < newIteration) {
+            throw new IllegalStateException("The new iteration for " + stateMachineNode + " of "
+                                            + newIteration + " is greater than the maximum of "
+                                            + stateMachineNode.getMaxOccurs() + '.');
+        }
+        iterationNum = newIteration;
+    }
+
+    void setDocumentNode(XmlSchemaDocumentNode<U> docNode) {
+        if (docNode.getStateMachineNode() != stateMachineNode) {
+            throw new IllegalArgumentException("The document node's state machine ("
+                                               + docNode.getStateMachineNode()
+                                               + ") must use the same state machine node as this path node ("
+                                               + stateMachineNode + ").");
+        }
+        documentNode = docNode;
+    }
+
+    void setNextNode(int nextNodeIndex, XmlSchemaPathNode<U, V> newNext) {
+
+        if ((nextNodeIndex == -1)
+            && ((newNext == null) || newNext.getDirection().equals(Direction.CONTENT)
+                || newNext.getDirection().equals(Direction.PARENT) || newNext.getDirection()
+                .equals(Direction.SIBLING))) {
+
+            /*
+             * If this is either a content node or a sibling node, no validation
+             * is needed because we didn't change our position in the document
+             * tree. If this is a parent node, no validation is possible because
+             * we do not track the prior state in the state machine. We can also
+             * reset lower nodes in the path as necessary.
+             */
+
+        } else if ((nextNodeIndex < 0) || (nextNodeIndex >= stateMachineNode.getPossibleNextStates().size())) {
+            throw new IllegalArgumentException("The node index ("
+                                               + nextNodeIndex
+                                               + ") is not within the range of "
+                                               + documentNode.getStateMachineNode().getPossibleNextStates()
+                                                   .size() + " possible next states.");
+
+        } else if (newNext == null) {
+            throw new IllegalArgumentException("The next node must be defined.");
+
+        } else if (!stateMachineNode.getPossibleNextStates().get(nextNodeIndex)
+            .equals(newNext.getStateMachineNode())) {
+
+            throw new IllegalArgumentException("The next possible state at index " + nextNodeIndex
+                                               + " does not match the state defined in the newNext.");
+        }
+
+        nextNodeStateIndex = nextNodeIndex;
+        nextNode = newNext;
+    }
+
+    /**
+     * Changes the previous node this one was pointing to. This is useful when
+     * cloning prior nodes in the chain.
+     *
+     * @param newPrevious The new previous node.
+     * @return The old previous node.
+     */
+    XmlSchemaPathNode<U, V> setPreviousNode(XmlSchemaPathNode<U, V> newPrevious) {
+        final XmlSchemaPathNode<U, V> oldPrevious = prevNode;
+        prevNode = newPrevious;
+        return oldPrevious;
+    }
+
+    /**
+     * Use this method when changing the the {@link XmlSchemaStateMachineNode}
+     * this <code>DocumentPathNode</code> refers to. The next node in the path
+     * is returned, as it will be discarded internally.
+     *
+     * @param newPrevious The new previous <code>DocumentPathNode</code> this
+     *            node is traversed from.
+     * @param newNode The new {@link XmlSchemaStateMachineNode} this node refers
+     *            to.
+     * @return The next node in the path that this node referred to, as it will
+     *         be discarded internally.
+     */
+    void update(Direction newDirection, XmlSchemaPathNode<U, V> newPrevious, XmlSchemaDocumentNode<U> newNode) {
+
+        update(newDirection, newPrevious, newNode.getStateMachineNode());
+        documentNode = newNode;
+    }
+
+    void update(Direction newDirection, XmlSchemaPathNode<U, V> newPrevious,
+                XmlSchemaStateMachineNode newStateMachineNode) {
+
+        direction = newDirection;
+        documentNode = null;
+        stateMachineNode = newStateMachineNode;
+        nextNodeStateIndex = -1;
+        iterationNum = 0;
+        prevNode = newPrevious;
+        nextNode = null;
+        userDefinedContent = null;
+    }
+
+    /**
+     * Retrieves any user-defined content attached to this
+     * <code>XmlSchemaPathNode</code>, or <code>null</code> if none.
+     */
+    public V getUserDefinedContent() {
+        return userDefinedContent;
+    }
+
+    /**
+     * Attaches user-defined content to this <code>XmlSchemaPathNode</code>.
+     */
+    public void setUserDefinedContent(V content) {
+        userDefinedContent = content;
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineGenerator.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineGenerator.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineGenerator.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineGenerator.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,362 @@
+/**
+ * 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.ws.commons.schema.docpath;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ws.commons.schema.XmlSchemaAll;
+import org.apache.ws.commons.schema.XmlSchemaAny;
+import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
+import org.apache.ws.commons.schema.XmlSchemaChoice;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.walker.XmlSchemaAttrInfo;
+import org.apache.ws.commons.schema.walker.XmlSchemaTypeInfo;
+import org.apache.ws.commons.schema.walker.XmlSchemaVisitor;
+
+/**
+ * Builds a state machine from an {@link org.apache.ws.commons.schema.XmlSchema}
+ * representing how to walk through the schema when parsing an XML document.
+ */
+public final class XmlSchemaStateMachineGenerator implements XmlSchemaVisitor {
+
+    private List<XmlSchemaStateMachineNode> stack;
+    private XmlSchemaStateMachineNode startNode;
+    private Map<QName, ElementInfo> elementInfoByQName;
+
+    private static class ElementInfo {
+        final List<XmlSchemaAttrInfo> attributes;
+        final XmlSchemaTypeInfo typeInfo;
+        final XmlSchemaElement element;
+
+        XmlSchemaStateMachineNode stateMachineNode;
+
+        ElementInfo(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo) {
+
+            this.element = element;
+            this.typeInfo = typeInfo;
+            this.attributes = new ArrayList<XmlSchemaAttrInfo>();
+            this.stateMachineNode = null;
+        }
+
+        void addAttribute(XmlSchemaAttrInfo attrInfo) {
+            attributes.add(attrInfo);
+        }
+    }
+
+    /**
+     * Constructs a new <code>XmlSchemaStateMachineGenerator</code>, ready to
+     * start walking {@link org.apache.ws.commons.schema.XmlSchema}s.
+     */
+    public XmlSchemaStateMachineGenerator() {
+        stack = new ArrayList<XmlSchemaStateMachineNode>();
+        elementInfoByQName = new HashMap<QName, ElementInfo>();
+        startNode = null;
+    }
+
+    /**
+     * Retrieves the start node of the state machine representing the
+     * most-recently walked {@link org.apache.ws.commons.schema.XmlSchema}.
+     */
+    public XmlSchemaStateMachineNode getStartNode() {
+        return startNode;
+    }
+
+    /**
+     * Retrieves the {@link XmlSchemaStateMachineNode}s representing each
+     * {@link XmlSchemaElement} in the walked
+     * {@link org.apache.ws.commons.schema.XmlSchema}.
+     * <p>
+     * Only top-level {@link XmlSchemaElement}s can be retrieved by calling
+     * {@link org.apache.ws.commons.schema.XmlSchema#getElementByName(QName)};
+     * this allows all elements to be retrieved without walking the schema
+     * again.
+     * </p>
+     */
+    public Map<QName, XmlSchemaStateMachineNode> getStateMachineNodesByQName() {
+        final HashMap<QName, XmlSchemaStateMachineNode> nodes = new HashMap<QName, XmlSchemaStateMachineNode>();
+
+        for (Map.Entry<QName, ElementInfo> entry : elementInfoByQName.entrySet()) {
+            nodes.put(entry.getKey(), entry.getValue().stateMachineNode);
+        }
+
+        return nodes;
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEnterElement(XmlSchemaElement, XmlSchemaTypeInfo,
+     *      boolean)
+     */
+    @Override
+    public void onEnterElement(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo, boolean previouslyVisited) {
+
+        if (!previouslyVisited) {
+            /*
+             * This is our first encounter of the element. We do not have the
+             * attributes yet, so we cannot create a state machine node for it.
+             * However, we will have all of the attributes once
+             * onEndAttributes() is called, so we can create an ElementInfo
+             * entry for it, and wait until later to create the state machine
+             * and add it to the stack.
+             */
+            final ElementInfo info = new ElementInfo(element, typeInfo);
+            elementInfoByQName.put(element.getQName(), info);
+
+        } else {
+            /*
+             * We have previously encountered this element, which means we have
+             * already collected all of the information we needed to build an
+             * XmlSchemaStateMachineNode. Likewise, we can just reference it.
+             */
+            final ElementInfo elemInfo = elementInfoByQName.get(element.getQName());
+            if ((elemInfo == null) || (elemInfo.stateMachineNode == null)) {
+                throw new IllegalStateException("Element " + element.getQName()
+                                                + " was already visited, but we do not"
+                                                + " have a state machine for it.");
+
+            } else if (stack.isEmpty()) {
+                throw new IllegalStateException("Element " + element.getQName()
+                                                + " was previously visited, but there is no"
+                                                + " parent state machine node to attach it to!");
+            }
+
+            XmlSchemaStateMachineNode stateMachineNode = elemInfo.stateMachineNode;
+
+            /*
+             * If this element is identical in every way except for the minimum
+             * and maximum number of occurrences, we want to create a new state
+             * machine node to represent this element.
+             */
+            if ((stateMachineNode.getMinOccurs() != element.getMinOccurs())
+                || (stateMachineNode.getMaxOccurs() != element.getMaxOccurs())) {
+                stateMachineNode = new XmlSchemaStateMachineNode(element, elemInfo.attributes,
+                                                                 elemInfo.typeInfo);
+            }
+
+            stack.get(stack.size() - 1).addPossibleNextState(stateMachineNode);
+
+            stack.add(stateMachineNode);
+        }
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onExitElement(XmlSchemaElement, XmlSchemaTypeInfo,
+     *      boolean)
+     */
+    @Override
+    public void onExitElement(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo, boolean previouslyVisited) {
+
+        if (stack.isEmpty()) {
+            throw new IllegalStateException("Exiting " + element.getQName() + ", but the stack is empty.");
+        }
+
+        final XmlSchemaStateMachineNode node = stack.remove(stack.size() - 1);
+        if (!node.getNodeType().equals(XmlSchemaStateMachineNode.Type.ELEMENT)) {
+            throw new IllegalStateException("Exiting element " + element.getQName() + ", but  " + node
+                                            + " is on the stack.");
+
+        } else if (!node.getElement().getQName().equals(element.getQName())) {
+            throw new IllegalStateException("Element " + element.getQName()
+                                            + " is not the same in-memory copy we received on creation.  Our"
+                                            + " copy is of a " + node.getElement().getQName());
+        }
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onVisitAttribute(XmlSchemaElement,
+     *      XmlSchemaAttrInfo)
+     */
+    @Override
+    public void onVisitAttribute(XmlSchemaElement element, XmlSchemaAttrInfo attrInfo) {
+
+        final ElementInfo elemInfo = elementInfoByQName.get(element.getQName());
+        if (elemInfo == null) {
+            throw new IllegalStateException("No record exists for element " + element.getQName());
+        }
+
+        elemInfo.addAttribute(attrInfo);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEndAttributes(XmlSchemaElement,
+     *      XmlSchemaTypeInfo)
+     */
+    @Override
+    public void onEndAttributes(XmlSchemaElement element, XmlSchemaTypeInfo elemTypeInfo) {
+
+        /*
+         * The parent of this group is an element that needs to be added to the
+         * stack.
+         */
+        final ElementInfo elemInfo = elementInfoByQName.get(element.getQName());
+
+        if (elemInfo.stateMachineNode != null) {
+            throw new IllegalStateException("Parent element " + element.getQName()
+                                            + " is supposedly undefined, but that entry already has a state"
+                                            + " machine of " + elemInfo.stateMachineNode);
+        }
+
+        elemInfo.stateMachineNode = new XmlSchemaStateMachineNode(elemInfo.element, elemInfo.attributes,
+                                                                  elemInfo.typeInfo);
+
+        if (!stack.isEmpty()) {
+            stack.get(stack.size() - 1).addPossibleNextState(elemInfo.stateMachineNode);
+        } else {
+            // This is the root node.
+            startNode = elemInfo.stateMachineNode;
+        }
+
+        stack.add(elemInfo.stateMachineNode);
+
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEnterSubstitutionGroup(XmlSchemaElement)
+     */
+    @Override
+    public void onEnterSubstitutionGroup(XmlSchemaElement base) {
+        if (stack.isEmpty()) {
+            // The root element is the base of a substitution group.
+            startNode = new XmlSchemaStateMachineNode(XmlSchemaStateMachineNode.Type.SUBSTITUTION_GROUP,
+                                                      base.getMinOccurs(), base.getMaxOccurs());
+            stack.add(startNode);
+        } else {
+            pushGroup(XmlSchemaStateMachineNode.Type.SUBSTITUTION_GROUP, base.getMinOccurs(),
+                      base.getMaxOccurs());
+        }
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onExitSubstitutionGroup(XmlSchemaElement)
+     */
+    @Override
+    public void onExitSubstitutionGroup(XmlSchemaElement base) {
+        popGroup(XmlSchemaStateMachineNode.Type.SUBSTITUTION_GROUP);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEnterAllGroup(XmlSchemaAll)
+     */
+    @Override
+    public void onEnterAllGroup(XmlSchemaAll all) {
+        pushGroup(XmlSchemaStateMachineNode.Type.ALL, all.getMinOccurs(), all.getMaxOccurs());
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onExitAllGroup(XmlSchemaAll)
+     */
+    @Override
+    public void onExitAllGroup(XmlSchemaAll all) {
+        popGroup(XmlSchemaStateMachineNode.Type.ALL);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEnterChoiceGroup(XmlSchemaChoice)
+     */
+    @Override
+    public void onEnterChoiceGroup(XmlSchemaChoice choice) {
+        pushGroup(XmlSchemaStateMachineNode.Type.CHOICE, choice.getMinOccurs(), choice.getMaxOccurs());
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onExitChoiceGroup(XmlSchemaChoice)
+     */
+    @Override
+    public void onExitChoiceGroup(XmlSchemaChoice choice) {
+        popGroup(XmlSchemaStateMachineNode.Type.CHOICE);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onEnterSequenceGroup(XmlSchemaSequence)
+     */
+    @Override
+    public void onEnterSequenceGroup(XmlSchemaSequence seq) {
+        pushGroup(XmlSchemaStateMachineNode.Type.SEQUENCE, seq.getMinOccurs(), seq.getMaxOccurs());
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onExitSequenceGroup(XmlSchemaSequence)
+     */
+    @Override
+    public void onExitSequenceGroup(XmlSchemaSequence seq) {
+        popGroup(XmlSchemaStateMachineNode.Type.SEQUENCE);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onVisitAny(XmlSchemaAny)
+     */
+    @Override
+    public void onVisitAny(XmlSchemaAny any) {
+        final XmlSchemaStateMachineNode node = new XmlSchemaStateMachineNode(any);
+
+        if (stack.isEmpty()) {
+            throw new IllegalStateException("Reached an wildcard with no parent!  The stack is empty.");
+        }
+
+        stack.get(stack.size() - 1).addPossibleNextState(node);
+    }
+
+    /**
+     * @see XmlSchemaVisitor#onVisitAnyAttribute(XmlSchemaElement,
+     *      XmlSchemaAnyAttribute)
+     */
+    @Override
+    public void onVisitAnyAttribute(XmlSchemaElement element, XmlSchemaAnyAttribute anyAttr) {
+
+        // Ignored.
+    }
+
+    private void pushGroup(XmlSchemaStateMachineNode.Type groupType, long minOccurs, long maxOccurs) {
+
+        if (stack.isEmpty()) {
+            throw new IllegalStateException("Attempted to create a(n) " + groupType
+                                            + " group with no parent - the stack is empty!");
+        }
+
+        final XmlSchemaStateMachineNode node = new XmlSchemaStateMachineNode(groupType, minOccurs, maxOccurs);
+
+        stack.get(stack.size() - 1).addPossibleNextState(node);
+        stack.add(node);
+    }
+
+    private void popGroup(XmlSchemaStateMachineNode.Type groupType) {
+        if (stack.isEmpty()) {
+            throw new IllegalStateException("Exiting an " + groupType + " group, but the stack is empty!");
+        }
+
+        final XmlSchemaStateMachineNode node = stack.remove(stack.size() - 1);
+
+        if (!node.getNodeType().equals(groupType)) {
+            throw new IllegalStateException("Attempted to pop a " + groupType
+                                            + " off of the stack, but found a " + node.getNodeType()
+                                            + " instead!");
+        }
+
+        if (!groupType.equals(XmlSchemaStateMachineNode.Type.SUBSTITUTION_GROUP) && stack.isEmpty()) {
+            throw new IllegalStateException("Popped a group of type " + groupType
+                                            + " only to find it did not have a parent.");
+        }
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineNode.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineNode.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineNode.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineNode.java Wed Sep 17 15:32:44 2014
@@ -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.ws.commons.schema.docpath;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.ws.commons.schema.XmlSchemaAny;
+import org.apache.ws.commons.schema.XmlSchemaAttribute;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.walker.XmlSchemaAttrInfo;
+import org.apache.ws.commons.schema.walker.XmlSchemaTypeInfo;
+
+/**
+ * This represents a node in the state machine used when parsing an XML
+ * {@link org.w3c.dom.Document} based on its
+ * {@link org.apache.ws.commons.schema.XmlSchema} and Avro
+ * {@link org.apache.avro.Schema}.
+ * <p>
+ * A <code>SchemaStateMachineNode</code> represents one of:
+ * <ul>
+ * <li>An element, its type, and its attributes</li>
+ * <li>An all group</li>
+ * <li>A choice group</li>
+ * <li>A sequence group</li>
+ * <li>An &lt;any&gt; wildcard element</li>
+ * <li>A substitution group</li>
+ * </ul>
+ * As a {@link org.w3c.dom.Document} is traversed, the state machine is used to
+ * determine how to process the current element. Two passes will be needed: the
+ * first pass will determine the correct path through the document's schema in
+ * order to properly parse the elements, and the second traversal will read the
+ * elements while following that path.
+ * </p>
+ */
+public final class XmlSchemaStateMachineNode {
+
+    private final Type nodeType;
+    private final XmlSchemaElement element;
+    private final List<XmlSchemaAttrInfo> attributes;
+    private final XmlSchemaTypeInfo typeInfo;
+    private final long minOccurs;
+    private final long maxOccurs;
+    private final XmlSchemaAny any;
+
+    private List<XmlSchemaStateMachineNode> possibleNextStates;
+
+    public enum Type {
+        ELEMENT, SUBSTITUTION_GROUP, ALL, CHOICE, SEQUENCE, ANY
+    }
+
+    /**
+     * Constructs a new <code>SchemaStateMachineNode</code> for a group.
+     *
+     * @param nodeType The type of the group node ({@link Type#ALL},
+     *            {@link Type#SUBSTITUTION_GROUP}, {@link Type#CHOICE},
+     *            {@link Type#SEQUENCE}, or {@link Type#ANY}).
+     * @param minOccurs The minimum number of occurrences of this group.
+     * @param maxOccurs The maximum number of occurrences of this group.
+     * @throws IllegalArgumentException if this constructor is used to define an
+     *             {@link Type#ELEMENT} or an {@link Type#ANY}.
+     */
+    XmlSchemaStateMachineNode(Type nodeType, long minOccurs, long maxOccurs) {
+
+        if (nodeType.equals(Type.ELEMENT)) {
+            throw new IllegalArgumentException("This constructor cannot be used for elements.");
+
+        } else if (nodeType.equals(Type.ANY)) {
+            throw new IllegalArgumentException("This constructor cannot be used for wildcard elements.");
+        }
+
+        this.nodeType = nodeType;
+        this.minOccurs = minOccurs;
+        this.maxOccurs = maxOccurs;
+
+        this.element = null;
+        this.attributes = null;
+        this.typeInfo = null;
+        this.any = null;
+
+        this.possibleNextStates = new ArrayList<XmlSchemaStateMachineNode>();
+    }
+
+    /**
+     * Constructs a new <code>SchemaStateMachineNode</code> for an element.
+     *
+     * @param elem The {@link XmlSchemaElement} this node represents.
+     * @param attrs The {@link XmlSchemaAttribute} contained by this element. An
+     *            empty {@link List} or <code>null</code> if none.
+     * @param typeInfo The type information, if the element has simple content.
+     *            <code>null</code> if not.
+     */
+    XmlSchemaStateMachineNode(XmlSchemaElement elem, List<XmlSchemaAttrInfo> attrs, XmlSchemaTypeInfo typeInfo) {
+        this.nodeType = Type.ELEMENT;
+        this.element = elem;
+        this.attributes = attrs;
+        this.typeInfo = typeInfo;
+        this.minOccurs = elem.getMinOccurs();
+        this.maxOccurs = elem.getMaxOccurs();
+
+        this.any = null;
+
+        this.possibleNextStates = new ArrayList<XmlSchemaStateMachineNode>();
+    }
+
+    /**
+     * Constructs a {@link XmlSchemaStateMachineNode} from the
+     * {@link XmlSchemaAny}.
+     *
+     * @param any The <code>XmlSchemaAny</code> to construct the node from.
+     */
+    XmlSchemaStateMachineNode(XmlSchemaAny any) {
+        this.nodeType = Type.ANY;
+        this.any = any;
+        this.minOccurs = any.getMinOccurs();
+        this.maxOccurs = any.getMaxOccurs();
+
+        this.element = null;
+        this.attributes = null;
+        this.typeInfo = null;
+
+        this.possibleNextStates = new ArrayList<XmlSchemaStateMachineNode>();
+    }
+
+    /**
+     * The XML Schema node {@link Type} this <code>SchemaStateMachineNode</code>
+     * represents.
+     */
+    public Type getNodeType() {
+        return nodeType;
+    }
+
+    /**
+     * If this <code>SchemaStateMachineNode</code> represents an
+     * {@link XmlSchemaElement}, the <code>XmlSchemaElement</code> it
+     * represents.
+     */
+    public XmlSchemaElement getElement() {
+        return element;
+    }
+
+    /**
+     * If this <code>SchemaStateMachineNode</code> represents an
+     * {@link XmlSchemaElement}, the {@link XmlSchemaTypeInfo} of the element it
+     * represents.
+     */
+    public XmlSchemaTypeInfo getElementType() {
+        return typeInfo;
+    }
+
+    /**
+     * If this <code>SchemaStateMachineNode</code> represents an
+     * {@link XmlSchemaElement}, the set of {@link XmlSchemaAttrInfo}s
+     * associated with the element it represents.
+     */
+    public List<XmlSchemaAttrInfo> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * The minimum number of times this <code>SchemaStateMachineNode</code> may
+     * appear in succession.
+     */
+    public long getMinOccurs() {
+        return minOccurs;
+    }
+
+    /**
+     * The maximum number of times this <code>SchemaStateMachineNode</code> may
+     * appear in succession.
+     */
+    public long getMaxOccurs() {
+        return maxOccurs;
+    }
+
+    /**
+     * Returns the {@link XmlSchemaAny} associated with this node, or
+     * <code>null</code if none.
+     */
+    public XmlSchemaAny getAny() {
+        return any;
+    }
+
+    /**
+     * Adds a state that could follow this <code>SchemaStateMachineNode</code>.
+     *
+     * @param next A node that could follow this one in the XML document.
+     * @return Itself, for chaining.
+     */
+    XmlSchemaStateMachineNode addPossibleNextState(XmlSchemaStateMachineNode next) {
+        possibleNextStates.add(next);
+        return this;
+    }
+
+    /**
+     * Adds the set of possible states that could follow this
+     * <code>SchemaStateMachineNode</code>.
+     *
+     * @param nextStates The set of possible nodes that could follow this one in
+     *            the XML document.
+     * @return Itself, for chaining.
+     */
+    XmlSchemaStateMachineNode addPossibleNextStates(java.util.Collection<XmlSchemaStateMachineNode> nextStates) {
+
+        possibleNextStates.addAll(nextStates);
+        return this;
+    }
+
+    /**
+     * All of the known possible states that could follow this one.
+     */
+    public List<XmlSchemaStateMachineNode> getPossibleNextStates() {
+        return possibleNextStates;
+    }
+
+    /**
+     * Builds a {@link String} representing this
+     * <code>XmlSchemaStateMachineNode</code>.
+     */
+    @Override
+    public String toString() {
+        StringBuilder name = new StringBuilder(nodeType.name());
+        switch (nodeType) {
+        case ELEMENT:
+            name.append(": ").append(element.getQName()).append(" [");
+            name.append(minOccurs).append(", ");
+            name.append(maxOccurs).append("]");
+            break;
+        case ANY:
+            name.append(": NS: \"").append(any.getNamespace()).append("\", ");
+            name.append("Processing: ").append(any.getProcessContent());
+            name.append(" [").append(minOccurs).append(", ").append(maxOccurs);
+            name.append(']');
+            break;
+        default:
+            name.append(" [").append(minOccurs).append(", ").append(maxOccurs);
+            name.append(']');
+        }
+        return name.toString();
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaStateMachineNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/package-info.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/package-info.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/package-info.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/package-info.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,182 @@
+/**
+ * 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.
+ */
+
+/**
+ * <h1>Building an XML Document's Conforming Path</h1>
+ *
+ * This package is dedicated to walking an XML Document using the SAX API,
+ * and building a path through its
+ * {@link org.apache.ws.commons.schema.XmlSchemaCollection} to determine
+ * how the document conforms to its schema.
+ * 
+ * <p>
+ * This is done in four steps:
+ *
+ * <ol>
+ *   <li>
+ *     Build a state machine of the
+ *     {@link org.apache.ws.commons.schema.XmlSchemaCollection},
+ *     represented as
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}s.
+ *   </li>
+ *   <li>
+ *     Start a SAX-based walk over the XML Document, either via
+ *     {@link javax.xml.parsers.SAXParser}, when working with raw XML, or
+ *     {@link org.apache.ws.commons.schema.docpath.SaxWalkerOverDom} when
+ *     working with an {@link org.w3c.dom.Document}.
+ *   </li>
+ *   <li>
+ *     Use {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathFinder}
+ *     to build a series of
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode}s
+ *     and {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode}s
+ *     representing a valid walk through the
+ *     {@link org.apache.ws.commons.schema.XmlSchemaCollection}.
+ *   </li>
+ *   <li>
+ *     Add any application-specific information to the paths through the
+ *     document using
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode#setUserDefinedContent(Object)}
+ *     and
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode#setUserDefinedContent(Object)}.
+ *   </li>
+ * </ol>
+ * </p>
+ *
+ * <h2>XmlSchemaStateMachineNode</h2>
+ * 
+ * <p>
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}
+ * represents a single node in the
+ * {@link org.apache.ws.commons.schema.XmlSchema} - either an element or a
+ * group - and the possible nodes that may follow (children of the element
+ * or group).  Only one state machine node will be created by the
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineGenerator}
+ * for each {@link org.apache.ws.commons.schema.XmlSchemaElement}, meaning
+ * the {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}s
+ * may loop back on themselves if an XML element is a child of itself.
+ * </p>
+ *
+ * <h2>XmlSchemaDocumentNode</h2>
+ * 
+ * <p>
+ * As {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}s
+ * represent the XML Schema,
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode}s
+ * represent the XML Schema as applied to an XML Document.  Each node
+ * represents all occurrences of the node in the XML Document, and a different
+ * set of children can be requested, one for each occurrence.  Document nodes
+ * never loop back on themselves; if an element is a child of itself, a new
+ * document node instance will be created at each level in the tree.
+ * </p>
+ *
+ * <p>
+ * As a result, the
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode}s form a
+ * tree structure, starting with the root node of the document and working
+ * downward.  User-defined content can be attached to each node in the tree
+ * using the
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode#setUserDefinedContent(Object)}.
+ * method.
+ * </p>
+ *
+ * <h2>XmlSchemaPathNode</h2>
+ *
+ * <p>
+ * Where {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode}s
+ * represent the XML Schema structure used to describe the XML Document,
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode}s define the
+ * actual walk through the XML Schema taken to represent that document.
+ * </p>
+ * <p>
+ * Paths may go in four
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction}s:
+ *
+ * <ul>
+ *   <li>
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#CHILD}:
+ *     The path moves from the current node in the tree (an element or group)
+ *     to one of its children.
+ *   <li>
+ *   <li>
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#PARENT}:
+ *     The path moves from the current node in the tree to its parent.  If
+ *     moving to the parent of an element, this closes the tag.
+ *   </li>
+ *   <li>
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#SIBLING}:
+ *     This initiates a new occurrence of the current (wildcard) element or
+ *     group.  If creating a sibling (wildcard) element, this closes the tag of
+ *     the existing element and opens a new one of the same name.
+ *   </li>
+ *   <li>
+ *     {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode.Direction#CONTENT}:
+ *     This represents content inside an element (not children tags).  This
+ *     will either be the simple content of a simple element, or the text
+ *     contained inside a mixed element.  Mixed content may occur as either
+ *     a direct child of the owning element, or inside one of the owning
+ *     element's child groups.
+ *   </li>
+ * </ul>
+ * </p>
+ *
+ * <h2>XmlSchemaPathFinder</h2>
+ * 
+ * <p>
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathFinder} builds
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode}s
+ * and {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathNode}s
+ * from {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}
+ * during a SAX walk of an XML document.  In addition to confirming the XML
+ * Document conforms to its schema's structure, it will also confirm attribute
+ * and element content conform to its expected type.
+ * </p>
+ *
+ * <p>
+ * <b>Note:</b> This is done entirely over a SAX walk, meaning the source need
+ * not be an XML Document at all.  Any data structure that can be traversed
+ * via a SAX walk can be confirmed to conform against an expected XML Schema.
+ * </p>
+ *
+ * <h2>SaxWalkerOverDom</h2>
+ *
+ * <p>
+ * This allows SAX-based walks over {@link org.w3c.dom.Document} objects.
+ * One can use this in conjunction with
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaPathFinder} to
+ * confirm a document parsed using a {@link javax.xml.parsers.DocumentBuilder}
+ * conforms to its XML Schema.
+ * </p>
+ *
+ * <h2>DomBuilderFromSax</h2>
+ *
+ * <p>
+ * In the reverse direction, one can use
+ * {@link org.apache.ws.commons.schema.docpath.DomBuilderFromSax} to build an
+ * {@link org.w3c.dom.Document} based on an XML Schema and a SAX walk over
+ * content that represents a document conforming to that
+ * {@link org.apache.ws.commons.schema.XmlSchema} .  For best results, use
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineGenerator}
+ * to build a mapping of {@link javax.xml.namespace.QName}s to
+ * {@link org.apache.ws.commons.schema.docpath.XmlSchemaStateMachineNode}s.
+ * This is used by the <code>DomBuilderFromSax</code> to resolve ambiguities
+ * in how to generate the XML Document based on the schema.
+ * </p>
+ */
+package org.apache.ws.commons.schema.docpath;
\ No newline at end of file

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaAttrInfo.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaAttrInfo.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaAttrInfo.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaAttrInfo.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,97 @@
+/**
+ * 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.ws.commons.schema.walker;
+
+import org.apache.ws.commons.schema.XmlSchemaAttribute;
+
+/**
+ * This represents a complete XML Schema Attribute, after references are
+ * followed and types are defined.
+ */
+public class XmlSchemaAttrInfo {
+
+    /**
+     * Constructs a new <code>XmlSchemaAttrInfo</code> from the provided
+     * {@link XmlSchemaAttribute} and {@link XmlSchemaTypeInfo}.
+     * <p>
+     * The <code>XmlSchemaAttribute</code> represents the XML attribute
+     * definition after any references have been resolved, and merged with the
+     * global definition.
+     * </p>
+     *
+     * @param attribute The underlying <code>XmlSchemaAttribute</code>.
+     * @param attrType The attribute's type.
+     */
+    public XmlSchemaAttrInfo(XmlSchemaAttribute attribute, XmlSchemaTypeInfo attrType) {
+
+        this(attribute);
+        this.attrType = attrType;
+    }
+
+    XmlSchemaAttrInfo(XmlSchemaAttribute attribute, boolean isTopLevel) {
+        this.attribute = attribute;
+        this.isTopLevel = isTopLevel;
+        this.attrType = null;
+    }
+
+    XmlSchemaAttrInfo(XmlSchemaAttribute attribute) {
+        this(attribute, attribute.isTopLevel());
+    }
+
+    /**
+     * The underlying {@link XmlSchemaAttribute}. If the attribute was
+     * originally a reference, this instance is merged with the global attribute
+     * it referenced.
+     * <p>
+     * The only exception is with {@link XmlSchemaAttribute#isTopLevel()}. A
+     * copy of the <code>XmlSchemaAttribute</code> may have been made in order
+     * to properly merge a local reference with a global definition. When that
+     * happens, <code>XmlSchemaAttribute.isTopLevel()</code> may not return the
+     * correct result. Use {@link #isTopLevel()} instead.
+     * </p>
+     */
+    public XmlSchemaAttribute getAttribute() {
+        return attribute;
+    }
+
+    /**
+     * The attribute's value type.
+     */
+    public XmlSchemaTypeInfo getType() {
+        return attrType;
+    }
+
+    /**
+     * Whether the attribute exists in the global namespace. Because a copy of
+     * {@link XmlSchemaAttribute} may have been made in order to merge a local
+     * reference with the global definition,
+     * {@link XmlSchemaAttribute#isTopLevel()} may no longer be accurate.
+     */
+    public boolean isTopLevel() {
+        return isTopLevel;
+    }
+
+    void setType(XmlSchemaTypeInfo attrType) {
+        this.attrType = attrType;
+    }
+
+    private final XmlSchemaAttribute attribute;
+    private final boolean isTopLevel;
+    private XmlSchemaTypeInfo attrType;
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaAttrInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaBaseSimpleType.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaBaseSimpleType.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaBaseSimpleType.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaBaseSimpleType.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,97 @@
+/**
+ * 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.ws.commons.schema.walker;
+
+import java.util.HashMap;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ws.commons.schema.constants.Constants;
+
+/**
+ * Represents the set of simple types defined by XML Schema, and conversions
+ * between them and their respective {@link QName}s. This set is limited to only
+ * <code>anyType</code>, <code>anySimpleType</code>, and the <a
+ * href="http://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes">
+ * primitive datatypes</a> defined by XML Schema.
+ */
+public enum XmlSchemaBaseSimpleType {
+    ANYTYPE(Constants.XSD_ANYTYPE), ANYSIMPLETYPE(Constants.XSD_ANYSIMPLETYPE), DURATION(
+        Constants.XSD_DURATION), DATETIME(Constants.XSD_DATETIME), TIME(Constants.XSD_TIME), DATE(
+        Constants.XSD_DATE), YEARMONTH(Constants.XSD_YEARMONTH), YEAR(Constants.XSD_YEAR), MONTHDAY(
+        Constants.XSD_MONTHDAY), DAY(Constants.XSD_DAY), MONTH(Constants.XSD_MONTH), STRING(
+        Constants.XSD_STRING), BOOLEAN(Constants.XSD_BOOLEAN), BIN_BASE64(Constants.XSD_BASE64), BIN_HEX(
+        Constants.XSD_HEXBIN), FLOAT(Constants.XSD_FLOAT), DECIMAL(Constants.XSD_DECIMAL), DOUBLE(
+        Constants.XSD_DOUBLE), ANYURI(Constants.XSD_ANYURI), QNAME(Constants.XSD_QNAME), NOTATION(
+        Constants.XSD_NOTATION);
+
+    private QName qName;
+
+    private XmlSchemaBaseSimpleType(QName qName) {
+        this.qName = qName;
+    }
+
+    /**
+     * The corresponding {@link QName} that the
+     * <code>XmlSchemaBaseSimpleType</code> represents in XML Schema.
+     */
+    public QName getQName() {
+        return qName;
+    }
+
+    private static HashMap<QName, XmlSchemaBaseSimpleType> reverseMap = new HashMap<QName, XmlSchemaBaseSimpleType>();
+
+    static {
+        final XmlSchemaBaseSimpleType[] types = XmlSchemaBaseSimpleType.values();
+        for (XmlSchemaBaseSimpleType type : types) {
+            reverseMap.put(type.getQName(), type);
+        }
+    }
+
+    /**
+     * Returns the XML Schema base simple type for the provided {@link QName}.
+     * If the <code>QName</code> represents <code>anyType</code>,
+     * <code>anySimpleType</code>, or one of the <a
+     * href="http://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes">
+     * primitive datatypes</a> defined by XML Schema, returns the corresponding
+     * <code>XmlSchemaBaseSimpleType</code>. Otherwise, returns
+     * <code>null</code>.
+     *
+     * @param qName The {@link QName} of an XML Schema base simple type.
+     * @return The corresponding {@link XmlSchemaBaseSimpleType}.
+     */
+    public static XmlSchemaBaseSimpleType getBaseSimpleTypeFor(QName qName) {
+        return reverseMap.get(qName);
+    }
+
+    /**
+     * Returns <code>true</code> if the provided {@link QName} references XML
+     * Schema's <code>anyType</code>, <code>anySimpleType</code>, or one of the
+     * <a href="http://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes">
+     * primitive datatypes</a> defined by XML Schema. Otherwise, returns
+     * <code>false</code>.
+     *
+     * @param qName The {@link QName} of an XML Schema type to check.
+     * @return Whether that type is a XML Schema base simple type.
+     */
+    public static boolean isBaseSimpleType(QName qName) {
+        return reverseMap.containsKey(qName);
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaBaseSimpleType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaRestriction.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaRestriction.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaRestriction.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaRestriction.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,214 @@
+/**
+ * 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.ws.commons.schema.walker;
+
+import org.apache.ws.commons.schema.XmlSchemaEnumerationFacet;
+import org.apache.ws.commons.schema.XmlSchemaFacet;
+import org.apache.ws.commons.schema.XmlSchemaFractionDigitsFacet;
+import org.apache.ws.commons.schema.XmlSchemaLengthFacet;
+import org.apache.ws.commons.schema.XmlSchemaMaxExclusiveFacet;
+import org.apache.ws.commons.schema.XmlSchemaMaxInclusiveFacet;
+import org.apache.ws.commons.schema.XmlSchemaMaxLengthFacet;
+import org.apache.ws.commons.schema.XmlSchemaMinExclusiveFacet;
+import org.apache.ws.commons.schema.XmlSchemaMinInclusiveFacet;
+import org.apache.ws.commons.schema.XmlSchemaMinLengthFacet;
+import org.apache.ws.commons.schema.XmlSchemaPatternFacet;
+import org.apache.ws.commons.schema.XmlSchemaTotalDigitsFacet;
+import org.apache.ws.commons.schema.XmlSchemaWhiteSpaceFacet;
+
+/**
+ * This represents an {@link XmlSchemaFacet}. It uses an enum to more easily
+ * work with different facets, and its {@link #equals(Object)} and
+ * {@link #hashCode()} reflect that only enumerations and patterns can have
+ * multiple constraints.
+ */
+public class XmlSchemaRestriction {
+
+    private Type type;
+    private Object value;
+    private boolean isFixed;
+
+    /**
+     * The facet type: one of the known <a
+     * href="http://www.w3.org/TR/xmlschema-2/#rf-facets">constraining
+     * facets</a> defined by XML Schema.
+     */
+    public enum Type {
+        ENUMERATION, EXCLUSIVE_MIN, EXCLUSIVE_MAX, INCLUSIVE_MIN, INCLUSIVE_MAX, PATTERN, WHITESPACE, LENGTH, LENGTH_MAX, LENGTH_MIN, DIGITS_FRACTION, DIGITS_TOTAL;
+    }
+
+    XmlSchemaRestriction(XmlSchemaFacet facet) {
+        if (facet instanceof XmlSchemaEnumerationFacet) {
+            type = Type.ENUMERATION;
+        } else if (facet instanceof XmlSchemaMaxExclusiveFacet) {
+            type = Type.EXCLUSIVE_MAX;
+        } else if (facet instanceof XmlSchemaMaxInclusiveFacet) {
+            type = Type.INCLUSIVE_MAX;
+        } else if (facet instanceof XmlSchemaMinExclusiveFacet) {
+            type = Type.EXCLUSIVE_MIN;
+        } else if (facet instanceof XmlSchemaMinInclusiveFacet) {
+            type = Type.INCLUSIVE_MIN;
+        } else if (facet instanceof XmlSchemaFractionDigitsFacet) {
+            type = Type.DIGITS_FRACTION;
+        } else if (facet instanceof XmlSchemaTotalDigitsFacet) {
+            type = Type.DIGITS_TOTAL;
+        } else if (facet instanceof XmlSchemaPatternFacet) {
+            type = Type.PATTERN;
+        } else if (facet instanceof XmlSchemaWhiteSpaceFacet) {
+            type = Type.WHITESPACE;
+        } else if (facet instanceof XmlSchemaLengthFacet) {
+            type = Type.LENGTH;
+        } else if (facet instanceof XmlSchemaMinLengthFacet) {
+            type = Type.LENGTH_MIN;
+        } else if (facet instanceof XmlSchemaMaxLengthFacet) {
+            type = Type.LENGTH_MAX;
+        } else {
+            throw new IllegalArgumentException("Unrecognized facet " + facet.getClass().getName());
+        }
+
+        value = facet.getValue();
+        isFixed = facet.isFixed();
+    }
+
+    /**
+     * Constructs a new {@link XmlSchemaRestriction} from only the {@link Type}.
+     *
+     * @param type The facet's type.
+     */
+    public XmlSchemaRestriction(Type type) {
+        this.type = type;
+        this.value = null;
+        this.isFixed = false;
+    }
+
+    /**
+     * Constructs a new {@link XmlSchemaRestriction} from the {@link Type},
+     * constraining value, and whether the facet may be overridden by child type
+     * definitions.
+     *
+     * @param type The constraining facet type.
+     * @param value The constraining value.
+     * @param isFixed Whether the value may be overridden in child definitions.
+     */
+    public XmlSchemaRestriction(Type type, Object value, boolean isFixed) {
+        this.type = type;
+        this.value = value;
+        this.isFixed = isFixed;
+    }
+
+    /**
+     * The constraining facet's {@link Type}.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * The facet's constraint value.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Whether the constraint value may be overridden in child definitions (
+     * <code>true</code> means it cannot).
+     */
+    public boolean isFixed() {
+        return isFixed;
+    }
+
+    /**
+     * Sets the constraint value.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Sets whether the constraint value may be overridden in child definitions
+     * (<code>true</code> means that it cannot).
+     */
+    public void setFixed(boolean isFixed) {
+        this.isFixed = isFixed;
+    }
+
+    /**
+     * Generates a hash code based on the contents. If the type is an
+     * enumeration, then the isFixed and value elements are used in calculating
+     * the hash code. All of the other Restrictions are considered to be the
+     * same.
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+
+        if ((type != null) && ((type == Type.ENUMERATION) || (type == Type.PATTERN))) {
+
+            result = prime * result + (isFixed ? 1231 : 1237);
+            result = prime * result + ((value == null) ? 0 : value.hashCode());
+        }
+        return result;
+    }
+
+    /**
+     * Determines equality. If the type is an enumeration, then the isFixed and
+     * value elements are used determining equality. All of the other
+     * Restrictions are considered to be equal to each other.
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        XmlSchemaRestriction other = (XmlSchemaRestriction)obj;
+        if (type != other.type)
+            return false;
+
+        if ((type != null) && ((type == Type.ENUMERATION) || (type == Type.PATTERN))) {
+
+            if (isFixed != other.isFixed)
+                return false;
+            if (value == null) {
+                if (other.value != null)
+                    return false;
+            } else if (!value.equals(other.value))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns a {@link String} representation of this facet.
+     */
+    @Override
+    public String toString() {
+        return type.name() + ": " + value + " (Fixed: " + isFixed + ")";
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaRestriction.java
------------------------------------------------------------------------------
    svn:eol-style = native