You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by he...@apache.org on 2006/11/19 23:22:44 UTC

svn commit: r476951 - in /jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection: Introspector.java IntrospectorBase.java IntrospectorCache.java IntrospectorCacheImpl.java IntrospectorCacheListener.java

Author: henning
Date: Sun Nov 19 14:22:43 2006
New Revision: 476951

URL: http://svn.apache.org/viewvc?view=rev&rev=476951
Log:
Factor out the Introspector cache. Add a cache listener interface and also
an interface definition for the Cache itself. Move all functionality into
the cache class, leaving Introspector and IntrospectorBase as very lean
classes. This shouldn't actually change too much of our public interface, but
a lot of the protected methods, but they were never part of our API anyway.

This change allows Velocity users to register listeners to the Cache and react
on events. There is now also a clear definition on what the Cache must implement
to be pluggable (what is still missing is actual lookup of the implementation class
from properties. Shouldn't be too hard to do.

First steps in the direction of fixing VELTOOLS-66 once and for all.

Added:
    jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java   (with props)
    jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java   (with props)
    jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java   (with props)
Modified:
    jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java
    jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java

Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java
URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java?view=diff&rev=476951&r1=476950&r2=476951
==============================================================================
--- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java (original)
+++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/Introspector.java Sun Nov 19 14:22:43 2006
@@ -142,12 +142,11 @@
     }
 
     /**
-     * Clears the classmap and classname
-     * caches, and logs that we did so
+     * Logs that the Introspector Cache has been cleared.
      */
-    protected void clearCache()
+    public void triggerClear()
     {
-        super.clearCache();
+	super.triggerClear();
         log.info(CACHEDUMP_MSG);
     }
 }

Modified: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java
URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java?view=diff&rev=476951&r1=476950&r2=476951
==============================================================================
--- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java (original)
+++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorBase.java Sun Nov 19 14:22:43 2006
@@ -19,22 +19,16 @@
  * under the License.    
  */
 
-import java.util.Map;
-import java.util.Set;
-import java.util.HashMap;
-import java.util.HashSet;
-
 import java.lang.reflect.Method;
 
 /**
- * This basic function of this class is to return a Method
- * object for a particular class given the name of a method
- * and the parameters to the method in the form of an Object[]
+ * Lookup a a Method object for a particular class given the name of a method
+ * and its parameters.
  *
  * The first time the Introspector sees a
  * class it creates a class method map for the
  * class in question. Basically the class method map
- * is a Hastable where Method objects are keyed by a
+ * is a Hashtable where Method objects are keyed by a
  * concatenation of the method name and the names of
  * classes that make up the parameters.
  *
@@ -47,28 +41,29 @@
  * "method" + "java.lang.String" + "java.lang.StringBuffer"
  *
  * This mapping is performed for all the methods in a class
- * and stored for
+ * and stored for.
  * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
  * @author <a href="mailto:bob@werken.com">Bob McWhirter</a>
  * @author <a href="mailto:szegedia@freemail.hu">Attila Szegedi</a>
  * @author <a href="mailto:paulo.gaspar@krankikom.de">Paulo Gaspar</a>
- * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
+o * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
  * @version $Id$
  */
-public class IntrospectorBase
+public abstract class IntrospectorBase
+	implements IntrospectorCacheListener
 {
+    /** The Introspector Cache */
+    private final IntrospectorCache introspectorCache;
+    
     /**
-     * Holds the method maps for the classes we know about, keyed by
-     * Class object.
-     */
-    private final Map classMethodMaps = new HashMap();
-
-    /**
-     * Holds the qualified class names for the classes
-     * we hold in the classMethodMaps hash
+     * C'tor.
      */
-    private final Set cachedClassNames = new HashSet();
-
+    protected IntrospectorBase()
+    {
+	 introspectorCache = new IntrospectorCacheImpl(); // TODO: Load that from properties.
+	 introspectorCache.addListener(this);
+    }
+    
     /**
      * Gets the method defined by <code>name</code> and
      * <code>params</code> for the Class <code>c</code>.
@@ -97,29 +92,15 @@
 
         ClassMap classMap = null;
 
-        synchronized(classMethodMaps)
+        IntrospectorCache ic = getIntrospectorCache();
+        
+        synchronized(ic)
         {
-            classMap = (ClassMap)classMethodMaps.get(c);
-
-            /*
-             *  if we don't have this, check to see if we have it
-             *  by name.  if so, then we have a classloader change
-             *  so dump our caches.
-             */
+            classMap = ic.get(c);
 
             if (classMap == null)
             {
-                if (cachedClassNames.contains(c.getName()))
-                {
-                    /*
-                     * we have a map for a class with same name, but not
-                     * this class we are looking at.  This implies a
-                     * classloader change, so dump
-                     */
-                    clearCache();
-                }
-
-                classMap = createClassMap(c);
+                classMap = ic.put(c);
             }
         }
 
