In order to eliminate redundant code and the potential cut-and-paste errors
that result, I have merged the two sets of very similar parallel methods
for loading classes and resources into a single set of methods.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@395572 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
index c32751e..b68c9a9 100755
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
@@ -274,6 +274,47 @@
     public Class findClass(IModule module, String name)
         throws ClassNotFoundException
     {
+        try
+        {
+            return (Class) findClassOrResource(module, name, true);
+        }
+        catch (ResourceNotFoundException ex)
+        {
+            // This should never happen, so just ignore it.
+        }
+        catch (ClassNotFoundException ex)
+        {
+            diagnoseClassLoadError(module, name);
+            throw ex;
+        }
+
+        // We should never reach this point.
+        return null;
+    }
+
+    public URL findResource(IModule module, String name)
+        throws ResourceNotFoundException
+    {
+        try
+        {
+            return (URL) findClassOrResource(module, name, false);
+        }
+        catch (ClassNotFoundException ex)
+        {
+            // This should never happen, so just ignore it.
+        }
+        catch (ResourceNotFoundException ex)
+        {
+            throw ex;
+        }
+    
+        // We should never reach this point.
+        return null;
+    }
+
+    private Object findClassOrResource(IModule module, String name, boolean isClass)
+        throws ClassNotFoundException, ResourceNotFoundException
+    {
         // First, try to resolve the originating module.
 // TODO: Consider opimizing this call to resolve, since it is called
 // for each class load.
@@ -283,16 +324,37 @@
         }
         catch (ResolveException ex)
         {
-            // We do not use the resolve exception as the
-            // cause of the exception, since this would
-            // potentially leak internal module information.
-            throw new ClassNotFoundException(
-                name + ": cannot resolve package "
-                + ex.getPackage());
+            if (isClass)
+            {
+                // We do not use the resolve exception as the
+                // cause of the exception, since this would
+                // potentially leak internal module information.
+                throw new ClassNotFoundException(
+                    name + ": cannot resolve package "
+                    + ex.getPackage());
+            }
+            else
+            {
+                // The spec states that if the bundle cannot be resolved, then
+                // only the local bundle's resources should be searched. So we
+                // will ask the module's own class path.
+                URL url = module.getContentLoader().getResource(name);
+                if (url != null)
+                {
+                    return url;
+                }
+   
+                // We need to throw a resource not found exception.
+                throw new ResourceNotFoundException(
+                    name + ": cannot resolve package "
+                    + ex.getPackage());
+            }
         }
 
-        // Get the package of the target class.
-        String pkgName = Util.getClassPackage(name);
+        // Get the package of the target class/resource.
+        String pkgName = (isClass)
+            ? Util.getClassPackage(name)
+            : Util.getResourcePackage(name);
 
         // Delegate any packages listed in the boot delegation
         // property to the parent class loader.
@@ -314,97 +376,104 @@
                     m_bootPkgs[i].regionMatches(0, pkgName, 0, pkgName.length())))
                     || (!m_bootPkgWildcards[i] && m_bootPkgs[i].equals(pkgName)))
                 {
-                    return getClass().getClassLoader().loadClass(name);
+                    return (isClass)
+                        ? (Object) getClass().getClassLoader().loadClass(name)
+                        : (Object) getClass().getClassLoader().getResource(name);
                 }
             }
         }
 
-        try
-        {
-            // Look in the module's imports.
-            Class clazz = findImportedClass(module, name, pkgName);
-    
-            // If not found, try the module's own class path.
-            if (clazz == null)
-            {
-                clazz = module.getContentLoader().getClass(name);
-    
-                // If still not found, then try the module's dynamic imports.
-                if (clazz == null)
-                {
-                    clazz = findDynamicallyImportedClass(module, name, pkgName);
-                }
-            }
+        // Look in the module's imports.
+        Object result = searchImports(module, name, isClass);
 
-            if (clazz == null)
+        // If not found, try the module's own class path.
+        if (result == null)
+        {
+            result = (isClass)
+                ? (Object) module.getContentLoader().getClass(name)
+                : (Object) module.getContentLoader().getResource(name);
+
+            // If still not found, then try the module's dynamic imports.
+            if (result == null)
+            {
+                result = searchDynamicImports(module, name, pkgName, isClass);
+            }
+        }
+     
+        if (result == null)
+        {
+            if (isClass)
             {
                 throw new ClassNotFoundException(name);
             }
-    
-            return clazz;
+            else
+            {
+                throw new ResourceNotFoundException(name);
+            }
         }
-        catch (ClassNotFoundException ex)
-        {
-            diagnoseClassLoadError(module, name, pkgName);
-            throw ex;
-        }
+     
+        return result;
     }
 
