EvaluatingContext.java
biz/hammurapi/eval/EvaluatingContext.java
Violations
Inspector |
Message |
Severity |
Location |
Java Inspector 006 |
Missing default case for switch statement |
1 |
485:25
|
Java Inspector 031 |
Switch statement case without 'break' |
1 |
489:33
|
Java Inspector 048 |
Copyrights information should be present in each file. |
1 |
|
Java Inspector 070-B |
Cyclomatic complexity is too high: 31, maximum allowed is 20 |
1 |
127:9
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
101:20
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
109:35
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
229:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
242:31
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
278:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
286:15
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
299:15
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
394:43
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
397:51
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
405:51
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
427:27
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
460:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
523:23
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
541:19
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
544:19
|
Java Inspector 049 |
Use a Collection instead of arrays Object[] |
2 |
546:23
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 31, maximum allowed is 12 |
2 |
127:9
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 14, maximum allowed is 12 |
2 |
316:5
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 13, maximum allowed is 12 |
2 |
383:9
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 19, maximum allowed is 12 |
2 |
447:5
|
Java Inspector 070-A |
Cyclomatic complexity is too high: 14, maximum allowed is 12 |
2 |
559:5
|
Java Inspector 073 [java.lang.StringBuffer] |
In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . |
2 |
161:33
|
Java Inspector 073 [java.lang.StringBuffer] |
In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . |
2 |
501:25
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
59:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
76:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
82:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
127:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
211:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
261:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
316:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
383:9
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
447:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
559:5
|
Java Inspector 085 |
Do not declare runtime exceptions in the throws clause. |
2 |
625:9
|
Java Inspector 089 |
Type is not documented |
2 |
50:1
|
Java Inspector 089 |
Undocumented constructor |
2 |
59:9
|
Java Inspector 089 |
Undocumented method |
2 |
76:9
|
Java Inspector 089 |
Undocumented method |
2 |
82:9
|
Java Inspector 089 |
Undocumented method |
2 |
221:17
|
Java Inspector 089 |
Undocumented method |
2 |
234:17
|
Java Inspector 089 |
Parameter name is not documented |
2 |
642:9
|
Java Inspector 089 |
Method return value is not properly documented |
2 |
642:9
|
Java Inspector 005 |
Classes, interfaces, methods, and variables should be named according to Sun's naming conventions. |
3 |
51:9
|
Java Inspector 024 |
Avoid hardwired character literals |
3 |
643:33
|
Java Inspector 024 |
Avoid hardwired character literals |
3 |
643:38
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
163:53
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
166:53
|
Java Inspector 025 |
Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] |
3 |
169:53
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
68:86
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
83:30
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
141:63
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
162:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
162:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
163:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
165:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
165:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
166:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
168:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
168:83
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
169:56
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
201:30
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
201:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
201:113
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
201:133
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
217:93
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
267:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
267:85
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
267:121
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
318:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
318:72
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
318:107
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
335:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
335:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
335:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
348:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
348:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
348:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
361:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
361:73
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
361:94
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
372:39
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
457:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
457:92
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
497:55
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
497:92
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
501:59
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
501:91
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
504:44
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
577:43
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
589:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
600:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
611:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
622:57
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
630:78
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
632:63
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
127:54
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
211:49
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
261:51
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
383:52
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
447:47
|
Java Inspector 040 |
Parameter name methods clashes with field name in EvaluatingContext |
3 |
447:94
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
587:54
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
598:50
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
609:50
|
Java Inspector 040 |
Parameter name context clashes with field name in EvaluatingContext |
3 |
620:51
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
59:9
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package biz.hammurapi.eval;
24
25import java.io.StringReader;
26import java.lang.reflect.Array;
27import java.lang.reflect.Method;
28import java.util.ArrayList;
29import java.util.Collection;
30import java.util.Enumeration;
31import java.util.Iterator;
32import java.util.List;
33import java.util.Map;
34
35import org.apache.log4j.Logger;
36
37import antlr.RecognitionException;
38import antlr.TokenStreamException;
39import biz.hammurapi.antlr.AST;
40import biz.hammurapi.antlr.Token;
41import biz.hammurapi.config.BeanContext;
42import biz.hammurapi.config.Context;
43import biz.hammurapi.convert.Converter;
44
45
46
47
48
49
50public class EvaluatingContext implements Context {
51 private static final Logger logger=Logger.getLogger(EvaluatingContext.class);
52
53 private Converter converter;
54
55 private Collection methods=new ArrayList();
56
57 private Context context;
58
59 public EvaluatingContext(Context context, Collection methods, Converter converter) throws EvaluationException {
60 this.context=context;
61 this.converter=converter;
62
63 if (methods!=null) {
64 this.methods.addAll(methods);
65 }
66
67 try {
68 this.methods.add(new MethodEntry(null, EvaluatingContext.class.getMethod("forEach", new Class[] {Object.class})));
69 } catch (SecurityException e) {
70 throw new EvaluationException(e);
71 } catch (NoSuchMethodException e) {
72 throw new EvaluationException(e);
73 }
74 }
75
76 public static MultiResult forEach(Object param) throws EvaluationException {
77 Collection values = new ArrayList();
78 populate(((SingleResult) param).getValue(), values);
79 return new MultiResult(null, values, null);
80 }
81
82 public Object get(String expression) throws EvaluationException {
83 logger.debug("New evaluator for expression: "+expression);
84 ExpressionLexer lexer=new ExpressionLexer(new StringReader(expression));
85 lexer.setTokenObjectClass(Token.class.getName());
86 ExpressionRecognizer parser=new ExpressionRecognizer(lexer);
87 parser.setASTNodeClass(AST.class.getName());
88 try {
89 parser.expressionList();
90 } catch (RecognitionException e) {
91 throw new EvaluationException(e);
92 } catch (TokenStreamException e) {
93 throw new EvaluationException(e);
94 }
95
96 List nodeList=new ArrayList();
97 for (AST ast=(AST) parser.getAST().getFirstChild(); ast!=null; ast=(AST) ast.getNextSibling()) {
98 nodeList.add(ast);
99 }
100
101 AST[] nodes = (AST[]) nodeList.toArray(new AST[nodeList.size()]);
102
103 Collection ret=new ArrayList();
104 for (int i=0; i<nodes.length; i++) {
105 Result result = evaluate(null, nodes[i], context);
106 if (result instanceof SingleResult) {
107 ret.add(((SingleResult) result).getValue());
108 } else {
109 Object[] values=((MultiResult) result).getValues();
110 for (int j=0; j<values.length; j++) {
111 ret.add(values[j]);
112 }
113 }
114 }
115
116 return ret.size()==1 ? ret.iterator().next() : ret;
117 }
118
119
120
121
122
123
124
125
126
127 private Result evaluate(Result res, AST ast, Context context) throws EvaluationException {
128 logAst(ast);
129 switch (ast.getType()) {
130 case ExpressionTokenTypes.MINUS:
131 return minus(res, ast, context);
132 case ExpressionTokenTypes.PLUS:
133 return plus(res, ast, context);
134 case ExpressionTokenTypes.LNOT:
135 return lnot(res, ast, context);
136 case ExpressionTokenTypes.TYPECAST:
137 return typecast(res, ast, context);
138 case ExpressionTokenTypes.METHOD_CALL:
139 return invoke(res, ast, context);
140 case ExpressionTokenTypes.ARRAY_DECLARATOR:
141 throw new EvaluationException("Handle it!");
142 case ExpressionTokenTypes.INDEX_OP:
143 return index(res, ast, context);
144 case ExpressionTokenTypes.DOT:
145 return dot(res, ast, context);
146 case ExpressionTokenTypes.IDENT:
147 Object obj = context.get(ast.getText());
148 return obj instanceof Result ? (Result) obj : new SingleResult(this.converter, null, obj);
149 case ExpressionTokenTypes.LITERAL_true:
150 return new SingleResult(this.converter, boolean.class, Boolean.TRUE);
151 case ExpressionTokenTypes.LITERAL_false:
152 return new SingleResult(this.converter, boolean.class, Boolean.FALSE);
153 case ExpressionTokenTypes.LITERAL_null:
154 return new SingleResult(this.converter, null, null);
155 case ExpressionTokenTypes.NUM_INT:
156 return new SingleResult(this.converter, int.class, new Integer(ast.getText()));
157 case ExpressionTokenTypes.CHAR_LITERAL:
158 return new SingleResult(this.converter, char.class, ast.getText().substring(0,1));
159 case ExpressionTokenTypes.STRING_LITERAL:
160 String rawText=ast.getText();
161 StringBuffer sb=new StringBuffer(rawText.substring(1, rawText.length()-1));
162 for (int i=sb.indexOf("\\n"); i!=-1; i=sb.indexOf("\\n")) {
163 sb.replace(i, i+2, "\n");
164 }
165 for (int i=sb.indexOf("\\r"); i!=-1; i=sb.indexOf("\\r")) {
166 sb.replace(i, i+2, "\r");
167 }
168 for (int i=sb.indexOf("\\t"); i!=-1; i=sb.indexOf("\\t")) {
169 sb.replace(i, i+2, "\t");
170 }
171 return new SingleResult(this.converter, String.class, sb.toString());
172 case ExpressionTokenTypes.NUM_FLOAT:
173 return new SingleResult(this.converter, float.class, new Float(ast.getText()));
174 case ExpressionTokenTypes.NUM_LONG:
175 return new SingleResult(this.converter, long.class, new Long(ast.getText()));
176 case ExpressionTokenTypes.NUM_DOUBLE:
177 return new SingleResult(this.converter, double.class, new Double(ast.getText()));
178 case ExpressionTokenTypes.LITERAL_boolean:
179 return new SingleResult(this.converter, boolean.class, null);
180 case ExpressionTokenTypes.LITERAL_byte:
181 return new SingleResult(this.converter, byte.class, null);
182 case ExpressionTokenTypes.LITERAL_char:
183 return new SingleResult(this.converter, char.class, null);
184 case ExpressionTokenTypes.LITERAL_short:
185 return new SingleResult(this.converter, short.class, null);
186 case ExpressionTokenTypes.LITERAL_float:
187 return new SingleResult(this.converter, float.class, null);
188 case ExpressionTokenTypes.LITERAL_long:
189 return new SingleResult(this.converter, long.class, null);
190 case ExpressionTokenTypes.LITERAL_double:
191 return new SingleResult(this.converter, double.class, null);
192 default:
193 throw new EvaluationException(ast);
194 }
195 }
196
197
198
199
200 private static void logAst(AST ast) {
201 logger.debug("Evaluating: ["+ExpressionRecognizer._tokenNames[ast.getType()]+"] "+ast.getLine()+":"+ast.getColumn()+" "+ast.toString());
202 }
203
204
205
206
207
208
209
210
211 private Result dot(Result res, AST ast, Context context) throws EvaluationException {
212 Result result=evaluate(res, (AST) ast.getFirstChild(), context);
213 String property = ast.getFirstChild().getNextSibling().getText();
214 if (result instanceof SingleResult) {
215 Object value = ((SingleResult) result).getValue();
216 if (value==null) {
217 throw new EvaluationException(ast.getFirstChild().getText()+" is null");
218 }
219
220 Context ctx= value instanceof Context ? (Context) value : new BeanContext(value) {
221 protected String translate(String name) {
222 return EvaluatingContext.this.translate(name);
223 }
224 };
225 Object ret = ctx.get(property);
226 return ret instanceof Result ? (Result) ret : new SingleResult(this.converter, null, ret);
227 }
228
229 Object[] values = ((MultiResult) result).getValues();
230
231 Collection cres=new ArrayList();
232 for (int i=0; i<values.length; i++) {
233 Context ctx = values[i] instanceof Context ? (Context) values[i] : new BeanContext(values[i]) {
234 protected String translate(String name) {
235 return EvaluatingContext.this.translate(name);
236 }
237 };
238 Object ret = ctx.get(property);
239 if (ret instanceof SingleResult) {
240 cres.add(((SingleResult) ret).getValue());
241 } else if (ret instanceof MultiResult) {
242 Object[] rets=((MultiResult) ret).getValues();
243 for (int j=0; j<rets.length; j++) {
244 cres.add(rets[j]);
245 }
246 } else {
247 cres.add(ret);
248 }
249 }
250 return new MultiResult(null, cres, converter);
251 }
252
253
254
255
256
257
258
259
260
261 private Result index(Result res, AST ast, Context context) throws EvaluationException {
262 AST objectNode = (AST) ast.getFirstChild();
263 Result result = evaluate(null, objectNode, context);
264 if (result instanceof SingleResult) {
265 Object obj=((SingleResult) result).getValue();
266 if (obj==null) {
267 throw new EvaluationException("Value "+objectNode.getText()+" is null at "+objectNode.getLine()+":"+objectNode.getColumn());
268 }
269
270 AST indexNode = (AST) objectNode.getNextSibling();
271 Result idr = evaluate(null, indexNode, context);
272 if (idr instanceof SingleResult) {
273 Object idx=((SingleResult) idr).getValue();
274 return new SingleResult(this.converter, null, index(ast, obj, indexNode, idx));
275 }
276
277 Collection values=new ArrayList();
278 Object[] idxa=((MultiResult) idr).getValues();
279 for (int i=0; i<idxa.length; i++) {
280 values.add(index(ast, obj, indexNode, idxa[i]));
281 }
282
283 return new MultiResult(null, values, converter);
284 }
285
286 Object[] objs=((MultiResult) result).getValues();
287
288 AST indexNode = (AST) objectNode.getNextSibling();
289 Collection values=new ArrayList();
290 Result idr = evaluate(null, indexNode, context);
291 if (idr instanceof SingleResult) {
292 Object idx=((SingleResult) idr).getValue();
293 for (int i=0; i<objs.length; i++) {
294 values.add(index(ast, objs[i], indexNode, idx));
295 }
296 return new MultiResult(null, values, converter);
297 }
298
299 Object[] idxa=((MultiResult) idr).getValues();
300 for (int j=0; j<objs.length; j++) {
301 for (int i=0; i<idxa.length; i++) {
302 values.add(index(ast, objs[j], indexNode, idxa[i]));
303 }
304 }
305
306 return new MultiResult(null, values, converter);
307 }
308
309
310
311
312
313
314
315
316 private Object index(AST ast, Object obj, AST indexNode, Object idx) throws EvaluationException {
317 if (idx==null) {
318 throw new EvaluationException("Index "+indexNode.getText()+" is null at "+indexNode.getLine()+":"+indexNode.getColumn());
319 }
320
321 if (obj.getClass().isArray()) {
322 return Array.get(obj, ((Number) converter.convert(idx, Number.class, null)).intValue());
323 }
324
325 if (obj instanceof Collection) {
326 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
327 Iterator it=((Collection) obj).iterator();
328 for (int i=0; it.hasNext(); i++) {
329 Object next = it.next();
330 if (i==index) {
331 return next;
332 }
333 }
334
335 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
336 }
337
338 if (obj instanceof Iterator) {
339 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
340 Iterator it=(Iterator) obj;
341 for (int i=0; it.hasNext(); i++) {
342 Object next = it.next();
343 if (i==index) {
344 return next;
345 }
346 }
347
348 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
349 }
350
351 if (obj instanceof Enumeration) {
352 int index=((Number) converter.convert(idx, Number.class, null)).intValue();
353 Enumeration enm=(Enumeration) obj;
354 for (int i=0; enm.hasMoreElements(); i++) {
355 Object nextElement = enm.nextElement();
356 if (i==index) {
357 return nextElement;
358 }
359 }
360
361 throw new EvaluationException("Index out of bounds: "+index+" at "+ast.getLine()+":"+ast.getColumn());
362 }
363
364 if (obj instanceof Context) {
365 return ((Context) obj).get(idx.toString());
366 }
367
368 if (obj instanceof Map) {
369 return ((Map) obj).get(idx);
370 }
371
372 throw new EvaluationException("Can't apply index operation to class "+obj.getClass().getName());
373 }
374
375
376
377
378
379
380
381
382
383 private Result invoke(Result res, AST ast, Context context) throws EvaluationException {
384 int paramCount = ast.getFirstChild().getNextSibling().getNumberOfChildren();
385 AST nameNode = (AST) ast.getFirstChild();
386 Object object;
387 String methodName;
388 switch (nameNode.getType()) {
389 case ExpressionRecognizer.DOT:
390 methodName = nameNode.getFirstChild().getNextSibling().getText();
391 Result result = evaluate(res, (AST) nameNode.getFirstChild(), context);
392 if (result instanceof MultiResult) {
393 Collection ret=new ArrayList();
394 Object[] values=((MultiResult) result).getValues();
395 for (int i=0; i<values.length; i++) {
396 ArrayList vCandidates=new ArrayList();
397 Method[] ma=values[i].getClass().getMethods();
398 for (int j=0; j<ma.length; j++) {
399 vCandidates.add(new MethodEntry(values[i], ma[j]));
400 }
401 Result ir = invokeInternal(res, context, paramCount, nameNode, vCandidates, methodName);
402 if (ir instanceof SingleResult) {
403 ret.add(((SingleResult) ir).getValue());
404 } else {
405 Object[] vv=((MultiResult) ir).getValues();
406 for (int k=0; k<vv.length; k++) {
407 ret.add(vv[k]);
408 }
409 }
410 }
411 return new MultiResult(null, ret, converter);
412 }
413 object = ((SingleResult) result).getValue();
414 break;
415 case ExpressionRecognizer.IDENT:
416 object=context;
417 methodName=nameNode.getText();
418 break;
419 default:
420 throw new EvaluationException(nameNode);
421 }
422
423 ArrayList candidates=new ArrayList();
424 if (object==null) {
425 candidates.addAll(methods);
426 } else {
427 Method[] ma=object.getClass().getMethods();
428 for (int i=0; i<ma.length; i++) {
429 candidates.add(new MethodEntry(object, ma[i]));
430 }
431 }
432
433 return invokeInternal(res, context, paramCount, nameNode, candidates, methodName);
434 }
435
436
437
438
439
440
441
442
443
444
445
446
447 private Result invokeInternal(Result res, Context context, int paramCount, AST nameNode, ArrayList methods, String methodName) throws EvaluationException {
448 Iterator it=methods.iterator();
449 while (it.hasNext()) {
450 MethodEntry me=(MethodEntry) it.next();
451 if (!me.name.equals(methodName) || me.method.getParameterTypes().length!=paramCount) {
452 it.remove();
453 }
454 }
455
456 if (methods.isEmpty()) {
457 throw new EvaluationException("No appropriate method '"+methodName+"'");
458 }
459
460 Result[] params=new Result[paramCount];
461 int idx=0;
462 boolean multiResult=false;
463 for (AST paramNode=(AST) nameNode.getNextSibling().getFirstChild(); paramNode!=null; paramNode=(AST) paramNode.getNextSibling(), idx++) {
464 params[idx]=evaluate(res, paramNode, context);
465 if (params[idx] instanceof MultiResult) {
466 multiResult=true;
467 }
468
469 if (params[idx].getType()!=null) {
470 it=methods.iterator();
471 while (it.hasNext()) {
472 MethodEntry me=(MethodEntry) it.next();
473 if (!me.method.getParameterTypes()[idx].isAssignableFrom(params[idx].getType())) {
474 it.remove();
475 }
476 }
477 }
478 }
479
480 it=methods.iterator();
481 Z: while (it.hasNext()) {
482 MethodEntry me=(MethodEntry) it.next();
483 Iterator jt=methods.iterator();
484 while (jt.hasNext()) {
485 switch (((MethodEntry) jt.next()).isMoreSpecific(me)) {
486 case 1:
487 it.remove();
488 break Z;
489 case -1:
490 jt.remove();
491 }
492 }
493 }
494
495
496 if (methods.isEmpty()) {
497 throw new EvaluationException("No appropriate method '"+methodName+"'");
498 }
499
500 if (methods.size()>1) {
501 StringBuffer msg=new StringBuffer("Ambiguous method '"+methodName+"': ");
502 it=methods.iterator();
503 while (it.hasNext()) {
504 msg.append("\n\t");
505 msg.append(((MethodEntry) it.next()).method);
506 }
507
508 throw new EvaluationException(msg.toString());
509 }
510
511 final MethodEntry methodEntry=(MethodEntry) methods.get(0);
512
513 if (multiResult) {
514 Collection ret=new ArrayList();
515 Collection args=new ArrayList();
516 args.add(new Object[params.length]);
517 for (int i=0; i<params.length; i++) {
518 args=setArgs(args, i, params[i], methodEntry.method.getParameterTypes()[i]);
519 }
520 return new MultiResult(methodEntry.method.getReturnType(), ret, converter);
521 }
522
523 Object[] args=new Object[params.length];
524 for (int i=0; i<params.length; i++) {
525 args[i]=converter.convert(((SingleResult) params[i]).getValue(), methodEntry.method.getParameterTypes()[i], null);
526 }
527
528 return new SingleResult(this.converter, methodEntry.method.getReturnType(), methodEntry.invoke(args));
529 }
530
531 private Collection setArgs(Collection args, int idx, Result arg, Class paramType) {
532 if (arg instanceof SingleResult) {
533 Iterator it=args.iterator();
534 while (it.hasNext()) {
535 ((Object[]) it.next())[idx]=converter.convert(((SingleResult) arg).getValue(), paramType, null);
536 }
537 return args;
538 }
539
540 Collection ret=new ArrayList();
541 Object[] values=((MultiResult) arg).getValues();
542 Iterator it=args.iterator();
543 while (it.hasNext()) {
544 Object[] objs = (Object[]) it.next();
545 for (int i=0; i<values.length; i++) {
546 Object[] cobjs=(Object[]) objs.clone();
547 cobjs[idx]=converter.convert(values[i], paramType, null);
548 ret.add(cobjs);
549 }
550 }
551 return ret;
552 }
553
554
555
556
557
558
559 private static void populate(Object object, Collection values) throws EvaluationException {
560 if (object.getClass().isArray()) {
561 for (int i=0, j=Array.getLength(object); i<j; i++) {
562 values.add(Array.get(object, i));
563 }
564 } else if (object instanceof Collection) {
565 values.addAll((Collection) object);
566 } else if (object instanceof Map) {
567 values.addAll(((Map) object).entrySet());
568 } else if (object instanceof Iterator) {
569 while (((Iterator) object).hasNext()) {
570 values.add(((Iterator) object).next());
571 }
572 } else if (object instanceof Enumeration) {
573 while (((Enumeration) object).hasMoreElements()) {
574 values.add(((Enumeration) object).nextElement());
575 }
576 } else {
577 throw new EvaluationException("forEach() is not applicable for "+object.getClass());
578 }
579 }
580
581
582
583
584
585
586
587 private Result typecast(Result res, AST ast, Context context) {
588 ast.print(ExpressionRecognizer._tokenNames, false);
589 throw new UnsupportedOperationException("Not yet implemented");
590 }
591
592
593
594
595
596
597
598 private Result lnot(Result res, AST ast, Context context) {
599 ast.print(ExpressionRecognizer._tokenNames, false);
600 throw new UnsupportedOperationException("Not yet implemented");
601 }
602
603
604
605
606
607
608
609 private Result plus(Result res, AST ast, Context context) {
610 ast.print(ExpressionRecognizer._tokenNames, false);
611 throw new UnsupportedOperationException("Not yet implemented");
612 }
613
614
615
616
617
618
619
620 private Result minus(Result res, AST ast, Context context) {
621 ast.print(ExpressionRecognizer._tokenNames, false);
622 throw new UnsupportedOperationException("Not yet implemented");
623 }
624
625 private String identifier(AST ast) throws EvaluationException {
626 switch (ast.getType()) {
627 case ExpressionTokenTypes.IDENT:
628 return ast.getText();
629 case ExpressionTokenTypes.DOT:
630 return identifier((AST) ast.getFirstChild())+"."+identifier((AST) ast.getFirstChild().getNextSibling());
631 default:
632 throw new EvaluationException("Unexpected node type: "+ExpressionRecognizer._tokenNames[ast.getType()]);
633 }
634 }
635
636
637
638
639
640
641
642 protected String translate(String name) {
643 return name.replace('_', ' ');
644 }
645}