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