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;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.NotSerializableException;
24  import java.io.ObjectInputStream;
25  import java.io.ObjectOutputStream;
26  import java.net.URL;
27  import java.util.List;
28  import java.util.Set;
29  
30  import junit.framework.Assert;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.commons.scxml.env.SimpleDispatcher;
35  import org.apache.commons.scxml.env.Tracer;
36  import org.apache.commons.scxml.env.jexl.JexlEvaluator;
37  import org.apache.commons.scxml.io.SCXMLDigester;
38  import org.apache.commons.scxml.io.SCXMLParser;
39  import org.apache.commons.scxml.model.SCXML;
40  import org.apache.commons.scxml.model.TransitionTarget;
41  import org.xml.sax.ErrorHandler;
42  /***
43   * Helper methods for running SCXML unit tests.
44   */
45  public class SCXMLTestHelper {
46  
47      /***
48       * Serialized Commons SCXML object model temporary store.
49       * Assumes the default build artifacts are generated in the
50       * "target" directory (so it can be removed via a clean build).
51       */
52      public static final String SERIALIZATION_DIR = "target/serialization";
53      public static final String SERIALIZATION_FILE_PREFIX =
54          SERIALIZATION_DIR + "/scxml";
55      public static final String SERIALIZATION_FILE_SUFFIX = ".ser";
56  
57      public static SCXML digest(final URL url) {
58          return digest(url, null, null);
59      }
60  
61      public static SCXML digest(final URL url, final List customActions) {
62          return digest(url, null, customActions);
63      }
64  
65      public static SCXML digest(final URL url, final ErrorHandler errHandler) {
66          return digest(url, errHandler, null);
67      }
68  
69      public static SCXML digest(final URL url, final ErrorHandler errHandler,
70              final List customActions) {
71          Assert.assertNotNull(url);
72          // SAX ErrorHandler may be null
73          SCXML scxml = null;
74          try {
75              scxml = SCXMLDigester.digest(url, errHandler, customActions);
76          } catch (Exception e) {
77              Log log = LogFactory.getLog(SCXMLTestHelper.class);
78              log.error(e.getMessage(), e);
79              Assert.fail(e.getMessage());
80          }
81          Assert.assertNotNull(scxml);
82          SCXML roundtrip = testModelSerializability(scxml);
83          Assert.assertNotNull(roundtrip);
84          return roundtrip;
85      }
86  
87      public static SCXML parse(final URL url) {
88          return parse(url, null, null);
89      }
90  
91      public static SCXML parse(final URL url, final List customActions) {
92          return parse(url, null, customActions);
93      }
94  
95      public static SCXML parse(final URL url, final ErrorHandler errHandler) {
96          return parse(url, errHandler, null);
97      }
98  
99      public static SCXML parse(final URL url, final ErrorHandler errHandler,
100             final List customActions) {
101         Assert.assertNotNull(url);
102         // SAX ErrorHandler may be null
103         SCXML scxml = null;
104         try {
105             scxml = SCXMLParser.parse(url, errHandler, customActions);
106         } catch (Exception e) {
107             Log log = LogFactory.getLog(SCXMLTestHelper.class);
108             log.error(e.getMessage(), e);
109             Assert.fail(e.getMessage());
110         }
111         Assert.assertNotNull(scxml);
112         SCXML roundtrip = testModelSerializability(scxml);
113         return roundtrip;
114     }
115 
116     public static SCXMLExecutor getExecutor(final URL url) {
117         SCXML scxml = digest(url);
118         Evaluator evaluator = new JexlEvaluator();
119         return getExecutor(evaluator, scxml);
120     }
121 
122     public static SCXMLExecutor getExecutor(final URL url,
123             final Evaluator evaluator) {
124         SCXML scxml = digest(url);
125         return getExecutor(evaluator, scxml);
126     }
127 
128     public static SCXMLExecutor getExecutor(final URL url,
129             final ErrorHandler errHandler) {
130         SCXML scxml = digest(url, errHandler);
131         Evaluator evaluator = new JexlEvaluator();
132         return getExecutor(evaluator, scxml);
133     }
134 
135     public static SCXMLExecutor getExecutor(SCXML scxml) {
136         return getExecutor(scxml, null);
137     }
138 
139     public static SCXMLExecutor getExecutor(SCXML scxml,
140             SCXMLSemantics semantics) {
141         Evaluator evaluator = new JexlEvaluator();
142         Context context = evaluator.newContext(null);
143         EventDispatcher ed = new SimpleDispatcher();
144         Tracer trc = new Tracer();
145         return getExecutor(context, evaluator, scxml, ed, trc, semantics);
146     }
147 
148     public static SCXMLExecutor getExecutor(Evaluator evaluator, SCXML scxml) {
149         EventDispatcher ed = new SimpleDispatcher();
150         Tracer trc = new Tracer();
151         Assert.assertNotNull("Null evaluator", evaluator);
152         Context context = evaluator.newContext(null);
153         return getExecutor(context, evaluator, scxml, ed, trc);
154     }
155 
156     public static SCXMLExecutor getExecutor(final URL url, final Context ctx,
157             final Evaluator evaluator) {
158         SCXML scxml = digest(url);
159         EventDispatcher ed = new SimpleDispatcher();
160         Tracer trc = new Tracer();
161         return getExecutor(ctx, evaluator, scxml, ed, trc);
162     }
163 
164     public static SCXMLExecutor getExecutor(final SCXML scxml,
165             final Context ctx, final Evaluator evaluator) {
166         EventDispatcher ed = new SimpleDispatcher();
167         Tracer trc = new Tracer();
168         return getExecutor(ctx, evaluator, scxml, ed, trc);
169     }
170 
171     public static SCXMLExecutor getExecutor(Context context,
172             Evaluator evaluator, SCXML scxml, EventDispatcher ed, Tracer trc) {
173         return getExecutor(context, evaluator, scxml, ed, trc, null);
174     }
175 
176     public static SCXMLExecutor getExecutor(Context context,
177             Evaluator evaluator, SCXML scxml, EventDispatcher ed,
178             Tracer trc, SCXMLSemantics semantics) {
179         Assert.assertNotNull(evaluator);
180         Assert.assertNotNull(context);
181         Assert.assertNotNull(scxml);
182         Assert.assertNotNull(ed);
183         Assert.assertNotNull(trc);
184         SCXMLExecutor exec = null;
185         try {
186             if (semantics == null) {
187                 exec = new SCXMLExecutor(evaluator, ed, trc);
188             } else {
189                 exec = new SCXMLExecutor(evaluator, ed, trc, semantics);
190             }
191             exec.addListener(scxml, trc);
192             exec.setRootContext(context);
193             exec.setSuperStep(true);
194             exec.setStateMachine(scxml);
195             exec.go();
196         } catch (Exception e) {
197             Log log = LogFactory.getLog(SCXMLTestHelper.class);
198             log.error(e.getMessage(), e);
199             Assert.fail(e.getMessage());
200         }
201         Assert.assertNotNull(exec);
202         return exec;
203     }
204 
205     public static TransitionTarget lookupTransitionTarget(SCXMLExecutor exec,
206             String id) {
207         return (TransitionTarget) exec.getStateMachine().getTargets().get(id);
208     }
209 
210     public static Context lookupContext(SCXMLExecutor exec,
211             TransitionTarget tt) {
212         return exec.getSCInstance().lookupContext(tt);
213     }
214 
215     public static Context lookupContext(SCXMLExecutor exec,
216             String id) {
217         TransitionTarget tt = lookupTransitionTarget(exec, id);
218         if (tt == null) {
219             return null;
220         }
221         return exec.getSCInstance().lookupContext(tt);
222     }
223 
224     public static Set fireEvent(SCXMLExecutor exec, String name) {
225         TriggerEvent[] evts = {new TriggerEvent(name,
226                 TriggerEvent.SIGNAL_EVENT, null)};
227         try {
228             exec.triggerEvents(evts);
229         } catch (Exception e) {
230             Log log = LogFactory.getLog(SCXMLTestHelper.class);
231             log.error(e.getMessage(), e);
232             Assert.fail(e.getMessage());
233         }
234         return exec.getCurrentStatus().getStates();
235     }
236 
237     public static Set fireEvent(SCXMLExecutor exec, TriggerEvent te) {
238         TriggerEvent[] evts = { te };
239         try {
240             exec.triggerEvents(evts);
241         } catch (Exception e) {
242             Log log = LogFactory.getLog(SCXMLTestHelper.class);
243             log.error(e.getMessage(), e);
244             Assert.fail(e.getMessage());
245         }
246         return exec.getCurrentStatus().getStates();
247     }
248 
249     public static Set fireEvents(SCXMLExecutor exec, TriggerEvent[] evts) {
250         try {
251             exec.triggerEvents(evts);
252         } catch (Exception e) {
253             Log log = LogFactory.getLog(SCXMLTestHelper.class);
254             log.error(e.getMessage(), e);
255             Assert.fail(e.getMessage());
256         }
257         return exec.getCurrentStatus().getStates();
258     }
259 
260     public static SCXML testModelSerializability(final SCXML scxml) {
261         File fileDir = new File(SERIALIZATION_DIR);
262         if (!fileDir.exists() && !fileDir.mkdir()) {
263             System.err.println("SKIPPED SERIALIZATION: Failed directory creation");
264             return scxml;
265         }
266         String filename = SERIALIZATION_FILE_PREFIX
267             + System.currentTimeMillis() + SERIALIZATION_FILE_SUFFIX;
268         SCXML roundtrip = null;
269         try {
270             ObjectOutputStream out =
271                 new ObjectOutputStream(new FileOutputStream(filename));
272             out.writeObject(scxml);
273             out.close();
274             ObjectInputStream in =
275                 new ObjectInputStream(new FileInputStream(filename));
276             roundtrip = (SCXML) in.readObject();
277             in.close();
278         } catch (NotSerializableException nse) {
279             // <data> nodes failed serialization
280             System.err.println("SERIALIZATION ERROR: The DOM implementation"
281                 + " in use is not serializable");
282             return scxml;
283         } catch(IOException ex) {
284             ex.printStackTrace();
285         } catch(ClassNotFoundException ex) {
286             ex.printStackTrace();
287         }
288         return roundtrip;
289     }
290 
291     public static SCXMLExecutor testExecutorSerializability(final SCXMLExecutor exec) {
292         File fileDir = new File(SERIALIZATION_DIR);
293         if (!fileDir.exists() && !fileDir.mkdir()) {
294             System.err.println("SKIPPED SERIALIZATION: Failed directory creation");
295             return exec;
296         }
297         String filename = SERIALIZATION_FILE_PREFIX
298             + System.currentTimeMillis() + SERIALIZATION_FILE_SUFFIX;
299         SCXMLExecutor roundtrip = null;
300         try {
301             ObjectOutputStream out =
302                 new ObjectOutputStream(new FileOutputStream(filename));
303             out.writeObject(exec);
304             out.close();
305             ObjectInputStream in =
306                 new ObjectInputStream(new FileInputStream(filename));
307             roundtrip = (SCXMLExecutor) in.readObject();
308             in.close();
309         } catch (NotSerializableException nse) {
310             // <data> nodes failed serialization, test cases do not add
311             // other non-serializable context data
312             System.err.println("SERIALIZATION ERROR: The DOM implementation"
313                 + " in use is not serializable");
314             return exec;
315         } catch(IOException ex) {
316             ex.printStackTrace();
317         } catch(ClassNotFoundException ex) {
318             ex.printStackTrace();
319         }
320         return roundtrip;
321     }
322 
323     /***
324      * Discourage instantiation.
325      */
326     private SCXMLTestHelper() {
327         super();
328     }
329 
330 }
331