You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2008/08/21 15:29:01 UTC

svn commit: r687752 - in /velocity/engine/trunk: src/java/org/apache/velocity/runtime/ src/java/org/apache/velocity/util/introspection/ src/test/org/apache/velocity/test/util/introspection/ xdocs/docs/

Author: cbrisson
Date: Thu Aug 21 06:28:59 2008
New Revision: 687752

URL: http://svn.apache.org/viewvc?rev=687752&view=rev
Log:
Uberspectors chaining, plus default automatic chaining for non chainable uberspectors

Added:
    velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/AbstractChainableUberspector.java
    velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/ChainableUberspector.java
    velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/LinkingUberspector.java
    velocity/engine/trunk/src/test/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java
Modified:
    velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
    velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
    velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
    velocity/engine/trunk/xdocs/docs/developer-guide.xml

Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=687752&r1=687751&r2=687752&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java Thu Aug 21 06:28:59 2008
@@ -288,7 +288,7 @@
     /** Default Encoding is ISO-8859-1. */
     String ENCODING_DEFAULT = "ISO-8859-1";
 
-    /** key name for uberspector. */
+    /** key name for uberspector. Multiple classnames can be specified,in which case uberspectors will be chained. */
     String UBERSPECT_CLASSNAME = "runtime.introspector.uberspect";
 
     /** A comma separated list of packages to restrict access to in the SecureIntrospector. */

Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java?rev=687752&r1=687751&r2=687752&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java Thu Aug 21 06:28:59 2008
@@ -63,6 +63,8 @@
 import org.apache.velocity.util.introspection.Introspector;
 import org.apache.velocity.util.introspection.Uberspect;
 import org.apache.velocity.util.introspection.UberspectLoggable;
+import org.apache.velocity.util.introspection.ChainableUberspector;
+import org.apache.velocity.util.introspection.LinkingUberspector;
 
 /**
  * This is the Runtime system for Velocity. It is the
@@ -302,10 +304,10 @@
     private void initializeIntrospection()
         throws Exception
     {
-        String rm = getString(RuntimeConstants.UBERSPECT_CLASSNAME);
-
-        if (rm != null && rm.length() > 0)
+        String[] uberspectors = configuration.getStringArray(RuntimeConstants.UBERSPECT_CLASSNAME);
+        for (int i=0; i <uberspectors.length;i++)
         {
+            String rm = uberspectors[i];
             Object o = null;
 
             try
@@ -330,32 +332,52 @@
                 throw new Exception(err);
             }
 
-            uberSpect = (Uberspect) o;
+            Uberspect u = (Uberspect)o;
 
-            if (uberSpect instanceof UberspectLoggable)
+            if (u instanceof UberspectLoggable)
             {
-                ((UberspectLoggable) uberSpect).setLog(getLog());
+                ((UberspectLoggable)u).setLog(getLog());
             }
 
-            if (uberSpect instanceof RuntimeServicesAware)
+            if (u instanceof RuntimeServicesAware)
             {
-                ((RuntimeServicesAware) uberSpect).setRuntimeServices(this);
+                ((RuntimeServicesAware)u).setRuntimeServices(this);
             }
-            
-            uberSpect.init();
-         }
-         else
-         {
-            /*
-             *  someone screwed up.  Lets not fool around...
-             */
 
-            String err = "It appears that no class was specified as the"
-            + " Uberspect.  Please ensure that all configuration"
-            + " information is correct.";
+            if (uberSpect == null)
+            {
+                uberSpect = u;
+            }
+            else
+            {
+                if (u instanceof ChainableUberspector)
+                {
+                    ((ChainableUberspector)u).wrap(uberSpect);
+                    uberSpect = u;
+                }
+                else
+                {
+                    uberSpect = new LinkingUberspector(uberSpect,u);
+                }
+            }
+        }
 
-            log.error(err);
-            throw new Exception(err);
+        if(uberSpect != null)
+        {
+            uberSpect.init();
+        }
+        else
+        {
+           /*
+            *  someone screwed up.  Lets not fool around...
+            */
+
+           String err = "It appears that no class was specified as the"
+           + " Uberspect.  Please ensure that all configuration"
+           + " information is correct.";
+
+           log.error(err);
+           throw new Exception(err);
         }
     }
 

