2
* Copyright © 2008-2012 NetAllied Systems GmbH, Ravensburg, Germany.
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
8
package de.netallied.xsd2cppsax.statemachine;
10
import java.util.ArrayList;
11
import java.util.List;
13
import org.apache.xerces.xs.XSComplexTypeDefinition;
14
import org.apache.xerces.xs.XSElementDeclaration;
15
import org.apache.xerces.xs.XSModelGroup;
16
import org.apache.xerces.xs.XSParticle;
17
import org.apache.xerces.xs.XSTypeDefinition;
19
import de.netallied.xsd2cppsax.Constants;
22
* Builds a state machine from a XSD complex type.
25
public class StateMachineBuilder {
28
* Small helper class to handle model groups with maxOccurs=unbounded.
35
* <choice minOccurs="0" maxOccurs="unbounded">
49
* <li>cat to black</li>
50
* <li>white to cat</li>
51
* <li>white to black</li>
53
* This class' purpose is to return black and white from the above example.
54
* black would be included in {@link #beginStates} and white in
59
protected static class ListPair {
60
protected List<StateMachineNode> beginStates;
62
protected List<StateMachineNode> endStates;
64
protected ListPair() {
65
beginStates = new ArrayList<StateMachineNode>();
66
endStates = new ArrayList<StateMachineNode>();
71
* Starts building of a state machine.
74
* XSD type to build state machine for.
75
* @return State machine or null.
77
public StateMachineRootNode build(XSComplexTypeDefinition type) {
78
if (type != null && type.getParticle() != null) {
79
return build(type.getParticle());
80
} else if (type != null && type.getBaseType() != null) {
81
return build(type.getBaseType());
87
* Does real state machine building. To be called after types have been
88
* checked and may be called for base types.
91
* XSParticle to build state machine for.
92
* @return State machine or null.
94
protected StateMachineRootNode build(XSParticle particle) {
95
if (particle.getTerm() instanceof XSModelGroup) {
96
XSModelGroup modelGroup = (XSModelGroup) particle.getTerm();
97
boolean foundNestedModelGroup = false;
98
for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
99
XSParticle subParticle = (XSParticle) modelGroup.getParticles().item(i);
100
if (subParticle.getTerm() instanceof XSModelGroup) {
101
foundNestedModelGroup = true;
105
if (!foundNestedModelGroup) {
109
StateMachineRootNode rootNode = new StateMachineRootNode(Constants.STATE_MACHINE_ROOT_NODE_NAME);
110
List<StateMachineNode> tmpList = new ArrayList<StateMachineNode>();
111
tmpList.add(rootNode);
112
tmpList = handleModelGroup(modelGroup, tmpList, rootNode, particle).endStates;
113
StateMachineNode endNode = new StateMachineNode(Constants.STATE_MACHINE_END_NODE_NAME);
114
rootNode.registerNode(endNode.getName(), endNode);
115
for (StateMachineNode node : tmpList) {
116
node.addFollowing(endNode);
124
* Convenience method allowing to pass any types.
126
public StateMachineRootNode build(XSTypeDefinition type) {
127
if (type instanceof XSComplexTypeDefinition) {
128
return build((XSComplexTypeDefinition) type);
134
* Recursive function to add elements of model group to existing state
138
* Model group to handle.
139
* @param previousNodes
140
* Existing state machine.
142
* Root node of current state machine. Used to register nodes.
143
* @param modelGroupParticle
144
* Particle of given model group. Needed for min/maxOccurs of
146
* @return Nodes which need following states.
148
protected ListPair handleModelGroup(XSModelGroup modelGroup, List<StateMachineNode> previousNodes,
149
StateMachineRootNode rootNode, XSParticle modelGroupParticle) {
151
if (modelGroupParticle.getTerm() != modelGroup) {
152
throw new IllegalArgumentException("given model group and particle don't match.");
155
ListPair returnLists = new ListPair();
156
List<StateMachineNode> originalPreviousNodes = new ArrayList<StateMachineNode>();
157
originalPreviousNodes.addAll(previousNodes);
159
switch (modelGroup.getCompositor()) {
161
case XSModelGroup.COMPOSITOR_SEQUENCE:
162
for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
163
XSParticle particle = (XSParticle) modelGroup.getParticles().item(i);
165
if (particle.getTerm() instanceof XSElementDeclaration) {
166
StateMachineNode newNode = new StateMachineNode(particle.getTerm().getName());
167
rootNode.registerNode(newNode.getName(), newNode);
169
if (particle.getMaxOccursUnbounded()) {
170
newNode.addFollowing(newNode);
173
List<StateMachineNode> tmp = new ArrayList<StateMachineNode>();
174
for (StateMachineNode prevNode : previousNodes) {
175
prevNode.addFollowing(newNode);
177
if (particle.getMinOccurs() == 0) {
182
previousNodes.add(newNode);
185
returnLists.beginStates.add(newNode);
188
} else if (particle.getTerm() instanceof XSModelGroup) {
189
ListPair listPair = handleModelGroup((XSModelGroup) particle.getTerm(), previousNodes, rootNode,
191
previousNodes = listPair.endStates;
194
returnLists.beginStates.addAll(listPair.beginStates);
199
returnLists.endStates = previousNodes;
202
case XSModelGroup.COMPOSITOR_CHOICE:
203
for (int i = 0; i < modelGroup.getParticles().getLength(); i++) {
204
XSParticle particle = (XSParticle) modelGroup.getParticles().item(i);
206
if (particle.getTerm() instanceof XSElementDeclaration) {
207
StateMachineNode newNode = new StateMachineNode(particle.getTerm().getName());
208
rootNode.registerNode(newNode.getName(), newNode);
209
returnLists.endStates.add(newNode);
210
returnLists.beginStates.add(newNode);
212
if (particle.getMinOccurs() == 0) {
213
for (StateMachineNode prevNode : previousNodes) {
214
if (!returnLists.endStates.contains(prevNode)) {
215
returnLists.endStates.add(prevNode);
219
if (particle.getMaxOccursUnbounded()) {
220
newNode.addFollowing(newNode);
223
for (StateMachineNode prevNode : previousNodes) {
224
prevNode.addFollowing(newNode);
227
} else if (particle.getTerm() instanceof XSModelGroup) {
228
ListPair listPair = handleModelGroup((XSModelGroup) particle.getTerm(), previousNodes, rootNode,
230
returnLists.endStates.addAll(listPair.endStates);
231
returnLists.beginStates.addAll(listPair.beginStates);
239
if (modelGroupParticle.getMaxOccursUnbounded()) {
240
for (StateMachineNode endNode : returnLists.endStates) {
241
for (StateMachineNode beginNode : returnLists.beginStates) {
242
endNode.addFollowing(beginNode);
246
if (modelGroupParticle.getMinOccurs() == 0) {
247
for (StateMachineNode prevNode : originalPreviousNodes) {
248
if (!returnLists.endStates.contains(prevNode)) {
249
returnLists.endStates.add(prevNode);