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