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.scxml.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 org.apache.commons.scxml.Context;
27  import org.apache.commons.scxml.Evaluator;
28  import org.apache.commons.scxml.EventDispatcher;
29  import org.apache.commons.scxml.SCXMLExecutor;
30  import org.apache.commons.scxml.SCXMLHelper;
31  import org.apache.commons.scxml.TriggerEvent;
32  import org.apache.commons.scxml.env.SimpleScheduler;
33  import org.apache.commons.scxml.env.Tracer;
34  import org.apache.commons.scxml.invoke.SimpleSCXMLInvoker;
35  import org.apache.commons.scxml.io.SCXMLDigester;
36  import org.apache.commons.scxml.io.SCXMLSerializer;
37  import org.apache.commons.scxml.model.ModelException;
38  import org.apache.commons.scxml.model.SCXML;
39  import org.xml.sax.SAXException;
40  
41  /***
42   * Utility methods used by command line SCXML execution, useful for
43   * debugging.
44   *
45   * The following expression languages are supported in SCXML documents:
46   * <ol>
47   *  <li>JEXL - Using Commons JEXL</li>
48   *  <li>EL - Using Commons EL</li>
49   * </ol>
50   *
51   * @see org.apache.commons.scxml.env.jexl
52   * @see org.apache.commons.scxml.env.jsp
53   */
54  public final class StandaloneUtils {
55  
56      /***
57       * Command line utility method for executing the state machine defined
58       * using the SCXML document described by the specified URI and using
59       * the specified expression evaluator.
60       *
61       * @param uri The URI or filename of the SCXML document
62       * @param evaluator The expression evaluator for the expression language
63       *                  used in the specified SCXML document
64       *
65       * <p>RUNNING:</p>
66       * <ul>
67       *  <li>Enter a space-separated list of "events"</li>
68       *  <li>To quit, enter "quit"</li>
69       *  <li>To populate a variable in the current context,
70       *      type "name=value"</li>
71       *  <li>To reset state machine, enter "reset"</li>
72       * </ul>
73       */
74      public static void execute(final String uri, final Evaluator evaluator) {
75          try {
76              String documentURI = getCanonicalURI(uri);
77              Context rootCtx = evaluator.newContext(null);
78              Tracer trc = new Tracer();
79              SCXML doc = SCXMLDigester.digest(new URL(documentURI), trc);
80              if (doc == null) {
81                  System.err.println("The SCXML document " + uri
82                          + " can not be parsed!");
83                  System.exit(-1);
84              }
85              System.out.println(SCXMLSerializer.serialize(doc));
86              SCXMLExecutor exec = new SCXMLExecutor(evaluator, null, trc);
87              EventDispatcher ed = new SimpleScheduler(exec);
88              exec.setEventdispatcher(ed);
89              exec.setStateMachine(doc);
90              exec.addListener(doc, trc);
91              exec.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
92              exec.setRootContext(rootCtx);
93              exec.go();
94              BufferedReader br = new BufferedReader(new
95                  InputStreamReader(System.in));
96              String event = null;
97              while ((event = br.readLine()) != null) {
98                  event = event.trim();
99                  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