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.test;
018:
019: import java.io.BufferedReader;
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.InputStreamReader;
023: import java.net.URL;
024: import java.util.StringTokenizer;
025:
026: import org.apache.commons.scxml.Context;
027: import org.apache.commons.scxml.Evaluator;
028: import org.apache.commons.scxml.EventDispatcher;
029: import org.apache.commons.scxml.SCXMLExecutor;
030: import org.apache.commons.scxml.SCXMLHelper;
031: import org.apache.commons.scxml.TriggerEvent;
032: import org.apache.commons.scxml.env.SimpleScheduler;
033: import org.apache.commons.scxml.env.Tracer;
034: import org.apache.commons.scxml.invoke.SimpleSCXMLInvoker;
035: import org.apache.commons.scxml.io.SCXMLDigester;
036: import org.apache.commons.scxml.io.SCXMLSerializer;
037: import org.apache.commons.scxml.model.ModelException;
038: import org.apache.commons.scxml.model.SCXML;
039: import org.xml.sax.SAXException;
040:
041: /**
042: * Utility methods used by command line SCXML execution, useful for
043: * debugging.
044: *
045: * The following expression languages are supported in SCXML documents:
046: * <ol>
047: * <li>JEXL - Using Commons JEXL</li>
048: * <li>EL - Using Commons EL</li>
049: * </ol>
050: *
051: * @see org.apache.commons.scxml.env.jexl
052: * @see org.apache.commons.scxml.env.jsp
053: */
054: public final class StandaloneUtils {
055:
056: /**
057: * Command line utility method for executing the state machine defined
058: * using the SCXML document described by the specified URI and using
059: * the specified expression evaluator.
060: *
061: * @param uri The URI or filename of the SCXML document
062: * @param evaluator The expression evaluator for the expression language
063: * used in the specified SCXML document
064: *
065: * <p>RUNNING:</p>
066: * <ul>
067: * <li>Enter a space-separated list of "events"</li>
068: * <li>To quit, enter "quit"</li>
069: * <li>To populate a variable in the current context,
070: * type "name=value"</li>
071: * <li>To reset state machine, enter "reset"</li>
072: * </ul>
073: */
074: public static void execute(final String uri,
075: final Evaluator evaluator) {
076: try {
077: String documentURI = getCanonicalURI(uri);
078: Context rootCtx = evaluator.newContext(null);
079: Tracer trc = new Tracer();
080: SCXML doc = SCXMLDigester.digest(new URL(documentURI), trc);
081: if (doc == null) {
082: System.err.println("The SCXML document " + uri
083: + " can not be parsed!");
084: System.exit(-1);
085: }
086: System.out.println(SCXMLSerializer.serialize(doc));
087: SCXMLExecutor exec = new SCXMLExecutor(evaluator, null, trc);
088: EventDispatcher ed = new SimpleScheduler(exec);
089: exec.setEventdispatcher(ed);
090: exec.setStateMachine(doc);
091: exec.addListener(doc, trc);
092: exec
093: .registerInvokerClass("scxml",
094: SimpleSCXMLInvoker.class);
095: exec.setRootContext(rootCtx);
096: exec.go();
097: BufferedReader br = new BufferedReader(
098: new InputStreamReader(System.in));
099: String event = null;
100: while ((event = br.readLine()) != null) {
101: event = event.trim();
102: if (event.equalsIgnoreCase("help") || event.equals("?")) {
103: System.out
104: .println("Enter a space-separated list of "
105: + "events");
106: System.out.println("To populate a variable in the "
107: + "current context, type \"name=value\"");
108: System.out.println("To quit, enter \"quit\"");
109: System.out.println("To reset state machine, enter "
110: + "\"reset\"");
111: } else if (event.equalsIgnoreCase("quit")) {
112: break;
113: } else if (event.equalsIgnoreCase("reset")) {
114: exec.reset();
115: } else if (event.indexOf('=') != -1) {
116: int marker = event.indexOf('=');
117: String name = event.substring(0, marker);
118: String value = event.substring(marker + 1);
119: rootCtx.setLocal(name, value);
120: System.out.println("Set variable " + name + " to "
121: + value);
122: } else if (SCXMLHelper.isStringEmpty(event)
123: || event.equalsIgnoreCase("null")) {
124: TriggerEvent[] evts = { new TriggerEvent(null,
125: TriggerEvent.SIGNAL_EVENT, null) };
126: exec.triggerEvents(evts);
127: if (exec.getCurrentStatus().isFinal()) {
128: System.out
129: .println("A final configuration reached.");
130: }
131: } else {
132: StringTokenizer st = new StringTokenizer(event);
133: int tkns = st.countTokens();
134: TriggerEvent[] evts = new TriggerEvent[tkns];
135: for (int i = 0; i < tkns; i++) {
136: evts[i] = new TriggerEvent(st.nextToken(),
137: TriggerEvent.SIGNAL_EVENT, null);
138: }
139: exec.triggerEvents(evts);
140: if (exec.getCurrentStatus().isFinal()) {
141: System.out
142: .println("A final configuration reached.");
143: }
144: }
145: }
146: } catch (IOException e) {
147: e.printStackTrace();
148: } catch (ModelException e) {
149: e.printStackTrace();
150: } catch (SAXException e) {
151: e.printStackTrace();
152: }
153: }
154:
155: /**
156: * @param uri an absolute or relative URL
157: * @return java.lang.String canonical URL (absolute)
158: * @throws java.io.IOException if a relative URL can not be resolved
159: * to a local file
160: */
161: private static String getCanonicalURI(final String uri)
162: throws IOException {
163: if (uri.toLowerCase().startsWith("http://")
164: || uri.toLowerCase().startsWith("file://")) {
165: return uri;
166: }
167: File in = new File(uri);
168: return "file:///" + in.getCanonicalPath();
169: }
170:
171: /**
172: * Discourage instantiation since this is a utility class.
173: */
174: private StandaloneUtils() {
175: super();
176: }
177:
178: }
|