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.scxml2.invoke;
18  
19  import java.io.IOException;
20  import java.io.Serializable;
21  import java.net.URL;
22  import java.util.Map;
23  
24  import javax.xml.stream.XMLStreamException;
25  
26  import org.apache.commons.scxml2.Context;
27  import org.apache.commons.scxml2.SCXMLExecutor;
28  import org.apache.commons.scxml2.SCXMLIOProcessor;
29  import org.apache.commons.scxml2.TriggerEvent;
30  import org.apache.commons.scxml2.env.SimpleSCXMLListener;
31  import org.apache.commons.scxml2.io.SCXMLReader;
32  import org.apache.commons.scxml2.model.ModelException;
33  import org.apache.commons.scxml2.model.SCXML;
34  
35  /**
36   * A simple {@link Invoker} for SCXML documents. Invoked SCXML document
37   * may not contain external namespace elements, further invokes etc.
38   */
39  public class SimpleSCXMLInvoker implements Invoker, Serializable {
40  
41      /** Serial version UID. */
42      private static final long serialVersionUID = 1L;
43      /** Parent state ID. */
44      private String parentStateId;
45      /** Invoking parent SCXMLExecutor */
46      private SCXMLExecutor parentSCXMLExecutor;
47      /** The invoked state machine executor. */
48      private SCXMLExecutor executor;
49      /** Cancellation status. */
50      private boolean cancelled;
51  
52  
53      /**
54       * {@inheritDoc}.
55       */
56      @Override
57      public String getInvokeId() {
58          return parentStateId;
59      }
60  
61      /**
62       * {@inheritDoc}.
63       */
64      @Override
65      public void setInvokeId(final String invokeId) {
66          this.parentStateId = invokeId;
67          this.cancelled = false;
68      }
69  
70      /**
71       * {@inheritDoc}.
72       */
73      @Override
74      public void setParentSCXMLExecutor(SCXMLExecutor parentSCXMLExecutor) {
75          this.parentSCXMLExecutor = parentSCXMLExecutor;
76      }
77  
78      /**
79       * {@inheritDoc}.
80       */
81      @Override
82      public SCXMLIOProcessor getChildIOProcessor() {
83          // not used
84          return executor;
85      }
86  
87      /**
88       * {@inheritDoc}.
89       */
90      @Override
91      public void invoke(final String source, final Map<String, Object> params)
92      throws InvokerException {
93          SCXML scxml;
94          try {
95              scxml = SCXMLReader.read(new URL(source));
96          } catch (ModelException me) {
97              throw new InvokerException(me.getMessage(), me.getCause());
98          } catch (IOException ioe) {
99              throw new InvokerException(ioe.getMessage(), ioe.getCause());
100         } catch (XMLStreamException xse) {
101             throw new InvokerException(xse.getMessage(), xse.getCause());
102         }
103         executor = new SCXMLExecutor(parentSCXMLExecutor);
104         try {
105             executor.setStateMachine(scxml);
106         }
107         catch (ModelException me) {
108             throw new InvokerException(me);
109         }
110         Context rootCtx = executor.getRootContext();
111         for (Map.Entry<String, Object> entry : params.entrySet()) {
112             rootCtx.setLocal(entry.getKey(), entry.getValue());
113         }
114         executor.addListener(scxml, new SimpleSCXMLListener());
115         try {
116             executor.go();
117         } catch (ModelException me) {
118             throw new InvokerException(me.getMessage(), me.getCause());
119         }
120         if (executor.getStatus().isFinal()) {
121             TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId, TriggerEvent.SIGNAL_EVENT);
122             new AsyncTrigger(parentSCXMLExecutor, te).start();
123         }
124     }
125 
126     /**
127      * {@inheritDoc}.
128      */
129     @Override
130     public void parentEvent(final TriggerEvent evt)
131     throws InvokerException {
132         if (cancelled) {
133             return; // no further processing should take place
134         }
135         boolean doneBefore = executor.getStatus().isFinal();
136         executor.addEvent(evt);
137         if (!doneBefore && executor.getStatus().isFinal()) {
138             TriggerEvent te = new TriggerEvent("done.invoke."+parentStateId,TriggerEvent.SIGNAL_EVENT);
139             new AsyncTrigger(parentSCXMLExecutor, te).start();
140         }
141     }
142 
143     /**
144      * {@inheritDoc}.
145      */
146     @Override
147     public void cancel()
148     throws InvokerException {
149         cancelled = true;
150         executor.addEvent(new TriggerEvent("cancel.invoke."+parentStateId, TriggerEvent.CANCEL_EVENT));
151     }
152 }
153