/xsd2cppsax/src/de/netallied/xsd2cppsax/statemachine/StateMachineBuilder.java

https://bitbucket.org/ZhangJingGuo/opencollada · Java · 256 lines · 147 code · 33 blank · 76 comment · 47 complexity · 931a69ea17900b83c9d5e86482fdfdba MD5 · raw file

  1. /**
  2. * Copyright © 2008-2012 NetAllied Systems GmbH, Ravensburg, Germany.
  3. *
  4. * Licensed under the MIT Open Source License,
  5. * for details please see LICENSE file or the website
  6. * http://www.opensource.org/licenses/mit-license.php
  7. */
  8. package de.netallied.xsd2cppsax.statemachine;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import org.apache.xerces.xs.XSComplexTypeDefinition;
  12. import org.apache.xerces.xs.XSElementDeclaration;
  13. import org.apache.xerces.xs.XSModelGroup;
  14. import org.apache.xerces.xs.XSParticle;
  15. import org.apache.xerces.xs.XSTypeDefinition;
  16. import de.netallied.xsd2cppsax.Constants;
  17. /**
  18. * Builds a state machine from a XSD complex type.
  19. *
  20. */
  21. public class StateMachineBuilder {
  22. /**
  23. * Small helper class to handle model groups with maxOccurs=unbounded.
  24. * <p>
  25. * e.g.
  26. *
  27. * <pre>
  28. * &lt;sequence&gt;
  29. * &lt;dog&gt;
  30. * &lt;choice minOccurs=&quot;0&quot; maxOccurs=&quot;unbounded&quot;&gt;
  31. * &lt;cat&gt;
  32. * &lt;sequence&gt;
  33. * &lt;black&gt;
  34. * &lt;white&gt;
  35. * &lt;/sequence&gt;
  36. * &lt;/choice&gt;
  37. * &lt;mouse&gt;
  38. * &lt;/sequence&gt;
  39. * </pre>
  40. *
  41. * We need links from
  42. * <ul>
  43. * <li>cat to cat</li>
  44. * <li>cat to black</li>
  45. * <li>white to cat</li>
  46. * <li>white to black</li>
  47. * </ul>
  48. * This class' purpose is to return black and white from the above example.
  49. * black would be included in {@link #beginStates} and white in
  50. * {@link #endStates}.
  51. * </p>
  52. *
  53. */
  54. protected static class ListPair {
  55. protected List<StateMachineNode> beginStates;
  56. protected List<StateMachineNode> endStates;
  57. protected ListPair() {
  58. beginStates = new ArrayList<StateMachineNode>();
  59. endStates = new ArrayList<StateMachineNode>();
  60. }
  61. }
  62. /**
  63. * Starts building of a state machine.
  64. *
  65. * @param type
  66. * XSD type to build state machine for.
  67. * @return State machine or null.
  68. */
  69. public StateMachineRootNode build(XSComplexTypeDefinition type) {
  70. if (type != null && type.getParticle() != null) {
  71. return build(type.getParticle());
  72. } else if (type != null && type.getBaseType() != null) {
  73. return build(type.getBaseType());
  74. }
  75. return null;
  76. }
  77. /**
  78. * Does real state machine building. To be called after types have been
  79. * checked and may be called for base types.
  80. *
  81. * @param particle
  82. * XSParticle to build state machine for.
  83. * @return State machine or null.
  84. */
  85. protected StateMachineRootNode build(XSParticle particle) {
  86. if (particle.getTerm() instanceof XSModelGroup) {
  87. XSModelGroup modelGroup = (XSModelGroup) particle.getTerm();
  88. boolean foundNestedModelGroup = false;
  89. for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
  90. XSParticle subParticle = (XSParticle) modelGroup.getParticles().item(i);
  91. if (subParticle.getTerm() instanceof XSModelGroup) {
  92. foundNestedModelGroup = true;
  93. break;
  94. }
  95. }
  96. if (!foundNestedModelGroup) {
  97. return null;
  98. }
  99. StateMachineRootNode rootNode = new StateMachineRootNode(Constants.STATE_MACHINE_ROOT_NODE_NAME);
  100. List<StateMachineNode> tmpList = new ArrayList<StateMachineNode>();
  101. tmpList.add(rootNode);
  102. tmpList = handleModelGroup(modelGroup, tmpList, rootNode, particle).endStates;
  103. StateMachineNode endNode = new StateMachineNode(Constants.STATE_MACHINE_END_NODE_NAME);
  104. rootNode.registerNode(endNode.getName(), endNode);
  105. for (StateMachineNode node : tmpList) {
  106. node.addFollowing(endNode);
  107. }
  108. return rootNode;
  109. }
  110. return null;
  111. }
  112. /**
  113. * Convenience method allowing to pass any types.
  114. */
  115. public StateMachineRootNode build(XSTypeDefinition type) {
  116. if (type instanceof XSComplexTypeDefinition) {
  117. return build((XSComplexTypeDefinition) type);
  118. }
  119. return null;
  120. }
  121. /**
  122. * Recursive function to add elements of model group to existing state
  123. * machine.
  124. *
  125. * @param modelGroup
  126. * Model group to handle.
  127. * @param previousNodes
  128. * Existing state machine.
  129. * @param rootNode
  130. * Root node of current state machine. Used to register nodes.
  131. * @param modelGroupParticle
  132. * Particle of given model group. Needed for min/maxOccurs of
  133. * whole model group.
  134. * @return Nodes which need following states.
  135. */
  136. protected ListPair handleModelGroup(XSModelGroup modelGroup, List<StateMachineNode> previousNodes,
  137. StateMachineRootNode rootNode, XSParticle modelGroupParticle) {
  138. if (modelGroupParticle.getTerm() != modelGroup) {
  139. throw new IllegalArgumentException("given model group and particle don't match.");
  140. }
  141. ListPair returnLists = new ListPair();
  142. List<StateMachineNode> originalPreviousNodes = new ArrayList<StateMachineNode>();
  143. originalPreviousNodes.addAll(previousNodes);
  144. switch (modelGroup.getCompositor()) {
  145. case XSModelGroup.COMPOSITOR_SEQUENCE:
  146. for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
  147. XSParticle particle = (XSParticle) modelGroup.getParticles().item(i);
  148. if (particle.getTerm() instanceof XSElementDeclaration) {
  149. StateMachineNode newNode = new StateMachineNode(particle.getTerm().getName());
  150. rootNode.registerNode(newNode.getName(), newNode);
  151. if (particle.getMaxOccursUnbounded()) {
  152. newNode.addFollowing(newNode);
  153. }
  154. List<StateMachineNode> tmp = new ArrayList<StateMachineNode>();
  155. for (StateMachineNode prevNode : previousNodes) {
  156. prevNode.addFollowing(newNode);
  157. if (particle.getMinOccurs() == 0) {
  158. tmp.add(prevNode);
  159. }
  160. }
  161. previousNodes = tmp;
  162. previousNodes.add(newNode);
  163. if (i == 0) {
  164. returnLists.beginStates.add(newNode);
  165. }
  166. } else if (particle.getTerm() instanceof XSModelGroup) {
  167. ListPair listPair = handleModelGroup((XSModelGroup) particle.getTerm(), previousNodes, rootNode,
  168. particle);
  169. previousNodes = listPair.endStates;
  170. if (i == 0) {
  171. returnLists.beginStates.addAll(listPair.beginStates);
  172. }
  173. }
  174. }
  175. returnLists.endStates = previousNodes;
  176. break;
  177. case XSModelGroup.COMPOSITOR_CHOICE:
  178. for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
  179. XSParticle particle = (XSParticle) modelGroup.getParticles().item(i);
  180. if (particle.getTerm() instanceof XSElementDeclaration) {
  181. StateMachineNode newNode = new StateMachineNode(particle.getTerm().getName());
  182. rootNode.registerNode(newNode.getName(), newNode);
  183. returnLists.endStates.add(newNode);
  184. returnLists.beginStates.add(newNode);
  185. if (particle.getMinOccurs() == 0) {
  186. for (StateMachineNode prevNode : previousNodes) {
  187. if (!returnLists.endStates.contains(prevNode)) {
  188. returnLists.endStates.add(prevNode);
  189. }
  190. }
  191. }
  192. if (particle.getMaxOccursUnbounded()) {
  193. newNode.addFollowing(newNode);
  194. }
  195. for (StateMachineNode prevNode : previousNodes) {
  196. prevNode.addFollowing(newNode);
  197. }
  198. } else if (particle.getTerm() instanceof XSModelGroup) {
  199. ListPair listPair = handleModelGroup((XSModelGroup) particle.getTerm(), previousNodes, rootNode,
  200. particle);
  201. returnLists.endStates.addAll(listPair.endStates);
  202. returnLists.beginStates.addAll(listPair.beginStates);
  203. }
  204. }
  205. break;
  206. }
  207. if (modelGroupParticle.getMaxOccursUnbounded()) {
  208. for (StateMachineNode endNode : returnLists.endStates) {
  209. for (StateMachineNode beginNode : returnLists.beginStates) {
  210. endNode.addFollowing(beginNode);
  211. }
  212. }
  213. }
  214. if (modelGroupParticle.getMinOccurs() == 0) {
  215. for (StateMachineNode prevNode : originalPreviousNodes) {
  216. if (!returnLists.endStates.contains(prevNode)) {
  217. returnLists.endStates.add(prevNode);
  218. }
  219. }
  220. }
  221. return returnLists;
  222. }
  223. }