1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
package org.apache.commons.scxml.semantics; |
19 |
|
|
20 |
|
import java.util.Arrays; |
21 |
|
import java.util.Collection; |
22 |
|
import java.util.Collections; |
23 |
|
import java.util.Comparator; |
24 |
|
import java.util.HashMap; |
25 |
|
import java.util.HashSet; |
26 |
|
import java.util.Iterator; |
27 |
|
import java.util.LinkedList; |
28 |
|
import java.util.List; |
29 |
|
import java.util.Map; |
30 |
|
import java.util.Set; |
31 |
|
|
32 |
|
import org.apache.commons.logging.Log; |
33 |
|
import org.apache.commons.logging.LogFactory; |
34 |
|
import org.apache.commons.scxml.Context; |
35 |
|
import org.apache.commons.scxml.ErrorReporter; |
36 |
|
import org.apache.commons.scxml.Evaluator; |
37 |
|
import org.apache.commons.scxml.EventDispatcher; |
38 |
|
import org.apache.commons.scxml.NotificationRegistry; |
39 |
|
import org.apache.commons.scxml.PathResolver; |
40 |
|
import org.apache.commons.scxml.SCInstance; |
41 |
|
import org.apache.commons.scxml.SCXMLExpressionException; |
42 |
|
import org.apache.commons.scxml.SCXMLHelper; |
43 |
|
import org.apache.commons.scxml.SCXMLSemantics; |
44 |
|
import org.apache.commons.scxml.Step; |
45 |
|
import org.apache.commons.scxml.TriggerEvent; |
46 |
|
import org.apache.commons.scxml.invoke.Invoker; |
47 |
|
import org.apache.commons.scxml.invoke.InvokerException; |
48 |
|
import org.apache.commons.scxml.model.Action; |
49 |
|
import org.apache.commons.scxml.model.Finalize; |
50 |
|
import org.apache.commons.scxml.model.History; |
51 |
|
import org.apache.commons.scxml.model.Initial; |
52 |
|
import org.apache.commons.scxml.model.Invoke; |
53 |
|
import org.apache.commons.scxml.model.ModelException; |
54 |
|
import org.apache.commons.scxml.model.OnEntry; |
55 |
|
import org.apache.commons.scxml.model.OnExit; |
56 |
|
import org.apache.commons.scxml.model.Parallel; |
57 |
|
import org.apache.commons.scxml.model.Path; |
58 |
|
import org.apache.commons.scxml.model.SCXML; |
59 |
|
import org.apache.commons.scxml.model.State; |
60 |
|
import org.apache.commons.scxml.model.Transition; |
61 |
|
import org.apache.commons.scxml.model.TransitionTarget; |
62 |
|
|
63 |
|
|
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
|
68 |
|
|
69 |
|
|
70 |
|
|
71 |
37 |
public class SCXMLSemanticsImpl implements SCXMLSemantics { |
72 |
|
|
73 |
|
|
74 |
|
|
75 |
|
|
76 |
37 |
private Log appLog = LogFactory.getLog("scxml.app.log"); |
77 |
|
|
78 |
|
|
79 |
|
|
80 |
|
|
81 |
37 |
private TransitionTargetComparator targetComparator = |
82 |
|
new TransitionTargetComparator(); |
83 |
|
|
84 |
|
|
85 |
|
|
86 |
|
|
87 |
|
|
88 |
|
|
89 |
|
|
90 |
|
|
91 |
|
public SCXML normalizeStateMachine(final SCXML input, |
92 |
|
final ErrorReporter errRep) { |
93 |
|
|
94 |
37 |
return input; |
95 |
|
} |
96 |
|
|
97 |
|
|
98 |
|
|
99 |
|
|
100 |
|
|
101 |
|
|
102 |
|
|
103 |
|
|
104 |
|
|
105 |
|
|
106 |
|
|
107 |
|
|
108 |
|
|
109 |
|
|
110 |
|
|
111 |
|
public void determineInitialStates(final SCXML input, final Set states, |
112 |
|
final List entryList, final ErrorReporter errRep, |
113 |
|
final SCInstance scInstance) |
114 |
|
throws ModelException { |
115 |
39 |
State tmp = input.getInitialState(); |
116 |
39 |
if (tmp == null) { |
117 |
0 |
errRep.onError(ErrorReporter.NO_INITIAL, |
118 |
|
"SCXML initialstate is missing!", input); |
119 |
|
} else { |
120 |
39 |
states.add(tmp); |
121 |
39 |
determineTargetStates(states, errRep, scInstance); |
122 |
|
|
123 |
39 |
Set onEntry = SCXMLHelper.getAncestorClosure(states, null); |
124 |
|
|
125 |
39 |
Object[] oen = onEntry.toArray(); |
126 |
39 |
onEntry.clear(); |
127 |
39 |
Arrays.sort(oen, getTTComparator()); |
128 |
|
|
129 |
39 |
List entering = Arrays.asList(oen); |
130 |
39 |
Collections.reverse(entering); |
131 |
39 |
entryList.addAll(entering); |
132 |
|
|
133 |
|
} |
134 |
39 |
} |
135 |
|
|
136 |
|
|
137 |
|
|
138 |
|
|
139 |
|
|
140 |
|
|
141 |
|
|
142 |
|
|
143 |
|
|
144 |
|
|
145 |
|
|
146 |
|
|
147 |
|
|
148 |
|
|
149 |
|
|
150 |
|
|
151 |
|
|
152 |
|
|
153 |
|
public void executeActions(final Step step, final SCXML stateMachine, |
154 |
|
final EventDispatcher evtDispatcher, |
155 |
|
final ErrorReporter errRep, final SCInstance scInstance) |
156 |
|
throws ModelException { |
157 |
244 |
NotificationRegistry nr = scInstance.getNotificationRegistry(); |
158 |
244 |
Collection internalEvents = step.getAfterStatus().getEvents(); |
159 |
244 |
Map invokers = scInstance.getInvokers(); |
160 |
|
|
161 |
244 |
for (Iterator i = step.getExitList().iterator(); i.hasNext();) { |
162 |
105 |
TransitionTarget tt = (TransitionTarget) i.next(); |
163 |
105 |
OnExit oe = tt.getOnExit(); |
164 |
|
try { |
165 |
105 |
for (Iterator onExitIter = oe.getActions().iterator(); |
166 |
125 |
onExitIter.hasNext();) { |
167 |
20 |
((Action) onExitIter.next()).execute(evtDispatcher, |
168 |
|
errRep, scInstance, appLog, internalEvents); |
169 |
|
} |
170 |
0 |
} catch (SCXMLExpressionException e) { |
171 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, e.getMessage(), |
172 |
|
oe); |
173 |
105 |
} |
174 |
|
|
175 |
105 |
if (invokers.containsKey(tt)) { |
176 |
0 |
Invoker toCancel = (Invoker) invokers.get(tt); |
177 |
|
try { |
178 |
0 |
toCancel.cancel(); |
179 |
0 |
} catch (InvokerException ie) { |
180 |
0 |
TriggerEvent te = new TriggerEvent(tt.getId() |
181 |
|
+ ".invoke.cancel.failed", TriggerEvent.ERROR_EVENT); |
182 |
0 |
internalEvents.add(te); |
183 |
0 |
} |
184 |
|
|
185 |
0 |
invokers.remove(tt); |
186 |
|
} |
187 |
105 |
nr.fireOnExit(tt, tt); |
188 |
105 |
nr.fireOnExit(stateMachine, tt); |
189 |
105 |
TriggerEvent te = new TriggerEvent(tt.getId() + ".exit", |
190 |
|
TriggerEvent.CHANGE_EVENT); |
191 |
105 |
internalEvents.add(te); |
192 |
|
} |
193 |
|
|
194 |
244 |
for (Iterator i = step.getTransitList().iterator(); i.hasNext();) { |
195 |
89 |
Transition t = (Transition) i.next(); |
196 |
|
try { |
197 |
89 |
for (Iterator transitIter = t.getActions().iterator(); |
198 |
89 |
transitIter.hasNext();) { |
199 |
0 |
((Action) transitIter.next()).execute(evtDispatcher, |
200 |
|
errRep, scInstance, appLog, internalEvents); |
201 |
|
} |
202 |
0 |
} catch (SCXMLExpressionException e) { |
203 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, |
204 |
|
e.getMessage(), t); |
205 |
89 |
} |
206 |
89 |
nr.fireOnTransition(t, t.getParent(), t.getRuntimeTarget(), t); |
207 |
89 |
nr.fireOnTransition(stateMachine, t.getParent(), |
208 |
|
t.getRuntimeTarget(), t); |
209 |
|
} |
210 |
|
|
211 |
244 |
for (Iterator i = step.getEntryList().iterator(); i.hasNext();) { |
212 |
187 |
TransitionTarget tt = (TransitionTarget) i.next(); |
213 |
187 |
OnEntry oe = tt.getOnEntry(); |
214 |
|
try { |
215 |
187 |
for (Iterator onEntryIter = oe.getActions().iterator(); |
216 |
251 |
onEntryIter.hasNext();) { |
217 |
64 |
((Action) onEntryIter.next()).execute(evtDispatcher, |
218 |
|
errRep, scInstance, appLog, internalEvents); |
219 |
|
} |
220 |
0 |
} catch (SCXMLExpressionException e) { |
221 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, e.getMessage(), |
222 |
|
oe); |
223 |
187 |
} |
224 |
187 |
nr.fireOnEntry(tt, tt); |
225 |
187 |
nr.fireOnEntry(stateMachine, tt); |
226 |
187 |
TriggerEvent te = new TriggerEvent(tt.getId() + ".entry", |
227 |
|
TriggerEvent.CHANGE_EVENT); |
228 |
187 |
internalEvents.add(te); |
229 |
|
|
230 |
187 |
if (tt instanceof State) { |
231 |
184 |
State ts = (State) tt; |
232 |
184 |
if (ts.getIsFinal()) { |
233 |
30 |
State parent = (State) ts.getParent(); |
234 |
30 |
String prefix = ""; |
235 |
30 |
if (parent != null) { |
236 |
19 |
prefix = parent.getId(); |
237 |
|
} |
238 |
30 |
te = new TriggerEvent(prefix + ".done", |
239 |
|
TriggerEvent.CHANGE_EVENT); |
240 |
30 |
internalEvents.add(te); |
241 |
30 |
if (parent != null) { |
242 |
19 |
parent.setDone(true); |
243 |
|
} |
244 |
30 |
if (parent != null && parent.isRegion()) { |
245 |
|
|
246 |
|
|
247 |
0 |
Parallel p = (Parallel) parent.getParent(); |
248 |
0 |
int finCount = 0; |
249 |
0 |
int pCount = p.getStates().size(); |
250 |
0 |
for (Iterator regions = p.getStates().iterator(); |
251 |
0 |
regions.hasNext();) { |
252 |
0 |
State reg = (State) regions.next(); |
253 |
0 |
if (reg.isDone()) { |
254 |
0 |
finCount++; |
255 |
|
} |
256 |
|
} |
257 |
0 |
if (finCount == pCount) { |
258 |
0 |
te = new TriggerEvent(p.getId() + ".done", |
259 |
|
TriggerEvent.CHANGE_EVENT); |
260 |
0 |
internalEvents.add(te); |
261 |
0 |
te = new TriggerEvent(p.getParent().getId() |
262 |
|
+ ".done", TriggerEvent.CHANGE_EVENT); |
263 |
0 |
internalEvents.add(te); |
264 |
|
|
265 |
0 |
p.getParentState().setDone(true); |
266 |
|
} |
267 |
|
} |
268 |
|
} |
269 |
|
} |
270 |
|
} |
271 |
244 |
} |
272 |
|
|
273 |
|
|
274 |
|
|
275 |
|
|
276 |
|
|
277 |
|
|
278 |
|
|
279 |
|
|
280 |
|
|
281 |
|
|
282 |
|
public void enumerateReachableTransitions(final SCXML stateMachine, |
283 |
|
final Step step, final ErrorReporter errRep) { |
284 |
|
|
285 |
205 |
Set transSet = new HashSet(); |
286 |
|
|
287 |
205 |
Set stateSet = new HashSet(step.getBeforeStatus().getStates()); |
288 |
|
|
289 |
205 |
LinkedList todoList = new LinkedList(stateSet); |
290 |
588 |
while (!todoList.isEmpty()) { |
291 |
383 |
State st = (State) todoList.removeFirst(); |
292 |
383 |
for (Iterator i = st.getTransitionsList().iterator(); |
293 |
708 |
i.hasNext();) { |
294 |
325 |
Transition t = (Transition) i.next(); |
295 |
325 |
if (!transSet.contains(t)) { |
296 |
325 |
transSet.add(t); |
297 |
325 |
step.getTransitList().add(t); |
298 |
|
} |
299 |
|
} |
300 |
383 |
State parent = st.getParentState(); |
301 |
383 |
if (parent != null && !stateSet.contains(parent)) { |
302 |
168 |
stateSet.add(parent); |
303 |
168 |
todoList.addLast(parent); |
304 |
|
} |
305 |
|
} |
306 |
205 |
transSet.clear(); |
307 |
205 |
stateSet.clear(); |
308 |
205 |
todoList.clear(); |
309 |
205 |
} |
310 |
|
|
311 |
|
|
312 |
|
|
313 |
|
|
314 |
|
|
315 |
|
|
316 |
|
|
317 |
|
|
318 |
|
|
319 |
|
|
320 |
|
|
321 |
|
|
322 |
|
|
323 |
|
public void filterTransitionsSet(final Step step, |
324 |
|
final EventDispatcher evtDispatcher, |
325 |
|
final ErrorReporter errRep, final SCInstance scInstance) |
326 |
|
throws ModelException { |
327 |
|
|
328 |
|
|
329 |
|
|
330 |
|
|
331 |
|
|
332 |
|
|
333 |
|
|
334 |
205 |
Set allEvents = new HashSet(step.getBeforeStatus().getEvents().size() |
335 |
|
+ step.getExternalEvents().size()); |
336 |
|
|
337 |
205 |
for (Iterator ei = step.getBeforeStatus().getEvents().iterator(); |
338 |
594 |
ei.hasNext();) { |
339 |
389 |
TriggerEvent te = (TriggerEvent) ei.next(); |
340 |
389 |
allEvents.add(te.getName()); |
341 |
|
} |
342 |
205 |
for (Iterator ei = step.getExternalEvents().iterator(); |
343 |
283 |
ei.hasNext();) { |
344 |
78 |
TriggerEvent te = (TriggerEvent) ei.next(); |
345 |
78 |
allEvents.add(te.getName()); |
346 |
|
} |
347 |
|
|
348 |
205 |
for (Iterator iter = scInstance.getInvokers().keySet().iterator(); |
349 |
205 |
iter.hasNext();) { |
350 |
0 |
State s = (State) iter.next(); |
351 |
0 |
if (finalizeMatch(s.getId(), allEvents)) { |
352 |
0 |
Finalize fn = s.getInvoke().getFinalize(); |
353 |
0 |
if (fn != null) { |
354 |
|
try { |
355 |
0 |
for (Iterator fnIter = fn.getActions().iterator(); |
356 |
0 |
fnIter.hasNext();) { |
357 |
0 |
((Action) fnIter.next()).execute(evtDispatcher, |
358 |
|
errRep, scInstance, appLog, |
359 |
|
step.getAfterStatus().getEvents()); |
360 |
|
} |
361 |
0 |
} catch (SCXMLExpressionException e) { |
362 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, |
363 |
|
e.getMessage(), fn); |
364 |
0 |
} |
365 |
|
} |
366 |
|
} |
367 |
|
} |
368 |
|
|
369 |
205 |
List removeList = new LinkedList(); |
370 |
|
|
371 |
205 |
for (Iterator iter = step.getTransitList().iterator(); |
372 |
530 |
iter.hasNext();) { |
373 |
325 |
Transition t = (Transition) iter.next(); |
374 |
|
|
375 |
325 |
String event = t.getEvent(); |
376 |
325 |
if (!eventMatch(event, allEvents)) { |
377 |
|
|
378 |
219 |
removeList.add(t); |
379 |
219 |
continue; |
380 |
|
} |
381 |
|
|
382 |
|
Boolean rslt; |
383 |
106 |
String expr = t.getCond(); |
384 |
106 |
if (SCXMLHelper.isStringEmpty(expr)) { |
385 |
46 |
rslt = Boolean.TRUE; |
386 |
|
} else { |
387 |
|
try { |
388 |
60 |
rslt = scInstance.getEvaluator().evalCond(scInstance. |
389 |
|
getContext(t.getParent()), t.getCond()); |
390 |
0 |
} catch (SCXMLExpressionException e) { |
391 |
0 |
rslt = Boolean.FALSE; |
392 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, e |
393 |
|
.getMessage(), t); |
394 |
60 |
} |
395 |
|
} |
396 |
106 |
if (!rslt.booleanValue()) { |
397 |
|
|
398 |
17 |
removeList.add(t); |
399 |
|
} |
400 |
|
} |
401 |
|
|
402 |
205 |
step.getTransitList().removeAll(removeList); |
403 |
|
|
404 |
205 |
allEvents.clear(); |
405 |
205 |
removeList.clear(); |
406 |
|
|
407 |
|
|
408 |
205 |
if (step.getTransitList().size() > 1) { |
409 |
|
|
410 |
0 |
Object[] trans = step.getTransitList().toArray(); |
411 |
0 |
Set currentStates = step.getBeforeStatus().getStates(); |
412 |
|
|
413 |
0 |
Set nonDeterm = new HashSet(); |
414 |
0 |
for (int i = 0; i < trans.length; i++) { |
415 |
0 |
Transition t = (Transition) trans[i]; |
416 |
0 |
TransitionTarget tsrc = t.getParent(); |
417 |
0 |
for (int j = i + 1; j < trans.length; j++) { |
418 |
0 |
Transition t2 = (Transition) trans[j]; |
419 |
0 |
boolean conflict = SCXMLHelper.inConflict(t, t2, |
420 |
|
currentStates); |
421 |
0 |
if (conflict) { |
422 |
|
|
423 |
0 |
TransitionTarget t2src = t2.getParent(); |
424 |
0 |
if (SCXMLHelper.isDescendant(t2src, tsrc)) { |
425 |
|
|
426 |
0 |
removeList.add(t); |
427 |
0 |
break; |
428 |
0 |
} else if (SCXMLHelper.isDescendant(tsrc, t2src)) { |
429 |
|
|
430 |
0 |
removeList.add(t2); |
431 |
|
} else { |
432 |
|
|
433 |
0 |
nonDeterm.add(t); |
434 |
0 |
nonDeterm.add(t2); |
435 |
|
} |
436 |
|
} |
437 |
|
} |
438 |
|
} |
439 |
|
|
440 |
0 |
nonDeterm.removeAll(removeList); |
441 |
0 |
if (nonDeterm.size() > 0) { |
442 |
0 |
errRep.onError(ErrorReporter.NON_DETERMINISTIC, |
443 |
|
"Multiple conflicting transitions enabled.", nonDeterm); |
444 |
|
} |
445 |
|
|
446 |
0 |
step.getTransitList().removeAll(removeList); |
447 |
0 |
removeList.clear(); |
448 |
0 |
nonDeterm.clear(); |
449 |
|
} |
450 |
205 |
} |
451 |
|
|
452 |
|
|
453 |
|
|
454 |
|
|
455 |
|
|
456 |
|
|
457 |
|
|
458 |
|
|
459 |
|
|
460 |
|
|
461 |
|
|
462 |
|
|
463 |
|
|
464 |
|
|
465 |
|
|
466 |
|
|
467 |
|
public Set seedTargetSet(final Set residual, final List transitList, |
468 |
|
final ErrorReporter errRep) { |
469 |
205 |
Set seedSet = new HashSet(); |
470 |
205 |
Set regions = new HashSet(); |
471 |
205 |
for (Iterator i = transitList.iterator(); i.hasNext();) { |
472 |
89 |
Transition t = (Transition) i.next(); |
473 |
|
|
474 |
89 |
if (t.getTarget() != null) { |
475 |
89 |
seedSet.add(t.getTarget()); |
476 |
|
} |
477 |
|
|
478 |
89 |
Path p = t.getPath(); |
479 |
89 |
if (p.isCrossRegion()) { |
480 |
0 |
List regs = p.getRegionsEntered(); |
481 |
0 |
for (Iterator j = regs.iterator(); j.hasNext();) { |
482 |
0 |
State region = (State) j.next(); |
483 |
0 |
regions.addAll(((Parallel) region.getParent()). |
484 |
|
getStates()); |
485 |
|
} |
486 |
|
} |
487 |
|
} |
488 |
|
|
489 |
205 |
Set allStates = new HashSet(residual); |
490 |
205 |
allStates.addAll(seedSet); |
491 |
205 |
allStates = SCXMLHelper.getAncestorClosure(allStates, null); |
492 |
205 |
regions.removeAll(allStates); |
493 |
|
|
494 |
205 |
for (Iterator i = regions.iterator(); i.hasNext();) { |
495 |
0 |
State reg = (State) i.next(); |
496 |
0 |
seedSet.add(reg); |
497 |
|
} |
498 |
205 |
return seedSet; |
499 |
|
} |
500 |
|
|
501 |
|
|
502 |
|
|
503 |
|
|
504 |
|
|
505 |
|
|
506 |
|
|
507 |
|
|
508 |
|
|
509 |
|
|
510 |
|
|
511 |
|
public void determineTargetStates(final Set states, |
512 |
|
final ErrorReporter errRep, final SCInstance scInstance) |
513 |
|
throws ModelException { |
514 |
244 |
LinkedList wrkSet = new LinkedList(states); |
515 |
|
|
516 |
244 |
states.clear(); |
517 |
428 |
while (!wrkSet.isEmpty()) { |
518 |
184 |
TransitionTarget tt = (TransitionTarget) wrkSet.removeFirst(); |
519 |
184 |
if (tt instanceof State) { |
520 |
170 |
State st = (State) tt; |
521 |
|
|
522 |
|
|
523 |
|
|
524 |
170 |
if (st.isSimple()) { |
525 |
132 |
states.add(st); |
526 |
38 |
} else if (st.isOrthogonal()) { |
527 |
3 |
wrkSet.addLast(st.getParallel()); |
528 |
|
} else { |
529 |
|
|
530 |
35 |
Initial ini = st.getInitial(); |
531 |
35 |
if (ini == null) { |
532 |
0 |
errRep.onError(ErrorReporter.NO_INITIAL, |
533 |
|
"Initial pseudostate is missing!", st); |
534 |
|
} else { |
535 |
|
|
536 |
|
|
537 |
35 |
Transition initialTransition = ini.getTransition(); |
538 |
35 |
if (initialTransition == null) { |
539 |
0 |
errRep.onError(ErrorReporter.ILLEGAL_INITIAL, |
540 |
|
"Initial transition is null!", st); |
541 |
|
} else { |
542 |
35 |
TransitionTarget init = initialTransition. |
543 |
|
getTarget(); |
544 |
35 |
if (init == null |
545 |
|
|| |
546 |
|
!(init instanceof State |
547 |
|
|| init instanceof History)) { |
548 |
0 |
errRep.onError(ErrorReporter.ILLEGAL_INITIAL, |
549 |
|
"Initial not pointing to a State or History!", |
550 |
|
st); |
551 |
|
} else { |
552 |
35 |
wrkSet.addLast(init); |
553 |
|
} |
554 |
|
} |
555 |
|
} |
556 |
|
} |
557 |
14 |
} else if (tt instanceof Parallel) { |
558 |
3 |
Parallel prl = (Parallel) tt; |
559 |
3 |
for (Iterator i = prl.getStates().iterator(); i.hasNext();) { |
560 |
|
|
561 |
7 |
wrkSet.addLast(i.next()); |
562 |
|
} |
563 |
11 |
} else if (tt instanceof History) { |
564 |
11 |
History h = (History) tt; |
565 |
11 |
if (scInstance.isEmpty(h)) { |
566 |
3 |
wrkSet.addLast(h.getTransition().getRuntimeTarget()); |
567 |
|
} else { |
568 |
8 |
wrkSet.addAll(scInstance.getLastConfiguration(h)); |
569 |
|
} |
570 |
|
} else { |
571 |
0 |
throw new ModelException("Unknown TransitionTarget subclass:" |
572 |
|
+ tt.getClass().getName()); |
573 |
|
} |
574 |
|
} |
575 |
244 |
} |
576 |
|
|
577 |
|
|
578 |
|
|
579 |
|
|
580 |
|
|
581 |
|
|
582 |
|
|
583 |
|
|
584 |
|
|
585 |
|
|
586 |
|
|
587 |
|
|
588 |
|
public void updateHistoryStates(final Step step, |
589 |
|
final ErrorReporter errRep, final SCInstance scInstance) { |
590 |
205 |
Set oldState = step.getBeforeStatus().getStates(); |
591 |
205 |
for (Iterator i = step.getExitList().iterator(); i.hasNext();) { |
592 |
105 |
Object o = i.next(); |
593 |
105 |
if (o instanceof State) { |
594 |
105 |
State s = (State) o; |
595 |
105 |
if (s.hasHistory()) { |
596 |
10 |
Set shallow = null; |
597 |
10 |
Set deep = null; |
598 |
10 |
for (Iterator j = s.getHistory().iterator(); |
599 |
20 |
j.hasNext();) { |
600 |
10 |
History h = (History) j.next(); |
601 |
10 |
if (h.isDeep()) { |
602 |
5 |
if (deep == null) { |
603 |
|
|
604 |
5 |
deep = new HashSet(); |
605 |
5 |
Iterator k = oldState.iterator(); |
606 |
10 |
while (k.hasNext()) { |
607 |
5 |
State os = (State) k.next(); |
608 |
5 |
if (SCXMLHelper.isDescendant(os, s)) { |
609 |
5 |
deep.add(os); |
610 |
|
} |
611 |
|
} |
612 |
|
} |
613 |
5 |
scInstance.setLastConfiguration(h, deep); |
614 |
|
} else { |
615 |
5 |
if (shallow == null) { |
616 |
|
|
617 |
|
|
618 |
5 |
shallow = new HashSet(); |
619 |
5 |
shallow.addAll(s.getChildren().values()); |
620 |
5 |
shallow.retainAll(SCXMLHelper |
621 |
|
.getAncestorClosure(oldState, null)); |
622 |
|
} |
623 |
5 |
scInstance.setLastConfiguration(h, shallow); |
624 |
|
} |
625 |
|
} |
626 |
10 |
shallow = null; |
627 |
10 |
deep = null; |
628 |
|
} |
629 |
|
} |
630 |
|
} |
631 |
205 |
} |
632 |
|
|
633 |
|
|
634 |
|
|
635 |
|
|
636 |
|
|
637 |
|
|
638 |
|
|
639 |
|
|
640 |
|
|
641 |
|
|
642 |
|
|
643 |
|
|
644 |
|
public void followTransitions(final Step step, |
645 |
|
final ErrorReporter errorReporter, final SCInstance scInstance) |
646 |
|
throws ModelException { |
647 |
205 |
Set currentStates = step.getBeforeStatus().getStates(); |
648 |
205 |
List transitions = step.getTransitList(); |
649 |
|
|
650 |
205 |
Set exitedStates = new HashSet(); |
651 |
205 |
for (Iterator i = transitions.iterator(); i.hasNext();) { |
652 |
89 |
Transition t = (Transition) i.next(); |
653 |
89 |
Set ext = SCXMLHelper.getStatesExited(t, currentStates); |
654 |
89 |
exitedStates.addAll(ext); |
655 |
|
} |
656 |
|
|
657 |
205 |
Set residual = new HashSet(currentStates); |
658 |
205 |
residual.removeAll(exitedStates); |
659 |
|
|
660 |
205 |
Set seedSet = seedTargetSet(residual, transitions, errorReporter); |
661 |
|
|
662 |
205 |
Set targetSet = step.getAfterStatus().getStates(); |
663 |
205 |
targetSet.addAll(seedSet); |
664 |
205 |
determineTargetStates(targetSet, errorReporter, scInstance); |
665 |
|
|
666 |
205 |
Set entered = SCXMLHelper.getAncestorClosure(targetSet, seedSet); |
667 |
205 |
seedSet.clear(); |
668 |
205 |
for (Iterator i = transitions.iterator(); i.hasNext();) { |
669 |
89 |
Transition t = (Transition) i.next(); |
670 |
89 |
entered.addAll(t.getPath().getDownwardSegment()); |
671 |
|
|
672 |
89 |
if (t.getRuntimeTarget() instanceof History) { |
673 |
9 |
entered.remove(t.getRuntimeTarget()); |
674 |
|
} |
675 |
|
} |
676 |
|
|
677 |
205 |
targetSet.addAll(residual); |
678 |
205 |
residual.clear(); |
679 |
205 |
if (!SCXMLHelper.isLegalConfig(targetSet, errorReporter)) { |
680 |
0 |
throw new ModelException("Illegal state machine configuration!"); |
681 |
|
} |
682 |
|
|
683 |
205 |
Object[] oex = exitedStates.toArray(); |
684 |
205 |
exitedStates.clear(); |
685 |
205 |
Object[] oen = entered.toArray(); |
686 |
205 |
entered.clear(); |
687 |
205 |
Arrays.sort(oex, getTTComparator()); |
688 |
205 |
Arrays.sort(oen, getTTComparator()); |
689 |
205 |
step.getExitList().addAll(Arrays.asList(oex)); |
690 |
|
|
691 |
205 |
List entering = Arrays.asList(oen); |
692 |
205 |
Collections.reverse(entering); |
693 |
205 |
step.getEntryList().addAll(entering); |
694 |
|
|
695 |
205 |
for (Iterator reset = entering.iterator(); reset.hasNext();) { |
696 |
116 |
Object o = reset.next(); |
697 |
116 |
if (o instanceof State) { |
698 |
115 |
((State) o).setDone(false); |
699 |
|
} |
700 |
|
} |
701 |
205 |
} |
702 |
|
|
703 |
|
|
704 |
|
|
705 |
|
|
706 |
|
|
707 |
|
|
708 |
|
|
709 |
|
|
710 |
|
|
711 |
|
|
712 |
|
|
713 |
|
|
714 |
|
|
715 |
|
public void processInvokes(final TriggerEvent[] events, |
716 |
|
final ErrorReporter errRep, final SCInstance scInstance) |
717 |
|
throws ModelException { |
718 |
116 |
Set eventNames = new HashSet(); |
719 |
|
|
720 |
194 |
for (int i = 0; i < events.length; i++) { |
721 |
78 |
eventNames.add(events[i].getName()); |
722 |
|
} |
723 |
116 |
for (Iterator invokeIter = scInstance.getInvokers().entrySet(). |
724 |
116 |
iterator(); invokeIter.hasNext();) { |
725 |
0 |
Map.Entry iEntry = (Map.Entry) invokeIter.next(); |
726 |
0 |
String parentId = ((TransitionTarget) iEntry.getKey()).getId(); |
727 |
0 |
if (!finalizeMatch(parentId, eventNames)) { |
728 |
0 |
Invoker inv = (Invoker) iEntry.getValue(); |
729 |
|
try { |
730 |
0 |
inv.parentEvents(events); |
731 |
0 |
} catch (InvokerException ie) { |
732 |
0 |
appLog.error(ie.getMessage(), ie); |
733 |
0 |
throw new ModelException(ie.getMessage(), ie.getCause()); |
734 |
0 |
} |
735 |
|
} |
736 |
|
} |
737 |
116 |
} |
738 |
|
|
739 |
|
|
740 |
|
|
741 |
|
|
742 |
|
|
743 |
|
|
744 |
|
|
745 |
|
|
746 |
|
|
747 |
|
|
748 |
|
|
749 |
|
public void initiateInvokes(final Step step, final ErrorReporter errRep, |
750 |
|
final SCInstance scInstance) { |
751 |
116 |
Evaluator eval = scInstance.getEvaluator(); |
752 |
116 |
Collection internalEvents = step.getAfterStatus().getEvents(); |
753 |
116 |
for (Iterator iter = step.getAfterStatus().getStates().iterator(); |
754 |
238 |
iter.hasNext();) { |
755 |
122 |
State s = (State) iter.next(); |
756 |
122 |
Context ctx = scInstance.getContext(s); |
757 |
122 |
Invoke i = s.getInvoke(); |
758 |
122 |
if (i != null && scInstance.getInvoker(s) == null) { |
759 |
1 |
String src = i.getSrc(); |
760 |
1 |
if (src == null) { |
761 |
0 |
String srcexpr = i.getSrcexpr(); |
762 |
0 |
Object srcObj = null; |
763 |
|
try { |
764 |
0 |
srcObj = eval.eval(ctx, srcexpr); |
765 |
0 |
src = String.valueOf(srcObj); |
766 |
0 |
} catch (SCXMLExpressionException see) { |
767 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, |
768 |
|
see.getMessage(), i); |
769 |
0 |
} |
770 |
|
} |
771 |
1 |
String source = src; |
772 |
1 |
PathResolver pr = i.getPathResolver(); |
773 |
1 |
if (pr != null) { |
774 |
1 |
source = i.getPathResolver().resolvePath(src); |
775 |
|
} |
776 |
1 |
String ttype = i.getTargettype(); |
777 |
1 |
Invoker inv = null; |
778 |
|
try { |
779 |
1 |
inv = scInstance.newInvoker(ttype); |
780 |
0 |
} catch (InvokerException ie) { |
781 |
0 |
TriggerEvent te = new TriggerEvent(s.getId() |
782 |
|
+ ".invoke.failed", TriggerEvent.ERROR_EVENT); |
783 |
0 |
internalEvents.add(te); |
784 |
0 |
continue; |
785 |
1 |
} |
786 |
1 |
inv.setParentStateId(s.getId()); |
787 |
1 |
inv.setSCInstance(scInstance); |
788 |
1 |
Map params = i.getParams(); |
789 |
1 |
Map args = new HashMap(); |
790 |
1 |
for (Iterator pIter = params.entrySet().iterator(); |
791 |
3 |
pIter.hasNext();) { |
792 |
2 |
Map.Entry entry = (Map.Entry) pIter.next(); |
793 |
2 |
String argName = (String) entry.getKey(); |
794 |
2 |
String argExpr = (String) entry.getValue(); |
795 |
2 |
Object argValue = null; |
796 |
2 |
if (argExpr != null && argExpr.trim().length() > 0) { |
797 |
|
try { |
798 |
2 |
argValue = eval.eval(ctx, argExpr); |
799 |
0 |
} catch (SCXMLExpressionException see) { |
800 |
0 |
errRep.onError(ErrorReporter.EXPRESSION_ERROR, |
801 |
|
see.getMessage(), i); |
802 |
2 |
} |
803 |
|
} |
804 |
2 |
args.put(argName, argValue); |
805 |
|
} |
806 |
|
try { |
807 |
1 |
inv.invoke(source, args); |
808 |
0 |
} catch (InvokerException ie) { |
809 |
0 |
TriggerEvent te = new TriggerEvent(s.getId() |
810 |
|
+ ".invoke.failed", TriggerEvent.ERROR_EVENT); |
811 |
0 |
internalEvents.add(te); |
812 |
0 |
continue; |
813 |
1 |
} |
814 |
1 |
scInstance.setInvoker(s, inv); |
815 |
|
} |
816 |
|
} |
817 |
116 |
} |
818 |
|
|
819 |
|
|
820 |
|
|
821 |
|
|
822 |
|
|
823 |
|
|
824 |
|
|
825 |
|
|
826 |
|
|
827 |
|
|
828 |
|
|
829 |
|
|
830 |
|
protected boolean eventMatch(final String transEvent, |
831 |
|
final Set eventOccurrences) { |
832 |
325 |
if (SCXMLHelper.isStringEmpty(transEvent)) { |
833 |
15 |
return true; |
834 |
|
} else { |
835 |
310 |
String transEventDot = transEvent + "."; |
836 |
310 |
Iterator i = eventOccurrences.iterator(); |
837 |
894 |
while (i.hasNext()) { |
838 |
675 |
String evt = (String) i.next(); |
839 |
675 |
if (evt == null) { |
840 |
0 |
continue; |
841 |
675 |
} else if (evt.equals("*")) { |
842 |
3 |
return true; |
843 |
672 |
} else if (evt.equals(transEvent) |
844 |
|
|| evt.startsWith(transEventDot)) { |
845 |
88 |
return true; |
846 |
|
} |
847 |
|
} |
848 |
219 |
return false; |
849 |
|
} |
850 |
|
} |
851 |
|
|
852 |
|
|
853 |
|
|
854 |
|
|
855 |
|
|
856 |
|
|
857 |
|
|
858 |
|
|
859 |
|
|
860 |
|
|
861 |
|
|
862 |
|
protected boolean finalizeMatch(final String parentStateId, |
863 |
|
final Set eventOccurrences) { |
864 |
0 |
String prefix = parentStateId + ".invoke."; |
865 |
0 |
Iterator i = eventOccurrences.iterator(); |
866 |
0 |
while (i.hasNext()) { |
867 |
0 |
String evt = (String) i.next(); |
868 |
0 |
if (evt == null) { |
869 |
0 |
continue; |
870 |
0 |
} else if (evt.startsWith(prefix)) { |
871 |
0 |
return true; |
872 |
|
} |
873 |
|
} |
874 |
0 |
return false; |
875 |
|
} |
876 |
|
|
877 |
|
|
878 |
|
|
879 |
|
|
880 |
|
|
881 |
|
protected Comparator getTTComparator() { |
882 |
449 |
return targetComparator; |
883 |
|
} |
884 |
|
|
885 |
|
|
886 |
|
|
887 |
|
|
888 |
|
|
889 |
|
|
890 |
|
protected void setLog(final Log log) { |
891 |
0 |
this.appLog = log; |
892 |
0 |
} |
893 |
|
|
894 |
|
|
895 |
|
|
896 |
|
|
897 |
|
|
898 |
|
|
899 |
|
protected Log getLog() { |
900 |
0 |
return appLog; |
901 |
|
} |
902 |
|
|
903 |
|
} |
904 |
|
|