1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
126 try {
127 double d = Double.parseDouble(strVal);
128 retVal = new Double(d);
129 } catch (NumberFormatException notADouble) {
130
131 try {
132 long l = Long.parseLong(strVal);
133 retVal = new Long(l);
134 } catch (NumberFormatException notALong) {
135
136 retVal = strVal;
137 }
138 }
139 return retVal;
140 }
141
142 }
143