Author: cbrisson
Date: Tue Apr 24 15:41:21 2012
New Revision: 1329799

URL: http://svn.apache.org/viewvc?rev=1329799&view=rev
Log:
commit Candid Dauth's patch for public fields uberspector (VELOCITY-12)

Added:
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
Modified:
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
    
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java

Added: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java?rev=1329799&view=auto
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
 (added)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/PublicFieldExecutor.java
 Tue Apr 24 15:41:21 2012
@@ -0,0 +1,126 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+/**
+ * Returns the value of a public field when executed.
+ */
+public class PublicFieldExecutor extends AbstractExecutor
+{
+    private final Introspector introspector;
+
+    /**
+     * Field to be accessed
+     */
+    private Field field = null;
+
+    /**
+     * @param log
+     * @param introspector
+     * @param clazz
+     * @param property
+     * @since 1.5
+     */
+    public PublicFieldExecutor(final Log log, final Introspector introspector,
+            final Class clazz, final String property)
+    {
+        this.log = log;
+        this.introspector = introspector;
+
+        // Don't allow passing in the empty string or null because
+        // it will either fail with a StringIndexOutOfBounds error
+        // or the introspector will get confused.
+        if (StringUtils.isNotEmpty(property))
+        {
+            discover(clazz, property);
+        }
+    }
+
+    public boolean isAlive() {
+        return getField() != null;
+    }
+
+    /**
+     * @return The current field.
+     */
+    public Field getField()
+    {
+        return field;
+    }
+
+    /**
+     * @param field
+     */
+    protected void setField(final Field field)
+    {
+        this.field = field;
+    }
+
+    /**
+     * @return The current introspector.
+     * @since 1.5
+     */
+    protected Introspector getIntrospector()
+    {
+        return this.introspector;
+    }
+
+    /**
+     * @param clazz
+     * @param property
+     */
+    protected void discover(final Class clazz, final String property)
+    {
+        try
+        {
+            setField(introspector.getField(clazz, property));
+        }
+        /**
+         * pass through application level runtime exceptions
+         */
+        catch( RuntimeException e )
+        {
+            throw e;
+        }
+        catch(Exception e)
+        {
+            String msg = "Exception while looking for public field '" + 
property;
+            log.error(msg, e);
+            throw new VelocityException(msg, e);
+        }
+    }
+
+    /**
+     * @see 
org.apache.velocity.runtime.parser.node.AbstractExecutor#execute(java.lang.Object)
+     */
+    public Object execute(Object o)
+        throws IllegalAccessException,  InvocationTargetException
+    {
+        return isAlive() ? getField().get(o) : null;
+    }
+}

Added: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java?rev=1329799&view=auto
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
 (added)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SetPublicFieldExecutor.java
 Tue Apr 24 15:41:21 2012
