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