Author: henning
Date: Wed Sep  6 08:37:44 2006
New Revision: 440737

URL: http://svn.apache.org/viewvc?view=rev&rev=440737
Log:
remodel the whole getPropertySet framework to look like the getPropertyGet 
framework. Modularize
the method look-ups using Executors. This fixes most of the issues of 
VELOCITY-456 and also in
a rare double-whammy patch, it also resolves the issues of VELOCITY-449.

Added:
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
   (with props)
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
   (with props)
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
   (with props)
Modified:
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/GetExecutor.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
    
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/GetExecutor.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/GetExecutor.java?view=diff&rev=440737&r1=440736&r2=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/GetExecutor.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/GetExecutor.java
 Wed Sep  6 08:37:44 2006
@@ -1,6 +1,6 @@
 package org.apache.velocity.runtime.parser.node;
 /*
- * Copyright 2000-2004 The Apache Software Foundation.
+ * Copyright 2000-2006 The Apache Software Foundation.
  *
  * Licensed under the Apache License, Version 2.0 (the "License")
  * you may not use this file except in compliance with the License.
@@ -37,8 +37,9 @@
  */
 public class GetExecutor extends AbstractExecutor
 {
-    private Introspector introspector = null;
+    private final Introspector introspector;
 
+    // This is still threadsafe because this object is only read except in the 
C'tor. 
     private Object [] params = {};
 
     public GetExecutor(final Log log, final Introspector introspector,
@@ -56,8 +57,7 @@
 
         if (property != null)
         {
-            this.params = new Object[1];
-            this.params[0] = property;
+            this.params = new Object[] { property };
         }
         discover(clazz);
     }

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java?view=diff&rev=440737&r1=440736&r2=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PropertyExecutor.java
 Wed Sep  6 08:37:44 2006
@@ -1,6 +1,6 @@
 package org.apache.velocity.runtime.parser.node;
 /*
- * Copyright 2000-2004 The Apache Software Foundation.
+ * Copyright 2000-2006 The Apache Software Foundation.
  *
  * Licensed under the Apache License, Version 2.0 (the "License")
  * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
  */
 public class PropertyExecutor extends AbstractExecutor
 {
-    private Introspector introspector = null;
+    private final Introspector introspector;
 
     public PropertyExecutor(final Log log, final Introspector introspector,
             final Class clazz, final String property)

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java?view=auto&rev=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
 Wed Sep  6 08:37:44 2006
@@ -0,0 +1,113 @@
+package org.apache.velocity.runtime.parser.node;
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.InvocationTargetException;
+
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+
+/**
+ * Executor that simply tries to execute a put(key, value)
+ * operation. This will try to find a put(key) method
+ * for any type of object, not just objects that
+ * implement the Map interface as was previously
+ * the case.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public class PutExecutor extends SetExecutor
+{
+    private final Introspector introspector;
+    private final String property;
+
+    public PutExecutor(final Log log, final Introspector introspector,
+            final Class clazz, final Object arg, final String property)
+    {
+        this.log = log;
+        this.introspector = introspector;
+        this.property = property;
+
+        discover(clazz, arg);
+    }
+
+    protected void discover(final Class clazz, final Object arg)
+    {
+        Object [] params;
+
+        // If you passed in null as property, we don't use the value
+        // for parameter lookup. Instead we just look for put(Object) without
+        // any parameters.
+        //
+        // In any other case, the following condition will set up an array
+        // for looking up put(String, Object) on the class.
+
+        if (property == null)
+        {
+            // The passed in arg object is used by the Cache to look up the 
method.
+            params = new Object[] { arg };
+        }
+        else
+        {
+            params = new Object[] { property, arg };
+        }
+
+        try
+        {
+            setMethod(introspector.getMethod(clazz, "put", params));
+        }
+        /**
+         * pass through application level runtime exceptions
+         */
+        catch( RuntimeException e )
+        {
+            throw e;
+        }
+        catch(Exception e)
+        {
+            log.error("While looking for put('" + params[0] + "') method:", e);
+        }
+    }
+
+    /**
+     * Execute method against context.
+     */
+    public Object execute(final Object o, final Object value)
+        throws IllegalAccessException,  InvocationTargetException
+    {
+        Object [] params;
+
+        if (isAlive())
+        {
+            // If property != null, pass in the name for put(key, value). Else 
just put(value).
+            if (property == null)
+            {
+                params = new Object [] { value };
+            }
+            else
+            {
+                params = new Object [] { property, value };
+            }
+
+            return getMethod().invoke(o, params);
+        }
+
+        return null;
+    }
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/PutExecutor.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java?view=auto&rev=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
 Wed Sep  6 08:37:44 2006
@@ -0,0 +1,71 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.velocity.runtime.log.Log;
+
+/**
+ * Abstract class that is used to execute an arbitrary
+ * method that is in introspected. This is the superclass
+ * for the PutExecutor and SetPropertyExecutor.
+ *
+ * There really should be a superclass for this and AbstractExecutor (which 
should
+ * be refactored to GetExecutor) because they differ only in the execute() 
method.
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public abstract class SetExecutor
+{
+    protected Log log = null;
+    
+    /**
+     * Method to be executed.
+     */
+    private Method method = null;
+    
+    /**
+     * Execute method against context.
+     */
+    public abstract Object execute(Object o, Object value)
+         throws IllegalAccessException, InvocationTargetException;
+
+    /**
+     * Tell whether the executor is alive by looking
+     * at the value of the method.
+     */
+    public boolean isAlive()
+    {
+        return (method != null);
+    }
+
+    public Method getMethod()
+    {
+        return method;
+    }
+
+    protected void setMethod(final Method method)
+    {
+        this.method = method;
+    }
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetExecutor.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java?view=auto&rev=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
 (added)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
 Wed Sep  6 08:37:44 2006
@@ -0,0 +1,109 @@
+package org.apache.velocity.runtime.parser.node;
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.InvocationTargetException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.util.introspection.Introspector;
+
+/**
+ * Executor for looking up property names in the passed in class
+ * This will try to find a set&lt;foo&gt;(key, value) method
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public class SetPropertyExecutor
+        extends SetExecutor
+{
+    private final Introspector introspector;
+
+    public SetPropertyExecutor(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);
+        }
+    }
+
+    protected Introspector getIntrospector()
+    {
+        return this.introspector;
+    }
+
+    protected void discover(final Class clazz, final String property, final 
Object arg)
+    {
+        Object [] params = new Object [] { arg };
+
+        try
+        {
+            StringBuffer sb = new StringBuffer("set");
+            sb.append(property);
+
+            setMethod(introspector.getMethod(clazz, sb.toString(), params));
+
+            if (!isAlive())
+            {
+                /*
+                 *  now the convenience, flip the 1st character
+                 */
+
+                char c = sb.charAt(3);
+
+                if (Character.isLowerCase(c))
+                {
+                    sb.setCharAt(3, Character.toUpperCase(c));
+                }
+                else
+                {
+                    sb.setCharAt(3, Character.toLowerCase(c));
+                }
+
+                setMethod(introspector.getMethod(clazz, sb.toString(), 
params));
+            }
+        }
+        /**
+         * pass through application level runtime exceptions
+         */
+        catch( RuntimeException e )
+        {
+            throw e;
+        }
+        catch(Exception e)
+        {
+            log.error("While looking for property setter for '" + property + 
"':", e);
+        }
+    }
+
+    /**
+     * Execute method against context.
+     */
+    public Object execute(final Object o, final Object value)
+        throws IllegalAccessException,  InvocationTargetException
+    {
+        Object [] params = new Object [] { value };
+        return isAlive() ? getMethod().invoke(o, params) : null;
+    }
+}

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SetPropertyExecutor.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Modified: 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
URL: 
http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java?view=diff&rev=440737&r1=440736&r2=440737
==============================================================================
--- 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
 (original)