@@ -0,0 +1,147 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+/**
+ * Executor for setting public fields in objects
+ *
+ * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
+ */
+public class SetPublicFieldExecutor
+        extends SetExecutor
+{
+    private final Introspector introspector;
+
+    /**
+     * Field to be accessed
+     */
+    private Field field = null;
+
+    /**
+     * @param log
+     * @param introspector
+     * @param clazz
+     * @param property
+     * @param arg
+     */
+    public SetPublicFieldExecutor(final Log log, final Introspector 
introspector,
+            final Class clazz, final String property, final Object arg)
+    {
+        this.log = log;
+        this.introspector = introspector;
+
+        // Don't allow passing in the empty string or null because
+        // it will either fail with a StringIndexOutOfBounds error
+        // or the introspector will get confused.
+        if (StringUtils.isNotEmpty(property))
+        {
+            discover(clazz, property, arg);
+        }
+    }
+
+    public boolean isAlive() {
+        return getField() != null;
+    }
+
+    /**
+     * @return The current field.
+     */
+    public Field getField()
+    {
+        return field;
+    }
+
+    /**
+     * @param field
+     */
+    protected void setField(final Field field)
+    {
+        this.field = field;
+    }
+
+    /**
+     * @return The current introspector.
+     */
+    protected Introspector getIntrospector()
+    {
+        return this.introspector;
+    }
+
+    /**
+     * @param clazz
+     * @param property
+     * @param arg
+     */
+    protected void discover(final Class clazz, final String property, final 
Object arg)
+    {
+        try
+        {
+            Field field = introspector.getField(clazz, property);
+            if(!Modifier.isFinal(field.getModifiers()))
+            {
+                setField(field);
+            }
+        }
+        /**
+         * pass through application level runtime exceptions
+         */
+        catch( RuntimeException e )
+        {
+            throw e;
+        }
+        catch(Exception e)
+        {
+            String msg = "Exception while looking for public field '" + 
property;
+            log.error(msg, e);
+            throw new VelocityException(msg, e);
+        }
+    }
+
+    /**
+     * Execute method against context.
+     * @param o
+     * @param value
+     * @return The value of the invocation.
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    public Object execute(final Object o, final Object value)
+        throws IllegalAccessException,  InvocationTargetException
+    {
+        if (isAlive())
+        {
+            Object oldValue = getField().get(o);
+            getField().set(o, value);
+            return oldValue;
+        }
+        else
+            return null;
+    }
+}

Added: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java?rev=1329799&view=auto
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
 (added)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/ClassFieldMap.java
 Tue Apr 24 15:41:21 2012
@@ -0,0 +1,176 @@
+package org.apache.velocity.util.introspection;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.velocity.runtime.log.Log;
+
+/**
+ * A cache of introspection information for a specific class instance.
+ * Keys {@link java.lang.reflect.Field} objects by the field names.
+ *
+ * @author <a href="mailto:jvan...@apache.org";>Jason van Zyl</a>
+ * @author <a href="mailto:b...@werken.com";>Bob McWhirter</a>
+ * @author <a href="mailto:szege...@freemail.hu";>Attila Szegedi</a>
+ * @author <a href="mailto:ge...@optonline.net";>Geir Magnusson Jr.</a>
+ * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author Nathan Bubna
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
+ */
+public class ClassFieldMap
+{
+    /** Set true if you want to debug the reflection code */
+    private static final boolean debugReflection = false;
+
+    /** Class logger */
+    private final Log log;
+
+    /**
+     * Class passed into the constructor used to as
+     * the basis for the Field map.
+     */
+    private final Class clazz;
+
+    /**
+     * String --&gt; Field map, the key is the field name
+     */
+    private final Map fieldCache;
+
+    /**
+     * Standard constructor
+     * @param clazz The class for which this ClassMap gets constructed.
+     */
+    public ClassFieldMap(final Class clazz, final Log log)
+    {
+        this.clazz = clazz;
+        this.log = log;
+
+        if (debugReflection && log.isDebugEnabled())
+        {
+            
log.debug("=================================================================");
+            log.debug("== Class: " + clazz);
+        }
+
+        fieldCache = createFieldCache();
+
+        if (debugReflection && log.isDebugEnabled())
+        {
+            
log.debug("=================================================================");
+        }
+    }
+
+    /**
+     * Returns the class object whose fields are cached by this map.
+     *
+     * @return The class object whose fields are cached by this map.
+     */
+    public Class getCachedClass()
+    {
+        return clazz;
+    }
+
+    /**
+     * Find a Field using the field name.
+     *
+     * @param name The field name to look up.
+     * @return A Field object representing the field to invoke or null.
+     */
+    public Field findField(final String name)
+    {
+        return (Field)fieldCache.get(name);
+    }
+
+    /**
+     * Populate the Map of direct hits. These
+     * are taken from all the public fields
+     * that our class, its parents and their implemented interfaces provide.
+     */
+    private Map createFieldCache()
+    {
+        Map fieldCache = new ConcurrentHashMap();
+       //
+       // Looks through all elements in the class hierarchy.
+       //
+       // We ignore all SecurityExceptions that might happen due to 
SecurityManager restrictions (prominently
+       // hit with Tomcat 5.5).
+        // Ah, the miracles of Java for(;;) ...
+        for (Class classToReflect = getCachedClass(); classToReflect != null ; 
classToReflect = classToReflect.getSuperclass())
+        {
+            if (Modifier.isPublic(classToReflect.getModifiers()))
+            {
+                populateFieldCacheWith(fieldCache, classToReflect);
+            }
+            Class [] interfaces = classToReflect.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++)
+            {
+                populateFieldCacheWithInterface(fieldCache, interfaces[i]);
+            }
+        }
+        // return the already initialized cache
+        return fieldCache;
+    }
+
+    /* recurses up interface heirarchy to get all super interfaces 
(VELOCITY-689) */
+    private void populateFieldCacheWithInterface(Map fieldCache, Class iface)
+    {
+        if (Modifier.isPublic(iface.getModifiers()))
+        {
+            populateFieldCacheWith(fieldCache, iface);
+        }
+        Class[] supers = iface.getInterfaces();
+        for (int i=0; i < supers.length; i++)
+        {
+            populateFieldCacheWithInterface(fieldCache, supers[i]);
+        }
+    }
+
+    private void populateFieldCacheWith(Map fieldCache, Class classToReflect)
+    {
+        if (debugReflection && log.isDebugEnabled())
+        {
+            log.debug("Reflecting " + classToReflect);
+        }
+
+        try
+        {
+            Field[] fields = classToReflect.getDeclaredFields();
+            for (int i = 0; i < fields.length; i++)
+            {
+                int modifiers = fields[i].getModifiers();
+                if (Modifier.isPublic(modifiers))
+                {
+                    fieldCache.put(fields[i].getName(), fields[i]);
+                }
+            }
+        }
+        catch (SecurityException se) // Everybody feels better with...
+        {
+            if (log.isDebugEnabled())
+            {
+                log.debug("While accessing fields of " + classToReflect + ": 
", se);
+            }
+        }
+    }
+
+}

Modified: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorBase.java
 Tue Apr 24 15:41:21 2012
@@ -19,6 +19,7 @@ package org.apache.velocity.util.introsp
  * under the License.    
  */
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 import org.apache.velocity.runtime.log.Log;
@@ -49,6 +50,7 @@ import org.apache.velocity.runtime.log.L
  * @author <a href="mailto:szege...@freemail.hu";>Attila Szegedi</a>
  * @author <a href="mailto:paulo.gas...@krankikom.de";>Paulo Gaspar</a>
  * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
  * @version $Id$
  */
 public abstract class IntrospectorBase
@@ -106,6 +108,35 @@ public abstract class IntrospectorBase
     }
 
     /**
+     * Gets the field defined by <code>name</code>.
+     *
+     * @param c Class in which the method search is taking place
+     * @param name Name of the field being searched for
+     *
+     * @return The desired Field object.
+     * @throws IllegalArgumentException When the parameters passed in can not 
be used for introspection.
+     */
+    public Field getField(final Class c, final String name)
+            throws IllegalArgumentException
+    {
+        if (c == null)
+        {
+            throw new IllegalArgumentException("class object is null!");
+        }
+
+        IntrospectorCache ic = getIntrospectorCache();
+
+        ClassFieldMap classFieldMap = ic.getFieldMap(c);
+        if (classFieldMap == null)
+        {
+            ic.put(c);
+            classFieldMap = ic.getFieldMap(c);
+        }
+
+        return classFieldMap.findField(name);
+    }
+
+    /**
      * Return the internal IntrospectorCache object.
      * 
      * @return The internal IntrospectorCache object.

Modified: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCache.java
 Tue Apr 24 15:41:21 2012
@@ -23,6 +23,7 @@ package org.apache.velocity.util.introsp
  * The introspector cache API definition.
  *
  * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
  * @version $Id$
  * @since 1.5
  */
@@ -44,6 +45,16 @@ public interface IntrospectorCache {
     ClassMap get(Class c);
 
     /**
+     * Lookup a given Class object in the cache. If it does not exist,
+     * check whether this is due to a class change and purge the caches
+     * eventually.
+     *
+     * @param c The class to look up.
+     * @return A ClassFieldMap object or null if it does not exist in the 
cache.
+     */
+    ClassFieldMap getFieldMap(final Class c);
+
+    /**
      * Creates a class map for specific class and registers it in the
      * cache.  Also adds the qualified name to the name-&gt;class map
      * for later Classloader change detection.

Modified: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java?rev=1329799&r1=1329798&r2=1329799&view=diff
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
 (original)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
 Tue Apr 24 15:41:21 2012
@@ -30,6 +30,7 @@ import org.apache.velocity.runtime.log.L
  * This is the internal introspector cache implementation.
  *
  * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
  * @version $Id$
  * @since 1.5
  */
@@ -50,6 +51,11 @@ public final class IntrospectorCacheImpl
     private final Map classMapCache = new HashMap();
 
     /**
+     * Holds the field maps for the classes we know about. Map: Class --&gt; 
ClassFieldMap object.
+     */
+    private final Map classFieldMapCache = new HashMap();
+
+    /**
      * Keep the names of the classes in another map. This is needed for a 
multi-classloader environment where it is possible
      * to have Class 'Foo' loaded by a classloader and then get asked to 
introspect on 'Foo' from another class loader. While these
      * two Class objects have the same name, a 
<code>classMethodMaps.get(Foo.class)</code> will return null. For that case, we
@@ -73,13 +79,14 @@ public final class IntrospectorCacheImpl
         synchronized (classMapCache)
         {
             classMapCache.clear();
+            classFieldMapCache.clear();
             classNameCache.clear();
             log.debug(CACHEDUMP_MSG);
         }
     }
 
     /**
-     * Lookup a given Class object in the cache. If it does not exist, 
+     * Lookup a given Class object in the cache. If it does not exist,
      * check whether this is due to a class change and purge the caches
      * eventually.
      *
@@ -114,6 +121,41 @@ public final class IntrospectorCacheImpl
     }
 
     /**
+     * Lookup a given Class object in the cache. If it does not exist,
+     * check whether this is due to a class change and purge the caches
+     * eventually.
+     *
+     * @param c The class to look up.
+     * @return A ClassFieldMap object or null if it does not exist in the 
cache.
+     */
+    public ClassFieldMap getFieldMap(final Class c)
+    {
+        if (c == null)
+        {
+            throw new IllegalArgumentException("class is null!");
+        }
+
+        ClassFieldMap classFieldMap = (ClassFieldMap)classFieldMapCache.get(c);
+        if (classFieldMap == null)
+        {
+            /*
+             * check to see if we have it by name.
+             * if so, then we have an object with the same
+             * name but loaded through a different class loader.
+             * In that case, we will just dump the cache to be sure.
+             */
+            synchronized (classMapCache)
+            {
+                if (classNameCache.contains(c.getName()))
+                {
+                    clear();
+                }
+            }
+        }
+        return classFieldMap;
+    }
+
+    /**
      * Creates a class map for specific class and registers it in the
      * cache.  Also adds the qualified name to the name-&gt;class map
      * for later Classloader change detection.
@@ -124,9 +166,11 @@ public final class IntrospectorCacheImpl
     public ClassMap put(final Class c)
     {
         final ClassMap classMap = new ClassMap(c, log);
+        final ClassFieldMap classFieldMap = new ClassFieldMap(c, log);
         synchronized (classMapCache)
         {
             classMapCache.put(c, classMap);
+            classFieldMapCache.put(c, classFieldMap);
             classNameCache.add(c.getName());
         }
         return classMap;

Added: 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java?rev=1329799&view=auto
==============================================================================
--- 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
 (added)
+++ 
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectPublicFields.java
 Tue Apr 24 15:41:21 2012
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.velocity.util.introspection;
+
+import java.util.Iterator;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.runtime.parser.node.PublicFieldExecutor;
+import org.apache.velocity.runtime.parser.node.SetPublicFieldExecutor;
+import org.apache.velocity.util.introspection.UberspectImpl.VelGetterImpl;
+import org.apache.velocity.util.introspection.UberspectImpl.VelSetterImpl;
+
+/**
+ * Implementation of Uberspect to additionally provide access to public fields.
+ *
+ * @author <a href="mailto:ge...@optonline.net";>Geir Magnusson Jr.</a>
+ * @author <a href="mailto:henn...@apache.org";>Henning P. Schmiedehausen</a>
+ * @author <a href="mailto:cda...@cdauth.eu";>Candid Dauth</a>
+ */
+public class UberspectPublicFields implements Uberspect, UberspectLoggable
+{
+    /**
+     *  Our runtime logger.
+     */
+    protected Log log;
+
+    /**
+     *  the default Velocity introspector
+     */
+    protected Introspector introspector;
+
+    /**
+     *  init - generates the Introspector. As the setup code
+     *  makes sure that the log gets set before this is called,
+     *  we can initialize the Introspector using the log object.
+     */
+    public void init()
+    {
+        introspector = new Introspector(log);
+    }
+
+    /**
+     *  Sets the runtime logger - this must be called before anything
+     *  else.
+     *
+     * @param log The logger instance to use.
+     * @since 1.5
+     */
+    public void setLog(Log log)
+    {
+        this.log = log;
+    }
+
+    /**
+     * Property getter
+     * @param obj
+     * @param identifier
+     * @param i
+     * @return A Velocity Getter Method.
+     * @throws Exception
+     */
+    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
+    {
+        if (obj == null)
+        {
+            return null;
+        }
+
+        Class claz = obj.getClass();
+
+        PublicFieldExecutor executor = new PublicFieldExecutor(log, 
introspector, claz, identifier);
+
+        return (executor.isAlive()) ? new VelGetterImpl(executor) : null;
+    }
+
+    /**
+     * Property setter
+     * @param obj
+     * @param identifier
+     * @param arg
+     * @param i
+     * @return A Velocity Setter method.
+     * @throws Exception
+     */
+    public VelPropertySet getPropertySet(Object obj, String identifier, Object 
arg, Info i)
+    {
+        if (obj == null)
+        {
+            return null;
+        }
+
+        Class claz = obj.getClass();
+
+        SetPublicFieldExecutor executor = new SetPublicFieldExecutor(log, 
introspector, claz, identifier, arg);
+
+        return (executor.isAlive()) ? new VelSetterImpl(executor) : null;
+    }
+
+    public Iterator getIterator(Object obj, Info info)
+    {
+        return null;
+    }
+
+    public VelMethod getMethod(Object obj, String method, Object[] args, Info 
info)
+    {
+        return null;
+    }
+
+}


Reply via email to