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.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      //// Constants
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; // no further processing should take place
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