View Javadoc

    1   /*
    2    *
    3    *   Copyright 2006 The Apache Software Foundation.
    4    *
    5    *  Licensed under the Apache License, Version 2.0 (the "License");
    6    *  you may not use this file except in compliance with the License.
    7    *  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   */
    18  package org.apache.commons.scxml;
    19
    20  import java.util.Iterator;
    21  import java.util.Set;
    22
    23  import javax.xml.transform.TransformerException;
    24
    25  import org.apache.commons.logging.Log;
    26  import org.apache.commons.logging.LogFactory;
    27  import org.apache.commons.scxml.model.TransitionTarget;
    28  import org.apache.xpath.XPathAPI;
    29  import org.w3c.dom.Node;
    30  import org.w3c.dom.NodeList;
    31
    32  /***
    33   * Implementations of builtin functions defined by the SCXML
    34   * specification.
    35   *
    36   * The current version of the specification defines one builtin
    37   * predicate In()
    38   */
    39  public class Builtin {
    40
    41      /***
    42       * Implements the In() predicate for SCXML documents. The method
    43       * name chosen is different since &quot;in&quot; is a reserved token
    44       * in some expression languages.
    45       *
    46       * Does this state belong to the given Set of States.
    47       * Simple ID based comparator, assumes IDs are unique.
    48       *
    49       * @param allStates The Set of State objects to look in
    50       * @param state The State ID to compare with
    51       * @return Whether this State belongs to this Set
    52       */
    53      public static boolean isMember(final Set allStates,
    54              final String state) {
    55          for (Iterator i = allStates.iterator(); i.hasNext();) {
    56              TransitionTarget tt = (TransitionTarget) i.next();
    57              if (state.equals(tt.getId())) {
    58                  return true;
    59              }
    60          }
    61          return false;
    62      }
    63
    64      /***
    65       * Implements the Data() function for Commons SCXML documents, that
    66       * can be used to obtain a node from one of the XML data trees.
    67       * Manifests within "location" attribute of &lt;assign&gt; element,
    68       * for Commons JEXL and Commons EL based documents.
    69       *
    70       * @param data The context Node, though the method accepts an Object
    71       *             so error is reported by Commons SCXML, rather
    72       *             than the underlying expression language.
    73       * @param path The XPath expression.
    74       * @return The first node matching the path, or null if no nodes match.
    75       */
    76      public static Node dataNode(final Object data, final String path) {
    77          if (data == null || !(data instanceof Node)) {
    78              Log log = LogFactory.getLog(Builtin.class);
    79              log.error("Data(): Cannot evaluate an XPath expression"
    80                  + " in the absence of a context Node, null returned");
    81              return null;
    82          }
    83          Node dataNode = (Node) data;
    84          NodeList result = null;
    85          try {
    86              result = XPathAPI.selectNodeList(dataNode, path);
    87          } catch (TransformerException te) {
    88              Log log = LogFactory.getLog(Builtin.class);
    89              log.error(te.getMessage(), te);
    90              return null;
    91          }
    92          int length = result.getLength();
    93          if (length == 0) {
    94              Log log = LogFactory.getLog(Builtin.class);
    95              log.warn("Data(): No nodes matching the XPath expression \""
    96                  + path + "\", returning null");
    97              return null;
    98          } else {
    99              if (length > 1) {
    100                 Log log = LogFactory.getLog(Builtin.class);
    101                 log.warn("Data(): Multiple nodes matching XPath expression"
    102                     + path + "\", returning first");
    103             }
    104             return result.item(0);
    105         }
    106     }
    107
    108     /***
    109      * A variant of the Data() function for Commons SCXML documents,
    110      * coerced to a Double, a Long or a String, whichever succeeds,
    111      * in that order.
    112      * Manifests within rvalue expressions in the document,
    113      * for Commons JEXL and Commons EL based documents..
    114      *
    115      * @param data The context Node, though the method accepts an Object
    116      *             so error is reported by Commons SCXML, rather
    117      *             than the underlying expression language.
    118      * @param path The XPath expression.
    119      * @return The first node matching the path, coerced to a String, or null
    120      *         if no nodes match.
    121      */
    122     public static Object data(final Object data, final String path) {
    123         Object retVal = null;
    124         String strVal = SCXMLHelper.getNodeValue(dataNode(data, path));
    125         // try as a double
    126         try {
    127             double d = Double.parseDouble(strVal);
    128             retVal = new Double(d);
    129         } catch (NumberFormatException notADouble) {
    130             // else as a long
    131             try {
    132                 long l = Long.parseLong(strVal);
    133                 retVal = new Long(l);
    134             } catch (NumberFormatException notALong) {
    135                 // fallback to string
    136                 retVal = strVal;
    137             }
    138         }
    139         return retVal;
    140     }
    141
    142 }
    143