001: package org.apache.velocity.util.introspection;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.lang.reflect.Method;
023: import java.util.Collection;
024: import java.util.Enumeration;
025: import java.util.Iterator;
026: import java.util.Map;
027:
028: import org.apache.velocity.runtime.RuntimeLogger;
029: import org.apache.velocity.runtime.log.Log;
030: import org.apache.velocity.runtime.log.RuntimeLoggerLog;
031: import org.apache.velocity.runtime.parser.node.AbstractExecutor;
032: import org.apache.velocity.runtime.parser.node.BooleanPropertyExecutor;
033: import org.apache.velocity.runtime.parser.node.GetExecutor;
034: import org.apache.velocity.runtime.parser.node.MapGetExecutor;
035: import org.apache.velocity.runtime.parser.node.MapSetExecutor;
036: import org.apache.velocity.runtime.parser.node.PropertyExecutor;
037: import org.apache.velocity.runtime.parser.node.PutExecutor;
038: import org.apache.velocity.runtime.parser.node.SetExecutor;
039: import org.apache.velocity.runtime.parser.node.SetPropertyExecutor;
040: import org.apache.velocity.util.ArrayIterator;
041: import org.apache.velocity.util.EnumerationIterator;
042:
043: /**
044: * Implementation of Uberspect to provide the default introspective
045: * functionality of Velocity
046: *
047: * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
048: * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
049: * @version $Id: UberspectImpl.java 463298 2006-10-12 16:10:32Z henning $
050: */
051: public class UberspectImpl implements Uberspect, UberspectLoggable {
052: /**
053: * Our runtime logger.
054: */
055: protected Log log;
056:
057: /**
058: * the default Velocity introspector
059: */
060: protected Introspector introspector;
061:
062: /**
063: * init - generates the Introspector. As the setup code
064: * makes sure that the log gets set before this is called,
065: * we can initialize the Introspector using the log object.
066: */
067: public void init() {
068: introspector = new Introspector(log);
069: }
070:
071: /**
072: * Sets the runtime logger - this must be called before anything
073: * else.
074: *
075: * @param log The logger instance to use.
076: */
077: public void setLog(Log log) {
078: this .log = log;
079: }
080:
081: /**
082: * @param runtimeLogger
083: * @deprecated Use setLog(Log log) instead.
084: */
085: public void setRuntimeLogger(RuntimeLogger runtimeLogger) {
086: // in the off chance anyone still uses this method
087: // directly, use this hack to keep it working
088: setLog(new RuntimeLoggerLog(runtimeLogger));
089: }
090:
091: /**
092: * To support iterative objects used in a <code>#foreach()</code>
093: * loop.
094: *
095: * @param obj The iterative object.
096: * @param i Info about the object's location.
097: * @return An {@link Iterator} object.
098: * @throws Exception
099: */
100: public Iterator getIterator(Object obj, Info i) throws Exception {
101: if (obj.getClass().isArray()) {
102: return new ArrayIterator(obj);
103: } else if (obj instanceof Collection) {
104: return ((Collection) obj).iterator();
105: } else if (obj instanceof Map) {
106: return ((Map) obj).values().iterator();
107: } else if (obj instanceof Iterator) {
108: if (log.isDebugEnabled()) {
109: log
110: .debug("The iterative object in the #foreach() loop at "
111: + i
112: + " is of type java.util.Iterator. Because "
113: + "it is not resettable, if used in more than once it "
114: + "may lead to unexpected results.");
115: }
116: return ((Iterator) obj);
117: } else if (obj instanceof Enumeration) {
118: if (log.isDebugEnabled()) {
119: log
120: .debug("The iterative object in the #foreach() loop at "
121: + i
122: + " is of type java.util.Enumeration. Because "
123: + "it is not resettable, if used in more than once it "
124: + "may lead to unexpected results.");
125: }
126: return new EnumerationIterator((Enumeration) obj);
127: }
128:
129: /* we have no clue what this is */
130: log
131: .info("Could not determine type of iterator in #foreach loop at "
132: + i);
133:
134: return null;
135: }
136:
137: /**
138: * Method
139: * @param obj
140: * @param methodName
141: * @param args
142: * @param i
143: * @return A Velocity Method.
144: * @throws Exception
145: */
146: public VelMethod getMethod(Object obj, String methodName,
147: Object[] args, Info i) throws Exception {
148: if (obj == null) {
149: return null;
150: }
151:
152: Method m = introspector.getMethod(obj.getClass(), methodName,
153: args);
154:
155: return (m != null) ? new VelMethodImpl(m) : null;
156: }
157:
158: /**
159: * Property getter
160: * @param obj
161: * @param identifier
162: * @param i
163: * @return A Velocity Getter Method.
164: * @throws Exception
165: */
166: public VelPropertyGet getPropertyGet(Object obj, String identifier,
167: Info i) throws Exception {
168: if (obj == null) {
169: return null;
170: }
171:
172: Class claz = obj.getClass();
173:
174: /*
175: * first try for a getFoo() type of property
176: * (also getfoo() )
177: */
178: AbstractExecutor executor = new PropertyExecutor(log,
179: introspector, claz, identifier);
180:
181: /*
182: * Let's see if we are a map...
183: */
184: if (!executor.isAlive()) {
185: executor = new MapGetExecutor(log, claz, identifier);
186: }
187:
188: /*
189: * if that didn't work, look for get("foo")
190: */
191:
192: if (!executor.isAlive()) {
193: executor = new GetExecutor(log, introspector, claz,
194: identifier);
195: }
196:
197: /*
198: * finally, look for boolean isFoo()
199: */
200:
201: if (!executor.isAlive()) {
202: executor = new BooleanPropertyExecutor(log, introspector,
203: claz, identifier);
204: }
205:
206: return (executor.isAlive()) ? new VelGetterImpl(executor)
207: : null;
208: }
209:
210: /**
211: * Property setter
212: * @param obj
213: * @param identifier
214: * @param arg
215: * @param i
216: * @return A Velocity Setter method.
217: * @throws Exception
218: */
219: public VelPropertySet getPropertySet(Object obj, String identifier,
220: Object arg, Info i) throws Exception {
221: if (obj == null) {
222: return null;
223: }
224:
225: Class claz = obj.getClass();
226:
227: /*
228: * first try for a setFoo() type of property
229: * (also setfoo() )
230: */
231: SetExecutor executor = new SetPropertyExecutor(log,
232: introspector, claz, identifier, arg);
233:
234: /*
235: * Let's see if we are a map...
236: */
237: if (!executor.isAlive()) {
238: executor = new MapSetExecutor(log, claz, identifier);
239: }
240:
241: /*
242: * if that didn't work, look for put("foo", arg)
243: */
244:
245: if (!executor.isAlive()) {
246: executor = new PutExecutor(log, introspector, claz, arg,
247: identifier);
248: }
249:
250: return (executor.isAlive()) ? new VelSetterImpl(executor)
251: : null;
252: }
253:
254: /**
255: * Implementation of VelMethod
256: */
257: public static class VelMethodImpl implements VelMethod {
258: final Method method;
259:
260: /**
261: * @param m
262: */
263: public VelMethodImpl(Method m) {
264: method = m;
265: }
266:
267: private VelMethodImpl() {
268: method = null;
269: }
270:
271: /**
272: * @see VelMethod#invoke(java.lang.Object, java.lang.Object[])
273: */
274: public Object invoke(Object o, Object[] params)
275: throws Exception {
276: return method.invoke(o, params);
277: }
278:
279: /**
280: * @see org.apache.velocity.util.introspection.VelMethod#isCacheable()
281: */
282: public boolean isCacheable() {
283: return true;
284: }
285:
286: /**
287: * @see org.apache.velocity.util.introspection.VelMethod#getMethodName()
288: */
289: public String getMethodName() {
290: return method.getName();
291: }
292:
293: /**
294: * @see org.apache.velocity.util.introspection.VelMethod#getReturnType()
295: */
296: public Class getReturnType() {
297: return method.getReturnType();
298: }
299: }
300:
301: /**
302: *
303: *
304: */
305: public static class VelGetterImpl implements VelPropertyGet {
306: final AbstractExecutor getExecutor;
307:
308: /**
309: * @param exec
310: */
311: public VelGetterImpl(AbstractExecutor exec) {
312: getExecutor = exec;
313: }
314:
315: private VelGetterImpl() {
316: getExecutor = null;
317: }
318:
319: /**
320: * @see org.apache.velocity.util.introspection.VelPropertyGet#invoke(java.lang.Object)
321: */
322: public Object invoke(Object o) throws Exception {
323: return getExecutor.execute(o);
324: }
325:
326: /**
327: * @see org.apache.velocity.util.introspection.VelPropertyGet#isCacheable()
328: */
329: public boolean isCacheable() {
330: return true;
331: }
332:
333: /**
334: * @see org.apache.velocity.util.introspection.VelPropertyGet#getMethodName()
335: */
336: public String getMethodName() {
337: return getExecutor.isAlive() ? getExecutor.getMethod()
338: .getName() : null;
339: }
340: }
341:
342: /**
343: *
344: */
345: public static class VelSetterImpl implements VelPropertySet {
346: private final SetExecutor setExecutor;
347:
348: /**
349: * @param setExecutor
350: */
351: public VelSetterImpl(final SetExecutor setExecutor) {
352: this .setExecutor = setExecutor;
353: }
354:
355: private VelSetterImpl() {
356: setExecutor = null;
357: }
358:
359: /**
360: * Invoke the found Set Executor.
361: *
362: * @param o is the Object to invoke it on.
363: * @param value in the Value to set.
364: * @return The resulting Object.
365: * @throws Exception
366: */
367: public Object invoke(final Object o, final Object value)
368: throws Exception {
369: return setExecutor.execute(o, value);
370: }
371:
372: /**
373: * @see org.apache.velocity.util.introspection.VelPropertySet#isCacheable()
374: */
375: public boolean isCacheable() {
376: return true;
377: }
378:
379: /**
380: * @see org.apache.velocity.util.introspection.VelPropertySet#getMethodName()
381: */
382: public String getMethodName() {
383: return setExecutor.isAlive() ? setExecutor.getMethod()
384: .getName() : null;
385: }
386: }
387: }
|