View Javadoc

1   /*
2    *
3    *   Copyright 2006 The Apache Software Foundation.
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
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      //// Constants
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; // no further processing should take place
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