Author: markt
Date: Wed Oct 19 09:17:41 2011
New Revision: 1186044

URL: http://svn.apache.org/viewvc?rev=1186044&view=rev
Log:
Prevent possible loss of cache entries due to GC by using strong rather
than weak references for the cache entries. This means removing the use
of Field and Method from the cache entry as they hold a strong reference
to Class which would break the cache since Class is the key for the
WeakHashMap that implements the cache.

Modified:
    tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java

Modified: tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java?rev=1186044&r1=1186043&r2=1186044&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java Wed 
Oct 19 09:17:41 2011
@@ -21,8 +21,6 @@ package org.apache.catalina.core;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -71,8 +69,8 @@ public class DefaultInstanceManager impl
     private final Properties restrictedFilters = new Properties();
     private final Properties restrictedListeners = new Properties();
     private final Properties restrictedServlets = new Properties();
-    private final Map<Class<?>,WeakReference<List<AnnotationCacheEntry>>> 
annotationCache =
-        new WeakHashMap<Class<?>, WeakReference<List<AnnotationCacheEntry>>>();
+    private final Map<Class<?>,List<AnnotationCacheEntry>> annotationCache =
+        new WeakHashMap<Class<?>, List<AnnotationCacheEntry>>();
 
     public DefaultInstanceManager(Context context, Map<String, Map<String, 
String>> injectionMap, org.apache.catalina.Context catalinaContext, ClassLoader 
containerClassLoader) {
         classLoader = catalinaContext.getLoader().getClassLoader();
@@ -181,11 +179,11 @@ public class DefaultInstanceManager impl
         // method is invoked
         List<AnnotationCacheEntry> annotations;
         synchronized (annotationCache) {
-            annotations = annotationCache.get(clazz).get();
+            annotations = annotationCache.get(clazz);
         }
         for (AnnotationCacheEntry entry : annotations) {
             if (entry.getType() == AnnotationCacheEntryType.POST_CONSTRUCT) {
-                Method postConstruct = (Method) entry.getAccessibleObject();
+                Method postConstruct = getMethod(clazz, entry);
                 synchronized (postConstruct) {
                     boolean accessibility = postConstruct.isAccessible();
                     postConstruct.setAccessible(true);
@@ -217,11 +215,7 @@ public class DefaultInstanceManager impl
         // method is invoked
         List<AnnotationCacheEntry> annotations = null;
         synchronized (annotationCache) {
-            WeakReference<List<AnnotationCacheEntry>> ref =
-                annotationCache.get(clazz);
-            if (ref != null) {
-                annotations = ref.get();
-            }
+            annotations = annotationCache.get(clazz);
         }
         if (annotations == null) {
             // instance not created through the instance manager
@@ -229,7 +223,7 @@ public class DefaultInstanceManager impl
         }
         for (AnnotationCacheEntry entry : annotations) {
             if (entry.getType() == AnnotationCacheEntryType.PRE_DESTROY) {
-                Method preDestroy = (Method) entry.getAccessibleObject();
+                Method preDestroy = getMethod(clazz, entry);
                 synchronized (preDestroy) {
                     boolean accessibility = preDestroy.isAccessible();
                     preDestroy.setAccessible(true);
@@ -260,11 +254,7 @@ public class DefaultInstanceManager impl
         while (clazz != null) {
             List<AnnotationCacheEntry> annotations = null;
             synchronized (annotationCache) {
-                WeakReference<List<AnnotationCacheEntry>> ref =
-                    annotationCache.get(clazz);
-                if (ref != null) {
-                    annotations = ref.get();
-                }
+                annotations = annotationCache.get(clazz);
             }
             if (annotations == null) {
                 annotations = new ArrayList<AnnotationCacheEntry>();
@@ -287,36 +277,37 @@ public class DefaultInstanceManager impl
                     }
                     for (Field field : fields) {
                         if (injections != null && 
injections.containsKey(field.getName())) {
-                            annotations.add(new AnnotationCacheEntry(field,
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null,
                                     injections.get(field.getName()),
                                     AnnotationCacheEntryType.FIELD));
                         } else if (field.isAnnotationPresent(Resource.class)) {
                             Resource annotation = 
field.getAnnotation(Resource.class);
-                            annotations.add(new AnnotationCacheEntry(field,
-                                    annotation.name(),
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null, annotation.name(),
                                     AnnotationCacheEntryType.FIELD));
                         } else if (field.isAnnotationPresent(EJB.class)) {
                             EJB annotation = field.getAnnotation(EJB.class);
-                            annotations.add(new AnnotationCacheEntry(field,
-                                    annotation.name(),
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null, annotation.name(),
                                     AnnotationCacheEntryType.FIELD));
                         } else if 
(field.isAnnotationPresent(WebServiceRef.class)) {
                             WebServiceRef annotation =
                                     field.getAnnotation(WebServiceRef.class);
-                            annotations.add(new AnnotationCacheEntry(field,
-                                    annotation.name(),
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null, annotation.name(),
                                     AnnotationCacheEntryType.FIELD));
                         } else if 
(field.isAnnotationPresent(PersistenceContext.class)) {
                             PersistenceContext annotation =
                                     
field.getAnnotation(PersistenceContext.class);
-                            annotations.add(new AnnotationCacheEntry(field,
-                                    annotation.name(),
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null, annotation.name(),
                                     AnnotationCacheEntryType.FIELD));
                         } else if 
(field.isAnnotationPresent(PersistenceUnit.class)) {
                             PersistenceUnit annotation =
                                     field.getAnnotation(PersistenceUnit.class);
-                            annotations.add(new AnnotationCacheEntry(field,
-                                    annotation.name(),
+                            annotations.add(new AnnotationCacheEntry(
+                                    field.getName(), null, annotation.name(),
                                     AnnotationCacheEntryType.FIELD));
                         }
                     }
@@ -345,40 +336,52 @@ public class DefaultInstanceManager impl
                         if (injections != null && methodName.startsWith("set") 
&& methodName.length() > 3) {
                             String fieldName = 
Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
                             if (injections.containsKey(fieldName)) {
-                                annotations.add(new 
AnnotationCacheEntry(method,
+                                annotations.add(new AnnotationCacheEntry(
+                                        method.getName(),
+                                        method.getParameterTypes(),
                                         injections.get(method.getName()),
-                                        AnnotationCacheEntryType.FIELD));
+                                        AnnotationCacheEntryType.SETTER));
                                 break;
                             }
                         }
                         if (method.isAnnotationPresent(Resource.class)) {
                             Resource annotation = 
method.getAnnotation(Resource.class);
-                            annotations.add(new AnnotationCacheEntry(method,
+                            annotations.add(new AnnotationCacheEntry(
+                                    method.getName(),
+                                    method.getParameterTypes(),
                                     annotation.name(),
-                                    AnnotationCacheEntryType.FIELD));
+                                    AnnotationCacheEntryType.SETTER));
                         } else if (method.isAnnotationPresent(EJB.class)) {
                             EJB annotation = method.getAnnotation(EJB.class);
-                            annotations.add(new AnnotationCacheEntry(method,
+                            annotations.add(new AnnotationCacheEntry(
+                                    method.getName(),
+                                    method.getParameterTypes(),
                                     annotation.name(),
-                                    AnnotationCacheEntryType.FIELD));
+                                    AnnotationCacheEntryType.SETTER));
                         } else if 
(method.isAnnotationPresent(WebServiceRef.class)) {
                             WebServiceRef annotation =
                                     method.getAnnotation(WebServiceRef.class);
-                            annotations.add(new AnnotationCacheEntry(method,
+                            annotations.add(new AnnotationCacheEntry(
+                                    method.getName(),
+                                    method.getParameterTypes(),
                                     annotation.name(),
-                                    AnnotationCacheEntryType.FIELD));
+                                    AnnotationCacheEntryType.SETTER));
                         } else if 
(method.isAnnotationPresent(PersistenceContext.class)) {
                             PersistenceContext annotation =
                                     
method.getAnnotation(PersistenceContext.class);
-                            annotations.add(new AnnotationCacheEntry(method,
+                            annotations.add(new AnnotationCacheEntry(
+                                    method.getName(),
+                                    method.getParameterTypes(),
                                     annotation.name(),
-                                    AnnotationCacheEntryType.FIELD));
+                                    AnnotationCacheEntryType.SETTER));
                         } else if 
(method.isAnnotationPresent(PersistenceUnit.class)) {
                             PersistenceUnit annotation =
                                     
method.getAnnotation(PersistenceUnit.class);
-                            annotations.add(new AnnotationCacheEntry(method,
+                            annotations.add(new AnnotationCacheEntry(
+                                    method.getName(),
+                                    method.getParameterTypes(),
                                     annotation.name(),
-                                    AnnotationCacheEntryType.FIELD));
+                                    AnnotationCacheEntryType.SETTER));
                         }
                     }
 
@@ -407,21 +410,23 @@ public class DefaultInstanceManager impl
                     }
                 }
                 if (postConstruct != null) {
-                    annotations.add(new AnnotationCacheEntry(postConstruct,
-                            null, AnnotationCacheEntryType.POST_CONSTRUCT));
+                    annotations.add(new AnnotationCacheEntry(
+                            postConstruct.getName(),
+                            postConstruct.getParameterTypes(), null,
+                            AnnotationCacheEntryType.POST_CONSTRUCT));
                 }
                 if (preDestroy != null) {
-                    annotations.add(new AnnotationCacheEntry(preDestroy,
-                            null, AnnotationCacheEntryType.PRE_DESTROY));
+                    annotations.add(new AnnotationCacheEntry(
+                            preDestroy.getName(),
+                            preDestroy.getParameterTypes(), null,
+                            AnnotationCacheEntryType.PRE_DESTROY));
                 }
                 if (annotations.size() == 0) {
                     // Use common empty list to save memory
                     annotations = Collections.emptyList();
                 }
                 synchronized (annotationCache) {
-                    annotationCache.put(clazz,
-                            new WeakReference<List<AnnotationCacheEntry>>(
-                                    annotations));
+                    annotationCache.put(clazz, annotations);
                 }
             }
             clazz = clazz.getSuperclass();
@@ -452,19 +457,17 @@ public class DefaultInstanceManager impl
         while (clazz != null) {
             List<AnnotationCacheEntry> annotations;
             synchronized (annotationCache) {
-                annotations = annotationCache.get(clazz).get();
+                annotations = annotationCache.get(clazz);
             }
             for (AnnotationCacheEntry entry : annotations) {
-                if (entry.getType() == AnnotationCacheEntryType.FIELD) {
-                    if (entry.getAccessibleObject() instanceof Method) {
-                        lookupMethodResource(context, instance,
-                                (Method) entry.getAccessibleObject(),
-                                entry.getName(), clazz);
-                    } else {
-                        lookupFieldResource(context, instance,
-                                (Field) entry.getAccessibleObject(),
-                                entry.getName(), clazz);
-                    }
+                if (entry.getType() == AnnotationCacheEntryType.SETTER) {
+                    lookupMethodResource(context, instance,
+                            getMethod(clazz, entry),
+                            entry.getName(), clazz);
+                } else if (entry.getType() == AnnotationCacheEntryType.FIELD) {
+                    lookupFieldResource(context, instance,
+                            getField(clazz, entry),
+                            entry.getName(), clazz);
                 }
             }
             clazz = clazz.getSuperclass();
@@ -647,20 +650,87 @@ public class DefaultInstanceManager impl
         return jndiName;
     }
 
+    private static Method getMethod(final Class<?> clazz,
+            final AnnotationCacheEntry entry) {
+        Method result = null;
+        if (Globals.IS_SECURITY_ENABLED) {
+            result = AccessController.doPrivileged(
+                    new PrivilegedAction<Method>() {
+                        @Override
+                        public Method run() {
+                            Method result = null;
+                            try {
+                                result = clazz.getDeclaredMethod(
+                                        entry.getAccessibleObjectName(),
+                                        entry.getParamTypes());
+                            } catch (NoSuchMethodException e) {
+                                // Should never happen. On that basis don't log
+                                // it.
+                            }
+                            return result;
+                        }
+            });
+        } else {
+            try {
+                result = clazz.getDeclaredMethod(
+                        entry.getName(), entry.getParamTypes());
+            } catch (NoSuchMethodException e) {
+                // Should never happen. On that basis don't log it.
+            }
+        }
+        return result;
+    }
+
+    private static Field getField(final Class<?> clazz,
+            final AnnotationCacheEntry entry) {
+        Field result = null;
+        if (Globals.IS_SECURITY_ENABLED) {
+            result = AccessController.doPrivileged(
+                    new PrivilegedAction<Field>() {
+                        @Override
+                        public Field run() {
+                            Field result = null;
+                            try {
+                                result = clazz.getDeclaredField(
+                                        entry.getAccessibleObjectName());
+                            } catch (NoSuchFieldException e) {
+                                // Should never happen. On that basis don't log
+                                // it.
+                            }
+                            return result;
+                        }
+            });
+        } else {
+            try {
+                result = clazz.getDeclaredField(entry.getName());
+            } catch (NoSuchFieldException e) {
+                // Should never happen. On that basis don't log it.
+            }
+        }
+        return result;
+    }
+
     private static final class AnnotationCacheEntry {
-        private final AccessibleObject accessibleObject;
+        private final String accessibleObjectName;
+        private final Class<?>[] paramTypes;
         private final String name;
         private final AnnotationCacheEntryType type;
 
-        public AnnotationCacheEntry(AccessibleObject accessibleObject,
-                String name, AnnotationCacheEntryType type) {
-            this.accessibleObject = accessibleObject;
+        public AnnotationCacheEntry(String accessibleObjectName,
+                Class<?>[] paramTypes, String name,
+                AnnotationCacheEntryType type) {
+            this.accessibleObjectName = accessibleObjectName;
+            this.paramTypes = paramTypes;
             this.name = name;
             this.type = type;
         }
 
-        public AccessibleObject getAccessibleObject() {
-            return accessibleObject;
+        public String getAccessibleObjectName() {
+            return accessibleObjectName;
+        }
+
+        public Class<?>[] getParamTypes() {
+            return paramTypes;
         }
 
         public String getName() {
@@ -672,6 +742,6 @@ public class DefaultInstanceManager impl
     }
 
     private static enum AnnotationCacheEntryType {
-        FIELD, POST_CONSTRUCT, PRE_DESTROY
+        FIELD, SETTER, POST_CONSTRUCT, PRE_DESTROY
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to