@@ -127,53 +108,73 @@
     }
 
     /**
+     * Return the internal IntrospectorCache object.
+     * 
+     * @return The internal IntrospectorCache object.
+     */
+    protected IntrospectorCache getIntrospectorCache()
+    {
+	return introspectorCache;
+    }
+    
+    /**
+     * Clears the internal cache.
+     * 
+     * @deprecated Use getIntrospectorCache().clear();
+     */
+    protected void clearCache()
+    {
+        getIntrospectorCache().clear();
+    }
+
+    /**
      * 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.
+     *
      * @param c The class for which the class map gets generated.
      * @return A ClassMap object.
+     * 
+     * @deprecated Use getIntrospectorCache().put(c);
      */
     protected ClassMap createClassMap(final Class c)
     {
-        ClassMap classMap = new ClassMap(c);
-        classMethodMaps.put(c, classMap);
-        cachedClassNames.add(c.getName());
-
-        return classMap;
+        return getIntrospectorCache().put(c);
     }
 
     /**
-     * Clears the classmap and classname caches.
+     * 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 ClassMap object or null if it does not exist in the cache.
+     * 
+     * @deprecated Use getIntrospectorCache().get(c);
      */
-    protected void clearCache()
+    protected ClassMap lookupClassMap(final Class c)
     {
-	/*
-	 * classes extending IntrospectorBase can request these objects through the
-	 * protected getters. If we swap them out with new objects, the base class
-	 * and the extended class can actually how two different objects. Don't do this.
-	 * Make the members final and use clear() to reset the cache.
-	 */
-        classMethodMaps.clear();
-        cachedClassNames.clear();
+        return getIntrospectorCache().get(c);
     }
-
+    
     /**
-     * Access to the classMethodMaps map.
-     *
-     * @return The classMethodsMaps HashMap.
+     * @see IntrospectorCacheListener#triggerClear()
      */
-    protected Map getClassMethodMaps()
+    public void triggerClear()
+    {
+    }
+    
+    /**
+     * @see IntrospectorCacheListener#triggerGet(Class, ClassMap)
+     */
+    public void triggerGet(Class c, ClassMap classMap)
     {
-        return classMethodMaps;
     }
 
     /**
-     * Access to the list of cached class names.
-     *
-     * @return A set of names cached.
+     * @see IntrospectorCacheListener#triggerPut(Class, ClassMap)
      */
