1 package org.apache.velocity.runtime.parser.node;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.InvocationTargetException;
23
24 import org.apache.commons.lang.ArrayUtils;
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.velocity.app.event.EventHandlerUtil;
27 import org.apache.velocity.context.InternalContextAdapter;
28 import org.apache.velocity.exception.MethodInvocationException;
29 import org.apache.velocity.exception.TemplateInitException;
30 import org.apache.velocity.runtime.parser.Parser;
31 import org.apache.velocity.runtime.parser.ParserVisitor;
32 import org.apache.velocity.util.introspection.Info;
33 import org.apache.velocity.util.introspection.IntrospectionCacheData;
34 import org.apache.velocity.util.introspection.VelMethod;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class ASTMethod extends SimpleNode
53 {
54 private String methodName = "";
55 private int paramCount = 0;
56
57 protected Info uberInfo;
58
59
60
61
62 public ASTMethod(int id)
63 {
64 super(id);
65 }
66
67
68
69
70
71 public ASTMethod(Parser p, int id)
72 {
73 super(p, id);
74 }
75
76
77
78
79 public Object jjtAccept(ParserVisitor visitor, Object data)
80 {
81 return visitor.visit(this, data);
82 }
83
84
85
86
87
88
89
90
91
92 public Object init( InternalContextAdapter context, Object data)
93 throws TemplateInitException
94 {
95 super.init( context, data );
96
97
98
99
100
101 uberInfo = new Info(context.getCurrentTemplateName(),
102 getLine(),getColumn());
103
104
105
106
107 methodName = getFirstToken().image;
108 paramCount = jjtGetNumChildren() - 1;
109
110 return data;
111 }
112
113
114
115
116
117
118
119
120
121
122 public Object execute(Object o, InternalContextAdapter context)
123 throws MethodInvocationException
124 {
125
126
127
128
129
130
131
132 VelMethod method = null;
133
134 Object [] params = new Object[paramCount];
135
136 try
137 {
138
139
140
141
142
143 final Class[] paramClasses = paramCount > 0 ? new Class[paramCount] : ArrayUtils.EMPTY_CLASS_ARRAY;
144
145 for (int j = 0; j < paramCount; j++)
146 {
147 params[j] = jjtGetChild(j + 1).value(context);
148
149 if (params[j] != null)
150 {
151 paramClasses[j] = params[j].getClass();
152 }
153 }
154
155
156
157
158
159 MethodCacheKey mck = new MethodCacheKey(methodName, paramClasses);
160 IntrospectionCacheData icd = context.icacheGet( mck );
161
162
163
164
165
166
167
168 if ( icd != null && (o != null && icd.contextData == o.getClass()) )
169 {
170
171
172
173
174
175 method = (VelMethod) icd.thingy;
176 }
177 else
178 {
179
180
181
182
183
184 method = rsvc.getUberspect().getMethod(o, methodName, params, new Info(context.getCurrentTemplateName(), getLine(), getColumn()));
185
186 if ((method != null) && (o != null))
187 {
188 icd = new IntrospectionCacheData();
189 icd.contextData = o.getClass();
190 icd.thingy = method;
191
192 context.icachePut( mck, icd );
193 }
194 }
195
196
197
198
199
200
201
202 if (method == null)
203 {
204 return null;
205 }
206 }
207 catch( MethodInvocationException mie )
208 {
209
210
211
212
213
214
215 throw mie;
216 }
217
218
219
220 catch( RuntimeException e )
221 {
222 throw e;
223 }
224 catch( Exception e )
225 {
226
227
228
229
230 log.error("ASTMethod.execute() : exception from introspection", e);
231 return null;
232 }
233
234 try
235 {
236
237
238
239
240
241
242
243
244
245 Object obj = method.invoke(o, params);
246
247 if (obj == null)
248 {
249 if( method.getReturnType() == Void.TYPE)
250 {
251 return "";
252 }
253 }
254
255 return obj;
256 }
257 catch( InvocationTargetException ite )
258 {
259
260
261
262
263
264
265
266
267
268
269
270
271 Throwable t = ite.getTargetException();
272 if (t instanceof Exception)
273 {
274 try
275 {
276 return EventHandlerUtil.methodException( rsvc, context, o.getClass(), methodName, (Exception) t );
277 }
278
279
280
281
282
283
284 catch( Exception e )
285 {
286 throw new MethodInvocationException(
287 "Invocation of method '"
288 + methodName + "' in " + o.getClass()
289 + " threw exception "
290 + e.toString(),
291 e, methodName, context.getCurrentTemplateName(), this.getLine(), this.getColumn());
292 }
293 }
294 else
295 {
296
297
298
299
300 throw new MethodInvocationException(
301 "Invocation of method '"
302 + methodName + "' in " + o.getClass()
303 + " threw exception "
304 + ite.getTargetException().toString(),
305 ite.getTargetException(), methodName, context.getCurrentTemplateName(), this.getLine(), this.getColumn());
306 }
307 }
308
309
310
311 catch( RuntimeException e )
312 {
313 throw e;
314 }
315 catch( Exception e )
316 {
317 log.error("ASTMethod.execute() : exception invoking method '"
318 + methodName + "' in " + o.getClass(), e);
319 return null;
320 }
321 }
322
323
324
325
326
327
328
329 public static class MethodCacheKey
330 {
331 private final String methodName;
332 private final Class[] params;
333
334 public MethodCacheKey(String methodName, Class[] params)
335 {
336
337
338
339
340 this.methodName = (methodName != null) ? methodName : StringUtils.EMPTY;
341 this.params = (params != null) ? params : ArrayUtils.EMPTY_CLASS_ARRAY;
342 }
343
344
345
346
347 public boolean equals(Object o)
348 {
349
350
351
352
353 if (o instanceof MethodCacheKey)
354 {
355 final MethodCacheKey other = (MethodCacheKey) o;
356 if (params.length == other.params.length &&
357 methodName.equals(other.methodName))
358 {
359 for (int i = 0; i < params.length; ++i)
360 {
361 if (params[i] == null)
362 {
363 if (params[i] != other.params[i])
364 {
365 return false;
366 }
367 }
368 else if (!params[i].equals(other.params[i]))
369 {
370 return false;
371 }
372 }
373 return true;
374 }
375 }
376 return false;
377 }
378
379
380
381
382
383 public int hashCode()
384 {
385 int result = 17;
386
387
388
389
390
391 for (int i = 0; i < params.length; ++i)
392 {
393 final Class param = params[i];
394 if (param != null)
395 {
396 result = result * 37 + param.hashCode();
397 }
398 }
399
400 result = result * 37 + methodName.hashCode();
401
402 return result;
403 }
404 }
405
406
407
408
409 public String getMethodName()
410 {
411 return methodName;
412 }
413
414
415 }