Added: velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/AbstractChainableUberspector.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/AbstractChainableUberspector.java?rev=687752&view=auto
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/AbstractChainableUberspector.java (added)
+++ velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/AbstractChainableUberspector.java Thu Aug 21 06:28:59 2008
@@ -0,0 +1,109 @@
+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.util.Iterator;
+
+/**
+ * Default implementation of a {@link ChainableUberspector chainable uberspector} that forwards all calls to the wrapped
+ * uberspector (when that is possible). It should be used as the base class for all chainable uberspectors.
+ * 
+ * @version $Id: $
+ * @since 1.6
+ * @see ChainableUberspector
+ */
+public abstract class AbstractChainableUberspector extends UberspectImpl implements ChainableUberspector
+{
+    /** The wrapped (decorated) uberspector. */
+    protected Uberspect inner;
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see ChainableUberspector#wrap(org.apache.velocity.util.introspection.Uberspect)
+     * @see #inner
+     */
+    public void wrap(Uberspect inner)
+    {
+        this.inner = inner;
+    }
+
+    /**
+     * init - the chainable uberspector is responsible for the initialization of the wrapped uberspector
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#init()
+     */
+    //@Override
+    public void init() throws Exception
+    {
+        if (this.inner != null) {
+            this.inner.init();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getIterator(java.lang.Object,
+     *      org.apache.velocity.util.introspection.Info)
+     */
+    //@SuppressWarnings("unchecked")
+    //@Override
+    public Iterator getIterator(Object obj, Info i) throws Exception
+    {
+        return (this.inner != null) ? this.inner.getIterator(obj, i) : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getMethod(java.lang.Object, java.lang.String,
+     *      java.lang.Object[], org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception
+    {
+        return (this.inner != null) ? this.inner.getMethod(obj, methodName, args, i) : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getPropertyGet(java.lang.Object, java.lang.String,
+     *      org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception
+    {
+        return (this.inner != null) ? this.inner.getPropertyGet(obj, identifier, i) : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getPropertySet(java.lang.Object, java.lang.String,
+     *      java.lang.Object, org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception
+    {
+        return (this.inner != null) ? this.inner.getPropertySet(obj, identifier, arg, i) : null;
+    }
+}

Added: velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/ChainableUberspector.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/ChainableUberspector.java?rev=687752&view=auto
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/ChainableUberspector.java (added)
+++ velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/ChainableUberspector.java Thu Aug 21 06:28:59 2008
@@ -0,0 +1,37 @@
+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.
+ */
+
+/**
+ * Interface that marks uberspectors as chainable, meaning that multiple uberspectors can be
+ * combined in a chain (using the Decorator pattern).
+ * 
+ * @version $Id: $
+ * @since 1.6
+ */
+public interface ChainableUberspector extends Uberspect
+{
+    /**
+     * Specify the decorated Uberspector
+     * 
+     * @param inner The decorated uberspector.
+     */
+    public void wrap(Uberspect inner);
+}

Added: velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/LinkingUberspector.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/LinkingUberspector.java?rev=687752&view=auto
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/LinkingUberspector.java (added)
+++ velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/LinkingUberspector.java Thu Aug 21 06:28:59 2008
@@ -0,0 +1,101 @@
+package org.apache.velocity.util.introspection;
+
+import java.util.Iterator;
+
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.util.RuntimeServicesAware;
+
+/**
+ * <p>
+ * When the runtime.introspection.uberspect configuration property contains several
+ * uberspector class names, it means those uberspectors will be chained. When an
+ * uberspector in the list other than the leftmost does not implement ChainableUberspector,
+ * then this utility class is used to provide a basic default chaining where the
+ * first non-null result is kept for each introspection call.
+ * </p>
+ * 
+ * @since 1.5RC1
+ * @see ChainableUberspector
+ * @version $Id: LinkingUberspector.java 10959 2008-07-01 00:12:29Z sdumitriu $
+ */
+public class LinkingUberspector extends AbstractChainableUberspector
+{
+    private Uberspect leftUberspect;
+    private Uberspect rightUberspect;
+
+    /**
+     * Constructor that takes the two uberspectors to link
+     */
+    public LinkingUberspector(Uberspect left,Uberspect right) {
+        leftUberspect = left;
+        rightUberspect = right;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Init both wrapped uberspectors
+     * </p>
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#init()
+     */
+    //@Override
+    public void init() throws Exception
+    {
+        leftUberspect.init();
+        rightUberspect.init();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getIterator(java.lang.Object,
+     *      org.apache.velocity.util.introspection.Info)
+     */
+    //@SuppressWarnings("unchecked")
+    //@Override
+    public Iterator getIterator(Object obj, Info i) throws Exception
+    {
+        Iterator it = leftUberspect.getIterator(obj,i);
+        return it != null ? it : rightUberspect.getIterator(obj,i);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getMethod(java.lang.Object, java.lang.String,
+     *      java.lang.Object[], org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception
+    {
+        VelMethod method = leftUberspect.getMethod(obj,methodName,args,i);
+        return method != null ? method : rightUberspect.getMethod(obj,methodName,args,i);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getPropertyGet(java.lang.Object, java.lang.String,
+     *      org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception
+    {
+        VelPropertyGet getter = leftUberspect.getPropertyGet(obj,identifier,i);
+        return getter != null ? getter : rightUberspect.getPropertyGet(obj,identifier,i);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.apache.velocity.util.introspection.Uberspect#getPropertySet(java.lang.Object, java.lang.String,
+     *      java.lang.Object, org.apache.velocity.util.introspection.Info)
+     */
+    //@Override
+    public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception
+    {
+        VelPropertySet setter = leftUberspect.getPropertySet(obj,identifier,arg,i);
+        return setter != null ? setter : rightUberspect.getPropertySet(obj,identifier,arg,i);
+    }
+}

Modified: velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java?rev=687752&r1=687751&r2=687752&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java Thu Aug 21 06:28:59 2008
@@ -67,7 +67,7 @@
      *  makes sure that the log gets set before this is called,
      *  we can initialize the Introspector using the log object.
      */
-    public void init()
+    public void init() throws Exception
     {
         introspector = new Introspector(log);
     }

Added: velocity/engine/trunk/src/test/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java?rev=687752&view=auto
==============================================================================
--- velocity/engine/trunk/src/test/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java (added)
+++ velocity/engine/trunk/src/test/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java Thu Aug 21 06:28:59 2008
@@ -0,0 +1,93 @@
+package org.apache.velocity.test.util.introspection;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.runtime.log.NullLogChute;
+import org.apache.velocity.util.introspection.*;
+import org.apache.velocity.test.BaseTestCase;
+import org.apache.velocity.VelocityContext;
+
+import java.io.StringWriter;
+
+/**
+ * Tests uberspectors chaining
+ */
+public class ChainedUberspectorsTestCase extends BaseTestCase {
+
+    public ChainedUberspectorsTestCase(String name)
+    	throws Exception
+    {
+        super(name);
+    }
+
+    public static Test suite()
+    {
+        return new TestSuite(ChainedUberspectorsTestCase.class);
+    }
+
+    public void setUp()
+            throws Exception
+    {
+        Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, NullLogChute.class.getName());
+        Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.util.introspection.UberspectImpl");
+        Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.test.util.introspection.ChainedUberspectorsTestCase$ChainedUberspector");
+        Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.test.util.introspection.ChainedUberspectorsTestCase$LinkedUberspector");
+	    Velocity.init();
+    }
+
+    public void tearDown()
+    {
+    }
+
+    public void testChaining()
+    	throws Exception
+    {
+        VelocityContext context = new VelocityContext();
+        context.put("foo",new Foo());
+        StringWriter writer = new StringWriter();
+
+        Velocity.evaluate(context,writer,"test","$foo.zeMethod()");
+        assertEquals(writer.toString(),"ok");
+
+        Velocity.evaluate(context,writer,"test","#set($foo.foo = 'someValue')");
+
+        writer = new StringWriter();
+        Velocity.evaluate(context,writer,"test","$foo.bar");
+        assertEquals(writer.toString(),"someValue");
+
+        writer = new StringWriter();
+        Velocity.evaluate(context,writer,"test","$foo.foo");
+        assertEquals(writer.toString(),"someValue");
+    }
+
+    // replaces getFoo by getBar
+    public static class ChainedUberspector extends AbstractChainableUberspector
+    {
+        public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info info) throws Exception
+        {
+            identifier = identifier.replaceAll("foo","bar");
+            return inner.getPropertySet(obj,identifier,arg,info);
+        }
+    }
+
+    // replaces setFoo by setBar
+    public static class LinkedUberspector extends UberspectImpl
+    {
+        public VelPropertyGet getPropertyGet(Object obj, String identifier, Info info) throws Exception
+        {
+            identifier = identifier.replaceAll("foo","bar");
+            return super.getPropertyGet(obj,identifier,info);
+        }
+    }
+
+    public static class Foo
+    {
+        private String bar;
+
+        public String zeMethod() { return "ok"; }
+        public String getBar() { return bar; }
+        public void setBar(String s) { bar = s; }
+    }
+
+}

Modified: velocity/engine/trunk/xdocs/docs/developer-guide.xml
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/xdocs/docs/developer-guide.xml?rev=687752&r1=687751&r2=687752&view=diff
==============================================================================
--- velocity/engine/trunk/xdocs/docs/developer-guide.xml (original)
+++ velocity/engine/trunk/xdocs/docs/developer-guide.xml Thu Aug 21 06:28:59 2008
@@ -1892,9 +1892,14 @@
 org.apache.velocity.util.introspection.UberspectImpl</code>
 <br/>
 This property sets the 'Uberspector', the introspection package that
-handles all introspection strategies for Velocity.  The default works just
-fine, so only replace if you have something really interesting and special
-to do.
+handles all introspection strategies for Velocity. You can specify a
+coma-separated list of Uberspector classes, in which case all Uberspectors are
+chained. The default chaining behaviour is to return the first non-null value
+for each introspection call among all provided uberspectors. You can modify
+this behaviour (for instance to restrict access to some methods) by subclassing
+org.apache.velocity.util.introspection.AbstractChainableUberspector (or
+implementing directly
+org.apache.velocity.util.introspection.ChainableUberspector).
 </p>
 
 </section>