-    protected Set getCachedClassNames()
+    public void triggerPut(Class c, ClassMap classMap)
     {
-        return cachedClassNames;
     }
 }

Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java?view=auto&rev=476951
==============================================================================
--- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java (added)
+++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java Sun Nov 19 14:22:43 2006
@@ -0,0 +1,69 @@
+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.    
+ */
+
+/**
+ * The introspector cache API definition.
+ *
+ * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public interface IntrospectorCache {
+
+    /**
+     * Clears the internal cache.
+     */
+    void clear();
+
+    /**
+     * 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 ClassMap object or null if it does not exist in the cache.
+     */
+    ClassMap get(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.
+     *
+     * @param c The class for which the class map gets generated.
+     * @return A ClassMap object.
+     */
+    ClassMap put(Class c);
+
+    /**
+     * Register a Cache listener.
+     *
+     * @param listener A Cache listener object.
+     */
+    void addListener(IntrospectorCacheListener listener);
+
+    /**
+     * Remove a Cache listener.
+     *
+     * @param listener A Cache listener object.
+     */
+    void removeListener(IntrospectorCacheListener listener);
+
+}

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCache.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java?view=auto&rev=476951
==============================================================================
--- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java (added)
+++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java Sun Nov 19 14:22:43 2006
@@ -0,0 +1,156 @@
+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.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This is the internal introspector cache implementation.
+ *
+ * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public final class IntrospectorCacheImpl
+        implements IntrospectorCache
+{
+    /**
+     * Holds the method maps for the classes we know about. Map: Class --&gt; ClassMap object.
+     */
+    private final Map classMapCache = 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
+     * keep a set of class names to recognize this case.  
+     */
+    private final Set classNameCache = new HashSet();
+
+    /**
+     * Set of IntrospectorCache Listeners.
+     */
+    private final Set listeners = new HashSet();
+
+    /**
+     * C'tor
+     */
+    public IntrospectorCacheImpl()
+    {
+    }
+
+    /**
+     * Clears the internal cache.
+     */
+    public synchronized void clear()
+    {
+        classMapCache.clear();
+        classNameCache.clear();
+        for (Iterator it = listeners.iterator(); it.hasNext(); )
+        {
+            ((IntrospectorCacheListener) it.next()).triggerClear();
+        }
+    }
+
+    /**
+     * 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 ClassMap object or null if it does not exist in the cache.
+     */
+    public synchronized ClassMap get(final Class c)
+    {
+        if (c == null)
+        {
+            throw new IllegalArgumentException("class is null!");
+        }
+
+        ClassMap classMap = (ClassMap) classMapCache.get(c);
+
+        /*
+         * If we don't have this, 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.
+         */
+        
+        if (classMap == null)
+        {
+            if (classNameCache.contains(c.getName()))
+            {
+                clear();
+            }
+        }
+
+        for (Iterator it = listeners.iterator(); it.hasNext(); )
+        {
+            ((IntrospectorCacheListener) it.next()).triggerGet(c, classMap);
+        }
+
+        return classMap;
+    }
+
+    /**
+     * 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.
+     *
+     * @param c The class for which the class map gets generated.
+     * @return A ClassMap object.
+     */
+    public synchronized ClassMap put(final Class c)
+    {
+        ClassMap classMap = new ClassMap(c);
+        classMapCache.put(c, classMap);
+        classNameCache.add(c.getName());
+        
+        for (Iterator it = listeners.iterator(); it.hasNext(); )
+        {
+            ((IntrospectorCacheListener) it.next()).triggerPut(c, classMap);
+        }
+
+        return classMap;
+    }
+
+    /**
+     * Register a Cache listener.
+     *
+     * @param listener A Cache listener object.
+     */
+    public void addListener(final IntrospectorCacheListener listener)
+    {
+        listeners.add(listener);
+    }
+
+    /**
+     * Remove a Cache listener.
+     *
+     * @param listener A Cache listener object.
+     */
+    public void removeListener(final IntrospectorCacheListener listener)
+    {
+        listeners.remove(listener);
+    }
+}

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheImpl.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Added: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java
URL: http://svn.apache.org/viewvc/jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java?view=auto&rev=476951
==============================================================================
--- jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java (added)
+++ jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java Sun Nov 19 14:22:43 2006
@@ -0,0 +1,52 @@
+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 to implement for listeners to the internal Introspector cache.
+ *
+ * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
+ * @version $Id$
+ */
+public interface IntrospectorCacheListener
+{
+    /**
+     * Gets called when the Cache is cleared.
+     */
+    void triggerClear();
+
+    /**
+     * Gets called when a ClassMap is requested from the Cache.
+     *
+     * @param c The class object to look up.
+     * @param classMap The Class map to return. Might be null.
+     */
+    void triggerGet(Class c, ClassMap classMap);
+
+    /**
+     * Gets called when a ClassMap is put into the Cache.
+     *
+     * @param c The class object to look up.
+     * @param classMap The Class map stored in the Cache. Is never null.
+     */
+    void triggerPut(Class c, ClassMap classMap);
+}
+
+

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/IntrospectorCacheListener.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@velocity.apache.org
For additional commands, e-mail: dev-help@velocity.apache.org


Re: svn commit: r476951 - in /jakarta/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection: Introspector.java IntrospectorBase.java IntrospectorCache.java IntrospectorCacheImpl.java IntrospectorCacheListener.java

Posted by Nathan Bubna <nb...@gmail.com>.
On 11/19/06, henning@apache.org <he...@apache.org> wrote:
> Author: henning
> Date: Sun Nov 19 14:22:43 2006
> New Revision: 476951
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=476951
> Log:
> Factor out the Introspector cache. Add a cache listener interface and also
> an interface definition for the Cache itself. Move all functionality into
> the cache class, leaving Introspector and IntrospectorBase as very lean
> classes. This shouldn't actually change too much of our public interface, but
> a lot of the protected methods, but they were never part of our API anyway.

Let's make sure this is documented clearly.  Changing protected
methods is always fine in my book as long as it is noted in release
notes and the change log so that any advanced users messing around
with them are warned.

> This change allows Velocity users to register listeners to the Cache and react
> on events. There is now also a clear definition on what the Cache must implement
> to be pluggable (what is still missing is actual lookup of the implementation class
> from properties. Shouldn't be too hard to do.
>
> First steps in the direction of fixing VELTOOLS-66 once and for all.

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@velocity.apache.org
For additional commands, e-mail: dev-help@velocity.apache.org