+++ 
jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
 Wed Sep  6 08:37:44 2006
@@ -17,18 +17,21 @@
  */
 
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.Map;
+
+import org.apache.velocity.runtime.RuntimeLogger;
 import org.apache.velocity.runtime.log.Log;
 import org.apache.velocity.runtime.log.RuntimeLoggerLog;
-import org.apache.velocity.runtime.RuntimeLogger;
 import org.apache.velocity.runtime.parser.node.AbstractExecutor;
 import org.apache.velocity.runtime.parser.node.BooleanPropertyExecutor;
 import org.apache.velocity.runtime.parser.node.GetExecutor;
 import org.apache.velocity.runtime.parser.node.PropertyExecutor;
+import org.apache.velocity.runtime.parser.node.PutExecutor;
+import org.apache.velocity.runtime.parser.node.SetExecutor;
+import org.apache.velocity.runtime.parser.node.SetPropertyExecutor;
 import org.apache.velocity.util.ArrayIterator;
 import org.apache.velocity.util.EnumerationIterator;
 
@@ -37,6 +40,7 @@
  *  functionality of Velocity
  *
  * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a>
  * @version $Id$
  */
 public class UberspectImpl implements Uberspect, UberspectLoggable
@@ -140,7 +144,9 @@
             throws Exception
     {
         if (obj == null)
+        {
             return null;
+        }
 
         Method m = introspector.getMethod(obj.getClass(), methodName, args);
 
@@ -164,7 +170,7 @@
          *  first try for a getFoo() type of property
          *  (also getfoo() )
          */
-        AbstractExecutor executor = new PropertyExecutor(log,introspector, 
claz, identifier);
+        AbstractExecutor executor = new PropertyExecutor(log, introspector, 
claz, identifier);
 
         /*
          *  if that didn't work, look for get("foo")
@@ -195,66 +201,29 @@
                                          Object arg, Info i)
             throws Exception
     {
-        Class claz = obj.getClass();
-
-        VelMethod vm = null;
-        try
+        if (obj == null)
         {
-            /*
-             *  first, we introspect for the set<identifier> setter method
-             */
-
-            Object[] params = {arg};
-
-            try
-            {
-                vm = getMethod(obj, "set" + identifier, params, i);
-
-                if (vm == null)
-                {
-                   throw new NoSuchMethodException();
-                }
-            }
-            catch(NoSuchMethodException nsme2)
-            {
-                StringBuffer sb = new StringBuffer("set");
-                sb.append(identifier);
-
-                if (Character.isLowerCase( sb.charAt(3)))
-                {
-                    sb.setCharAt(3, Character.toUpperCase(sb.charAt(3)));
-                }
-                else
-                {
-                    sb.setCharAt(3, Character.toLowerCase(sb.charAt(3)));
-                }
-
-                vm = getMethod(obj, sb.toString(), params, i);
-
-                if (vm == null)
-                {
-                   throw new NoSuchMethodException();
-                }
-            }
+            return null;
         }