-    private Class findImportedClass(IModule module, String name, String pkgName)
-        throws ClassNotFoundException
+    private Object searchImports(IModule module, String name, boolean isClass)
+        throws ClassNotFoundException, ResourceNotFoundException
     {
-        // We delegate to the module's wires to find the class.
+        // We delegate to the module's wires to find the class or resource.
         R4Wire[] wires = getWires(module);
         for (int i = 0; (wires != null) && (i < wires.length); i++)
         {
-            // If we find the class, then return it.
-            Class clazz = wires[i].getClass(name);
-            if (clazz != null)
+            // If we find the class or resource, then return it.
+            Object result = (isClass)
+                ? (Object) wires[i].getClass(name)
+                : (Object) wires[i].getResource(name);
+            if (result != null)
             {
-                return clazz;
+                return result;
             }
         }
 
         return null;
     }
 
-    private Class findDynamicallyImportedClass(
-        IModule module, String name, String pkgName)
-        throws ClassNotFoundException
+    private Object searchDynamicImports(
+        IModule module, String name, String pkgName, boolean isClass)
+        throws ClassNotFoundException, ResourceNotFoundException
     {
         // At this point, the module's imports were searched and so was the
         // the module's content. Now we make an attempt to load the
-        // class via a dynamic import, if possible.
+        // class/resource via a dynamic import, if possible.
         R4Wire wire = attemptDynamicImport(module, pkgName);
 
         // If the dynamic import was successful, then this initial
         // time we must directly return the result from dynamically
-        // created wire, but subsequent requests for classes in
-        // the associated package will be processed as part of
+        // created wire, but subsequent requests for classes/resources
+        // in the associated package will be processed as part of
         // normal static imports.
         if (wire != null)
         {
-            // Return the class.
-            return wire.getClass(name);
+            // Return the class or resource.
+            return (isClass)
+                ? (Object) wire.getClass(name)
+                : (Object) wire.getResource(name);
         }
 
-        // At this point, the class could not be found by the bundle's static
-        // or dynamic imports, nor its own resources. Before we throw
+        // At this point, the class/resource could not be found by the bundle's
+        // static or dynamic imports, nor its own content. Before we throw
         // an exception, we will try to determine if the instigator of the
-        // class load was a class from a bundle or not. This is necessary
+        // class/resource load was a class from a bundle or not. This is necessary
         // because the specification mandates that classes on the class path
         // should be hidden (except for java.*), but it does allow for these
-        // classes to be exposed by the system bundle as an export. However,
-        // in some situations classes on the class path make the faulty
+        // classes/resources to be exposed by the system bundle as an export.
+        // However, in some situations classes on the class path make the faulty
         // assumption that they can access everything on the class path from
         // every other class loader that they come in contact with. This is
         // not true if the class loader in question is from a bundle. Thus,
         // this code tries to detect that situation. If the class
-        // instigating the class load was NOT from a bundle, then we will
+        // instigating the load request was NOT from a bundle, then we will
         // make the assumption that the caller actually wanted to use the
         // parent class loader and we will delegate to it. If the class was
         // from a bundle, then we will enforce strict class loading rules
-        // for the bundle and throw a class not found exception.
+        // for the bundle and throw an exception.
 
         // Get the class context to see the classes on the stack.
         Class[] classes = m_sm.getClassContext();
@@ -434,175 +503,6 @@
         return null;
     }
 
