1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.scxml.env.jsp;
18
19 import java.io.Serializable;
20 import java.lang.reflect.Method;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.regex.Pattern;
24
25 import javax.servlet.jsp.el.ELException;
26 import javax.servlet.jsp.el.ExpressionEvaluator;
27 import javax.servlet.jsp.el.FunctionMapper;
28 import javax.servlet.jsp.el.VariableResolver;
29
30 import org.apache.commons.el.ExpressionEvaluatorImpl;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.commons.scxml.Builtin;
34 import org.apache.commons.scxml.Context;
35 import org.apache.commons.scxml.Evaluator;
36 import org.apache.commons.scxml.SCXMLExpressionException;
37 import org.w3c.dom.Node;
38
39
40
41
42
43
44 public class ELEvaluator implements Evaluator, Serializable {
45
46
47 private static final long serialVersionUID = 1L;
48
49 private Log log = LogFactory.getLog(Evaluator.class);
50
51 private FunctionMapper builtinFnMapper = new BuiltinFunctionMapper();
52
53
54 private FunctionMapper fnMapper;
55
56 private static Pattern inFct = Pattern.compile("In\\(");
57
58 private static Pattern dataFct = Pattern.compile("Data\\(");
59
60
61 private transient ExpressionEvaluator ee = null;
62
63
64
65
66 public ELEvaluator() {
67 ee = new ExpressionEvaluatorImpl();
68 }
69
70
71
72
73
74
75
76 public ELEvaluator(final FunctionMapper fnMapper) {
77 ee = new ExpressionEvaluatorImpl();
78 this.fnMapper = fnMapper;
79 }
80
81
82
83
84
85
86
87
88
89
90 public Object eval(final Context ctx, final String expr)
91 throws SCXMLExpressionException {
92 if (expr == null) {
93 return null;
94 }
95 VariableResolver vr = null;
96 if (ctx instanceof VariableResolver) {
97 vr = (VariableResolver) ctx;
98 } else {
99 vr = new ContextWrapper(ctx);
100 }
101 try {
102 String evalExpr = inFct.matcher(expr).
103 replaceAll("In(_ALL_STATES, ");
104 evalExpr = dataFct.matcher(evalExpr).
105 replaceAll("Data(_ALL_NAMESPACES, ");
106 Object rslt = getEvaluator().evaluate(evalExpr, Object.class, vr,
107 builtinFnMapper);
108 if (log.isTraceEnabled()) {
109 log.trace(expr + " = " + String.valueOf(rslt));
110 }
111 return rslt;
112 } catch (ELException e) {
113 throw new SCXMLExpressionException("eval('" + expr + "'):"
114 + e.getMessage(), e);
115 }
116 }
117
118
119
120
121 public Boolean evalCond(final Context ctx, final String expr)
122 throws SCXMLExpressionException {
123 if (expr == null) {
124 return null;
125 }
126 VariableResolver vr = null;
127 if (ctx instanceof VariableResolver) {
128 vr = (VariableResolver) ctx;
129 } else {
130 vr = new ContextWrapper(ctx);
131 }
132 try {
133 String evalExpr = inFct.matcher(expr).
134 replaceAll("In(_ALL_STATES, ");
135 evalExpr = dataFct.matcher(evalExpr).
136 replaceAll("Data(_ALL_NAMESPACES, ");
137 Boolean rslt = (Boolean) getEvaluator().evaluate(evalExpr,
138 Boolean.class, vr, builtinFnMapper);
139 if (log.isDebugEnabled()) {
140 log.debug(expr + " = " + String.valueOf(rslt));
141 }
142 return rslt;
143 } catch (ELException e) {
144 throw new SCXMLExpressionException("eval('" + expr + "'):"
145 + e.getMessage(), e);
146 }
147 }
148
149
150
151
152 public Node evalLocation(final Context ctx, final String expr)
153 throws SCXMLExpressionException {
154 if (expr == null) {
155 return null;
156 }
157 VariableResolver vr = null;
158 if (ctx instanceof VariableResolver) {
159 vr = (VariableResolver) ctx;
160 } else {
161 vr = new ContextWrapper(ctx);
162 }
163 try {
164 String evalExpr = inFct.matcher(expr).
165 replaceAll("In(_ALL_STATES, ");
166 evalExpr = dataFct.matcher(evalExpr).
167 replaceAll("Data(_ALL_NAMESPACES, ");
168 evalExpr = dataFct.matcher(evalExpr).
169 replaceFirst("LData(");
170 Node rslt = (Node) getEvaluator().evaluate(evalExpr, Node.class,
171 vr, builtinFnMapper);
172 if (log.isDebugEnabled()) {
173 log.debug(expr + " = " + String.valueOf(rslt));
174 }
175 return rslt;
176 } catch (ELException e) {
177 throw new SCXMLExpressionException("eval('" + expr + "'):"
178 + e.getMessage(), e);
179 }
180 }
181
182
183
184
185
186
187
188
189 public Context newContext(final Context parent) {
190 return new ELContext(parent);
191 }
192
193
194
195
196
197
198 protected void setLog(final Log log) {
199 this.log = log;
200 }
201
202
203
204
205
206
207 protected Log getLog() {
208 return log;
209 }
210
211
212
213
214
215
216 private ExpressionEvaluator getEvaluator() {
217 if (ee == null) {
218 ee = new ExpressionEvaluatorImpl();
219 }
220 return ee;
221 }
222
223
224
225
226 static class ContextWrapper implements VariableResolver, Serializable {
227
228 private static final long serialVersionUID = 1L;
229
230 private Context ctx = null;
231
232 private Log log = LogFactory.getLog(ContextWrapper.class);
233
234
235
236
237 ContextWrapper(final Context ctx) {
238 this.ctx = ctx;
239 }
240
241 public Object resolveVariable(final String pName) throws ELException {
242 Object rslt = ctx.get(pName);
243 if (rslt == null) {
244 log.info("Variable \"" + pName + "\" does not exist!");
245 }
246 return rslt;
247 }
248 }
249
250
251
252
253 class BuiltinFunctionMapper implements FunctionMapper, Serializable {
254
255 private static final long serialVersionUID = 1L;
256
257 private Log log = LogFactory.getLog(BuiltinFunctionMapper.class);
258
259
260
261 public Method resolveFunction(final String prefix,
262 final String localName) {
263 if (localName.equals("In")) {
264 Class[] attrs = new Class[] {Set.class, String.class};
265 try {
266 return Builtin.class.getMethod("isMember", attrs);
267 } catch (SecurityException e) {
268 log.error("resolving isMember(Set, String)", e);
269 } catch (NoSuchMethodException e) {
270 log.error("resolving isMember(Set, String)", e);
271 }
272 } else if (localName.equals("Data")) {
273
274 Class[] attrs =
275 new Class[] {Map.class, Object.class, String.class};
276 try {
277 return Builtin.class.getMethod("data", attrs);
278 } catch (SecurityException e) {
279 log.error("resolving data(Node, String)", e);
280 } catch (NoSuchMethodException e) {
281 log.error("resolving data(Node, String)", e);
282 }
283 } else if (localName.equals("LData")) {
284
285 Class[] attrs =
286 new Class[] {Map.class, Object.class, String.class};
287 try {
288 return Builtin.class.getMethod("dataNode", attrs);
289 } catch (SecurityException e) {
290 log.error("resolving data(Node, String)", e);
291 } catch (NoSuchMethodException e) {
292 log.error("resolving data(Node, String)", e);
293 }
294 } else if (fnMapper != null) {
295 return fnMapper.resolveFunction(prefix, localName);
296 }
297 return null;
298 }
299 }
300
301
302
303
304
305
306 protected FunctionMapper getBuiltinFnMapper() {
307 return builtinFnMapper;
308 }
309
310 }
311