1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package com.rapiddweller.benerator.sample;
28
29 import com.rapiddweller.benerator.Generator;
30 import com.rapiddweller.benerator.GeneratorContext;
31 import com.rapiddweller.benerator.IllegalGeneratorStateException;
32 import com.rapiddweller.benerator.InvalidGeneratorSetupException;
33 import com.rapiddweller.benerator.util.UnsafeNonNullGenerator;
34 import com.rapiddweller.benerator.wrapper.ProductWrapper;
35 import com.rapiddweller.common.ConfigurationError;
36 import com.rapiddweller.common.ParseException;
37 import com.rapiddweller.common.StringUtil;
38 import com.rapiddweller.script.DatabeneScriptParser;
39 import com.rapiddweller.script.WeightedTransition;
40
41 import java.util.HashMap;
42 import java.util.Map;
43
44
45
46
47
48
49
50
51
52
53 public class StateGenerator<E> extends UnsafeNonNullGenerator<E> {
54
55 private final Class<E> generatedType;
56 private final Map<E, AttachedWeightSampleGenerator<E>> transitionsGenerators;
57 private E nextState;
58
59
60
61
62
63
64 public StateGenerator() {
65 this((String) null);
66 }
67
68
69
70
71
72
73 @SuppressWarnings("unchecked")
74 public StateGenerator(String transitionSpec) {
75 this((Class<E>) Object.class);
76 setTransitions(transitionSpec);
77 }
78
79
80
81
82
83
84 public StateGenerator(Class<E> generatedType) {
85 this.generatedType = generatedType;
86 this.transitionsGenerators = new HashMap<>();
87 this.nextState = null;
88 }
89
90
91
92
93
94
95 @SuppressWarnings("unchecked")
96 public void setTransitions(String transitionSpec) {
97 if (StringUtil.isEmpty(transitionSpec)) {
98 transitionsGenerators.clear();
99 return;
100 }
101 try {
102 WeightedTransition[] ts = DatabeneScriptParser.parseTransitionList(transitionSpec);
103 for (WeightedTransition t : ts) {
104 addTransition((E) t.getFrom(), (E) t.getTo(), t.getWeight());
105 }
106 } catch (ParseException e) {
107 throw new ConfigurationError("Error parsing state machine specification: " + transitionSpec, e);
108 }
109 }
110
111
112
113
114
115
116
117
118 public void addTransition(E from, E to, double weight) {
119 AttachedWeightSampleGenerator<E> subGenerator = transitionsGenerators.get(from);
120 if (subGenerator == null) {
121 subGenerator = new AttachedWeightSampleGenerator<>(generatedType);
122 transitionsGenerators.put(from, subGenerator);
123 }
124 subGenerator.addSample(to, weight);
125 }
126
127
128
129 @Override
130 public Class<E> getGeneratedType() {
131 return generatedType;
132 }
133
134 @Override
135 public void init(GeneratorContext context) throws InvalidGeneratorSetupException {
136 assertNotInitialized();
137 boolean hasEndTransition = false;
138 for (AttachedWeightSampleGenerator<E> tmp : transitionsGenerators.values()) {
139 if (tmp.containsSample(null)) {
140 hasEndTransition = true;
141 break;
142 }
143 }
144 if (!hasEndTransition) {
145 throw new InvalidGeneratorSetupException("No final state defined for " + this);
146 }
147 for (Generator<E> tmp : transitionsGenerators.values()) {
148 tmp.init(context);
149 }
150 AttachedWeightSampleGenerator<E> gen = this.transitionsGenerators.get(null);
151 nextState = gen.generate(getResultWrapper()).unwrap();
152 super.init(context);
153 }
154
155 @Override
156 public E generate() {
157 if (nextState == null) {
158 return null;
159 }
160 E result = nextState;
161 AttachedWeightSampleGenerator<E> transitionGenerator = transitionsGenerators.get(nextState);
162 ProductWrapper<E> wrapper = transitionGenerator.generate(getResultWrapper());
163 nextState = (wrapper != null ? wrapper.unwrap() : null);
164 return result;
165 }
166
167 @Override
168 public void reset() throws IllegalGeneratorStateException {
169 AttachedWeightSampleGenerator<E> transitionGenerator = this.transitionsGenerators.get(null);
170 ProductWrapper<E> wrapper = transitionGenerator.generate(getResultWrapper());
171 nextState = (wrapper != null ? wrapper.unwrap() : null);
172 super.reset();
173 }
174
175 @Override
176 public void close() {
177 super.close();
178 }
179
180
181
182 @Override
183 public String toString() {
184 return getClass().getSimpleName() + transitionsGenerators;
185 }
186
187 }