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 <any> 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