1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.scxml.invoke;
19
20 import java.io.IOException;
21 import java.util.Iterator;
22 import java.util.Map;
23
24 import org.apache.commons.scxml.Context;
25 import org.apache.commons.scxml.Evaluator;
26 import org.apache.commons.scxml.SCInstance;
27 import org.apache.commons.scxml.SCXMLExecutor;
28 import org.apache.commons.scxml.TriggerEvent;
29 import org.apache.commons.scxml.env.SimpleDispatcher;
30 import org.apache.commons.scxml.env.SimpleErrorHandler;
31 import org.apache.commons.scxml.env.SimpleErrorReporter;
32 import org.apache.commons.scxml.env.SimpleSCXMLListener;
33 import org.apache.commons.scxml.io.SCXMLDigester;
34 import org.apache.commons.scxml.model.ModelException;
35 import org.apache.commons.scxml.model.SCXML;
36 import org.xml.sax.SAXException;
37
38 /***
39 * A simple {@link Invoker} for SCXML documents. Invoked SCXML document
40 * may not contain external namespace elements, further invokes etc.
41 */
42 public class SimpleSCXMLInvoker implements Invoker {
43
44 /*** Parent state ID. */
45 private String parentStateId;
46 /*** Event prefix, all events sent to the parent executor must begin
47 * with this prefix. */
48 private String eventPrefix;
49 /*** Invoking document's SCInstance. */
50 private SCInstance parentSCInstance;
51 /*** The invoked state machine executor. */
52 private SCXMLExecutor executor;
53 /*** Cancellation status. */
54 private boolean cancelled;
55
56
57 /*** Prefix for all events sent to the parent state machine. */
58 private static String invokePrefix = ".invoke.";
59 /*** Suffix for invoke done event. */
60 private static String invokeDone = "done";
61 /*** Suffix for invoke cancel response event. */
62 private static String invokeCancelResponse = "cancel.response";
63
64 /***
65 * {@inheritDoc}.
66 */
67 public void setParentStateId(final String parentStateId) {
68 this.parentStateId = parentStateId;
69 this.eventPrefix = parentStateId + invokePrefix;
70 this.cancelled = false;
71 }
72
73 /***
74 * {@inheritDoc}.
75 */
76 public void setSCInstance(final SCInstance scInstance) {
77 this.parentSCInstance = scInstance;
78 }
79
80 /***
81 * {@inheritDoc}.
82 */
83 public void invoke(final String source, final Map params)
84 throws InvokerException {
85 SCXML scxml = null;
86 try {
87 scxml = SCXMLDigester.digest(source,
88 new SimpleErrorHandler(), null);
89 } catch (ModelException me) {
90 throw new InvokerException(me.getMessage(), me.getCause());
91 } catch (IOException ioe) {
92 throw new InvokerException(ioe.getMessage(), ioe.getCause());
93 } catch (SAXException se) {
94 throw new InvokerException(se.getMessage(), se.getCause());
95 }
96 Evaluator eval = parentSCInstance.getEvaluator();
97 executor = new SCXMLExecutor(eval,
98 new SimpleDispatcher(), new SimpleErrorReporter());
99 Context rootCtx = eval.newContext(null);
100 for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) {
101 Map.Entry entry = (Map.Entry) iter.next();
102 rootCtx.setLocal((String) entry.getKey(), entry.getValue());
103 }
104 executor.setRootContext(rootCtx);
105 executor.setStateMachine(scxml);
106 executor.addListener(scxml, new SimpleSCXMLListener());
107 try {
108 executor.go();
109 } catch (ModelException me) {
110 throw new InvokerException(me.getMessage(), me.getCause());
111 }
112 }
113
114 /***
115 * {@inheritDoc}.
116 */
117 public void parentEvents(final TriggerEvent[] evts)
118 throws InvokerException {
119 if (cancelled) {
120 return;
121 }
122 boolean doneBefore = executor.getCurrentStatus().isFinal();
123 try {
124 executor.triggerEvents(evts);
125 } catch (ModelException me) {
126 throw new InvokerException(me.getMessage(), me.getCause());
127 }
128 if (!doneBefore && executor.getCurrentStatus().isFinal()) {
129 TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone,
130 TriggerEvent.SIGNAL_EVENT);
131 new AsyncTrigger(parentSCInstance.getExecutor(), te);
132 }
133 }
134
135 /***
136 * {@inheritDoc}.
137 */
138 public void cancel()
139 throws InvokerException {
140 cancelled = true;
141 TriggerEvent te = new TriggerEvent(eventPrefix
142 + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT);
143 new AsyncTrigger(parentSCInstance.getExecutor(), te);
144 }
145
146 }
147