001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.scxml.invoke;
018:
019: import java.io.IOException;
020: import java.io.Serializable;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import org.apache.commons.scxml.Context;
025: import org.apache.commons.scxml.Evaluator;
026: import org.apache.commons.scxml.SCInstance;
027: import org.apache.commons.scxml.SCXMLExecutor;
028: import org.apache.commons.scxml.TriggerEvent;
029: import org.apache.commons.scxml.env.SimpleDispatcher;
030: import org.apache.commons.scxml.env.SimpleErrorHandler;
031: import org.apache.commons.scxml.env.SimpleErrorReporter;
032: import org.apache.commons.scxml.env.SimpleSCXMLListener;
033: import org.apache.commons.scxml.io.SCXMLDigester;
034: import org.apache.commons.scxml.model.ModelException;
035: import org.apache.commons.scxml.model.SCXML;
036: import org.xml.sax.SAXException;
037:
038: /**
039: * A simple {@link Invoker} for SCXML documents. Invoked SCXML document
040: * may not contain external namespace elements, further invokes etc.
041: */
042: public class SimpleSCXMLInvoker implements Invoker, Serializable {
043:
044: /** Serial version UID. */
045: private static final long serialVersionUID = 1L;
046: /** Parent state ID. */
047: private String parentStateId;
048: /** Event prefix, all events sent to the parent executor must begin
049: * with this prefix. */
050: private String eventPrefix;
051: /** Invoking document's SCInstance. */
052: private SCInstance parentSCInstance;
053: /** The invoked state machine executor. */
054: private SCXMLExecutor executor;
055: /** Cancellation status. */
056: private boolean cancelled;
057:
058: //// Constants
059: /** Prefix for all events sent to the parent state machine. */
060: private static String invokePrefix = ".invoke.";
061: /** Suffix for invoke done event. */
062: private static String invokeDone = "done";
063: /** Suffix for invoke cancel response event. */
064: private static String invokeCancelResponse = "cancel.response";
065:
066: /**
067: * {@inheritDoc}.
068: */
069: public void setParentStateId(final String parentStateId) {
070: this .parentStateId = parentStateId;
071: this .eventPrefix = parentStateId + invokePrefix;
072: this .cancelled = false;
073: }
074:
075: /**
076: * {@inheritDoc}.
077: */
078: public void setSCInstance(final SCInstance scInstance) {
079: this .parentSCInstance = scInstance;
080: }
081:
082: /**
083: * {@inheritDoc}.
084: */
085: public void invoke(final String source, final Map params)
086: throws InvokerException {
087: SCXML scxml = null;
088: try {
089: scxml = SCXMLDigester.digest(source,
090: new SimpleErrorHandler(), null);
091: } catch (ModelException me) {
092: throw new InvokerException(me.getMessage(), me.getCause());
093: } catch (IOException ioe) {
094: throw new InvokerException(ioe.getMessage(), ioe.getCause());
095: } catch (SAXException se) {
096: throw new InvokerException(se.getMessage(), se.getCause());
097: }
098: Evaluator eval = parentSCInstance.getEvaluator();
099: executor = new SCXMLExecutor(eval, new SimpleDispatcher(),
100: new SimpleErrorReporter());
101: Context rootCtx = eval.newContext(null);
102: for (Iterator iter = params.entrySet().iterator(); iter
103: .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: try {
111: executor.go();
112: } catch (ModelException me) {
113: throw new InvokerException(me.getMessage(), me.getCause());
114: }
115: }
116:
117: /**
118: * {@inheritDoc}.
119: */
120: public void parentEvents(final TriggerEvent[] evts)
121: throws InvokerException {
122: if (cancelled) {
123: return; // no further processing should take place
124: }
125: boolean doneBefore = executor.getCurrentStatus().isFinal();
126: try {
127: executor.triggerEvents(evts);
128: } catch (ModelException me) {
129: throw new InvokerException(me.getMessage(), me.getCause());
130: }
131: if (!doneBefore && executor.getCurrentStatus().isFinal()) {
132: TriggerEvent te = new TriggerEvent(
133: eventPrefix + invokeDone, TriggerEvent.SIGNAL_EVENT);
134: new AsyncTrigger(parentSCInstance.getExecutor(), te);
135: }
136: }
137:
138: /**
139: * {@inheritDoc}.
140: */
141: public void cancel() throws InvokerException {
142: cancelled = true;
143: TriggerEvent te = new TriggerEvent(eventPrefix
144: + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT);
145: new AsyncTrigger(parentSCInstance.getExecutor(), te);
146: }
147:
148: }
|