| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.scxml.invoke; |
| |
| import java.io.IOException; |
| import java.io.Serializable; |
| import java.net.URL; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.commons.scxml.Context; |
| import org.apache.commons.scxml.Evaluator; |
| import org.apache.commons.scxml.SCInstance; |
| import org.apache.commons.scxml.SCXMLExecutor; |
| import org.apache.commons.scxml.TriggerEvent; |
| import org.apache.commons.scxml.env.SimpleDispatcher; |
| import org.apache.commons.scxml.env.SimpleErrorHandler; |
| import org.apache.commons.scxml.env.SimpleErrorReporter; |
| import org.apache.commons.scxml.env.SimpleSCXMLListener; |
| import org.apache.commons.scxml.io.SCXMLParser; |
| import org.apache.commons.scxml.model.ModelException; |
| import org.apache.commons.scxml.model.SCXML; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * A simple {@link Invoker} for SCXML documents. Invoked SCXML document |
| * may not contain external namespace elements, further invokes etc. |
| */ |
| public class SimpleSCXMLInvoker implements Invoker, Serializable { |
| |
| /** Serial version UID. */ |
| private static final long serialVersionUID = 1L; |
| /** Parent state ID. */ |
| private String parentStateId; |
| /** Event prefix, all events sent to the parent executor must begin |
| * with this prefix. */ |
| private String eventPrefix; |
| /** Invoking document's SCInstance. */ |
| private SCInstance parentSCInstance; |
| /** The invoked state machine executor. */ |
| private SCXMLExecutor executor; |
| /** Cancellation status. */ |
| private boolean cancelled; |
| |
| //// Constants |
| /** Prefix for all events sent to the parent state machine. */ |
| private static String invokePrefix = ".invoke."; |
| /** Suffix for invoke done event. */ |
| private static String invokeDone = "done"; |
| /** Suffix for invoke cancel response event. */ |
| private static String invokeCancelResponse = "cancel.response"; |
| |
| /** |
| * {@inheritDoc}. |
| */ |
| public void setParentStateId(final String parentStateId) { |
| this.parentStateId = parentStateId; |
| this.eventPrefix = this.parentStateId + invokePrefix; |
| this.cancelled = false; |
| } |
| |
| /** |
| * {@inheritDoc}. |
| */ |
| public void setSCInstance(final SCInstance scInstance) { |
| this.parentSCInstance = scInstance; |
| } |
| |
| /** |
| * {@inheritDoc}. |
| */ |
| public void invoke(final String source, final Map params) |
| throws InvokerException { |
| SCXML scxml = null; |
| try { |
| scxml = SCXMLParser.parse(new URL(source), |
| new SimpleErrorHandler()); |
| } catch (ModelException me) { |
| throw new InvokerException(me.getMessage(), me.getCause()); |
| } catch (IOException ioe) { |
| throw new InvokerException(ioe.getMessage(), ioe.getCause()); |
| } catch (SAXException se) { |
| throw new InvokerException(se.getMessage(), se.getCause()); |
| } |
| Evaluator eval = parentSCInstance.getEvaluator(); |
| executor = new SCXMLExecutor(eval, |
| new SimpleDispatcher(), new SimpleErrorReporter()); |
| Context rootCtx = eval.newContext(null); |
| for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| rootCtx.setLocal((String) entry.getKey(), entry.getValue()); |
| } |
| executor.setRootContext(rootCtx); |
| executor.setStateMachine(scxml); |
| executor.addListener(scxml, new SimpleSCXMLListener()); |
| executor.registerInvokerClass("scxml", this.getClass()); |
| try { |
| executor.go(); |
| } catch (ModelException me) { |
| throw new InvokerException(me.getMessage(), me.getCause()); |
| } |
| if (executor.getCurrentStatus().isFinal()) { |
| TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone, |
| TriggerEvent.SIGNAL_EVENT); |
| new AsyncTrigger(parentSCInstance.getExecutor(), te).start(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc}. |
| */ |
| public void parentEvents(final TriggerEvent[] evts) |
| throws InvokerException { |
| if (cancelled) { |
| return; // no further processing should take place |
| } |
| boolean doneBefore = executor.getCurrentStatus().isFinal(); |
| try { |
| executor.triggerEvents(evts); |
| } catch (ModelException me) { |
| throw new InvokerException(me.getMessage(), me.getCause()); |
| } |
| if (!doneBefore && executor.getCurrentStatus().isFinal()) { |
| TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone, |
| TriggerEvent.SIGNAL_EVENT); |
| new AsyncTrigger(parentSCInstance.getExecutor(), te).start(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc}. |
| */ |
| public void cancel() |
| throws InvokerException { |
| cancelled = true; |
| TriggerEvent te = new TriggerEvent(eventPrefix |
| + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT); |
| new AsyncTrigger(parentSCInstance.getExecutor(), te).start(); |
| } |
| |
| } |
| |