View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  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  package org.apache.commons.scxml.invoke;
18  
19  import java.io.IOException;
20  import java.io.Serializable;
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, Serializable {
43  
44      /*** Serial version UID. */
45      private static final long serialVersionUID = 1L;
46      /*** Parent state ID. */
47      private String parentStateId;
48      /*** Event prefix, all events sent to the parent executor must begin
49       *  with this prefix. */
50      private String eventPrefix;
51      /*** Invoking document's SCInstance. */
52      private SCInstance parentSCInstance;
53      /*** The invoked state machine executor. */
54      private SCXMLExecutor executor;
55      /*** Cancellation status. */
56      private boolean cancelled;
57  
58      //// Constants
59      /*** Prefix for all events sent to the parent state machine. */
60      private static String invokePrefix = ".invoke.";
61      /*** Suffix for invoke done event. */
62      private static String invokeDone = "done";
63      /*** Suffix for invoke cancel response event. */
64      private static String invokeCancelResponse = "cancel.response";
65  
66      /***
67       * {@inheritDoc}.
68       */
69      public void setParentStateId(final String parentStateId) {
70          this.parentStateId = parentStateId;
71          this.eventPrefix = parentStateId + invokePrefix;
72          this.cancelled = false;
73      }
74  
75      /***
76       * {@inheritDoc}.
77       */
78      public void setSCInstance(final SCInstance scInstance) {
79          this.parentSCInstance = scInstance;
80      }
81  
82      /***
83       * {@inheritDoc}.
84       */
85      public void invoke(final String source, final Map params)
86      throws InvokerException {
87          SCXML scxml = null;
88          try {
89              scxml = SCXMLDigester.digest(source,
90                  new SimpleErrorHandler(), null);
91          } catch (ModelException me) {
92              throw new InvokerException(me.getMessage(), me.getCause());
93          } catch (IOException ioe) {
94              throw new InvokerException(ioe.getMessage(), ioe.getCause());
95          } catch (SAXException se) {
96              throw new InvokerException(se.getMessage(), se.getCause());
97          }
98          Evaluator eval = parentSCInstance.getEvaluator();
99          executor = new SCXMLExecutor(eval,
100             new SimpleDispatcher(), new SimpleErrorReporter());
101         Context rootCtx = eval.newContext(null);
102         for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) {
103             Map.Entry entry = (Map.Entry) iter.next();
104             rootCtx.setLocal((String) entry.getKey(), entry.getValue());
105         }
106         executor.setRootContext(rootCtx);
107         executor.setStateMachine(scxml);
108         executor.addListener(scxml, new SimpleSCXMLListener());
109         try {
110             executor.go();
111         } catch (ModelException me) {
112             throw new InvokerException(me.getMessage(), me.getCause());
113         }
114     }
115 
116     /***
117      * {@inheritDoc}.
118      */
119     public void parentEvents(final TriggerEvent[] evts)
120     throws InvokerException {
121         if (cancelled) {
122             return; // no further processing should take place
123         }
124         boolean doneBefore = executor.getCurrentStatus().isFinal();
125         try {
126             executor.triggerEvents(evts);
127         } catch (ModelException me) {
128             throw new InvokerException(me.getMessage(), me.getCause());
129         }
130         if (!doneBefore && executor.getCurrentStatus().isFinal()) {
131             TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone,
132                 TriggerEvent.SIGNAL_EVENT);
133             new AsyncTrigger(parentSCInstance.getExecutor(), te);
134         }
135     }
136 
137     /***
138      * {@inheritDoc}.
139      */
140     public void cancel()
141     throws InvokerException {
142         cancelled = true;
143         TriggerEvent te = new TriggerEvent(eventPrefix
144             + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT);
145         new AsyncTrigger(parentSCInstance.getExecutor(), te);
146     }
147 
148 }
149