You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by xu...@apache.org on 2010/08/09 04:27:42 UTC

svn commit: r983503 - in /geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel: ClassLoading.java config/MultiParentClassLoader.java

Author: xuhaihong
Date: Mon Aug  9 02:27:41 2010
New Revision: 983503

URL: http://svn.apache.org/viewvc?rev=983503&view=rev
Log:
GERONIMO-4217 Check for all data primitive types when shortcutting to the primordial classloader

Modified:
    geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/ClassLoading.java
    geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/config/MultiParentClassLoader.java

Modified: geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/ClassLoading.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/ClassLoading.java?rev=983503&r1=983502&r2=983503&view=diff
==============================================================================
--- geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/ClassLoading.java (original)
+++ geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/ClassLoading.java Mon Aug  9 02:27:41 2010
@@ -49,15 +49,18 @@ public class ClassLoading {
     /**
      * Table for mapping primitive class names/signatures to the implementing
      * class object
+     * initialCapacity is calculated from 12 * 0.75 = 9
      */
-    private static final HashMap PRIMITIVE_CLASS_MAP = new HashMap();
+    private static final HashMap<String, Class<?>> HUMAN_READABLE_PRIMITIVE_CLASS_MAP = new HashMap<String, Class<?>>(12);
+
+    private static final HashMap<String, Class<?>> BINARY_NAME_PRIMITIVE_CLASS_MAP = new HashMap<String, Class<?>>(12);
 
     /**
      * Table for mapping primitive classes back to their name signature type, which
      * allows a reverse mapping to be performed from a class object into a resolvable
      * signature.
      */
-    private static final HashMap CLASS_TO_SIGNATURE_MAP = new HashMap();
+    private static final HashMap<Class<?>, String> CLASS_TO_SIGNATURE_MAP = new HashMap<Class<?>, String>(12);
 
 
     /**
@@ -65,24 +68,24 @@ public class ClassLoading {
      * human readable name and the method signature shorthand type.
      */
     static {
-        PRIMITIVE_CLASS_MAP.put("boolean", boolean.class);
-        PRIMITIVE_CLASS_MAP.put("Z", boolean.class);
-        PRIMITIVE_CLASS_MAP.put("byte", byte.class);
-        PRIMITIVE_CLASS_MAP.put("B", byte.class);
-        PRIMITIVE_CLASS_MAP.put("char", char.class);
-        PRIMITIVE_CLASS_MAP.put("C", char.class);
-        PRIMITIVE_CLASS_MAP.put("short", short.class);
-        PRIMITIVE_CLASS_MAP.put("S", short.class);
-        PRIMITIVE_CLASS_MAP.put("int", int.class);
-        PRIMITIVE_CLASS_MAP.put("I", int.class);
-        PRIMITIVE_CLASS_MAP.put("long", long.class);
-        PRIMITIVE_CLASS_MAP.put("J", long.class);
-        PRIMITIVE_CLASS_MAP.put("float", float.class);
-        PRIMITIVE_CLASS_MAP.put("F", float.class);
-        PRIMITIVE_CLASS_MAP.put("double", double.class);
-        PRIMITIVE_CLASS_MAP.put("D", double.class);
-        PRIMITIVE_CLASS_MAP.put("void", void.class);
-        PRIMITIVE_CLASS_MAP.put("V", void.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("boolean", boolean.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("Z", boolean.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("byte", byte.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("B", byte.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("char", char.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("C", char.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("short", short.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("S", short.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("int", int.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("I", int.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("long", long.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("J", long.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("float", float.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("F", float.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("double", double.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("D", double.class);
+        HUMAN_READABLE_PRIMITIVE_CLASS_MAP.put("void", void.class);
+        BINARY_NAME_PRIMITIVE_CLASS_MAP.put("V", void.class);
 
         // Now build a reverse mapping table.  The table above has a many-to-one mapping for
         // class names.  To do the reverse, we need to pick just one.  As long as the
@@ -123,6 +126,16 @@ public class ClassLoading {
         if (classLoader == null) {
             throw new IllegalArgumentException("classLoader is null");
         }
+
+        //First check the human readable primitive class from cached map
+        Class<?> resolvedClass;
+        if (className.length() <= 7) {
+            resolvedClass = HUMAN_READABLE_PRIMITIVE_CLASS_MAP.get(className);
+            if (resolvedClass != null) {
+                return resolvedClass;
+            }
+        }
+
         // The easiest case is a proper class name.  We just have the class loader resolve this.
         // If the class loader throws a ClassNotFoundException, then we need to check each of the
         // special name encodings we support.
@@ -135,7 +148,7 @@ public class ClassLoading {
 
         // The second easiest version to resolve is a direct map to a primitive type name
         // or method signature.  Check our name-to-class map for one of those.
-        Class resolvedClass = (Class) PRIMITIVE_CLASS_MAP.get(className);
+        resolvedClass = BINARY_NAME_PRIMITIVE_CLASS_MAP.get(className);
         if (resolvedClass != null) {
             return resolvedClass;
         }
@@ -250,7 +263,7 @@ public class ClassLoading {
         // we're down to the base type.  If this is a primitive, then
         // we poke in the single-character type specifier.
         if (type.isPrimitive()) {
-            name.append((String) CLASS_TO_SIGNATURE_MAP.get(type));
+            name.append(CLASS_TO_SIGNATURE_MAP.get(type));
         }
         // a "normal" class.  This gets expressing using the "Lmy.class.name;" syntax.
         else {
@@ -319,7 +332,7 @@ public class ClassLoading {
      */
     public static Class[] reduceInterfaces(Class[] source) {
         // use a copy of the sorce array
-        source = (Class[]) source.clone();
+        source = source.clone();
 
         for (int leftIndex = 0; leftIndex < source.length-1; leftIndex++) {
             Class left = source[leftIndex];

Modified: geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/config/MultiParentClassLoader.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/config/MultiParentClassLoader.java?rev=983503&r1=983502&r2=983503&view=diff
==============================================================================
--- geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/config/MultiParentClassLoader.java (original)
+++ geronimo/server/branches/2.2/framework/modules/geronimo-kernel/src/main/java/org/apache/geronimo/kernel/config/MultiParentClassLoader.java Mon Aug  9 02:27:41 2010
@@ -63,33 +63,33 @@ public class MultiParentClassLoader exte
     private boolean destroyed = false;
     private Map<String,Object> resourcesNotFound = new ConcurrentHashMap<String,Object>();
 
-    // I used this pattern as its temporary and with the static final we get compile time 
+    // I used this pattern as its temporary and with the static final we get compile time
     // optimizations.
     private final static int classLoaderSearchMode;
     private final static int ORIGINAL_SEARCH = 1;
     private final static int OPTIMIZED_SEARCH = 2;
 
     private final static boolean LONG_CLASSLOADER_TO_STRING = false;
-     
+
     static {
-    	// Extract the classLoaderSearchMode if specified.  If not, default to "safe".
-    	String mode = System.getProperty("Xorg.apache.geronimo.kernel.config.MPCLSearchOption");
-    	int runtimeMode = OPTIMIZED_SEARCH;  // Default to optimized
-    	String runtimeModeMessage = "Original Classloading";
-    	if (mode != null) { 
-    		if (mode.equals("safe")) {
+        // Extract the classLoaderSearchMode if specified.  If not, default to "safe".
+        String mode = System.getProperty("Xorg.apache.geronimo.kernel.config.MPCLSearchOption");
+        int runtimeMode = OPTIMIZED_SEARCH; // Default to optimized
+        String runtimeModeMessage = "Original Classloading";
+        if (mode != null) {
+            if (mode.equals("safe")) {
                 runtimeMode = ORIGINAL_SEARCH;
                 runtimeModeMessage = "Safe ClassLoading";
-    		} else if (mode.equals("optimized"))
-    			runtimeMode = OPTIMIZED_SEARCH;
-    	}
-    	
-		classLoaderSearchMode = runtimeMode;
-		LoggerFactory.getLogger(MultiParentClassLoader.class).info(
-                 "ClassLoading behaviour has changed.  The "+runtimeModeMessage+" mode is in effect.  If you are experiencing a problem\n"+
-				 "you can change the behaviour by specifying -DXorg.apache.geronimo.kernel.config.MPCLSearchOption= property.  Specify \n"+
-				 "=\"safe\" to revert to the original behaviour.  This is a temporary change until we decide whether or not to make it\n"+
-				 "permanent for the 2.0 release");
+            } else if (mode.equals("optimized"))
+                runtimeMode = OPTIMIZED_SEARCH;
+        }
+
+        classLoaderSearchMode = runtimeMode;
+        LoggerFactory.getLogger(MultiParentClassLoader.class).info(
+                "ClassLoading behaviour has changed.  The "+runtimeModeMessage+" mode is in effect.  If you are experiencing a problem\n"+
+                "you can change the behaviour by specifying -DXorg.apache.geronimo.kernel.config.MPCLSearchOption= property.  Specify \n"+
+                "=\"safe\" to revert to the original behaviour.  This is a temporary change until we decide whether or not to make it\n"+
+                "permanent for the 2.0 release");
     }
 
     /**
@@ -101,7 +101,7 @@ public class MultiParentClassLoader exte
     public MultiParentClassLoader(Artifact id, URL[] urls) {
         super(urls);
         this.id = id;
-        
+
         parents = new ClassLoader[]{ClassLoader.getSystemClassLoader()};
         classLoadingRules = new ClassLoadingRules();
         ClassLoaderRegistry.add(this);
@@ -191,7 +191,7 @@ public class MultiParentClassLoader exte
         super(urls, null, factory);
         this.id = id;
         this.parents = copyParents(parents);
-        
+
         classLoadingRules = new ClassLoadingRules();
         ClassLoaderRegistry.add(this);
     }
@@ -247,19 +247,19 @@ public class MultiParentClassLoader exte
     }
 
     /**
-     * TODO This method should be removed and replaced with the best classLoading option.  Its intent is to 
+     * TODO This method should be removed and replaced with the best classLoading option.  Its intent is to
      * provide a way for folks to switch back to the old classLoader if this fix breaks something.
      */
     protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
-    	if (classLoaderSearchMode == ORIGINAL_SEARCH) 
+    	if (classLoaderSearchMode == ORIGINAL_SEARCH)
     		return loadSafeClass(name, resolve);
     	else
     		return loadOptimizedClass(name, resolve);
     }
-    
+
     /**
      * This method executes the old class loading behaviour before optimization.
-     * 
+     *
      * @param name
      * @param resolve
      * @return
@@ -281,15 +281,7 @@ public class MultiParentClassLoader exte
         // The order is based on profiling the server.  It may not be optimal for all
         // workloads.
 
-        if (name.startsWith("java.") ||
-                name.equals("boolean") ||
-                name.equals("int") ||
-                name.equals("double") ||
-                name.equals("long") ||
-                name.equals("short") ||
-                name.equals("float") ||
-                name.equals("byte") ||
-                name.equals("char")) {
+        if (name.startsWith("java.")) {
             Class clazz = ClassLoader.getSystemClassLoader().loadClass(name);
             return resolveClass(clazz, resolve);
         }
@@ -334,22 +326,22 @@ public class MultiParentClassLoader exte
         }
 
         throw new ClassNotFoundException(name + " in classloader " + id);
-    }    
-    
+    }
+
     /**
-     * 
+     *
      * Optimized classloading.
-     * 
-     * This method is the normal way to resolve class loads.  This method recursively calls its parents to resolve 
+     *
+     * This method is the normal way to resolve class loads.  This method recursively calls its parents to resolve
      * classloading requests.  Here is the sequence of operations:
-     * 
+     *
      *   1. Call findLoadedClass to see if we already have this class loaded.
      *   2. If this class is a java.* or data primitive class, call the SystemClassLoader.
      *   3. If inverse loading and class is not in the non-overridable list, check the local ClassLoader.
      *   4. If the class is not a hidden class, search our parents, recursively.  Keeping track of which parents have already been called.
      *      Since MultiParentClassLoaders can appear more than once we do not search an already searched ClassLoader.
-     *   5. Finally, search this ClassLoader.  
-     * 
+     *   5. Finally, search this ClassLoader.
+     *
      */
     protected synchronized Class<?> loadOptimizedClass(String name, boolean resolve) throws ClassNotFoundException {
 
@@ -366,15 +358,7 @@ public class MultiParentClassLoader exte
         //
         // The order is based on profiling the server.  It may not be optimal for all
         // workloads.
-        if (name.startsWith("java.") ||
-                name.equals("boolean") ||
-                name.equals("int") ||
-                name.equals("double") ||
-                name.equals("long") ||
-                name.equals("short") ||
-                name.equals("float") ||
-                name.equals("byte") ||
-                name.equals("char")) {
+        if (name.startsWith("java.")) {
             try {
         	    return resolveClass(findSystemClass(name), resolve);
             } catch (ClassNotFoundException cnfe) {
@@ -392,7 +376,7 @@ public class MultiParentClassLoader exte
             } catch (ClassNotFoundException ignored) {
             }
         }
-        
+
         //
         // Check parent class loaders
         //
@@ -422,13 +406,13 @@ public class MultiParentClassLoader exte
 
         throw new ClassNotFoundException(name + " in classloader " + id);
     }
-    
+
     /**
      * This method is an internal hook that allows us to be performant on Class lookups when multiparent
      * classloaders are involved.  We can bypass certain lookups that have already occurred in the initiating
      * classloader.  Also, we track the classLoaders that are visited by adding them to an already vistied list.
      * In this way, we can bypass redundant checks for the same class.
-     * 
+     *
      * @param name
      * @param visitedClassLoaders
      * @return
@@ -454,7 +438,7 @@ public class MultiParentClassLoader exte
         	    // ignore
             }
         }
-        
+
         //
         // if we are not using inverse class loading, check local urls now
         //
@@ -470,12 +454,12 @@ public class MultiParentClassLoader exte
     }
 
     /**
-     * In order to optimize the classLoading process and visit a directed set of 
-     * classloaders this internal method for Geronimo MultiParentClassLoaders 
+     * In order to optimize the classLoading process and visit a directed set of
+     * classloaders this internal method for Geronimo MultiParentClassLoaders
      * is used.  Effectively, as each classloader is visited it is passed a linked
      * list of classloaders that have already been visited and can safely be skipped.
      * This method assumes the context of an MPCL and is not for use external to this class.
-     * 
+     *
      * @param name
      * @param visitedClassLoaders
      * @return
@@ -501,7 +485,7 @@ public class MultiParentClassLoader exte
                     log.debug("Failed findClass for {}", name, me);
                 }
             }
-    	} 
+    	}
      	// To avoid yet another CNFE we'll simply return null and let the caller handle appropriately.
     	return null;
     }
@@ -564,10 +548,10 @@ public class MultiParentClassLoader exte
             }
         }
 
-        // 
+        //
         // Resource not found -- no need to search for it again
         // Use the name as key and value. We don't care about the value and it needs to be non-null.
-        // 
+        //
         resourcesNotFound.put(name, name);
 
         return null;
@@ -649,7 +633,7 @@ public class MultiParentClassLoader exte
             getAncestorsInternal(ancestors, cl);
         }
     }
-    
+
     public String toString() {
         StringBuilder b = new StringBuilder();
         if (LONG_CLASSLOADER_TO_STRING) {
@@ -730,5 +714,5 @@ public class MultiParentClassLoader exte
         ClassLoaderRegistry.remove(this);
         super.finalize();
     }
-    
+
 }