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