1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl2;
18
19 import java.lang.reflect.Array;
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.commons.jexl2.parser.SimpleNode;
28 import org.apache.commons.logging.Log;
29
30 import org.apache.commons.jexl2.parser.ASTFloatLiteral;
31 import org.apache.commons.jexl2.parser.ASTIntegerLiteral;
32 import org.apache.commons.jexl2.parser.JexlNode;
33 import org.apache.commons.jexl2.parser.ASTAdditiveNode;
34 import org.apache.commons.jexl2.parser.ASTAdditiveOperator;
35 import org.apache.commons.jexl2.parser.ASTAndNode;
36 import org.apache.commons.jexl2.parser.ASTAmbiguous;
37 import org.apache.commons.jexl2.parser.ASTArrayAccess;
38 import org.apache.commons.jexl2.parser.ASTArrayLiteral;
39 import org.apache.commons.jexl2.parser.ASTAssignment;
40 import org.apache.commons.jexl2.parser.ASTBitwiseAndNode;
41 import org.apache.commons.jexl2.parser.ASTBitwiseComplNode;
42 import org.apache.commons.jexl2.parser.ASTBitwiseOrNode;
43 import org.apache.commons.jexl2.parser.ASTBitwiseXorNode;
44 import org.apache.commons.jexl2.parser.ASTBlock;
45 import org.apache.commons.jexl2.parser.ASTConstructorNode;
46 import org.apache.commons.jexl2.parser.ASTDivNode;
47 import org.apache.commons.jexl2.parser.ASTEQNode;
48 import org.apache.commons.jexl2.parser.ASTERNode;
49 import org.apache.commons.jexl2.parser.ASTEmptyFunction;
50 import org.apache.commons.jexl2.parser.ASTFalseNode;
51 import org.apache.commons.jexl2.parser.ASTFunctionNode;
52 import org.apache.commons.jexl2.parser.ASTForeachStatement;
53 import org.apache.commons.jexl2.parser.ASTGENode;
54 import org.apache.commons.jexl2.parser.ASTGTNode;
55 import org.apache.commons.jexl2.parser.ASTIdentifier;
56 import org.apache.commons.jexl2.parser.ASTIfStatement;
57 import org.apache.commons.jexl2.parser.ASTJexlScript;
58 import org.apache.commons.jexl2.parser.ASTLENode;
59 import org.apache.commons.jexl2.parser.ASTLTNode;
60 import org.apache.commons.jexl2.parser.ASTMapEntry;
61 import org.apache.commons.jexl2.parser.ASTMapLiteral;
62 import org.apache.commons.jexl2.parser.ASTMethodNode;
63 import org.apache.commons.jexl2.parser.ASTModNode;
64 import org.apache.commons.jexl2.parser.ASTMulNode;
65 import org.apache.commons.jexl2.parser.ASTNENode;
66 import org.apache.commons.jexl2.parser.ASTNRNode;
67 import org.apache.commons.jexl2.parser.ASTNotNode;
68 import org.apache.commons.jexl2.parser.ASTNullLiteral;
69 import org.apache.commons.jexl2.parser.ASTNumberLiteral;
70 import org.apache.commons.jexl2.parser.ASTOrNode;
71 import org.apache.commons.jexl2.parser.ASTReference;
72 import org.apache.commons.jexl2.parser.ASTReferenceExpression;
73 import org.apache.commons.jexl2.parser.ASTReturnStatement;
74 import org.apache.commons.jexl2.parser.ASTSizeFunction;
75 import org.apache.commons.jexl2.parser.ASTSizeMethod;
76 import org.apache.commons.jexl2.parser.ASTStringLiteral;
77 import org.apache.commons.jexl2.parser.ASTTernaryNode;
78 import org.apache.commons.jexl2.parser.ASTTrueNode;
79 import org.apache.commons.jexl2.parser.ASTUnaryMinusNode;
80 import org.apache.commons.jexl2.parser.ASTWhileStatement;
81 import org.apache.commons.jexl2.parser.Node;
82 import org.apache.commons.jexl2.parser.ParserVisitor;
83
84 import org.apache.commons.jexl2.introspection.Uberspect;
85 import org.apache.commons.jexl2.introspection.JexlMethod;
86 import org.apache.commons.jexl2.introspection.JexlPropertyGet;
87 import org.apache.commons.jexl2.introspection.JexlPropertySet;
88 import org.apache.commons.jexl2.parser.ASTVar;
89
90
91
92
93
94
95 public class Interpreter implements ParserVisitor {
96
97 protected final Log logger;
98
99 protected final Uberspect uberspect;
100
101 protected final JexlArithmetic arithmetic;
102
103 protected final Map<String, Object> functions;
104
105 protected Map<String, Object> functors;
106
107 protected final JexlContext context;
108
109 protected boolean strict;
110
111 protected boolean silent;
112
113 protected final boolean cache;
114
115 protected Object[] registers = null;
116
117
118
119
120
121 @SuppressWarnings("unused")
122 private String[] parameters = null;
123
124
125
126
127
128
129 private volatile boolean cancelled = false;
130
131
132 protected static final Object[] EMPTY_PARAMS = new Object[0];
133
134
135
136
137
138
139
140 @Deprecated
141 public Interpreter(JexlEngine jexl, JexlContext aContext) {
142 this(jexl, aContext, !jexl.isLenient(), jexl.isSilent());
143 }
144
145
146
147
148
149
150
151
152
153 public Interpreter(JexlEngine jexl, JexlContext aContext, boolean strictFlag, boolean silentFlag) {
154 this.logger = jexl.logger;
155 this.uberspect = jexl.uberspect;
156 this.arithmetic = jexl.arithmetic;
157 this.functions = jexl.functions;
158 this.strict = strictFlag;
159 this.silent = silentFlag;
160 this.cache = jexl.cache != null;
161 this.context = aContext != null? aContext : JexlEngine.EMPTY_CONTEXT;
162 this.functors = null;
163 }
164
165
166
167
168
169
170 protected Interpreter(Interpreter base) {
171 this.logger = base.logger;
172 this.uberspect = base.uberspect;
173 this.arithmetic = base.arithmetic;
174 this.functions = base.functions;
175 this.strict = base.strict;
176 this.silent = base.silent;
177 this.cache = base.cache;
178 this.context = base.context;
179 this.functors = base.functors;
180 }
181
182
183
184
185
186
187
188
189 @Deprecated
190 public void setStrict(boolean flag) {
191 this.strict = flag;
192 }
193
194
195
196
197
198
199 @Deprecated
200 public void setSilent(boolean flag) {
201 this.silent = flag;
202 }
203
204
205
206
207
208
209 public boolean isStrict() {
210 return this.strict;
211 }
212
213
214
215
216
217 public boolean isSilent() {
218 return this.silent;
219 }
220
221
222
223
224
225
226
227
228
229
230 public Object interpret(JexlNode node) {
231 try {
232 return node.jjtAccept(this, null);
233 } catch (JexlException.Return xreturn) {
234 Object value = xreturn.getValue();
235 return value;
236 } catch (JexlException xjexl) {
237 if (silent) {
238 logger.warn(xjexl.getMessage(), xjexl.getCause());
239 return null;
240 }
241 throw xjexl;
242 } finally {
243 functors = null;
244 parameters = null;
245 registers = null;
246 }
247 }
248
249
250
251
252
253
254 protected JexlContext getContext() {
255 return context;
256 }
257
258
259
260
261
262 protected Uberspect getUberspect() {
263 return uberspect;
264 }
265
266
267
268
269
270
271 @Deprecated
272 protected void setRegisters(Object... theRegisters) {
273 if (theRegisters != null) {
274 String[] regStrs = new String[theRegisters.length];
275 for (int r = 0; r < regStrs.length; ++r) {
276 regStrs[r] = "#" + r;
277 }
278 this.parameters = regStrs;
279 }
280 this.registers = theRegisters;
281 }
282
283
284
285
286
287
288 protected void setFrame(JexlEngine.Frame frame) {
289 if (frame != null) {
290 this.parameters = frame.getParameters();
291 this.registers = frame.getRegisters();
292 } else {
293 this.parameters = null;
294 this.registers = null;
295 }
296 }
297
298
299
300
301
302
303
304
305
306 protected JexlNode findNullOperand(RuntimeException xrt, JexlNode node, Object left, Object right) {
307 if (xrt instanceof ArithmeticException
308 && JexlException.NULL_OPERAND == xrt.getMessage()) {
309 if (left == null) {
310 return node.jjtGetChild(0);
311 }
312 if (right == null) {
313 return node.jjtGetChild(1);
314 }
315 }
316 return node;
317 }
318
319
320
321
322
323
324 protected Object unknownVariable(JexlException xjexl) {
325 if (strict) {
326 throw xjexl;
327 }
328 if (!silent) {
329 logger.warn(xjexl.getMessage());
330 }
331 return null;
332 }
333
334
335
336
337
338
339 protected Object invocationFailed(JexlException xjexl) {
340 if (strict || xjexl instanceof JexlException.Return) {
341 throw xjexl;
342 }
343 if (!silent) {
344 logger.warn(xjexl.getMessage(), xjexl.getCause());
345 }
346 return null;
347 }
348
349
350
351
352
353
354 protected boolean isCancelled() {
355 if (cancelled | Thread.interrupted()) {
356 cancelled = true;
357 }
358 return cancelled;
359 }
360
361
362
363
364
365
366
367
368
369 protected Object resolveNamespace(String prefix, JexlNode node) {
370 Object namespace = null;
371
372 if (functors != null) {
373 namespace = functors.get(prefix);
374 if (namespace != null) {
375 return namespace;
376 }
377 }
378
379 if (context instanceof NamespaceResolver) {
380 namespace = ((NamespaceResolver) context).resolveNamespace(prefix);
381 }
382 if (namespace == null) {
383 namespace = functions.get(prefix);
384 if (prefix != null && namespace == null) {
385 throw new JexlException(node, "no such function namespace " + prefix);
386 }
387 }
388
389 if (namespace instanceof Class<?>) {
390 Object[] args = new Object[]{context};
391 JexlMethod ctor = uberspect.getConstructorMethod(namespace, args, node);
392 if (ctor != null) {
393 try {
394 namespace = ctor.invoke(namespace, args);
395 if (functors == null) {
396 functors = new HashMap<String, Object>();
397 }
398 functors.put(prefix, namespace);
399 } catch (Exception xinst) {
400 throw new JexlException(node, "unable to instantiate namespace " + prefix, xinst);
401 }
402 }
403 }
404 return namespace;
405 }
406
407
408 public Object visit(ASTAdditiveNode node, Object data) {
409
410
411
412
413
414
415
416 Object left = node.jjtGetChild(0).jjtAccept(this, data);
417 for (int c = 2, size = node.jjtGetNumChildren(); c < size; c += 2) {
418 Object right = node.jjtGetChild(c).jjtAccept(this, data);
419 try {
420 JexlNode op = node.jjtGetChild(c - 1);
421 if (op instanceof ASTAdditiveOperator) {
422 String which = op.image;
423 if ("+".equals(which)) {
424 left = arithmetic.add(left, right);
425 continue;
426 }
427 if ("-".equals(which)) {
428 left = arithmetic.subtract(left, right);
429 continue;
430 }
431 throw new UnsupportedOperationException("unknown operator " + which);
432 }
433 throw new IllegalArgumentException("unknown operator " + op);
434 } catch (ArithmeticException xrt) {
435 JexlNode xnode = findNullOperand(xrt, node, left, right);
436 throw new JexlException(xnode, "+/- error", xrt);
437 }
438 }
439 return left;
440 }
441
442
443 public Object visit(ASTAdditiveOperator node, Object data) {
444 throw new UnsupportedOperationException("Shoud not be called.");
445 }
446
447
448 public Object visit(ASTAndNode node, Object data) {
449 Object left = node.jjtGetChild(0).jjtAccept(this, data);
450 try {
451 boolean leftValue = arithmetic.toBoolean(left);
452 if (!leftValue) {
453 return Boolean.FALSE;
454 }
455 } catch (RuntimeException xrt) {
456 throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt);
457 }
458 Object right = node.jjtGetChild(1).jjtAccept(this, data);
459 try {
460 boolean rightValue = arithmetic.toBoolean(right);
461 if (!rightValue) {
462 return Boolean.FALSE;
463 }
464 } catch (ArithmeticException xrt) {
465 throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt);
466 }
467 return Boolean.TRUE;
468 }
469
470
471 public Object visit(ASTArrayAccess node, Object data) {
472
473 Object object = node.jjtGetChild(0).jjtAccept(this, data);
474
475 int numChildren = node.jjtGetNumChildren();
476 for (int i = 1; i < numChildren; i++) {
477 JexlNode nindex = node.jjtGetChild(i);
478 if (nindex instanceof JexlNode.Literal<?>) {
479 object = nindex.jjtAccept(this, object);
480 } else {
481 Object index = nindex.jjtAccept(this, null);
482 object = getAttribute(object, index, nindex);
483 }
484 }
485
486 return object;
487 }
488
489
490 public Object visit(ASTArrayLiteral node, Object data) {
491 Object literal = node.getLiteral();
492 if (literal == null) {
493 int childCount = node.jjtGetNumChildren();
494 Object[] array = new Object[childCount];
495 for (int i = 0; i < childCount; i++) {
496 Object entry = node.jjtGetChild(i).jjtAccept(this, data);
497 array[i] = entry;
498 }
499 literal = arithmetic.narrowArrayType(array);
500 node.setLiteral(literal);
501 }
502 return literal;
503 }
504
505
506 public Object visit(ASTAssignment node, Object data) {
507
508 int register = -1;
509 JexlNode left = node.jjtGetChild(0);
510 if (left instanceof ASTIdentifier) {
511 ASTIdentifier var = (ASTIdentifier) left;
512 register = var.getRegister();
513 if (register < 0) {
514 throw new JexlException(left, "unknown variable " + left.image);
515 }
516 } else if (!(left instanceof ASTReference)) {
517 throw new JexlException(left, "illegal assignment form 0");
518 }
519
520 Object right = node.jjtGetChild(1).jjtAccept(this, data);
521
522
523 JexlNode objectNode = null;
524 Object object = register >= 0 ? registers[register] : null;
525 JexlNode propertyNode = null;
526 Object property = null;
527 boolean isVariable = true;
528 int v = 0;
529 StringBuilder variableName = null;
530
531 int last = left.jjtGetNumChildren() - 1;
532
533 boolean isRegister = last < 0 && register >= 0;
534
535 for (int c = register >= 0 ? 1 : 0; c < last; ++c) {
536 objectNode = left.jjtGetChild(c);
537
538 object = objectNode.jjtAccept(this, object);
539 if (object != null) {
540 continue;
541 }
542 isVariable &= objectNode instanceof ASTIdentifier
543 || (objectNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) objectNode).isInteger());
544
545 if (isVariable) {
546 if (v == 0) {
547 variableName = new StringBuilder(left.jjtGetChild(0).image);
548 v = 1;
549 }
550 for (; v <= c; ++v) {
551 variableName.append('.');
552 variableName.append(left.jjtGetChild(v).image);
553 }
554 object = context.get(variableName.toString());
555
556 if (object != null) {
557 isVariable = false;
558 }
559 } else {
560 throw new JexlException(objectNode, "illegal assignment form");
561 }
562 }
563
564 propertyNode = isRegister ? null : left.jjtGetChild(last);
565 boolean antVar = false;
566 if (propertyNode instanceof ASTIdentifier) {
567 ASTIdentifier identifier = (ASTIdentifier) propertyNode;
568 register = identifier.getRegister();
569 if (register >= 0) {
570 isRegister = true;
571 } else {
572 property = identifier.image;
573 antVar = true;
574 }
575 } else if (propertyNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) propertyNode).isInteger()) {
576 property = ((ASTNumberLiteral) propertyNode).getLiteral();
577 antVar = true;
578 } else if (propertyNode instanceof ASTArrayAccess) {
579
580 objectNode = propertyNode;
581 ASTArrayAccess narray = (ASTArrayAccess) objectNode;
582 Object nobject = narray.jjtGetChild(0).jjtAccept(this, object);
583 if (nobject == null) {
584 throw new JexlException(objectNode, "array element is null");
585 } else {
586 object = nobject;
587 }
588
589
590 last = narray.jjtGetNumChildren() - 1;
591 for (int i = 1; i < last; i++) {
592 objectNode = narray.jjtGetChild(i);
593 if (objectNode instanceof JexlNode.Literal<?>) {
594 object = objectNode.jjtAccept(this, object);
595 } else {
596 Object index = objectNode.jjtAccept(this, null);
597 object = getAttribute(object, index, objectNode);
598 }
599 }
600 property = narray.jjtGetChild(last).jjtAccept(this, null);
601 } else if (!isRegister) {
602 throw new JexlException(objectNode, "illegal assignment form");
603 }
604
605 if (isRegister) {
606 registers[register] = right;
607 return right;
608 } else if (antVar) {
609 if (isVariable && object == null) {
610 if (variableName != null) {
611 if (last > 0) {
612 variableName.append('.');
613 }
614 variableName.append(property);
615 property = variableName.toString();
616 }
617 try {
618 context.set(String.valueOf(property), right);
619 } catch (UnsupportedOperationException xsupport) {
620 throw new JexlException(node, "context is readonly", xsupport);
621 }
622 return right;
623 }
624 }
625 if (property == null) {
626
627 throw new JexlException(propertyNode, "property is null");
628 }
629 if (object == null) {
630
631 throw new JexlException(objectNode, "bean is null");
632 }
633
634 setAttribute(object, property, right, propertyNode);
635 return right;
636 }
637
638
639 public Object visit(ASTBitwiseAndNode node, Object data) {
640 Object left = node.jjtGetChild(0).jjtAccept(this, data);
641 Object right = node.jjtGetChild(1).jjtAccept(this, data);
642 try {
643 return arithmetic.bitwiseAnd(left, right);
644 } catch (ArithmeticException xrt) {
645 throw new JexlException(node, "& error", xrt);
646 }
647 }
648
649
650 public Object visit(ASTBitwiseComplNode node, Object data) {
651 Object left = node.jjtGetChild(0).jjtAccept(this, data);
652 try {
653 return arithmetic.bitwiseComplement(left);
654 } catch (ArithmeticException xrt) {
655 throw new JexlException(node, "~ error", xrt);
656 }
657 }
658
659
660 public Object visit(ASTBitwiseOrNode node, Object data) {
661 Object left = node.jjtGetChild(0).jjtAccept(this, data);
662 Object right = node.jjtGetChild(1).jjtAccept(this, data);
663 try {
664 return arithmetic.bitwiseOr(left, right);
665 } catch (ArithmeticException xrt) {
666 throw new JexlException(node, "| error", xrt);
667 }
668 }
669
670
671 public Object visit(ASTBitwiseXorNode node, Object data) {
672 Object left = node.jjtGetChild(0).jjtAccept(this, data);
673 Object right = node.jjtGetChild(1).jjtAccept(this, data);
674 try {
675 return arithmetic.bitwiseXor(left, right);
676 } catch (ArithmeticException xrt) {
677 throw new JexlException(node, "^ error", xrt);
678 }
679 }
680
681
682 public Object visit(ASTBlock node, Object data) {
683 int numChildren = node.jjtGetNumChildren();
684 Object result = null;
685 for (int i = 0; i < numChildren; i++) {
686 result = node.jjtGetChild(i).jjtAccept(this, data);
687 }
688 return result;
689 }
690
691
692 public Object visit(ASTDivNode node, Object data) {
693 Object left = node.jjtGetChild(0).jjtAccept(this, data);
694 Object right = node.jjtGetChild(1).jjtAccept(this, data);
695 try {
696 return arithmetic.divide(left, right);
697 } catch (ArithmeticException xrt) {
698 if (!strict) {
699 return new Double(0.0);
700 }
701 JexlNode xnode = findNullOperand(xrt, node, left, right);
702 throw new JexlException(xnode, "divide error", xrt);
703 }
704 }
705
706
707 public Object visit(ASTEmptyFunction node, Object data) {
708 Object o = node.jjtGetChild(0).jjtAccept(this, data);
709 if (o == null) {
710 return Boolean.TRUE;
711 }
712 if (o instanceof String && "".equals(o)) {
713 return Boolean.TRUE;
714 }
715 if (o.getClass().isArray() && ((Object[]) o).length == 0) {
716 return Boolean.TRUE;
717 }
718 if (o instanceof Collection<?>) {
719 return ((Collection<?>) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE;
720 }
721
722 if (o instanceof Map<?, ?>) {
723 return ((Map<?, ?>) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE;
724 }
725 return Boolean.FALSE;
726 }
727
728
729 public Object visit(ASTEQNode node, Object data) {
730 Object left = node.jjtGetChild(0).jjtAccept(this, data);
731 Object right = node.jjtGetChild(1).jjtAccept(this, data);
732 try {
733 return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
734 } catch (ArithmeticException xrt) {
735 throw new JexlException(node, "== error", xrt);
736 }
737 }
738
739
740 public Object visit(ASTFalseNode node, Object data) {
741 return Boolean.FALSE;
742 }
743
744
745 public Object visit(ASTForeachStatement node, Object data) {
746 Object result = null;
747
748 ASTReference loopReference = (ASTReference) node.jjtGetChild(0);
749 ASTIdentifier loopVariable = (ASTIdentifier) loopReference.jjtGetChild(0);
750 int register = loopVariable.getRegister();
751
752 Object iterableValue = node.jjtGetChild(1).jjtAccept(this, data);
753
754 if (iterableValue != null && node.jjtGetNumChildren() >= 3) {
755
756 JexlNode statement = node.jjtGetChild(2);
757
758
759 Iterator<?> itemsIterator = uberspect.getIterator(iterableValue, node);
760 if (itemsIterator != null) {
761 while (itemsIterator.hasNext()) {
762 if (isCancelled()) {
763 throw new JexlException.Cancel(node);
764 }
765
766 Object value = itemsIterator.next();
767 if (register < 0) {
768 context.set(loopVariable.image, value);
769 } else {
770 registers[register] = value;
771 }
772
773 result = statement.jjtAccept(this, data);
774 }
775 }
776 }
777 return result;
778 }
779
780
781 public Object visit(ASTGENode node, Object data) {
782 Object left = node.jjtGetChild(0).jjtAccept(this, data);
783 Object right = node.jjtGetChild(1).jjtAccept(this, data);
784 try {
785 return arithmetic.greaterThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE;
786 } catch (ArithmeticException xrt) {
787 throw new JexlException(node, ">= error", xrt);
788 }
789 }
790
791
792 public Object visit(ASTGTNode node, Object data) {
793 Object left = node.jjtGetChild(0).jjtAccept(this, data);
794 Object right = node.jjtGetChild(1).jjtAccept(this, data);
795 try {
796 return arithmetic.greaterThan(left, right) ? Boolean.TRUE : Boolean.FALSE;
797 } catch (ArithmeticException xrt) {
798 throw new JexlException(node, "> error", xrt);
799 }
800 }
801
802
803 public Object visit(ASTERNode node, Object data) {
804 Object left = node.jjtGetChild(0).jjtAccept(this, data);
805 Object right = node.jjtGetChild(1).jjtAccept(this, data);
806 try {
807
808 if (right instanceof java.util.regex.Pattern || right instanceof String) {
809 return arithmetic.matches(left, right) ? Boolean.TRUE : Boolean.FALSE;
810 }
811
812
813 if (right instanceof Set<?>) {
814 return ((Set<?>) right).contains(left) ? Boolean.TRUE : Boolean.FALSE;
815 }
816
817 if (right instanceof Map<?, ?>) {
818 return ((Map<?, ?>) right).containsKey(left) ? Boolean.TRUE : Boolean.FALSE;
819 }
820
821 if (right instanceof Collection<?>) {
822 return ((Collection<?>) right).contains(left) ? Boolean.TRUE : Boolean.FALSE;
823 }
824
825 try {
826 Object[] argv = {left};
827 JexlMethod vm = uberspect.getMethod(right, "contains", argv, node);
828 if (vm != null) {
829 return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.TRUE : Boolean.FALSE;
830 } else if (arithmetic.narrowArguments(argv)) {
831 vm = uberspect.getMethod(right, "contains", argv, node);
832 if (vm != null) {
833 return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.TRUE : Boolean.FALSE;
834 }
835 }
836 } catch (InvocationTargetException e) {
837 throw new JexlException(node, "=~ invocation error", e.getCause());
838 } catch (Exception e) {
839 throw new JexlException(node, "=~ error", e);
840 }
841
842 Iterator<?> it = uberspect.getIterator(right, node);
843 if (it != null) {
844 while (it.hasNext()) {
845 Object next = it.next();
846 if (next == left || (next != null && next.equals(left))) {
847 return Boolean.TRUE;
848 }
849 }
850 return Boolean.FALSE;
851 }
852
853 return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
854 } catch (ArithmeticException xrt) {
855 throw new JexlException(node, "=~ error", xrt);
856 }
857 }
858
859
860 public Object visit(ASTIdentifier node, Object data) {
861 if (isCancelled()) {
862 throw new JexlException.Cancel(node);
863 }
864 String name = node.image;
865 if (data == null) {
866 int register = node.getRegister();
867 if (register >= 0) {
868 return registers[register];
869 }
870 Object value = context.get(name);
871 if (value == null
872 && !(node.jjtGetParent() instanceof ASTReference)
873 && !context.has(name)
874 && !isTernaryProtected(node)) {
875 JexlException xjexl = new JexlException.Variable(node, name);
876 return unknownVariable(xjexl);
877 }
878 return value;
879 } else {
880 return getAttribute(data, name, node);
881 }
882 }
883
884
885
886
887 @Deprecated
888 public Object visit(ASTFloatLiteral node, Object data) {
889 throw new UnsupportedOperationException("Method should not be called; only present for API compatibiltiy");
890 }
891
892
893
894
895 @Deprecated
896 public Object visit(ASTIntegerLiteral node, Object data) {
897 throw new UnsupportedOperationException("Method should not be called; only present for API compatibiltiy");
898 }
899
900
901 public Object visit(ASTVar node, Object data) {
902 return visit((ASTIdentifier) node, data);
903 }
904
905
906 public Object visit(ASTIfStatement node, Object data) {
907 int n = 0;
908 try {
909 Object result = null;
910
911 Object expression = node.jjtGetChild(0).jjtAccept(this, data);
912 if (arithmetic.toBoolean(expression)) {
913
914 n = 1;
915 result = node.jjtGetChild(1).jjtAccept(this, data);
916 } else {
917
918
919 if (node.jjtGetNumChildren() == 3) {
920 n = 2;
921 result = node.jjtGetChild(2).jjtAccept(this, data);
922 }
923 }
924 return result;
925 } catch (JexlException error) {
926 throw error;
927 } catch (ArithmeticException xrt) {
928 throw new JexlException(node.jjtGetChild(n), "if error", xrt);
929 }
930 }
931
932
933 public Object visit(ASTNumberLiteral node, Object data) {
934 if (data != null && node.isInteger()) {
935 return getAttribute(data, node.getLiteral(), node);
936 }
937 return node.getLiteral();
938 }
939
940
941 public Object visit(ASTJexlScript node, Object data) {
942 int numChildren = node.jjtGetNumChildren();
943 Object result = null;
944 for (int i = 0; i < numChildren; i++) {
945 JexlNode child = node.jjtGetChild(i);
946 result = child.jjtAccept(this, data);
947 }
948 return result;
949 }
950
951
952 public Object visit(ASTLENode node, Object data) {
953 Object left = node.jjtGetChild(0).jjtAccept(this, data);
954 Object right = node.jjtGetChild(1).jjtAccept(this, data);
955 try {
956 return arithmetic.lessThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE;
957 } catch (ArithmeticException xrt) {
958 throw new JexlException(node, "<= error", xrt);
959 }
960 }
961
962
963 public Object visit(ASTLTNode node, Object data) {
964 Object left = node.jjtGetChild(0).jjtAccept(this, data);
965 Object right = node.jjtGetChild(1).jjtAccept(this, data);
966 try {
967 return arithmetic.lessThan(left, right) ? Boolean.TRUE : Boolean.FALSE;
968 } catch (ArithmeticException xrt) {
969 throw new JexlException(node, "< error", xrt);
970 }
971 }
972
973
974 public Object visit(ASTMapEntry node, Object data) {
975 Object key = node.jjtGetChild(0).jjtAccept(this, data);
976 Object value = node.jjtGetChild(1).jjtAccept(this, data);
977 return new Object[]{key, value};
978 }
979
980
981 public Object visit(ASTMapLiteral node, Object data) {
982 int childCount = node.jjtGetNumChildren();
983 Map<Object, Object> map = new HashMap<Object, Object>();
984
985 for (int i = 0; i < childCount; i++) {
986 Object[] entry = (Object[]) (node.jjtGetChild(i)).jjtAccept(this, data);
987 map.put(entry[0], entry[1]);
988 }
989
990 return map;
991 }
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007 private Object call(JexlNode node, Object bean, ASTIdentifier methodNode, int argb) {
1008 if (isCancelled()) {
1009 throw new JexlException.Cancel(node);
1010 }
1011 String methodName = methodNode.image;
1012
1013 int argc = node.jjtGetNumChildren() - argb;
1014 Object[] argv = new Object[argc];
1015 for (int i = 0; i < argc; i++) {
1016 argv[i] = node.jjtGetChild(i + argb).jjtAccept(this, null);
1017 }
1018
1019 JexlException xjexl = null;
1020 try {
1021
1022 if (cache) {
1023 Object cached = node.jjtGetValue();
1024 if (cached instanceof JexlMethod) {
1025 JexlMethod me = (JexlMethod) cached;
1026 Object eval = me.tryInvoke(methodName, bean, argv);
1027 if (!me.tryFailed(eval)) {
1028 return eval;
1029 }
1030 }
1031 }
1032 boolean cacheable = cache;
1033 JexlMethod vm = uberspect.getMethod(bean, methodName, argv, node);
1034
1035 if (vm == null) {
1036 if (arithmetic.narrowArguments(argv)) {
1037 vm = uberspect.getMethod(bean, methodName, argv, node);
1038 }
1039 if (vm == null) {
1040 Object functor = null;
1041
1042 if (bean == context) {
1043 int register = methodNode.getRegister();
1044 if (register >= 0) {
1045 functor = registers[register];
1046 } else {
1047 functor = context.get(methodName);
1048 }
1049 } else {
1050 JexlPropertyGet gfunctor = uberspect.getPropertyGet(bean, methodName, node);
1051 if (gfunctor != null) {
1052 functor = gfunctor.tryInvoke(bean, methodName);
1053 }
1054 }
1055
1056 if (functor instanceof Script) {
1057 return ((Script) functor).execute(context, argv.length > 0 ? argv : null);
1058 } else if (functor instanceof JexlMethod) {
1059 vm = (JexlMethod) functor;
1060 cacheable = false;
1061 } else {
1062 xjexl = new JexlException.Method(node, methodName);
1063 }
1064 }
1065 }
1066 if (xjexl == null) {
1067
1068 Object eval = vm.invoke(bean, argv);
1069
1070 if (cacheable && vm.isCacheable()) {
1071 node.jjtSetValue(vm);
1072 }
1073 return eval;
1074 }
1075 } catch (InvocationTargetException e) {
1076 xjexl = new JexlException(node, "method invocation error", e.getCause());
1077 } catch (Exception e) {
1078 xjexl = new JexlException(node, "method error", e);
1079 }
1080 return invocationFailed(xjexl);
1081 }
1082
1083
1084 public Object visit(ASTMethodNode node, Object data) {
1085
1086 if (data == null) {
1087
1088
1089 if (node.jjtGetParent().jjtGetChild(0) == node) {
1090 data = resolveNamespace(null, node);
1091 if (data == null) {
1092 data = context;
1093 }
1094 } else {
1095 throw new JexlException(node, "attempting to call method on null");
1096 }
1097 }
1098
1099 ASTIdentifier methodNode = (ASTIdentifier) node.jjtGetChild(0);
1100 return call(node, data, methodNode, 1);
1101 }
1102
1103
1104 public Object visit(ASTFunctionNode node, Object data) {
1105
1106 String prefix = node.jjtGetChild(0).image;
1107 Object namespace = resolveNamespace(prefix, node);
1108
1109 ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(1);
1110 return call(node, namespace, functionNode, 2);
1111 }
1112
1113
1114 public Object visit(ASTConstructorNode node, Object data) {
1115 if (isCancelled()) {
1116 throw new JexlException.Cancel(node);
1117 }
1118
1119 Object cobject = node.jjtGetChild(0).jjtAccept(this, data);
1120
1121 int argc = node.jjtGetNumChildren() - 1;
1122 Object[] argv = new Object[argc];
1123 for (int i = 0; i < argc; i++) {
1124 argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, null);
1125 }
1126
1127 JexlException xjexl = null;
1128 try {
1129
1130 if (cache) {
1131 Object cached = node.jjtGetValue();
1132 if (cached instanceof JexlMethod) {
1133 JexlMethod mctor = (JexlMethod) cached;
1134 Object eval = mctor.tryInvoke(null, cobject, argv);
1135 if (!mctor.tryFailed(eval)) {
1136 return eval;
1137 }
1138 }
1139 }
1140 JexlMethod ctor = uberspect.getConstructorMethod(cobject, argv, node);
1141
1142 if (ctor == null) {
1143 if (arithmetic.narrowArguments(argv)) {
1144 ctor = uberspect.getConstructorMethod(cobject, argv, node);
1145 }
1146 if (ctor == null) {
1147 xjexl = new JexlException.Method(node, cobject.toString());
1148 }
1149 }
1150 if (xjexl == null) {
1151 Object instance = ctor.invoke(cobject, argv);
1152
1153 if (cache && ctor.isCacheable()) {
1154 node.jjtSetValue(ctor);
1155 }
1156 return instance;
1157 }
1158 } catch (InvocationTargetException e) {
1159 xjexl = new JexlException(node, "constructor invocation error", e.getCause());
1160 } catch (Exception e) {
1161 xjexl = new JexlException(node, "constructor error", e);
1162 }
1163 return invocationFailed(xjexl);
1164 }
1165
1166
1167 public Object visit(ASTModNode node, Object data) {
1168 Object left = node.jjtGetChild(0).jjtAccept(this, data);
1169 Object right = node.jjtGetChild(1).jjtAccept(this, data);
1170 try {
1171 return arithmetic.mod(left, right);
1172 } catch (ArithmeticException xrt) {
1173 if (!strict) {
1174 return new Double(0.0);
1175 }
1176 JexlNode xnode = findNullOperand(xrt, node, left, right);
1177 throw new JexlException(xnode, "% error", xrt);
1178 }
1179 }
1180
1181
1182 public Object visit(ASTMulNode node, Object data) {
1183 Object left = node.jjtGetChild(0).jjtAccept(this, data);
1184 Object right = node.jjtGetChild(1).jjtAccept(this, data);
1185 try {
1186 return arithmetic.multiply(left, right);
1187 } catch (ArithmeticException xrt) {
1188 JexlNode xnode = findNullOperand(xrt, node, left, right);
1189 throw new JexlException(xnode, "* error", xrt);
1190 }
1191 }
1192
1193
1194 public Object visit(ASTNENode node, Object data) {
1195 Object left = node.jjtGetChild(0).jjtAccept(this, data);
1196 Object right = node.jjtGetChild(1).jjtAccept(this, data);
1197 try {
1198 return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE;
1199 } catch (ArithmeticException xrt) {
1200 JexlNode xnode = findNullOperand(xrt, node, left, right);
1201 throw new JexlException(xnode, "!= error", xrt);
1202 }
1203 }
1204
1205
1206 public Object visit(ASTNRNode node, Object data) {
1207 Object left = node.jjtGetChild(0).jjtAccept(this, data);
1208 Object right = node.jjtGetChild(1).jjtAccept(this, data);
1209 try {
1210 if (right instanceof java.util.regex.Pattern || right instanceof String) {
1211
1212 return arithmetic.matches(left, right) ? Boolean.FALSE : Boolean.TRUE;
1213 }
1214
1215 if (right instanceof Set<?>) {
1216 return ((Set<?>) right).contains(left) ? Boolean.FALSE : Boolean.TRUE;
1217 }
1218
1219 if (right instanceof Map<?, ?>) {
1220 return ((Map<?, ?>) right).containsKey(left) ? Boolean.FALSE : Boolean.TRUE;
1221 }
1222
1223 if (right instanceof Collection<?>) {
1224 return ((Collection<?>) right).contains(left) ? Boolean.FALSE : Boolean.TRUE;
1225 }
1226
1227 try {
1228 Object[] argv = {left};
1229 JexlMethod vm = uberspect.getMethod(right, "contains", argv, node);
1230 if (vm != null) {
1231 return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE;
1232 } else if (arithmetic.narrowArguments(argv)) {
1233 vm = uberspect.getMethod(right, "contains", argv, node);
1234 if (vm != null) {
1235 return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE;
1236 }
1237 }
1238 } catch (InvocationTargetException e) {
1239 throw new JexlException(node, "!~ invocation error", e.getCause());
1240 } catch (Exception e) {
1241 throw new JexlException(node, "!~ error", e);
1242 }
1243
1244 Iterator<?> it = uberspect.getIterator(right, node.jjtGetChild(1));
1245 if (it != null) {
1246 while (it.hasNext()) {
1247 Object next = it.next();
1248 if (next == left || (next != null && next.equals(left))) {
1249 return Boolean.FALSE;
1250 }
1251 }
1252 return Boolean.TRUE;
1253 }
1254
1255 return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE;
1256 } catch (ArithmeticException xrt) {
1257 throw new JexlException(node, "!~ error", xrt);
1258 }
1259 }
1260
1261
1262 public Object visit(ASTNotNode node, Object data) {
1263 Object val = node.jjtGetChild(0).jjtAccept(this, data);
1264 return arithmetic.toBoolean(val) ? Boolean.FALSE : Boolean.TRUE;
1265 }
1266
1267
1268 public Object visit(ASTNullLiteral node, Object data) {
1269 return null;
1270 }
1271
1272
1273 public Object visit(ASTOrNode node, Object data) {
1274 Object left = node.jjtGetChild(0).jjtAccept(this, data);
1275 try {
1276 boolean leftValue = arithmetic.toBoolean(left);
1277 if (leftValue) {
1278 return Boolean.TRUE;
1279 }
1280 } catch (ArithmeticException xrt) {
1281 throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt);
1282 }
1283 Object right = node.jjtGetChild(1).jjtAccept(this, data);
1284 try {
1285 boolean rightValue = arithmetic.toBoolean(right);
1286 if (rightValue) {
1287 return Boolean.TRUE;
1288 }
1289 } catch (ArithmeticException xrt) {
1290 throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt);
1291 }
1292 return Boolean.FALSE;
1293 }
1294
1295
1296 public Object visit(ASTReference node, Object data) {
1297
1298
1299
1300 int numChildren = node.jjtGetNumChildren();
1301
1302 Object result = null;
1303 StringBuilder variableName = null;
1304 String propertyName = null;
1305 boolean isVariable = true;
1306 int v = 0;
1307 for (int c = 0; c < numChildren; c++) {
1308 if (isCancelled()) {
1309 throw new JexlException.Cancel(node);
1310 }
1311 JexlNode theNode = node.jjtGetChild(c);
1312
1313 if (result == null && theNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) theNode).isInteger()) {
1314 isVariable &= v > 0;
1315 } else {
1316 isVariable &= (theNode instanceof ASTIdentifier);
1317 result = theNode.jjtAccept(this, result);
1318 }
1319
1320 if (result == null && isVariable) {
1321 if (v == 0) {
1322 variableName = new StringBuilder(node.jjtGetChild(0).image);
1323 v = 1;
1324 }
1325 for (; v <= c; ++v) {
1326 variableName.append('.');
1327 variableName.append(node.jjtGetChild(v).image);
1328 }
1329 result = context.get(variableName.toString());
1330 } else {
1331 propertyName = theNode.image;
1332 }
1333 }
1334 if (result == null) {
1335 if (isVariable && !isTernaryProtected(node)
1336
1337 && !(context.has(variableName.toString())
1338 || (numChildren == 1
1339 && node.jjtGetChild(0) instanceof ASTIdentifier
1340 && ((ASTIdentifier) node.jjtGetChild(0)).getRegister() >= 0))) {
1341 JexlException xjexl = propertyName != null
1342 ? new JexlException.Property(node, propertyName)
1343 : new JexlException.Variable(node, variableName.toString());
1344 return unknownVariable(xjexl);
1345 }
1346 }
1347 return result;
1348 }
1349
1350
1351
1352
1353
1354 public Object visit(ASTReferenceExpression node, Object data) {
1355 ASTArrayAccess upper = node;
1356 return visit(upper, data);
1357 }
1358
1359
1360
1361
1362
1363 public Object visit(ASTReturnStatement node, Object data) {
1364 Object val = node.jjtGetChild(0).jjtAccept(this, data);
1365 throw new JexlException.Return(node, null, val);
1366 }
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376 private boolean isTernaryProtected(JexlNode node) {
1377 for (JexlNode walk = node.jjtGetParent(); walk != null; walk = walk.jjtGetParent()) {
1378 if (walk instanceof ASTTernaryNode) {
1379 return true;
1380 } else if (!(walk instanceof ASTReference || walk instanceof ASTArrayAccess)) {
1381 break;
1382 }
1383 }
1384 return false;
1385 }
1386
1387
1388 public Object visit(ASTSizeFunction node, Object data) {
1389 Object val = node.jjtGetChild(0).jjtAccept(this, data);
1390 if (val == null) {
1391 throw new JexlException(node, "size() : argument is null", null);
1392 }
1393 return Integer.valueOf(sizeOf(node, val));
1394 }
1395
1396
1397 public Object visit(ASTSizeMethod node, Object data) {
1398 return Integer.valueOf(sizeOf(node, data));
1399 }
1400
1401
1402 public Object visit(ASTStringLiteral node, Object data) {
1403 if (data != null) {
1404 return getAttribute(data, node.getLiteral(), node);
1405 }
1406 return node.image;
1407 }
1408
1409
1410 public Object visit(ASTTernaryNode node, Object data) {
1411 Object condition = node.jjtGetChild(0).jjtAccept(this, data);
1412 if (node.jjtGetNumChildren() == 3) {
1413 if (condition != null && arithmetic.toBoolean(condition)) {
1414 return node.jjtGetChild(1).jjtAccept(this, data);
1415 } else {
1416 return node.jjtGetChild(2).jjtAccept(this, data);
1417 }
1418 }
1419 if (condition != null && arithmetic.toBoolean(condition)) {
1420 return condition;
1421 } else {
1422 return node.jjtGetChild(1).jjtAccept(this, data);
1423 }
1424 }
1425
1426
1427 public Object visit(ASTTrueNode node, Object data) {
1428 return Boolean.TRUE;
1429 }
1430
1431
1432 public Object visit(ASTUnaryMinusNode node, Object data) {
1433 JexlNode valNode = node.jjtGetChild(0);
1434 Object val = valNode.jjtAccept(this, data);
1435 try {
1436 Object number = arithmetic.negate(val);
1437
1438 if (valNode instanceof ASTNumberLiteral && number instanceof Number) {
1439 number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass());
1440 }
1441 return number;
1442 } catch (ArithmeticException xrt) {
1443 throw new JexlException(valNode, "arithmetic error", xrt);
1444 }
1445 }
1446
1447
1448 public Object visit(ASTWhileStatement node, Object data) {
1449 Object result = null;
1450
1451 Node expressionNode = node.jjtGetChild(0);
1452 while (arithmetic.toBoolean(expressionNode.jjtAccept(this, data))) {
1453 if (isCancelled()) {
1454 throw new JexlException.Cancel(node);
1455 }
1456
1457 if (node.jjtGetNumChildren() > 1) {
1458 result = node.jjtGetChild(1).jjtAccept(this, data);
1459 }
1460 }
1461 return result;
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471 private int sizeOf(JexlNode node, Object val) {
1472 if (val instanceof Collection<?>) {
1473 return ((Collection<?>) val).size();
1474 } else if (val.getClass().isArray()) {
1475 return Array.getLength(val);
1476 } else if (val instanceof Map<?, ?>) {
1477 return ((Map<?, ?>) val).size();
1478 } else if (val instanceof String) {
1479 return ((String) val).length();
1480 } else {
1481
1482
1483 Object[] params = new Object[0];
1484 JexlMethod vm = uberspect.getMethod(val, "size", EMPTY_PARAMS, node);
1485 if (vm != null && vm.getReturnType() == Integer.TYPE) {
1486 Integer result;
1487 try {
1488 result = (Integer) vm.invoke(val, params);
1489 } catch (Exception e) {
1490 throw new JexlException(node, "size() : error executing", e);
1491 }
1492 return result.intValue();
1493 }
1494 throw new JexlException(node, "size() : unsupported type : " + val.getClass(), null);
1495 }
1496 }
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506 public Object getAttribute(Object object, Object attribute) {
1507 return getAttribute(object, attribute, null);
1508 }
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519 protected Object getAttribute(Object object, Object attribute, JexlNode node) {
1520 if (object == null) {
1521 throw new JexlException(node, "object is null");
1522 }
1523 if (isCancelled()) {
1524 throw new JexlException.Cancel(node);
1525 }
1526
1527 if (node != null && cache) {
1528 Object cached = node.jjtGetValue();
1529 if (cached instanceof JexlPropertyGet) {
1530 JexlPropertyGet vg = (JexlPropertyGet) cached;
1531 Object value = vg.tryInvoke(object, attribute);
1532 if (!vg.tryFailed(value)) {
1533 return value;
1534 }
1535 }
1536 }
1537 JexlPropertyGet vg = uberspect.getPropertyGet(object, attribute, node);
1538 if (vg != null) {
1539 try {
1540 Object value = vg.invoke(object);
1541
1542 if (node != null && cache && vg.isCacheable()) {
1543 node.jjtSetValue(vg);
1544 }
1545 return value;
1546 } catch (Exception xany) {
1547 if (node == null) {
1548 throw new RuntimeException(xany);
1549 } else {
1550 JexlException xjexl = new JexlException.Property(node, attribute.toString());
1551 if (strict) {
1552 throw xjexl;
1553 }
1554 if (!silent) {
1555 logger.warn(xjexl.getMessage());
1556 }
1557 }
1558 }
1559 }
1560 return null;
1561 }
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571 public void setAttribute(Object object, Object attribute, Object value) {
1572 setAttribute(object, attribute, value, null);
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584 protected void setAttribute(Object object, Object attribute, Object value, JexlNode node) {
1585 if (isCancelled()) {
1586 throw new JexlException.Cancel(node);
1587 }
1588
1589 if (node != null && cache) {
1590 Object cached = node.jjtGetValue();
1591 if (cached instanceof JexlPropertySet) {
1592 JexlPropertySet setter = (JexlPropertySet) cached;
1593 Object eval = setter.tryInvoke(object, attribute, value);
1594 if (!setter.tryFailed(eval)) {
1595 return;
1596 }
1597 }
1598 }
1599 JexlException xjexl = null;
1600 JexlPropertySet vs = uberspect.getPropertySet(object, attribute, value, node);
1601
1602 if (vs == null) {
1603
1604 Object[] narrow = {value};
1605 if (arithmetic.narrowArguments(narrow)) {
1606 vs = uberspect.getPropertySet(object, attribute, narrow[0], node);
1607 }
1608 }
1609 if (vs != null) {
1610 try {
1611
1612 vs.invoke(object, value);
1613 if (node != null && cache && vs.isCacheable()) {
1614 node.jjtSetValue(vs);
1615 }
1616 return;
1617 } catch (RuntimeException xrt) {
1618 if (node == null) {
1619 throw xrt;
1620 }
1621 xjexl = new JexlException(node, "set object property error", xrt);
1622 } catch (Exception xany) {
1623 if (node == null) {
1624 throw new RuntimeException(xany);
1625 }
1626 xjexl = new JexlException(node, "set object property error", xany);
1627 }
1628 }
1629 if (xjexl == null) {
1630 if (node == null) {
1631 String error = "unable to set object property"
1632 + ", class: " + object.getClass().getName()
1633 + ", property: " + attribute
1634 + ", argument: " + value.getClass().getSimpleName();
1635 throw new UnsupportedOperationException(error);
1636 }
1637 xjexl = new JexlException.Property(node, attribute.toString());
1638 }
1639 if (strict) {
1640 throw xjexl;
1641 }
1642 if (!silent) {
1643 logger.warn(xjexl.getMessage());
1644 }
1645 }
1646
1647
1648
1649
1650
1651
1652
1653 public Object visit(SimpleNode node, Object data) {
1654 throw new UnsupportedOperationException("Not supported yet.");
1655 }
1656
1657
1658
1659
1660
1661
1662
1663 public Object visit(ASTAmbiguous node, Object data) {
1664 throw new UnsupportedOperationException("unexpected type of node");
1665 }
1666 }