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