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 "in" 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 <assign> 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