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.SCXMLParser;
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, final Evaluator evaluator) {
075 try {
076 String documentURI = getCanonicalURI(uri);
077 Context rootCtx = evaluator.newContext(null);
078 Tracer trc = new Tracer();
079 SCXML doc = SCXMLParser.parse(new URL(documentURI), trc);
080 if (doc == null) {
081 System.err.println("The SCXML document " + uri
082 + " can not be parsed!");
083 System.exit(-1);
084 }
085 System.out.println(SCXMLSerializer.serialize(doc));
086 SCXMLExecutor exec = new SCXMLExecutor(evaluator, null, trc);
087 EventDispatcher ed = new SimpleScheduler(exec);
088 exec.setEventdispatcher(ed);
089 exec.setStateMachine(doc);
090 exec.addListener(doc, trc);
091 exec.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
092 exec.setRootContext(rootCtx);
093 exec.go();
094 BufferedReader br = new BufferedReader(new
095 InputStreamReader(System.in));
096 String event = null;
097 while ((event = br.readLine()) != null) {
098 event = event.trim();
099 if (event.equalsIgnoreCase("help") || event.equals("?")) {
100 System.out.println("Enter a space-separated list of "
101 + "events");
102 System.out.println("To populate a variable in the "
103 + "current context, type \"name=value\"");
104 System.out.println("To quit, enter \"quit\"");
105 System.out.println("To reset state machine, enter "
106 + "\"reset\"");
107 } else if (event.equalsIgnoreCase("quit")) {
108 break;
109 } else if (event.equalsIgnoreCase("reset")) {
110 exec.reset();
111 } else if (event.indexOf('=') != -1) {
112 int marker = event.indexOf('=');
113 String name = event.substring(0, marker);
114 String value = event.substring(marker + 1);
115 rootCtx.setLocal(name, value);
116 System.out.println("Set variable " + name + " to "
117 + value);
118 } else if (SCXMLHelper.isStringEmpty(event)
119 || event.equalsIgnoreCase("null")) {
120 TriggerEvent[] evts = {new TriggerEvent(null,
121 TriggerEvent.SIGNAL_EVENT, null)};
122 exec.triggerEvents(evts);
123 if (exec.getCurrentStatus().isFinal()) {
124 System.out.println("A final configuration reached.");
125 }
126 } else {
127 StringTokenizer st = new StringTokenizer(event);
128 int tkns = st.countTokens();
129 TriggerEvent[] evts = new TriggerEvent[tkns];
130 for (int i = 0; i < tkns; i++) {
131 evts[i] = new TriggerEvent(st.nextToken(),
132 TriggerEvent.SIGNAL_EVENT, null);
133 }
134 exec.triggerEvents(evts);
135 if (exec.getCurrentStatus().isFinal()) {
136 System.out.println("A final configuration reached.");
137 }
138 }
139 }
140 } catch (IOException e) {
141 e.printStackTrace();
142 } catch (ModelException e) {
143 e.printStackTrace();
144 } catch (SAXException e) {
145 e.printStackTrace();
146 }
147 }
148
149 /**
150 * @param uri an absolute or relative URL
151 * @return java.lang.String canonical URL (absolute)
152 * @throws java.io.IOException if a relative URL can not be resolved
153 * to a local file
154 */
155 private static String getCanonicalURI(final String uri)
156 throws IOException {
157 if (uri.toLowerCase().startsWith("http://")
158 || uri.toLowerCase().startsWith("file://")) {
159 return uri;
160 }
161 File in = new File(uri);
162 return "file:///" + in.getCanonicalPath();
163 }
164
165 /**
166 * Discourage instantiation since this is a utility class.
167 */
168 private StandaloneUtils() {
169 super();
170 }
171
172 }
173