-    public URL findResource(IModule module, String name)
-        throws ResourceNotFoundException
-    {
-        // First, try to resolve the originating module.
-// TODO: Consider opimizing this call to resolve, since it is called
-// for each class load.
-        try
-        {
-            resolve(module);
-        }
-        catch (ResolveException ex)
-        {
-            // The spec states that if the bundle cannot be resolved, then
-            // only the local bundle's resources should be searched. So we
-            // will ask the module's own class path.
-            URL url = module.getContentLoader().getResource(name);
-            if (url != null)
-            {
-                return url;
-            }
-
-            // We need to throw a resource not found exception.
-            throw new ResourceNotFoundException(
-                name + ": cannot resolve package "
-                + ex.getPackage());
-        }
-
-        // Get the package of the target class.
-        String pkgName = Util.getResourcePackage(name);
-
-        // Delegate any packages listed in the boot delegation
-        // property to the parent class loader.
-        for (int i = 0; i < m_bootPkgs.length; i++)
-        {
-            // A wildcarded boot delegation package will be in the form of "foo.",
-            // so if the package is wildcarded do a startsWith() or a regionMatches()
-            // to ignore the trailing "." to determine if the request should be
-            // delegated to the parent class loader. If the package is not wildcarded,
-            // then simply do an equals() test to see if the request should be
-            // delegated to the parent class loader.
-            if (pkgName.length() > 0)
-            {
-                // Only consider delegation if we have a package name, since
-                // we don't want to promote the default package. The spec does
-                // not take a stand on this issue.
-                if ((m_bootPkgWildcards[i] &&
-                    (pkgName.startsWith(m_bootPkgs[i]) ||
-                    m_bootPkgs[i].regionMatches(0, pkgName, 0, pkgName.length())))
-                    || (!m_bootPkgWildcards[i] && m_bootPkgs[i].equals(pkgName)))
-                {
-                    return getClass().getClassLoader().getResource(name);
-                }
-            }
-        }
-
-        try
-        {
-            // Look in the module's imports.
-            URL url = findImportedResource(module, name);
-
-            // If not found, try the module's own class path.
-            if (url == null)
-            {
-                url = module.getContentLoader().getResource(name);
-
-                // If still not found, then try the module's dynamic imports.
-                if (url == null)
-                {
-                    url = findDynamicallyImportedResource(module, name, pkgName);
-                }
-            }
-        
-            if (url == null)
-            {
-                throw new ResourceNotFoundException(name);
-            }
-        
-            return url;
-        }
-        catch (ResourceNotFoundException ex)
-        {
-            throw ex;
-        }
-    }
-
-    private URL findImportedResource(IModule module, String name)
-        throws ResourceNotFoundException
-    {
-        // We delegate to the module's wires to find the class.
-        R4Wire[] wires = getWires(module);
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            // If we find the resource, then return it.
-            URL url = wires[i].getResource(name);
-            if (url != null)
-            {
-                return url;
-            }
-        }
-
-        return null;
-    }
-
-    private URL findDynamicallyImportedResource(
-        IModule module, String name, String pkgName)
-        throws ResourceNotFoundException
-    {
-        // At this point, the module's imports were searched and so was the
-        // the module's content. Now we make an attempt to load the
-        // class via a dynamic import, if possible.
-        R4Wire wire = attemptDynamicImport(module, pkgName);
-
-        // If the dynamic import was successful, then this initial
-        // time we must directly return the result from dynamically
-        // created wire, but subsequent requests for resources in
-        // the associated package will be processed as part of
-        // normal static imports.
-        if (wire != null)
-        {
-            // Return the resource.
-            return wire.getResource(name);
-        }
-
-        // At this point, the resource could not be found by the bundle's static
-        // or dynamic imports, nor its own resources. Before we throw
-        // an exception, we will try to determine if the instigator of the
-        // resource load was a class from a bundle or not. This is necessary
-        // because the specification mandates that classes on the class path
-        // should be hidden (except for java.*), but it does allow for these
-        // classes to be exposed by the system bundle as an export. However,
-        // in some situations classes on the class path make the faulty
-        // assumption that they can access everything on the class path from
-        // every other class loader that they come in contact with. This is
-        // not true if the class loader in question is from a bundle. Thus,
-        // this code tries to detect that situation. If the class
-        // instigating the resource load was NOT from a bundle, then we will
-        // make the assumption that the caller actually wanted to use the
-        // parent class loader and we will delegate to it. If the class was
-        // from a bundle, then we will enforce strict class loading rules
-        // for the bundle and throw a resource not found exception.
-
-        // Get the class context to see the classes on the stack.
-        Class[] classes = m_sm.getClassContext();
-        // Start from 1 to skip security manager class.
-        for (int i = 1; i < classes.length; i++)
-        {
-            // Find the first class on the call stack that is not one
-            // of the R4 search policy classes, nor a class loader or
-            // class itself, because we want to ignore the calls to
-            // ClassLoader.loadClass() and Class.forName().
-            if (!R4SearchPolicyCore.class.equals(classes[i])
-                && !R4SearchPolicy.class.equals(classes[i])
-                && !ClassLoader.class.isAssignableFrom(classes[i])
-                && !Class.class.isAssignableFrom(classes[i]))
-            {
-                // If the instigating class was not from a bundle, then
-                // delegate to the parent class loader. Otherwise, break
-                // out of loop and return null.
-                if (!ContentClassLoader.class.isInstance(classes[i].getClassLoader()))
-                {
-                    return this.getClass().getClassLoader().getResource(name);
-                }
-                break;
-            }
-        }
-
-        return null;
-    }
-
     private R4Wire attemptDynamicImport(IModule module, String pkgName)
     {
         R4Wire wire = null;
@@ -1711,7 +1611,7 @@
         }
     }
 
-    private void diagnoseClassLoadError(IModule module, String name, String pkgName)
+    private void diagnoseClassLoadError(IModule module, String name)
     {
         // We will try to do some diagnostics here to help the developer
         // deal with this exception.
@@ -1719,6 +1619,9 @@
         boolean imported = false;
         boolean exported = false;
 
+        // Get package name.
+        String pkgName = Util.getClassPackage(name);
+
         // First, get the bundle ID of the module doing the class loader.
         long impId = Util.getBundleIdFromModuleId(module.getId());