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.scxml2.test;
18  
19  import java.io.BufferedReader;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStreamReader;
23  import java.net.URL;
24  import java.util.StringTokenizer;
25  
26  import javax.xml.stream.XMLStreamException;
27  
28  import org.apache.commons.scxml2.Context;
29  import org.apache.commons.scxml2.Evaluator;
30  import org.apache.commons.scxml2.SCXMLExecutor;
31  import org.apache.commons.scxml2.TriggerEvent;
32  import org.apache.commons.scxml2.env.Tracer;
33  import org.apache.commons.scxml2.invoke.SimpleSCXMLInvoker;
34  import org.apache.commons.scxml2.io.SCXMLReader;
35  import org.apache.commons.scxml2.io.SCXMLWriter;
36  import org.apache.commons.scxml2.model.ModelException;
37  import org.apache.commons.scxml2.model.SCXML;
38  
39  /**
40   * Utility methods used by command line SCXML execution, useful for
41   * debugging.
42   *
43   * The following expression languages are supported in SCXML documents:
44   * <ol>
45   *  <li>JEXL - Using Commons JEXL</li>
46   * </ol>
47   *
48   * @see org.apache.commons.scxml2.env.jexl
49   */
50  public final class StandaloneUtils {
51  
52      /**
53       * Command line utility method for executing the state machine defined
54       * using the SCXML document described by the specified URI and using
55       * the specified expression evaluator.
56       *
57       * @param uri The URI or filename of the SCXML document
58       * @param evaluator The expression evaluator for the expression language
59       *                  used in the specified SCXML document
60       *
61       * <p>RUNNING:</p>
62       * <ul>
63       *  <li>Enter a space-separated list of "events"</li>
64       *  <li>To quit, enter "quit"</li>
65       *  <li>To populate a variable in the current context,
66       *      type "name=value"</li>
67       *  <li>To reset state machine, enter "reset"</li>
68       * </ul>
69       */
70      public static void execute(final String uri, final Evaluator evaluator) {
71          try {
72              String documentURI = getCanonicalURI(uri);
73              Context rootCtx = evaluator.newContext(null);
74              Tracer trc = new Tracer();
75              SCXML doc = SCXMLReader.read(new URL(documentURI));
76              if (doc == null) {
77                  System.err.println("The SCXML document " + uri
78                          + " can not be parsed!");
79                  System.exit(-1);
80              }
81              System.out.println(SCXMLWriter.write(doc));
82              SCXMLExecutor exec = new SCXMLExecutor(evaluator, null, trc);
83              exec.setStateMachine(doc);
84              exec.addListener(doc, trc);
85              exec.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
86              exec.setRootContext(rootCtx);
87              exec.go();
88              BufferedReader br = new BufferedReader(new
89                  InputStreamReader(System.in));
90              String event;
91              while ((event = br.readLine()) != null) {
92                  event = event.trim();
93                  if (event.equalsIgnoreCase("help") || event.equals("?")) {
94                      System.out.println("Enter a space-separated list of "
95                          + "events");
96                      System.out.println("To populate a variable in the "
97                          + "current context, type \"name=value\"");
98                      System.out.println("To quit, enter \"quit\"");
99                      System.out.println("To reset state machine, enter "
100                         + "\"reset\"");
101                 } else if (event.equalsIgnoreCase("quit")) {
102                     break;
103                 } else if (event.equalsIgnoreCase("reset")) {
104                     exec.reset();
105                 } else if (event.indexOf('=') != -1) {
106                     int marker = event.indexOf('=');
107                     String name = event.substring(0, marker);
108                     String value = event.substring(marker + 1);
109                     rootCtx.setLocal(name, value);
110                     System.out.println("Set variable " + name + " to "
111                         + value);
112                 } else if (event.trim().length() == 0
113                            || event.equalsIgnoreCase("null")) {
114                     TriggerEvent[] evts = {new TriggerEvent(null,
115                         TriggerEvent.SIGNAL_EVENT, null)};
116                     exec.triggerEvents(evts);
117                     if (exec.getStatus().isFinal()) {
118                         System.out.println("A final configuration reached.");
119                     }
120                 } else {
121                     StringTokenizer st = new StringTokenizer(event);
122                     int tkns = st.countTokens();
123                     TriggerEvent[] evts = new TriggerEvent[tkns];
124                     for (int i = 0; i < tkns; i++) {
125                         evts[i] = new TriggerEvent(st.nextToken(),
126                                 TriggerEvent.SIGNAL_EVENT, null);
127                     }
128                     exec.triggerEvents(evts);
129                     if (exec.getStatus().isFinal()) {
130                         System.out.println("A final configuration reached.");
131                     }
132                 }
133             }
134         } catch (IOException e) {
135             e.printStackTrace();
136         } catch (ModelException e) {
137             e.printStackTrace();
138         } catch (XMLStreamException e) {
139         	e.printStackTrace();
140         }
141     }
142 
143     /**
144      * @param uri an absolute or relative URL
145      * @return java.lang.String canonical URL (absolute)
146      * @throws java.io.IOException if a relative URL can not be resolved
147      *         to a local file
148      */
149     private static String getCanonicalURI(final String uri)
150     throws IOException {
151         if (uri.toLowerCase().startsWith("http://")
152             || uri.toLowerCase().startsWith("file://")) {
153                 return uri;
154         }
155         File in = new File(uri);
156         return "file:///" + in.getCanonicalPath();
157     }
158 
159     /**
160      * Discourage instantiation since this is a utility class.
161      */
162     private StandaloneUtils() {
163         super();
164     }
165 
166 }
167