1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl.util.introspection;
18
19 import org.apache.commons.jexl.util.ArrayIterator;
20 import org.apache.commons.jexl.util.EnumerationIterator;
21 import org.apache.commons.jexl.util.AbstractExecutor;
22 import org.apache.commons.jexl.util.GetExecutor;
23 import org.apache.commons.jexl.util.BooleanPropertyExecutor;
24 import org.apache.commons.jexl.util.PropertyExecutor;
25 import org.apache.commons.logging.Log;
26
27 import java.lang.reflect.Method;
28 import java.lang.reflect.InvocationTargetException;
29 import java.util.Iterator;
30 import java.util.Collection;
31 import java.util.Map;
32 import java.util.Enumeration;
33 import java.util.ArrayList;
34
35 /***
36 * Implementation of Uberspect to provide the default introspective
37 * functionality of Velocity
38 *
39 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
40 * @version $Id: UberspectImpl.java,v 1.6 2004/08/19 17:15:59 dion Exp $
41 */
42 public class UberspectImpl implements Uberspect, UberspectLoggable
43 {
44 /***
45 * Our runtime logger.
46 */
47 private Log rlog;
48
49 /***
50 * the default Velocity introspector
51 */
52 private static Introspector introspector;
53
54 /***
55 * init - does nothing - we need to have setRuntimeLogger
56 * called before getting our introspector, as the default
57 * vel introspector depends upon it.
58 */
59 public void init()
60 throws Exception
61 {
62 }
63
64 /***
65 * Sets the runtime logger - this must be called before anything
66 * else besides init() as to get the logger. Makes the pull
67 * model appealing...
68 */
69 public void setRuntimeLogger(Log runtimeLogger)
70 {
71 rlog = runtimeLogger;
72 introspector = new Introspector(rlog);
73 }
74
75 /***
76 * To support iteratives - #foreach()
77 */
78 public Iterator getIterator(Object obj, Info i)
79 throws Exception
80 {
81 if (obj.getClass().isArray())
82 {
83 return new ArrayIterator(obj);
84 }
85 else if (obj instanceof Collection)
86 {
87 return ((Collection) obj).iterator();
88 }
89 else if (obj instanceof Map)
90 {
91 return ((Map) obj).values().iterator();
92 }
93 else if (obj instanceof Iterator)
94 {
95 rlog.warn ("Warning! The iterative "
96 + " is an Iterator in the #foreach() loop at ["
97 + i.getLine() + "," + i.getColumn() + "]"
98 + " in template " + i.getTemplateName()
99 + ". Because it's not resetable,"
100 + " if used in more than once, this may lead to"
101 + " unexpected results.");
102
103 return ((Iterator) obj);
104 }
105 else if (obj instanceof Enumeration)
106 {
107 rlog.warn ("Warning! The iterative "
108 + " is an Enumeration in the #foreach() loop at ["
109 + i.getLine() + "," + i.getColumn() + "]"
110 + " in template " + i.getTemplateName()
111 + ". Because it's not resetable,"
112 + " if used in more than once, this may lead to"
113 + " unexpected results.");
114
115 return new EnumerationIterator((Enumeration) obj);
116 }
117
118
119 rlog.warn ("Could not determine type of iterator in "
120 + "#foreach loop "
121 + " at [" + i.getLine() + "," + i.getColumn() + "]"
122 + " in template " + i.getTemplateName() );
123
124 return null;
125 }
126
127 /***
128 * Method
129 */
130 public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i)
131 throws Exception
132 {
133 if (obj == null)
134 return null;
135
136 Method m = introspector.getMethod(obj.getClass(), methodName, args);
137
138 return (m != null) ? new VelMethodImpl(m) : null;
139 }
140
141 /***
142 * Property getter
143 */
144 public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
145 throws Exception
146 {
147 AbstractExecutor executor;
148
149 Class claz = obj.getClass();
150
151
152
153
154
155
156 executor = new PropertyExecutor(rlog,introspector, claz, identifier);
157
158
159
160
161
162 if( executor.isAlive() == false)
163 {
164 executor = new BooleanPropertyExecutor(rlog, introspector, claz, identifier);
165 }
166
167
168
169
170
171 if (executor.isAlive() == false)
172 {
173 executor = new GetExecutor(rlog, introspector, claz, identifier);
174 }
175
176 return (executor != null) ? new VelGetterImpl(executor) : null;
177 }
178
179 /***
180 * Property setter
181 */
182 public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i)
183 throws Exception
184 {
185 Class claz = obj.getClass();
186
187 VelMethod vm = null;
188 try
189 {
190
191
192
193
194 Object[] params = {arg};
195
196 try
197 {
198 vm = getMethod(obj, "set" + identifier, params, i);
199
200 if (vm == null)
201 {
202 throw new NoSuchMethodException();
203 }
204 }
205 catch(NoSuchMethodException nsme2)
206 {
207 StringBuffer sb = new StringBuffer("set");
208 sb.append(identifier);
209
210 if (Character.isLowerCase( sb.charAt(3)))
211 {
212 sb.setCharAt(3, Character.toUpperCase(sb.charAt(3)));
213 }
214 else
215 {
216 sb.setCharAt(3, Character.toLowerCase(sb.charAt(3)));
217 }
218
219 vm = getMethod(obj, sb.toString(), params, i);
220
221 if (vm == null)
222 {
223 throw new NoSuchMethodException();
224 }
225 }
226 }
227 catch (NoSuchMethodException nsme)
228 {
229
230
231
232
233 if (Map.class.isAssignableFrom(claz))
234 {
235 Object[] params = {new Object(), new Object()};
236
237 vm = getMethod(obj, "put", params, i);
238
239 if (vm!=null)
240 return new VelSetterImpl(vm, identifier);
241 }
242 }
243
244 return (vm!=null) ? new VelSetterImpl(vm) : null;
245 }
246
247 /***
248 * Implementation of VelMethod
249 */
250 public class VelMethodImpl implements VelMethod
251 {
252 Method method = null;
253
254 public VelMethodImpl(Method m)
255 {
256 method = m;
257 }
258
259 private VelMethodImpl()
260 {
261 }
262
263 public Object invoke(Object o, Object[] params)
264 throws Exception
265 {
266 try
267 {
268 return method.invoke(o, params);
269 }
270 catch( InvocationTargetException e )
271 {
272 final Throwable t = e.getTargetException();
273
274 if( t instanceof Exception )
275 {
276 throw (Exception)t;
277 }
278 else if (t instanceof Error)
279 {
280 throw (Error)t;
281 }
282 else
283 {
284 throw e;
285 }
286 }
287 }
288
289 public boolean isCacheable()
290 {
291 return true;
292 }
293
294 public String getMethodName()
295 {
296 return method.getName();
297 }
298
299 public Class getReturnType()
300 {
301 return method.getReturnType();
302 }
303 }
304
305 public class VelGetterImpl implements VelPropertyGet
306 {
307 AbstractExecutor ae = null;
308
309 public VelGetterImpl(AbstractExecutor exec)
310 {
311 ae = exec;
312 }
313
314 private VelGetterImpl()
315 {
316 }
317
318 public Object invoke(Object o)
319 throws Exception
320 {
321 return ae.execute(o);
322 }
323
324 public boolean isCacheable()
325 {
326 return true;
327 }
328
329 public String getMethodName()
330 {
331 return ae.getMethod().getName();
332 }
333
334 }
335
336 public class VelSetterImpl implements VelPropertySet
337 {
338 VelMethod vm = null;
339 String putKey = null;
340
341 public VelSetterImpl(VelMethod velmethod)
342 {
343 this.vm = velmethod;
344 }
345
346 public VelSetterImpl(VelMethod velmethod, String key)
347 {
348 this.vm = velmethod;
349 putKey = key;
350 }
351
352 private VelSetterImpl()
353 {
354 }
355
356 public Object invoke(Object o, Object value)
357 throws Exception
358 {
359 ArrayList al = new ArrayList();
360
361 if (putKey != null)
362 {
363 al.add(putKey);
364 al.add(value);
365 }
366 else
367 {
368 al.add(value);
369 }
370
371 return vm.invoke(o,al.toArray());
372 }
373
374 public boolean isCacheable()
375 {
376 return true;
377 }
378
379 public String getMethodName()
380 {
381 return vm.getMethodName();
382 }
383
384 }
385 }