%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.jexl.util.introspection.UberspectImpl |
|
|
1 | /* |
|
2 | * Copyright 2002,2004 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
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 | * @since 1.0 |
|
40 | * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> |
|
41 | * @version $Id: UberspectImpl.java 398509 2006-05-01 03:34:35Z dion $ |
|
42 | */ |
|
43 | 4 | public class UberspectImpl implements Uberspect, UberspectLoggable { |
44 | /** index of the first character of the property. */ |
|
45 | private static final int PROPERTY_START_INDEX = 3; |
|
46 | ||
47 | /** |
|
48 | * Our runtime logger. |
|
49 | */ |
|
50 | private Log rlog; |
|
51 | ||
52 | /** |
|
53 | * the default Velocity introspector. |
|
54 | */ |
|
55 | private static Introspector introspector; |
|
56 | ||
57 | /** |
|
58 | * init - does nothing - we need to have setRuntimeLogger called before |
|
59 | * getting our introspector, as the default vel introspector depends upon |
|
60 | * it. |
|
61 | * @throws Exception on any error. |
|
62 | */ |
|
63 | public void init() throws Exception { |
|
64 | 0 | } |
65 | ||
66 | /** |
|
67 | * Sets the runtime logger - this must be called before anything else |
|
68 | * besides init() as to get the logger. Makes the pull model appealing... |
|
69 | * @param runtimeLogger service to use for logging. |
|
70 | */ |
|
71 | public void setRuntimeLogger(Log runtimeLogger) { |
|
72 | 4 | rlog = runtimeLogger; |
73 | 4 | introspector = new Introspector(rlog); |
74 | 4 | } |
75 | ||
76 | /** |
|
77 | * {@inheritDoc} |
|
78 | */ |
|
79 | public Iterator getIterator(Object obj, Info i) throws Exception { |
|
80 | 8 | if (obj.getClass().isArray()) { |
81 | 2 | return new ArrayIterator(obj); |
82 | 6 | } else if (obj instanceof Collection) { |
83 | 3 | return ((Collection) obj).iterator(); |
84 | 3 | } else if (obj instanceof Map) { |
85 | 1 | return ((Map) obj).values().iterator(); |
86 | 2 | } else if (obj instanceof Iterator) { |
87 | 1 | rlog.warn("Warning! The iterative " + " is an Iterator in the #foreach() loop at [" + i.getLine() + "," |
88 | + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable," |
|
89 | + " if used in more than once, this may lead to" + " unexpected results."); |
|
90 | ||
91 | 1 | return ((Iterator) obj); |
92 | 1 | } else if (obj instanceof Enumeration) { |
93 | 1 | rlog.warn("Warning! The iterative " + " is an Enumeration in the #foreach() loop at [" + i.getLine() + "," |
94 | + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable," |
|
95 | + " if used in more than once, this may lead to" + " unexpected results."); |
|
96 | ||
97 | 1 | return new EnumerationIterator((Enumeration) obj); |
98 | } |
|
99 | ||
100 | /* we have no clue what this is */ |
|
101 | 0 | rlog.warn("Could not determine type of iterator in " + "#foreach loop " + " at [" + i.getLine() + "," |
102 | + i.getColumn() + "]" + " in template " + i.getTemplateName()); |
|
103 | ||
104 | 0 | return null; |
105 | } |
|
106 | ||
107 | /** |
|
108 | * {@inheritDoc} |
|
109 | */ |
|
110 | public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception { |
|
111 | 47 | if (obj == null) { |
112 | 0 | return null; |
113 | } |
|
114 | ||
115 | 47 | Method m = introspector.getMethod(obj.getClass(), methodName, args); |
116 | 47 | if (m == null && obj instanceof Class) { |
117 | 1 | m = introspector.getMethod((Class) obj, methodName, args); |
118 | } |
|
119 | ||
120 | 47 | return (m == null) ? class="keyword">null : new VelMethodImpl(m); |
121 | } |
|
122 | ||
123 | /** |
|
124 | * {@inheritDoc} |
|
125 | */ |
|
126 | public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception { |
|
127 | AbstractExecutor executor; |
|
128 | ||
129 | 23 | Class claz = obj.getClass(); |
130 | ||
131 | /* |
|
132 | * first try for a getFoo() type of property (also getfoo() ) |
|
133 | */ |
|
134 | ||
135 | 23 | executor = new PropertyExecutor(rlog, introspector, claz, identifier); |
136 | ||
137 | /* |
|
138 | * look for boolean isFoo() |
|
139 | */ |
|
140 | ||
141 | 23 | if (!executor.isAlive()) { |
142 | 3 | executor = new BooleanPropertyExecutor(rlog, introspector, claz, identifier); |
143 | } |
|
144 | ||
145 | /* |
|
146 | * if that didn't work, look for get("foo") |
|
147 | */ |
|
148 | ||
149 | 23 | if (!executor.isAlive()) { |
150 | 1 | executor = new GetExecutor(rlog, introspector, claz, identifier); |
151 | } |
|
152 | ||
153 | 23 | return (executor == null) ? class="keyword">null : new VelGetterImpl(executor); |
154 | } |
|
155 | ||
156 | /** |
|
157 | * {@inheritDoc} |
|
158 | */ |
|
159 | public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception { |
|
160 | 0 | Class claz = obj.getClass(); |
161 | ||
162 | 0 | VelMethod vm = null; |
163 | try { |
|
164 | /* |
|
165 | * first, we introspect for the set<identifier> setter method |
|
166 | */ |
|
167 | ||
168 | 0 | Object[] params = {arg}; |
169 | ||
170 | try { |
|
171 | 0 | vm = getMethod(obj, "set" + identifier, params, i); |
172 | ||
173 | 0 | if (vm == null) { |
174 | 0 | throw new NoSuchMethodException(); |
175 | } |
|
176 | 0 | } catch (NoSuchMethodException nsme2) { |
177 | 0 | StringBuffer sb = new StringBuffer("set"); |
178 | 0 | sb.append(identifier); |
179 | ||
180 | 0 | if (Character.isLowerCase(sb.charAt(PROPERTY_START_INDEX))) { |
181 | 0 | sb.setCharAt(PROPERTY_START_INDEX, Character.toUpperCase(sb.charAt(PROPERTY_START_INDEX))); |
182 | } else { |
|
183 | 0 | sb.setCharAt(PROPERTY_START_INDEX, Character.toLowerCase(sb.charAt(PROPERTY_START_INDEX))); |
184 | } |
|
185 | ||
186 | 0 | vm = getMethod(obj, sb.toString(), params, i); |
187 | ||
188 | 0 | if (vm == null) { |
189 | 0 | throw new NoSuchMethodException(); |
190 | } |
|
191 | } |
|
192 | 0 | } catch (NoSuchMethodException nsme) { |
193 | /* |
|
194 | * right now, we only support the Map interface |
|
195 | */ |
|
196 | ||
197 | 0 | if (Map.class.isAssignableFrom(claz)) { |
198 | 0 | Object[] params = {new Object(), class="keyword">new Object()}; |
199 | ||
200 | 0 | vm = getMethod(obj, "put", params, i); |
201 | ||
202 | 0 | if (vm != null) { |
203 | 0 | return new VelSetterImpl(vm, identifier); |
204 | } |
|
205 | } |
|
206 | } |
|
207 | ||
208 | 0 | return (vm == null) ? class="keyword">null : new VelSetterImpl(vm); |
209 | } |
|
210 | ||
211 | /** |
|
212 | * An implementation of {@link VelMethod}. |
|
213 | */ |
|
214 | public class VelMethodImpl implements VelMethod { |
|
215 | /** the method. */ |
|
216 | protected Method method = null; |
|
217 | /** |
|
218 | * Create a new instance. |
|
219 | * |
|
220 | * @param m the method. |
|
221 | */ |
|
222 | public VelMethodImpl(Method m) { |
|
223 | method = m; |
|
224 | } |
|
225 | ||
226 | /** |
|
227 | * {@inheritDoc} |
|
228 | */ |
|
229 | public Object invoke(Object o, Object[] params) throws Exception { |
|
230 | try { |
|
231 | return method.invoke(o, params); |
|
232 | } catch (InvocationTargetException e) { |
|
233 | final Throwable t = e.getTargetException(); |
|
234 | ||
235 | if (t instanceof Exception) { |
|
236 | throw (Exception) t; |
|
237 | } else if (t instanceof Error) { |
|
238 | throw (Error) t; |
|
239 | } else { |
|
240 | throw e; |
|
241 | } |
|
242 | } |
|
243 | } |
|
244 | ||
245 | /** |
|
246 | * {@inheritDoc} |
|
247 | */ |
|
248 | public boolean isCacheable() { |
|
249 | return true; |
|
250 | } |
|
251 | ||
252 | /** |
|
253 | * {@inheritDoc} |
|
254 | */ |
|
255 | public String getMethodName() { |
|
256 | return method.getName(); |
|
257 | } |
|
258 | ||
259 | /** |
|
260 | * {@inheritDoc} |
|
261 | */ |
|
262 | public Class getReturnType() { |
|
263 | return method.getReturnType(); |
|
264 | } |
|
265 | } |
|
266 | ||
267 | /** |
|
268 | * {@inheritDoc} |
|
269 | */ |
|
270 | public class VelGetterImpl implements VelPropertyGet { |
|
271 | /** executor for performing the get. */ |
|
272 | protected AbstractExecutor ae = null; |
|
273 | ||
274 | /** |
|
275 | * Create the getter using an {@link AbstractExecutor} to |
|
276 | * do the work. |
|
277 | * @param exec the executor. |
|
278 | */ |
|
279 | public VelGetterImpl(AbstractExecutor exec) { |
|
280 | ae = exec; |
|
281 | } |
|
282 | ||
283 | /** |
|
284 | * {@inheritDoc} |
|
285 | */ |
|
286 | public Object invoke(Object o) throws Exception { |
|
287 | return ae.execute(o); |
|
288 | } |
|
289 | ||
290 | /** |
|
291 | * {@inheritDoc} |
|
292 | */ |
|
293 | public boolean isCacheable() { |
|
294 | return true; |
|
295 | } |
|
296 | ||
297 | /** |
|
298 | * {@inheritDoc} |
|
299 | */ |
|
300 | public String getMethodName() { |
|
301 | return ae.getMethod().getName(); |
|
302 | } |
|
303 | } |
|
304 | ||
305 | /** |
|
306 | * {@inheritDoc} |
|
307 | */ |
|
308 | public class VelSetterImpl implements VelPropertySet { |
|
309 | /** the method to call. */ |
|
310 | protected VelMethod vm = null; |
|
311 | /** the key for indexed and other properties. */ |
|
312 | protected String putKey = null; |
|
313 | ||
314 | /** |
|
315 | * Create an instance. |
|
316 | * @param velmethod the method to call on set. |
|
317 | */ |
|
318 | public VelSetterImpl(VelMethod velmethod) { |
|
319 | this.vm = velmethod; |
|
320 | } |
|
321 | ||
322 | /** |
|
323 | * Create an instance. |
|
324 | * @param velmethod the method to call on set. |
|
325 | * @param key the index or other value passed to a |
|
326 | * setProperty(xxx, value) method. |
|
327 | */ |
|
328 | public VelSetterImpl(VelMethod velmethod, String key) { |
|
329 | this.vm = velmethod; |
|
330 | putKey = key; |
|
331 | } |
|
332 | ||
333 | /** {@inheritDoc} */ |
|
334 | public Object invoke(Object o, Object value) throws Exception { |
|
335 | ArrayList al = new ArrayList(); |
|
336 | ||
337 | if (putKey == null) { |
|
338 | al.add(value); |
|
339 | } else { |
|
340 | al.add(putKey); |
|
341 | al.add(value); |
|
342 | } |
|
343 | ||
344 | return vm.invoke(o, al.toArray()); |
|
345 | } |
|
346 | ||
347 | /** {@inheritDoc} */ |
|
348 | public boolean isCacheable() { |
|
349 | return true; |
|
350 | } |
|
351 | ||
352 | /** {@inheritDoc} */ |
|
353 | public String getMethodName() { |
|
354 | return vm.getMethodName(); |
|
355 | } |
|
356 | ||
357 | } |
|
358 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |