    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.JexlContext;
    37  import org.apache.commons.scxml.env.jexl.JexlEvaluator;
    38  import org.apache.commons.scxml.io.SCXMLDigester;
    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          return roundtrip;
    84      }
    85
    86      public static SCXMLExecutor getExecutor(final URL url) {
    87          SCXML scxml = digest(url);
    88          Evaluator evaluator = new JexlEvaluator();
    89          return getExecutor(evaluator, scxml);
    90      }
    91
    92      public static SCXMLExecutor getExecutor(final URL url,
    93              final Evaluator evaluator) {
    94          SCXML scxml = digest(url);
    95          return getExecutor(evaluator, scxml);
    96      }
    97
    98      public static SCXMLExecutor getExecutor(final URL url,
    99              final ErrorHandler errHandler) {
    100         SCXML scxml = digest(url, errHandler);
    101         Evaluator evaluator = new JexlEvaluator();
    102         return getExecutor(evaluator, scxml);
    103     }
    104
    105     public static SCXMLExecutor getExecutor(SCXML scxml) {
    106         return getExecutor(scxml, null);
    107     }
    108
    109     public static SCXMLExecutor getExecutor(SCXML scxml,
    110             SCXMLSemantics semantics) {
    111         Context context = new JexlContext();
    112         Evaluator evaluator = new JexlEvaluator();
    113         EventDispatcher ed = new SimpleDispatcher();
    114         Tracer trc = new Tracer();
    115         return getExecutor(context, evaluator, scxml, ed, trc, semantics);
    116     }
    117
    118     public static SCXMLExecutor getExecutor(Evaluator evaluator, SCXML scxml) {
    119         EventDispatcher ed = new SimpleDispatcher();
    120         Tracer trc = new Tracer();
    121         Context context = new JexlContext();
    122         return getExecutor(context, evaluator, scxml, ed, trc);
    123     }
    124
    125     public static SCXMLExecutor getExecutor(final URL url, final Context ctx,
    126             final Evaluator evaluator) {
    127         SCXML scxml = digest(url);
    128         EventDispatcher ed = new SimpleDispatcher();
    129         Tracer trc = new Tracer();
    130         return getExecutor(ctx, evaluator, scxml, ed, trc);
    131     }
    132
    133     public static SCXMLExecutor getExecutor(final SCXML scxml,
    134             final Context ctx, final Evaluator evaluator) {
    135         EventDispatcher ed = new SimpleDispatcher();
    136         Tracer trc = new Tracer();
    137         return getExecutor(ctx, evaluator, scxml, ed, trc);
    138     }
    139
    140     public static SCXMLExecutor getExecutor(Context context,
    141             Evaluator evaluator, SCXML scxml, EventDispatcher ed, Tracer trc) {
    142         return getExecutor(context, evaluator, scxml, ed, trc, null);
    143     }
    144
    145     public static SCXMLExecutor getExecutor(Context context,
    146             Evaluator evaluator, SCXML scxml, EventDispatcher ed,
    147             Tracer trc, SCXMLSemantics semantics) {
    148         Assert.assertNotNull(evaluator);
    149         Assert.assertNotNull(context);
    150         Assert.assertNotNull(scxml);
    151         Assert.assertNotNull(ed);
    152         Assert.assertNotNull(trc);
    153         SCXMLExecutor exec = null;
    154         try {
    155             if (semantics == null) {
    156                 exec = new SCXMLExecutor(evaluator, ed, trc);
    157             } else {
    158                 exec = new SCXMLExecutor(evaluator, ed, trc, semantics);
    159             }
    160             exec.addListener(scxml, trc);
    161             exec.setRootContext(context);
    162             exec.setSuperStep(true);
    163             exec.setStateMachine(scxml);
    164             exec.go();
    165         } catch (Exception e) {
    166             Log log = LogFactory.getLog(SCXMLTestHelper.class);
    167             log.error(e.getMessage(), e);
    168             Assert.fail(e.getMessage());
    169         }
    170         Assert.assertNotNull(exec);
    171         return exec;
    172     }
    173
    174     public static TransitionTarget lookupTransitionTarget(SCXMLExecutor exec,
    175             String id) {
    176         return (TransitionTarget) exec.getStateMachine().getTargets().get(id);
    177     }
    178
    179     public static Context lookupContext(SCXMLExecutor exec,
    180             TransitionTarget tt) {
    181         return exec.getSCInstance().lookupContext(tt);
    182     }
    183
    184     public static Context lookupContext(SCXMLExecutor exec,
    185             String id) {
    186         TransitionTarget tt = lookupTransitionTarget(exec, id);
    187         if (tt == null) {
    188             return null;
    189         }
    190         return exec.getSCInstance().lookupContext(tt);
    191     }
    192
    193     public static Set fireEvent(SCXMLExecutor exec, String name) {
    194         TriggerEvent[] evts = {new TriggerEvent(name,
    195                 TriggerEvent.SIGNAL_EVENT, null)};
    196         try {
    197             exec.triggerEvents(evts);
    198         } catch (Exception e) {
    199             Log log = LogFactory.getLog(SCXMLTestHelper.class);
    200             log.error(e.getMessage(), e);
    201             Assert.fail(e.getMessage());
    202         }
    203         return exec.getCurrentStatus().getStates();
    204     }
    205
    206     public static Set fireEvent(SCXMLExecutor exec, TriggerEvent te) {
    207         TriggerEvent[] evts = { te };
    208         try {
    209             exec.triggerEvents(evts);
    210         } catch (Exception e) {
    211             Log log = LogFactory.getLog(SCXMLTestHelper.class);
    212             log.error(e.getMessage(), e);
    213             Assert.fail(e.getMessage());
    214         }
    215         return exec.getCurrentStatus().getStates();
    216     }
    217
    218     public static Set fireEvents(SCXMLExecutor exec, TriggerEvent[] evts) {
    219         try {
    220             exec.triggerEvents(evts);
    221         } catch (Exception e) {
    222             Log log = LogFactory.getLog(SCXMLTestHelper.class);
    223             log.error(e.getMessage(), e);
    224             Assert.fail(e.getMessage());
    225         }
    226         return exec.getCurrentStatus().getStates();
    227     }
    228
    229     public static SCXML testModelSerializability(final SCXML scxml) {
    230         File fileDir = new File(SERIALIZATION_DIR);
    231         if (!fileDir.exists() && !fileDir.mkdir()) {
    232             return null;
    233         }
    234         String filename = SERIALIZATION_FILE_PREFIX
    235             + System.currentTimeMillis() + SERIALIZATION_FILE_SUFFIX;
    236         SCXML roundtrip = null;
    237         try {
    238             ObjectOutputStream out =
    239                 new ObjectOutputStream(new FileOutputStream(filename));
    240             out.writeObject(scxml);
    241             out.close();
    242             ObjectInputStream in =
    243                 new ObjectInputStream(new FileInputStream(filename));
    244             roundtrip = (SCXML) in.readObject();
    245             in.close();
    246         } catch (NotSerializableException nse) {
    247             // <data> nodes failed serialization
    248             System.err.println("SERIALIZATION ERROR: The DOM implementation"
    249                 + " in use is not serializable");
    250             return scxml;
    251         } catch(IOException ex) {
    252             ex.printStackTrace();
    253         } catch(ClassNotFoundException ex) {
    254             ex.printStackTrace();
    255         }
    256         return roundtrip;
    257     }
    258
    259     public static SCXMLExecutor testExecutorSerializability(final SCXMLExecutor exec) {
    260         File fileDir = new File(SERIALIZATION_DIR);
    261         if (!fileDir.exists() && !fileDir.mkdir()) {
    262             return null;
    263         }
    264         String filename = SERIALIZATION_FILE_PREFIX
    265             + System.currentTimeMillis() + SERIALIZATION_FILE_SUFFIX;
    266         SCXMLExecutor roundtrip = null;
    267         try {
    268             ObjectOutputStream out =
    269                 new ObjectOutputStream(new FileOutputStream(filename));
    270             out.writeObject(exec);
    271             out.close();
    272             ObjectInputStream in =
    273                 new ObjectInputStream(new FileInputStream(filename));
    274             roundtrip = (SCXMLExecutor) in.readObject();
    275             in.close();
    276         } catch (NotSerializableException nse) {
    277             // <data> nodes failed serialization, test cases do not add
    278             // other non-serializable context data
    279             System.err.println("SERIALIZATION ERROR: The DOM implementation"
    280                 + " in use is not serializable");
    281             return exec;
    282         } catch(IOException ex) {
    283             ex.printStackTrace();
    284         } catch(ClassNotFoundException ex) {
    285             ex.printStackTrace();
    286         }
    287         return roundtrip;
    288     }
    289
    290     /***
    291      * Discourage instantiation.
    292      */
    293     private SCXMLTestHelper() {
    294         super();
    295     }
    296
    297 }
    298