-        catch (NoSuchMethodException nsme)
-        {
-            /*
-             *  right now, we only support the Map interface
-             */
+        
+        Class claz = obj.getClass();
 
-            if (Map.class.isAssignableFrom(claz))
-            {
-                Object[] params = {new Object(), new Object()};
+        /*
+         *  first try for a setFoo() type of property
+         *  (also setfoo() )
+         */
+        SetExecutor executor = new SetPropertyExecutor(log, introspector, 
claz, identifier, arg);
 
-                vm = getMethod(obj, "put", params, i);
+        /*
+         *  if that didn't work, look for put("foo", arg)
+         */
 
-                if (vm!=null)
-                    return new VelSetterImpl(vm, identifier);
-            }
-       }
+        if (!executor.isAlive())
+        {
+            executor = new PutExecutor(log, introspector, claz, arg, 
identifier);
+        }
 
-       return (vm!=null) ?  new VelSetterImpl(vm) : null;
+        return (executor.isAlive()) ? new VelSetterImpl(executor) : null;
     }
 
     /**
@@ -262,7 +231,7 @@
      */
     public static class VelMethodImpl implements VelMethod
     {
-        Method method = null;
+        final Method method;
 
         public VelMethodImpl(Method m)
         {
@@ -271,6 +240,7 @@
 
         private VelMethodImpl()
         {
+            method = null;
         }
 
         public Object invoke(Object o, Object[] params)
@@ -297,21 +267,22 @@
 
     public static class VelGetterImpl implements VelPropertyGet
     {
-        AbstractExecutor ae = null;
+        final AbstractExecutor getExecutor;
 
         public VelGetterImpl(AbstractExecutor exec)
         {
-            ae = exec;
+            getExecutor = exec;
         }
 
         private VelGetterImpl()
         {
+            getExecutor = null;
         }
 
         public Object invoke(Object o)
             throws Exception
         {
-            return ae.execute(o);
+            return getExecutor.execute(o);
         }
 
         public boolean isCacheable()
@@ -321,46 +292,34 @@
 
         public String getMethodName()
         {
-            return ae.getMethod().getName();
+            return getExecutor.isAlive() ? getExecutor.getMethod().getName() : 
null;
         }
     }
 
     public static class VelSetterImpl implements VelPropertySet
     {
-        VelMethod vm = null;
-        String putKey = null;
+        private final SetExecutor setExecutor;
 
-        public VelSetterImpl(VelMethod velmethod)
+        public VelSetterImpl(final SetExecutor setExecutor)
         {
-            this.vm = velmethod;
-        }
-
-        public VelSetterImpl(VelMethod velmethod, String key)
-        {
-            this.vm = velmethod;
-            putKey = key;
+            this.setExecutor = setExecutor;
         }
 
         private VelSetterImpl()
         {
+            setExecutor = null;
         }
 
-        public Object invoke(Object o, Object value)
+        /**
+         * Invoke the found Set Executor.
+         *
+         * @param o is the Object to invoke it on.
+         * @param value in the Value to set.
+         */
+        public Object invoke(final Object o, final Object value)
             throws Exception
         {
-            ArrayList al = new ArrayList();
-
-            if (putKey != null)
-            {
-                al.add(putKey);
-                al.add(value);
-            }
-            else
-            {
-                al.add(value);
-            }
-
-            return vm.invoke(o,al.toArray());
+            return setExecutor.execute(o, value);
         }
 
         public boolean isCacheable()
@@ -370,7 +329,7 @@
 
         public String getMethodName()
         {
-            return vm.getMethodName();
+            return setExecutor.isAlive() ? setExecutor.getMethod().getName() : 
null;
         }
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to