You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2011/02/23 17:37:46 UTC

svn commit: r1073815 - /myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java

Author: jakobk
Date: Wed Feb 23 16:37:45 2011
New Revision: 1073815

URL: http://svn.apache.org/viewvc?rev=1073815&view=rev
Log:
MYFACES-3051 Use multiple ClassLoaders to find resources (not only ContextClassLoader) (improve MyFacesClassLoader)

Modified:
    myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java

Modified: myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java?rev=1073815&r1=1073814&r2=1073815&view=diff
==============================================================================
--- myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java (original)
+++ myfaces/shared/trunk/core/src/main/java/org/apache/myfaces/shared/util/MyFacesClassLoader.java Wed Feb 23 16:37:45 2011
@@ -18,11 +18,16 @@
  */
 package org.apache.myfaces.shared.util;
 
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Custom ClassLoader that sets the current Thread's context ClassLoader as parent ClassLoader
@@ -33,16 +38,60 @@ import java.util.Enumeration;
 public class MyFacesClassLoader extends ClassLoader
 {
 
+    private static final String APPLICATION_MAP_KEY = MyFacesClassLoader.class.getName();
+
+    /**
+     * Returns the cached instance of the MyFacesClassLoader for this application or a new
+     * one if now cached instance is available yet.
+     *
+     * @param externalContext
+     * @return
+     */
+    public static final MyFacesClassLoader getCurrentInstance(ExternalContext externalContext)
+    {
+        if (externalContext == null)
+        {
+            // if no ExternalContext is available, return a new instance
+            // this may be the case in Unit tests or outside of the JSF lifecycle
+            return new MyFacesClassLoader();
+        }
+
+        Map<String, Object> applicationMap = externalContext.getApplicationMap();
+        MyFacesClassLoader classLoader = (MyFacesClassLoader) applicationMap.get(APPLICATION_MAP_KEY);
+
+        if (classLoader == null)
+        {
+            // no instance available for this application yet, create one and cache it
+            classLoader = new MyFacesClassLoader();
+            applicationMap.put(APPLICATION_MAP_KEY, classLoader);
+        }
+
+        return classLoader;
+    }
+
+    private static ClassLoader getContextClassLoaderFailsafe()
+    {
+        ClassLoader contextClassLoader = ClassLoaderUtils.getContextClassLoader();
+
+        if (contextClassLoader == null)
+        {
+            // fall back to the ClassLoader of this class if the current Thread has no ContextClassLoader
+            contextClassLoader = MyFacesClassLoader.class.getClassLoader();
+        }
+
+        return contextClassLoader;
+    }
+
     private ClassLoader apiClassLoader;
     private ClassLoader implClassLoader;
 
     public MyFacesClassLoader()
     {
         // context ClassLoader is parent ClassLoader
-        super(ClassLoaderUtils.getContextClassLoader());
+        super(getContextClassLoaderFailsafe());
 
         apiClassLoader = FacesContext.class.getClassLoader(); // myfaces-api classloader
-        implClassLoader = getClass().getClassLoader();  // myfaces-impl classloader
+        implClassLoader = getClass().getClassLoader();  // myfaces-impl (or tomahawk) classloader
     }
 
     @Override
@@ -69,22 +118,19 @@ public class MyFacesClassLoader extends 
     @Override
     public Enumeration<URL> getResources(String s) throws IOException
     {
+        // use all 3 classloaders and merge without duplicates
+        Set<URL> urls = new HashSet<URL>(); // no duplicates
+
         // context classloader
-        Enumeration<URL> urls = super.getResources(s);
+        urls.addAll(Collections.list(super.getResources(s)));
 
-        if (urls == null || !urls.hasMoreElements())
-        {
-            // try api
-            urls = apiClassLoader.getResources(s);
+        // api classlaoder
+        urls.addAll(Collections.list(apiClassLoader.getResources(s)));
 
-            if (urls == null || !urls.hasMoreElements())
-            {
-                // try impl
-                urls = implClassLoader.getResources(s);
-            }
-        }
+        // impl classlaoder
+        urls.addAll(Collections.list(implClassLoader.getResources(s)));
 
-        return urls;
+        return Collections.enumeration(urls);
     }
 
     @Override
@@ -146,6 +192,20 @@ public class MyFacesClassLoader extends 
         return clazz;
     }
 
+    @Override
+    public boolean equals(Object o)
+    {
+        if (o instanceof MyFacesClassLoader)
+        {
+            MyFacesClassLoader other = (MyFacesClassLoader) o;
+
+            // same parent --> same ContextClassLoader --> same MyFacesClassLoader
+            return (other.getParent().equals(this.getParent()));
+        }
+
+        return false;
+    }
+
     private Class<?> loadClassFailsafe(String s, ClassLoader classLaoder)
     {
         try