    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