Made ModuleClassLoader an inner class of ModuleImpl, since they are so
intimately connected, which allowed us to hide/eliminate some cruft. Also
changed how the class loading infrastructure detects cycles, which allowed
us to eliminate much cruft and make class loading more consistent. (FELIX-851)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@739113 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 90c86f3..9787953 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -294,7 +294,7 @@
         Properties mergedProperties = new Properties();
         for (Iterator it = resourceList.iterator(); it.hasNext(); )
         {
-            URL temp = this.getCurrentModule().getResourceFromModule(it.next() + ".properties");
+            URL temp = this.getCurrentModule().getResourceByDelegation(it.next() + ".properties");
             if (temp == null)
             {
                 continue;
@@ -923,8 +923,6 @@
         }
         module.setSecurityContext(new BundleProtectionDomain(getFramework(), this));
 
-        ((ModuleImpl) module).setBundle(this);
-
         IModule[] dest = new IModule[m_modules.length + 1];
         System.arraycopy(m_modules, 0, dest, 0, m_modules.length);
         dest[m_modules.length] = module;
@@ -947,6 +945,7 @@
             getFramework().getLogger(),
             getFramework().getConfig(),
             getFramework().getResolver(),
+            this,
             Long.toString(getBundleId()) + "." + Integer.toString(revision),
             headerMap,
             m_archive.getRevision(revision).getContent());
diff --git a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
index 9fc10a0..718e3a8 100644
--- a/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
+++ b/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
@@ -139,9 +139,9 @@
      * @param config the configuration to read properties from.
      * @param systemBundleInfo the info to change if we need to add exports.
      */
-    ExtensionManager(Logger logger, Map configMap) throws BundleException
+    ExtensionManager(Logger logger, Felix felix) throws BundleException
     {
-        m_module = new ExtensionManagerModule();
+        m_module = new ExtensionManagerModule(felix);
         m_extensions = null;
         m_names = null;
         m_sourceToExtensions = null;
@@ -150,7 +150,7 @@
 // TODO: FRAMEWORK - Not all of this stuff really belongs here, probably only exports.
         // Populate system bundle header map.
         m_headerMap.put(FelixConstants.BUNDLE_VERSION,
-            configMap.get(FelixConstants.FELIX_VERSION_PROPERTY));
+            felix.getConfig().get(FelixConstants.FELIX_VERSION_PROPERTY));
         m_headerMap.put(FelixConstants.BUNDLE_SYMBOLICNAME,
             FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
         m_headerMap.put(FelixConstants.BUNDLE_NAME, "System Bundle");
@@ -166,11 +166,11 @@
         // We must construct the system bundle's export metadata.
         // Get configuration property that specifies which class path
         // packages should be exported by the system bundle.
-        String syspkgs = (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES);
+        String syspkgs = (String) felix.getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES);
         // If no system packages were specified, load our default value.
         syspkgs = (syspkgs == null) ? loadDefaultSystemPackages(m_logger) : syspkgs;
         // If any extra packages are specified, then append them.
-        String extra = (String) configMap.get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
+        String extra = (String) felix.getConfig().get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
         syspkgs = (extra == null) ? syspkgs : syspkgs + "," + extra;
         try
         {
@@ -453,7 +453,7 @@
 
         for (Iterator iter = m_extensions.iterator(); iter.hasNext();)
         {
-            URL result = ((BundleImpl) iter.next()).getCurrentModule().getResourceFromContent(path);
+            URL result = ((BundleImpl) iter.next()).getCurrentModule().getEntry(path);
 
             if (result != null)
             {
@@ -613,9 +613,9 @@
 
     class ExtensionManagerModule extends ModuleImpl
     {
-        ExtensionManagerModule() throws BundleException
+        ExtensionManagerModule(Felix felix) throws BundleException
         {
-            super(m_logger, null, null, "0", null, null);
+            super(m_logger, null, null, felix, "0", null, null);
         }
 
         public Map getHeaders()
@@ -635,20 +635,40 @@
 
         public Class getClassByDelegation(String name) throws ClassNotFoundException
         {
-            // System bundle does not delegate to other modules.
-            return getClassFromModule(name);
+            if (!m_exportNames.contains(Util.getClassPackage(name)))
+            {
+                return null;
+            }
+
+            try
+            {
+                return getClass().getClassLoader().loadClass(name);
+            }
+            catch (ClassNotFoundException ex)
+            {
+                m_logger.log(
+                    Logger.LOG_WARNING,
+                    ex.getMessage(),
+                    ex);
+            }
+            return null;
         }
 
         public URL getResourceByDelegation(String name)
         {
-            // System bundle does not delegate to other modules.
-            return getResourceFromModule(name);
+            return getClass().getClassLoader().getResource(name);
         }
 
         public Enumeration getResourcesByDelegation(String name)
         {
-            // System bundle does not delegate to other modules.
-            return getResourcesFromModule(name);
+           try
+           {
+               return getClass().getClassLoader().getResources(name);
+           }
+           catch (IOException ex)
+           {
+               return null;
+           }
         }
 
         public Logger getLogger()
@@ -666,12 +686,7 @@
             return null;
         }
 
-        public synchronized IContent[] getClassPath()
-        {
-            throw new UnsupportedOperationException("Should not be used!");
-        }
-
-        public synchronized void attachFragmentContents(IContent[] fragmentContents)
+        public void attachFragmentContents(IContent[] fragmentContents)
             throws Exception
         {
             throw new UnsupportedOperationException("Should not be used!");
@@ -697,60 +712,7 @@
             return m_urlPolicy;
         }
 
-        public Class findClassByDelegation(String name) throws ClassNotFoundException
-        {
-            return getClassFromModule(name);
-        }
-
-        public URL findResourceByDelegation(String name) throws ResourceNotFoundException
-        {
-            return getResourceFromModule(name);
-        }
-
-        public Enumeration findResourcesByDelegation(String name) throws ResourceNotFoundException
-        {
-            return getResourcesFromModule(name);
-        }
-
-        public Class getClassFromModule(String name)
-        {
-            if (!m_exportNames.contains(Util.getClassPackage(name)))
-            {
-                return null;
-            }
-
-            try
-            {
-                return getClass().getClassLoader().loadClass(name);
-            }
-            catch (ClassNotFoundException ex)
-            {
-                m_logger.log(
-                    Logger.LOG_WARNING,
-                    ex.getMessage(),
-                    ex);
-            }
-            return null;
-        }
-
-        public URL getResourceFromModule(String name)
-        {
-            return getClass().getClassLoader().getResource(name);
-        }
-
-        public Enumeration getResourcesFromModule(String name)
-        {
-           try
-           {
-               return getClass().getClassLoader().getResources(name);
-           }
-           catch (IOException ex)
-           {
-               return null;
-           }
-        }
-
-        public URL getResourceFromContent(String name)
+        public URL getEntry(String name)
         {
             // There is no content for the system bundle, so return null.
             return null;
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 7c27ea6..25b6167 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -27,7 +27,7 @@
 import org.apache.felix.framework.cache.*;
 import org.apache.felix.framework.ext.SecurityProvider;
 import org.apache.felix.framework.searchpolicy.*;
-import org.apache.felix.framework.searchpolicy.PackageSource;
+import org.apache.felix.framework.searchpolicy.ModuleImpl.ModuleClassLoader;
 import org.apache.felix.framework.util.*;
 import org.apache.felix.framework.util.manifestparser.*;
 import org.apache.felix.moduleloader.*;
@@ -295,7 +295,7 @@
 
         // Create the extension manager, which we will use as the module
         // definition for creating the system bundle module.
-        m_extensionManager = new ExtensionManager(m_logger, m_configMap);
+        m_extensionManager = new ExtensionManager(m_logger, this);
         addModule(m_extensionManager.getModule());
     }
 
@@ -1168,7 +1168,7 @@
         {
             throw new IllegalStateException("The bundle is uninstalled.");
         }
-        return bundle.getCurrentModule().getResourceFromContent(name);
+        return bundle.getCurrentModule().getEntry(name);
     }
 
     /**
diff --git a/framework/src/main/java/org/apache/felix/framework/FindEntriesEnumeration.java b/framework/src/main/java/org/apache/felix/framework/FindEntriesEnumeration.java
index 3bd1b9a..c95acf9 100644
--- a/framework/src/main/java/org/apache/felix/framework/FindEntriesEnumeration.java
+++ b/framework/src/main/java/org/apache/felix/framework/FindEntriesEnumeration.java
@@ -113,8 +113,7 @@
                     if (checkSubstring(m_filePattern, lastElement))
                     {
                         // Convert entry name into an entry URL.
-                        return m_bundle.getCurrentModule()
-                            .getResourceFromContent(entryName);
+                        return m_bundle.getCurrentModule().getEntry(entryName);
                     }
                 }
             }
diff --git a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
index f2f72f6..812bc7f 100644
--- a/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
+++ b/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
@@ -18,7 +18,6 @@
  */
 package org.apache.felix.framework;
 
-import java.io.IOException;
 import java.net.ContentHandler;
 import java.net.ContentHandlerFactory;
 import java.net.MalformedURLException;
@@ -33,7 +32,7 @@
 import java.util.Map;
 import java.util.StringTokenizer;
 
-import org.apache.felix.framework.searchpolicy.ModuleClassLoader;
+import org.apache.felix.framework.searchpolicy.ModuleImpl.ModuleClassLoader;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.SecureAction;
 import org.apache.felix.framework.util.SecurityManagerEx;
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleClassLoader.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleClassLoader.java
deleted file mode 100644
index e93b911..0000000
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleClassLoader.java
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * 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.
- */
-package org.apache.felix.framework.searchpolicy;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.security.ProtectionDomain;
-import java.security.SecureClassLoader;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.felix.framework.Logger;
-import org.apache.felix.framework.cache.JarContent;
-import org.apache.felix.framework.util.Util;
-import org.apache.felix.framework.util.manifestparser.R4Library;
-import org.apache.felix.framework.util.manifestparser.Requirement;
-import org.apache.felix.moduleloader.ICapability;
-import org.apache.felix.moduleloader.IContent;
-import org.apache.felix.moduleloader.IModule;
-import org.apache.felix.moduleloader.IRequirement;
-import org.apache.felix.moduleloader.IWire;
-import org.apache.felix.moduleloader.ResourceNotFoundException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-
-public class ModuleClassLoader extends SecureClassLoader
-{
-    private static final Constructor m_dexFileClassConstructor;
-    private static final Method m_dexFileClassLoadClass;
-    static
-    {
-        Constructor dexFileClassConstructor = null;
-        Method dexFileClassLoadClass = null;
-        try
-        {
-            Class dexFileClass;
-            try
-            {
-                dexFileClass = Class.forName("dalvik.system.DexFile");
-            }
-            catch (Exception ex)
-            {
-                dexFileClass = Class.forName("android.dalvik.DexFile");
-            }
-
-            dexFileClassConstructor = dexFileClass.getConstructor(
-                new Class[] { java.io.File.class });
-            dexFileClassLoadClass = dexFileClass.getMethod("loadClass",
-                new Class[] { String.class, ClassLoader.class });
-        }
-        catch (Exception ex)
-        {
-           dexFileClassConstructor = null;
-           dexFileClassLoadClass = null;
-        }
-        m_dexFileClassConstructor = dexFileClassConstructor;
-        m_dexFileClassLoadClass = dexFileClassLoadClass;
-    }
-
-    private final ModuleImpl m_module;
-    private final ProtectionDomain m_protectionDomain;
-    private final Map m_jarContentToDexFile;
-
-    public ModuleClassLoader(ModuleImpl module, ProtectionDomain protectionDomain)
-    {
-        m_module = module;
-        m_protectionDomain = protectionDomain;
-        if (m_dexFileClassConstructor != null)
-        {
-            m_jarContentToDexFile = new HashMap();
-        }
-        else
-        {
-            m_jarContentToDexFile = null;
-        }
-    }
-
-    public IModule getModule()
-    {
-        return m_module;
-    }
-
-    protected Class loadClass(String name, boolean resolve)
-        throws ClassNotFoundException
-    {
-        Class clazz = null;
-
-        // Make sure the class was not already loaded.
-        synchronized (this)
-        {
-            clazz = findLoadedClass(name);
-        }
-
-        if (clazz == null)
-        {
-            try
-            {
-                return (Class) m_module.findClassOrResourceByDelegation(name, true);
-            }
-            catch (ResourceNotFoundException ex)
-            {
-                // This should never happen since we are asking for a class,
-                // so just ignore it.
-            }
-            catch (ClassNotFoundException cnfe)
-            {
-                ClassNotFoundException ex = cnfe;
-                String msg = name;
-                if (m_module.getLogger().getLogLevel() >= Logger.LOG_DEBUG)
-                {
-                    msg = diagnoseClassLoadError(m_module, name);
-                    ex = new ClassNotFoundException(msg, cnfe);
-                }
-                throw ex;
-            }
-        }
-
-        // Resolve the class and return it.
-        if (resolve)
-        {
-            resolveClass(clazz);
-        }
-        return clazz;
-    }
-
-    protected Class findClass(String name) throws ClassNotFoundException
-    {
-        // Do a quick check here to see if we can short-circuit this
-        // entire process if the class was already loaded.
-        Class clazz = null;
-        synchronized (this)
-        {
-            clazz = findLoadedClass(name);
-        }
-
-        // Search for class in module.
-        if (clazz == null)
-        {
-            String actual = name.replace('.', '/') + ".class";
-
-            byte[] bytes = null;
-
-            IContent content = null;
-            // Check the module class path.
-            for (int i = 0;
-                (bytes == null) &&
-                (i < m_module.getClassPath().length); i++)
-            {
-                bytes = m_module.getClassPath()[i].getEntryAsBytes(actual);
-                content = m_module.getClassPath()[i];
-            }
-
-            if (bytes != null)
-            {
-                // Before we actually attempt to define the class, grab
-                // the lock for this class loader and make sure than no
-                // other thread has defined this class in the meantime.
-                synchronized (this)
-                {
-                    clazz = findLoadedClass(name);
-
-                    if (clazz == null)
-                    {
-                        // We need to try to define a Package object for the class
-                        // before we call defineClass(). Get the package name and
-                        // see if we have already created the package.
-                        String pkgName = Util.getClassPackage(name);
-                        if (pkgName.length() > 0)
-                        {
-                            if (getPackage(pkgName) == null)
-                            {
-                                Object[] params = definePackage(pkgName);
-                                if (params != null)
-                                {
-                                    definePackage(
-                                        pkgName,
-                                        (String) params[0],
-                                        (String) params[1],
-                                        (String) params[2],
-                                        (String) params[3],
-                                        (String) params[4],
-                                        (String) params[5],
-                                        null);
-                                }
-                                else
-                                {
-                                    definePackage(pkgName, null, null,
-                                        null, null, null, null, null);
-                                }
-                            }
-                        }
-
-                        // If we can load the class from a dex file do so
-                        if (content instanceof JarContent)
-                        {
-                            try
-                            {
-                                clazz = getDexFileClass((JarContent) content, name, this);
-                            }
-                            catch (Exception ex)
-                            {
-                                // Looks like we can't
-                            }
-                        }
-
-                        if (clazz == null)
-                        {
-                            // If we have a security context, then use it to
-                            // define the class with it for security purposes,
-                            // otherwise define the class without a protection domain.
-                            if (m_protectionDomain != null)
-                            {
-                                clazz = defineClass(name, bytes, 0, bytes.length,
-                                    m_protectionDomain);
-                            }
-                            else
-                            {
-                                clazz = defineClass(name, bytes, 0, bytes.length);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        return clazz;
-    }
-
-    private Object[] definePackage(String pkgName)
-    {
-        Map headerMap = m_module.getHeaders();
-        String spectitle = (String) headerMap.get("Specification-Title");
-        String specversion = (String) headerMap.get("Specification-Version");
-        String specvendor = (String) headerMap.get("Specification-Vendor");
-        String impltitle = (String) headerMap.get("Implementation-Title");
-        String implversion = (String) headerMap.get("Implementation-Version");
-        String implvendor = (String) headerMap.get("Implementation-Vendor");
-        if ((spectitle != null)
-            || (specversion != null)
-            || (specvendor != null)
-            || (impltitle != null)
-            || (implversion != null)
-            || (implvendor != null))
-        {
-            return new Object[] {
-                spectitle, specversion, specvendor, impltitle, implversion, implvendor
-            };
-        }
-        return null;
-    }
-
-    private Class getDexFileClass(JarContent content, String name, ClassLoader loader)
-        throws Exception
-    {
-        if (m_jarContentToDexFile == null)
-        {
-            return null;
-        }
-
-        Object dexFile = null;
-
-        if (!m_jarContentToDexFile.containsKey(content))
-        {
-            try
-            {
-                dexFile = m_dexFileClassConstructor.newInstance(
-                    new Object[] { content.getFile() });
-            }
-            finally
-            {
-                m_jarContentToDexFile.put(content, dexFile);
-            }
-        }
-        else
-        {
-            dexFile = m_jarContentToDexFile.get(content);
-        }
-
-        if (dexFile != null)
-        {
-            return (Class) m_dexFileClassLoadClass.invoke(dexFile,
-                new Object[] { name.replace('.','/'), loader });
-        }
-        return null;
-    }
-
-    public URL getResource(String name)
-    {
-        try
-        {
-            return (URL) m_module.findClassOrResourceByDelegation(name, false);
-        }
-        catch (ClassNotFoundException ex)
-        {
-            // This should never happen, so just ignore it.
-        }
-        catch (ResourceNotFoundException ex)
-        {
-            // Not much we can do here since getResource() does not throw any
-            // exceptions, so just ignore it too.
-        }
-        return null;
-    }
-
-    protected URL findResource(String name)
-    {
-        return m_module.getResourceFromModule(name);
-    }
-
-    // This should actually be findResources(), but it can't be for the
-    // reason described below for the actual findResources() method.
-    Enumeration findResourcesFromModule(String name)
-    {
-        return m_module.getResourcesFromModule(name);
-    }
-
-    // The findResources() method should only look at the module itself, but
-    // instead it tries to delegate because in Java version prior to 1.5 the
-    // getResources() method was final and could not be overridden. We should
-    // override getResources() like getResource() to make it delegate, but we
-    // can't. As a workaround, we make findResources() delegate instead.
-    protected Enumeration findResources(String name)
-    {
-        return m_module.getResourcesByDelegation(name);
-    }
-
-    protected String findLibrary(String name)
-    {
-        // Remove leading slash, if present.
-        if (name.startsWith("/"))
-        {
-            name = name.substring(1);
-        }
-
-        R4Library[] libs = m_module.getNativeLibraries();
-        for (int i = 0; (libs != null) && (i < libs.length); i++)
-        {
-            if (libs[i].match(name))
-            {
-                return m_module.getContent()
-                    .getEntryAsNativeLibrary(libs[i].getEntryName());
-            }
-        }
-
-        return null;
-    }
-
-    public String toString()
-    {
-        return m_module.toString();
-    }
-
-    private static String diagnoseClassLoadError(ModuleImpl module, String name)
-    {
-        // We will try to do some diagnostics here to help the developer
-        // deal with this exception.
-
-        // 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());
-
-        // Next, check to see if the module imports the package.
-        IWire[] wires = module.getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            if (wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
-                wires[i].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
-            {
-                long expId = Util.getBundleIdFromModuleId(wires[i].getExporter().getId());
-
-                StringBuffer sb = new StringBuffer("*** Package '");
-                sb.append(pkgName);
-                sb.append("' is imported by bundle ");
-                sb.append(impId);
-                sb.append(" from bundle ");
-                sb.append(expId);
-                sb.append(", but the exported package from bundle ");
-                sb.append(expId);
-                sb.append(" does not contain the requested class '");
-                sb.append(name);
-                sb.append("'. Please verify that the class name is correct in the importing bundle ");
-                sb.append(impId);
-                sb.append(" and/or that the exported package is correctly bundled in ");
-                sb.append(expId);
-                sb.append(". ***");
-
-                return sb.toString();
-            }
-        }
-
-        // Next, check to see if the package was optionally imported and
-        // whether or not there is an exporter available.
-        IRequirement[] reqs = module.getRequirements();
-/*
- * TODO: RB - Fix diagnostic message for optional imports.
-        for (int i = 0; (reqs != null) && (i < reqs.length); i++)
-        {
-            if (reqs[i].getName().equals(pkgName) && reqs[i].isOptional())
-            {
-                // Try to see if there is an exporter available.
-                IModule[] exporters = getResolvedExporters(reqs[i], true);
-                exporters = (exporters.length == 0)
-                    ? getUnresolvedExporters(reqs[i], true) : exporters;
-
-                // An exporter might be available, but it may have attributes
-                // that do not match the importer's required attributes, so
-                // check that case by simply looking for an exporter of the
-                // desired package without any attributes.
-                if (exporters.length == 0)
-                {
-                    IRequirement pkgReq = new Requirement(
-                        ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
-                    exporters = getResolvedExporters(pkgReq, true);
-                    exporters = (exporters.length == 0)
-                        ? getUnresolvedExporters(pkgReq, true) : exporters;
-                }
-
-                long expId = (exporters.length == 0)
-                    ? -1 : Util.getBundleIdFromModuleId(exporters[0].getId());
-
-                StringBuffer sb = new StringBuffer("*** Class '");
-                sb.append(name);
-                sb.append("' was not found, but this is likely normal since package '");
-                sb.append(pkgName);
-                sb.append("' is optionally imported by bundle ");
-                sb.append(impId);
-                sb.append(".");
-                if (exporters.length > 0)
-                {
-                    sb.append(" However, bundle ");
-                    sb.append(expId);
-                    if (reqs[i].isSatisfied(
-                        Util.getExportPackage(exporters[0], reqs[i].getName())))
-                    {
-                        sb.append(" does export this package. Bundle ");
-                        sb.append(expId);
-                        sb.append(" must be installed before bundle ");
-                        sb.append(impId);
-                        sb.append(" is resolved or else the optional import will be ignored.");
-                    }
-                    else
-                    {
-                        sb.append(" does export this package with attributes that do not match.");
-                    }
-                }
-                sb.append(" ***");
-
-                return sb.toString();
-            }
-        }
-*/
-        // Next, check to see if the package is dynamically imported by the module.
-/* TODO: RESOLVER: Need to fix this too.
-        IRequirement[] dynamics = module.getDefinition().getDynamicRequirements();
-        for (int dynIdx = 0; dynIdx < dynamics.length; dynIdx++)
-        {
-            IRequirement target = createDynamicRequirement(dynamics[dynIdx], pkgName);
-            if (target != null)
-            {
-                // Try to see if there is an exporter available.
-                PackageSource[] exporters = getResolvedCandidates(target);
-                exporters = (exporters.length == 0)
-                    ? getUnresolvedCandidates(target) : exporters;
-
-                // An exporter might be available, but it may have attributes
-                // that do not match the importer's required attributes, so
-                // check that case by simply looking for an exporter of the
-                // desired package without any attributes.
-                if (exporters.length == 0)
-                {
-                    try
-                    {
-                        IRequirement pkgReq = new Requirement(
-                            ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
-                        exporters = getResolvedCandidates(pkgReq);
-                        exporters = (exporters.length == 0)
-                            ? getUnresolvedCandidates(pkgReq) : exporters;
-                    }
-                    catch (InvalidSyntaxException ex)
-                    {
-                        // This should never happen.
-                    }
-                }
-
-                long expId = (exporters.length == 0)
-                    ? -1 : Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
-
-                StringBuffer sb = new StringBuffer("*** Class '");
-                sb.append(name);
-                sb.append("' was not found, but this is likely normal since package '");
-                sb.append(pkgName);
-                sb.append("' is dynamically imported by bundle ");
-                sb.append(impId);
-                sb.append(".");
-                if (exporters.length > 0)
-                {
-                    try
-                    {
-                        if (!target.isSatisfied(
-                            Util.getSatisfyingCapability(exporters[0].m_module,
-                                new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"))))
-                        {
-                            sb.append(" However, bundle ");
-                            sb.append(expId);
-                            sb.append(" does export this package with attributes that do not match.");
-                        }
-                    }
-                    catch (InvalidSyntaxException ex)
-                    {
-                        // This should never happen.
-                    }
-                }
-                sb.append(" ***");
-
-                return sb.toString();
-            }
-        }
-*/
-        IRequirement pkgReq = null;
-        try
-        {
-            pkgReq = new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
-        }
-        catch (InvalidSyntaxException ex)
-        {
-            // This should never happen.
-        }
-        PackageSource[] exporters =
-            module.getResolver().getResolvedCandidates(pkgReq);
-        exporters = (exporters.length == 0)
-            ? module.getResolver().getUnresolvedCandidates(pkgReq)
-            : exporters;
-        if (exporters.length > 0)
-        {
-            boolean classpath = false;
-            try
-            {
-                ModuleClassLoader.class.getClassLoader().loadClass(name);
-                classpath = true;
-            }
-            catch (NoClassDefFoundError err)
-            {
-                // Ignore
-            }
-            catch (Exception ex)
-            {
-                // Ignore
-            }
-
-            long expId = Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
-
-            StringBuffer sb = new StringBuffer("*** Class '");
-            sb.append(name);
-            sb.append("' was not found because bundle ");
-            sb.append(impId);
-            sb.append(" does not import '");
-            sb.append(pkgName);
-            sb.append("' even though bundle ");
-            sb.append(expId);
-            sb.append(" does export it.");
-            if (classpath)
-            {
-                sb.append(" Additionally, the class is also available from the system class loader. There are two fixes: 1) Add an import for '");
-                sb.append(pkgName);
-                sb.append("' to bundle ");
-                sb.append(impId);
-                sb.append("; imports are necessary for each class directly touched by bundle code or indirectly touched, such as super classes if their methods are used. ");
-                sb.append("2) Add package '");
-                sb.append(pkgName);
-                sb.append("' to the '");
-                sb.append(Constants.FRAMEWORK_BOOTDELEGATION);
-                sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity.");
-            }
-            else
-            {
-                sb.append(" To resolve this issue, add an import for '");
-                sb.append(pkgName);
-                sb.append("' to bundle ");
-                sb.append(impId);
-                sb.append(".");
-            }
-            sb.append(" ***");
-
-            return sb.toString();
-        }
-
-        // Next, try to see if the class is available from the system
-        // class loader.
-        try
-        {
-            ModuleClassLoader.class.getClassLoader().loadClass(name);
-
-            StringBuffer sb = new StringBuffer("*** Package '");
-            sb.append(pkgName);
-            sb.append("' is not imported by bundle ");
-            sb.append(impId);
-            sb.append(", nor is there any bundle that exports package '");
-            sb.append(pkgName);
-            sb.append("'. However, the class '");
-            sb.append(name);
-            sb.append("' is available from the system class loader. There are two fixes: 1) Add package '");
-            sb.append(pkgName);
-            sb.append("' to the '");
-            sb.append(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
-            sb.append("' property and modify bundle ");
-            sb.append(impId);
-            sb.append(" to import this package; this causes the system bundle to export class path packages. 2) Add package '");
-            sb.append(pkgName);
-            sb.append("' to the '");
-            sb.append(Constants.FRAMEWORK_BOOTDELEGATION);
-            sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity.");
-            sb.append(" ***");
-
-            return sb.toString();
-        }
-        catch (Exception ex2)
-        {
-        }
-
-        // Finally, if there are no imports or exports for the package
-        // and it is not available on the system class path, simply
-        // log a message saying so.
-        StringBuffer sb = new StringBuffer("*** Class '");
-        sb.append(name);
-        sb.append("' was not found. Bundle ");
-        sb.append(impId);
-        sb.append(" does not import package '");
-        sb.append(pkgName);
-        sb.append("', nor is the package exported by any other bundle or available from the system class loader.");
-        sb.append(" ***");
-
-        return sb.toString();
-    }
-}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
index f70b147..1e63832 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
@@ -21,18 +21,25 @@
 import org.apache.felix.moduleloader.*;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.net.URL;
 import java.security.ProtectionDomain;
+import java.security.SecureClassLoader;
 import java.util.ArrayList;
 import java.util.Enumeration;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.Vector;
 import org.apache.felix.framework.Felix.FelixResolver;
 import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.cache.JarContent;
 import org.apache.felix.framework.util.CompoundEnumeration;
 import org.apache.felix.framework.util.FelixConstants;
 import org.apache.felix.framework.util.SecureAction;
@@ -40,9 +47,11 @@
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.ManifestParser;
 import org.apache.felix.framework.util.manifestparser.R4Library;
+import org.apache.felix.framework.util.manifestparser.Requirement;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.Version;
 
 public class ModuleImpl implements IModule
@@ -62,8 +71,7 @@
     private final IRequirement[] m_requirements;
     private final IRequirement[] m_dynamicRequirements;
     private final R4Library[] m_nativeLibraries;
-
-    private Bundle m_bundle = null;
+    private final Bundle m_bundle;
 
     private IModule[] m_fragments = null;
     private IWire[] m_wires = null;
@@ -86,12 +94,18 @@
     // Re-usable security manager for accessing class context.
     private static SecurityManagerEx m_sm = new SecurityManagerEx();
 
-    public ModuleImpl(Logger logger, Map configMap, FelixResolver resolver,
-        String id, Map headerMap, IContent content) throws BundleException
+    // Thread local to detect class loading cycles.
+    private final ThreadLocal m_cycleCheck = new ThreadLocal();
+
+    public ModuleImpl(
+        Logger logger, Map configMap, FelixResolver resolver,
+        Bundle bundle, String id, Map headerMap, IContent content)
+        throws BundleException
     {
         m_logger = logger;
         m_configMap = configMap;
         m_resolver = resolver;
+        m_bundle = bundle;
         m_id = id;
         m_headerMap = headerMap;
         m_content = content;
@@ -190,32 +204,18 @@
         }
    }
 
-    Logger getLogger()
+    //
+    // Metadata access methods.
+    //
+
+    public Map getHeaders()
     {
-        return m_logger;
+        return m_headerMap;
     }
 
-    FelixResolver getResolver()
+    public String getSymbolicName()
     {
-        return m_resolver;
-    }
-
-    public synchronized Bundle getBundle()
-    {
-        return m_bundle;
-    }
-
-    public synchronized void setBundle(Bundle bundle)
-    {
-        if (m_bundle == null)
-        {
-            m_bundle = bundle;
-        }
-    }
-
-    public String getId()
-    {
-        return m_id;
+        return m_symbolicName;
     }
 
     public String getManifestVersion()
@@ -228,16 +228,6 @@
         return m_version;
     }
 
-    public String getSymbolicName()
-    {
-        return m_symbolicName;
-    }
-
-    public Map getHeaders()
-    {
-        return m_headerMap;
-    }
-
     public ICapability[] getCapabilities()
     {
         return m_capabilities;
@@ -258,63 +248,18 @@
         return m_nativeLibraries;
     }
 
-    public synchronized IModule[] getFragments()
+    //
+    // Run-time data access.
+    //
+
+    public Bundle getBundle()
     {
-        return m_fragments;
+        return m_bundle;
     }
 
-    public synchronized void attachFragments(IModule[] fragments) throws Exception
+    public String getId()
     {
-        // Remove module from old fragment dependencies.
-        // We will generally only remove module fragment
-        // dependencies when we are uninstalling the module.
-        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
-        {
-            ((ModuleImpl) m_fragments[i]).removeDependentHost(this);
-        }
-
-        // Update the dependencies on the new fragments.
-        m_fragments = fragments;
-
-        // We need to add ourself as a dependent of each fragment
-        // module. We also need to create an array of fragment contents
-        // to attach to our content loader.
-        if (m_fragments != null)
-        {
-            IContent[] fragmentContents = new IContent[m_fragments.length];
-            for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
-            {
-                ((ModuleImpl) m_fragments[i]).addDependentHost(this);
-                fragmentContents[i] =
-                    m_fragments[i].getContent()
-                        .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
-            }
-            // Now attach the fragment contents to our content loader.
-            attachFragmentContents(fragmentContents);
-        }
-    }
-
-    private void attachFragmentContents(IContent[] fragmentContents)
-        throws Exception
-    {
-        // Close existing fragment contents.
-        if (m_fragmentContents != null)
-        {
-            for (int i = 0; i < m_fragmentContents.length; i++)
-            {
-                m_fragmentContents[i].close();
-            }
-        }
-        m_fragmentContents = fragmentContents;
-
-        if (m_contentPath != null)
-        {
-            for (int i = 0; i < m_contentPath.length; i++)
-            {
-                m_contentPath[i].close();
-            }
-        }
-        m_contentPath = initializeContentPath();
+        return m_id;
     }
 
     public synchronized IWire[] getWires()
@@ -355,263 +300,6 @@
         }
     }
 
-    public synchronized IModule[] getDependentHosts()
-    {
-        return m_dependentHosts;
-    }
-
-    public synchronized void addDependentHost(IModule module)
-    {
-        m_dependentHosts = addDependent(m_dependentHosts, module);
-    }
-
-    public synchronized void removeDependentHost(IModule module)
-    {
-        m_dependentHosts = removeDependent(m_dependentHosts, module);
-    }
-
-    public synchronized IModule[] getDependentImporters()
-    {
-        return m_dependentImporters;
-    }
-
-    public synchronized void addDependentImporter(IModule module)
-    {
-        m_dependentImporters = addDependent(m_dependentImporters, module);
-    }
-
-    public synchronized void removeDependentImporter(IModule module)
-    {
-        m_dependentImporters = removeDependent(m_dependentImporters, module);
-    }
-
-    public synchronized IModule[] getDependentRequirers()
-    {
-        return m_dependentRequirers;
-    }
-
-    public synchronized void addDependentRequirer(IModule module)
-    {
-        m_dependentRequirers = addDependent(m_dependentRequirers, module);
-    }
-
-    public synchronized void removeDependentRequirer(IModule module)
-    {
-        m_dependentRequirers = removeDependent(m_dependentRequirers, module);
-    }
-
-    public synchronized IModule[] getDependents()
-    {
-        IModule[] dependents = new IModule[
-            m_dependentHosts.length + m_dependentImporters.length + m_dependentRequirers.length];
-        System.arraycopy(
-            m_dependentHosts,
-            0,
-            dependents,
-            0,
-            m_dependentHosts.length);
-        System.arraycopy(
-            m_dependentImporters,
-            0,
-            dependents,
-            m_dependentHosts.length,
-            m_dependentImporters.length);
-        System.arraycopy(
-            m_dependentRequirers,
-            0,
-            dependents,
-            m_dependentHosts.length + m_dependentImporters.length,
-            m_dependentRequirers.length);
-        return dependents;
-    }
-
-    public Class getClassByDelegation(String name) throws ClassNotFoundException
-    {
-        try
-        {
-            return getClassLoader().loadClass(name);
-        }
-        catch (ClassNotFoundException ex)
-        {
-// TODO: REFACTOR - Should this log?
-            m_logger.log(
-                Logger.LOG_WARNING,
-                ex.getMessage(),
-                ex);
-            throw ex;
-        }
-    }
-
-    public URL getResourceByDelegation(String name)
-    {
-        return getClassLoader().getResource(name);
-    }
-
-    public Enumeration getResourcesByDelegation(String name)
-    {
-        Enumeration urls = null;
-        List enums = new ArrayList();
-
-        // First, try to resolve the originating module.
-// TODO: FRAMEWORK - Consider opimizing this call to resolve, since it is called
-// for each class load.
-        try
-        {
-            m_resolver.resolve(this);
-        }
-        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.
-            urls = getResourcesFromModule(name);
-            return urls;
-        }
-
-        // Get the package of the target class/resource.
-        String pkgName = Util.getResourcePackage(name);
-
-        // Delegate any packages listed in the boot delegation
-        // property to the parent class loader.
-        // NOTE for the default package:
-        // 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 (pkgName.length() > 0)
-        {
-            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 ((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)))
-                {
-                    try
-                    {
-                        urls = getClass().getClassLoader().getResources(name);
-                    }
-                    catch (IOException ex)
-                    {
-                        // This shouldn't happen and even if it does, there
-                        // is nothing we can do, so just ignore it.
-                    }
-                    // If this is a java.* package, then always terminate the
-                    // search; otherwise, continue to look locally.
-                    if (m_bootPkgs[i].startsWith("java."))
-                    {
-                        return urls;
-                    }
-
-                    enums.add(urls);
-                    break;
-                }
-            }
-        }
-
-        // Look in the module's imports.
-        // We delegate to the module's wires for the resources.
-        // If any resources are found, this means that the package of these
-        // resources is imported, we must not keep looking since we do not
-        // support split-packages.
-
-        // Note that the search may be aborted if this method throws an
-        // exception, otherwise it continues if a null is returned.
-        IWire[] wires = getWires();
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            if (wires[i] instanceof R4Wire)
-            {
-                try
-                {
-                    // If we find the class or resource, then return it.
-                    urls = wires[i].getResources(name);
-                }
-                catch (ResourceNotFoundException ex)
-                {
-                    urls = null;
-                }
-                if (urls != null)
-                {
-                    enums.add(urls);
-                    return new CompoundEnumeration((Enumeration[])
-                        enums.toArray(new Enumeration[enums.size()]));
-                }
-            }
-        }
-
-        // See whether we can get the resource from the required bundles and
-        // regardless of whether or not this is the case continue to the next
-        // step potentially passing on the result of this search (if any).
-        for (int i = 0; (wires != null) && (i < wires.length); i++)
-        {
-            if (wires[i] instanceof R4WireModule)
-            {
-                try
-                {
-                    // If we find the class or resource, then add it.
-                    urls = wires[i].getResources(name);
-                }
-                catch (ResourceNotFoundException ex)
-                {
-                    urls = null;
-                }
-                if (urls != null)
-                {
-                    enums.add(urls);
-                }
-            }
-        }
-
-        // Try the module's own class path. If we can find the resource then
-        // return it together with the results from the other searches else
-        // try to look into the dynamic imports.
-        urls = getResourcesFromModule(name);
-        if (urls != null)
-        {
-            enums.add(urls);
-        }
-        else
-        {
-            // If not found, then try the module's dynamic imports.
-            // 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/resource via a dynamic import, if possible.
-            IWire wire = null;
-            try
-            {
-                wire = m_resolver.resolveDynamicImport(this, pkgName);
-            }
-            catch (ResolveException ex)
-            {
-                // Ignore this since it is likely normal.
-            }
-            if (wire != null)
-            {
-                try
-                {
-                    urls = wire.getResources(name);
-                }
-                catch (ResourceNotFoundException ex)
-                {
-                    urls = null;
-                }
-                if (urls != null)
-                {
-                    enums.add(urls);
-                }
-            }
-        }
-
-        return new CompoundEnumeration((Enumeration[])
-            enums.toArray(new Enumeration[enums.size()]));
-    }
-
     public boolean isResolved()
     {
         return m_isResolved;
@@ -622,78 +310,16 @@
         m_isResolved = true;
     }
 
-    public String toString()
-    {
-        return m_id;
-    }
-
-    private static IModule[] addDependent(IModule[] modules, IModule module)
-    {
-        // Make sure the dependent module is not already present.
-        for (int i = 0; i < modules.length; i++)
-        {
-            if (modules[i].equals(module))
-            {
-                return modules;
-            }
-        }
-        IModule[] tmp = new IModule[modules.length + 1];
-        System.arraycopy(modules, 0, tmp, 0, modules.length);
-        tmp[modules.length] = module;
-        return tmp;
-    }
-
-    private static IModule[] removeDependent(IModule[] modules, IModule module)
-    {
-        IModule[] tmp = modules;
-
-        // Make sure the dependent module is present.
-        for (int i = 0; i < modules.length; i++)
-        {
-            if (modules[i].equals(module))
-            {
-                // If this is the module, then point to empty list.
-                if ((modules.length - 1) == 0)
-                {
-                    tmp = new IModule[0];
-                }
-                // Otherwise, we need to do some array copying.
-                else
-                {
-                    tmp = new IModule[modules.length - 1];
-                    System.arraycopy(modules, 0, tmp, 0, i);
-                    if (i < tmp.length)
-                    {
-                        System.arraycopy(modules, i + 1, tmp, i, tmp.length - i);
-                    }
-                }
-                break;
-            }
-        }
-
-        return tmp;
-    }
-
-    public synchronized void close()
-    {
-        m_content.close();
-        for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++)
-        {
-            m_contentPath[i].close();
-        }
-        for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
-        {
-            m_fragmentContents[i].close();
-        }
-        m_classLoader = null;
-    }
+    //
+    // Content access methods.
+    //
 
     public IContent getContent()
     {
         return m_content;
     }
 
-    synchronized IContent[] getClassPath()
+    private synchronized IContent[] getContentPath()
     {
         if (m_contentPath == null)
         {
@@ -709,185 +335,6 @@
         return m_contentPath;
     }
 
-    public synchronized void setURLPolicy(IURLPolicy urlPolicy)
-    {
-        m_urlPolicy = urlPolicy;
-    }
-
-    public synchronized IURLPolicy getURLPolicy()
-    {
-        return m_urlPolicy;
-    }
-
-    public synchronized void setSecurityContext(Object securityContext)
-    {
-        m_protectionDomain = (ProtectionDomain) securityContext;
-    }
-
-    public synchronized Object getSecurityContext()
-    {
-        return m_protectionDomain;
-    }
-
-    public Class getClassFromModule(String name) throws ClassNotFoundException
-    {
-        try
-        {
-            return getClassLoader().findClass(name);
-        }
-        catch (ClassNotFoundException ex)
-        {
-            m_logger.log(
-                Logger.LOG_WARNING,
-                ex.getMessage(),
-                ex);
-            throw ex;
-        }
-    }
-
-    public URL getResourceFromModule(String name)
-    {
-        URL url = null;
-
-        // Remove leading slash, if present, but special case
-        // "/" so that it returns a root URL...this isn't very
-        // clean or meaninful, but the Spring guys want it.
-        if (name.equals("/"))
-        {
-            // Just pick a class path index since it doesn't really matter.
-            url = getURLPolicy().createURL(1, name);
-        }
-        else if (name.startsWith("/"))
-        {
-            name = name.substring(1);
-        }
-
-        // Check the module class path.
-        IContent[] contentPath = getClassPath();
-        for (int i = 0;
-            (url == null) &&
-            (i < contentPath.length); i++)
-        {
-            if (contentPath[i].hasEntry(name))
-            {
-                url = getURLPolicy().createURL(i + 1, name);
-            }
-        }
-
-        return url;
-    }
-
-    public Enumeration getResourcesFromModule(String name)
-    {
-        Vector v = new Vector();
-
-        // Special case "/" so that it returns a root URLs for
-        // each bundle class path entry...this isn't very
-        // clean or meaningful, but the Spring guys want it.
-        if (name.equals("/"))
-        {
-            for (int i = 0; i < getClassPath().length; i++)
-            {
-                v.addElement(getURLPolicy().createURL(i + 1, name));
-            }
-        }
-        else
-        {
-            // Remove leading slash, if present.
-            if (name.startsWith("/"))
-            {
-                name = name.substring(1);
-            }
-
-            // Check the module class path.
-            IContent[] contentPath = getClassPath();
-            for (int i = 0; i < contentPath.length; i++)
-            {
-                if (contentPath[i].hasEntry(name))
-                {
-                    // Use the class path index + 1 for creating the path so
-                    // that we can differentiate between module content URLs
-                    // (where the path will start with 0) and module class
-                    // path URLs.
-                    v.addElement(getURLPolicy().createURL(i + 1, name));
-                }
-            }
-        }
-
-        return v.elements();
-    }
-
-    // TODO: API: Investigate how to handle this better, perhaps we need
-    // multiple URL policies, one for content -- one for class path.
-    public URL getResourceFromContent(String name)
-    {
-        URL url = null;
-
-        // Check for the special case of "/", which represents
-        // the root of the bundle according to the spec.
-        if (name.equals("/"))
-        {
-            url = getURLPolicy().createURL(0, "/");
-        }
-
-        if (url == null)
-        {
-            // Remove leading slash, if present.
-            if (name.startsWith("/"))
-            {
-                name = name.substring(1);
-            }
-
-            // Check the module content.
-            if (getContent().hasEntry(name))
-            {
-                // Module content URLs start with 0, whereas module
-                // class path URLs start with the index into the class
-                // path + 1.
-                url = getURLPolicy().createURL(0, name);
-            }
-        }
-
-        return url;
-    }
-
-    public boolean hasInputStream(int index, String urlPath)
-    {
-        if (urlPath.startsWith("/"))
-        {
-            urlPath = urlPath.substring(1);
-        }
-        if (index == 0)
-        {
-            return m_content.hasEntry(urlPath);
-        }
-        return getClassPath()[index - 1].hasEntry(urlPath);
-    }
-
-    public InputStream getInputStream(int index, String urlPath)
-        throws IOException
-    {
-        if (urlPath.startsWith("/"))
-        {
-            urlPath = urlPath.substring(1);
-        }
-        if (index == 0)
-        {
-            return m_content.getEntryAsStream(urlPath);
-        }
-        return getClassPath()[index - 1].getEntryAsStream(urlPath);
-    }
-
-    private synchronized ModuleClassLoader getClassLoader()
-    {
-        if (m_classLoader == null)
-        {
-            m_classLoader = m_secureAction.createModuleClassLoader(
-                this, m_protectionDomain);
-        }
-        return m_classLoader;
-    }
-
     private IContent[] initializeContentPath() throws Exception
     {
         List contentList = new ArrayList();
@@ -979,9 +426,70 @@
         return contentList;
     }
 
-// From ModuleClassLoader
+    public Class getClassByDelegation(String name) throws ClassNotFoundException
+    {
+        Set pkgCycleSet = (Set) m_cycleCheck.get();
+        if (pkgCycleSet == null)
+        {
+            pkgCycleSet = new HashSet();
+            m_cycleCheck.set(pkgCycleSet);
+        }
+        if (!pkgCycleSet.contains(name))
+        {
+            pkgCycleSet.add(name);
+            try
+            {
+                return getClassLoader().loadClass(name);
+            }
+            catch (ClassNotFoundException ex)
+            {
+// TODO: REFACTOR - Should this log?
+                m_logger.log(
+                    Logger.LOG_WARNING,
+                    ex.getMessage(),
+                    ex);
+                throw ex;
+            }
+            finally
+            {
+                pkgCycleSet.remove(name);
+            }
+        }
+        return null;
+    }
 
-    Object findClassOrResourceByDelegation(String name, boolean isClass)
+    public URL getResourceByDelegation(String name)
+    {
+        Set pkgCycleSet = (Set) m_cycleCheck.get();
+        if (pkgCycleSet == null)
+        {
+            pkgCycleSet = new HashSet();
+            m_cycleCheck.set(pkgCycleSet);
+        }
+        if (!pkgCycleSet.contains(name))
+        {
+            pkgCycleSet.add(name);
+            try
+            {
+                return (URL) findClassOrResourceByDelegation(name, false);
+            }
+            catch (ClassNotFoundException ex)
+            {
+            }
+            catch (ResourceNotFoundException ex)
+            {
+// TODO: REFACTOR - Should this log?
+            }
+            finally
+            {
+                pkgCycleSet.remove(name);
+            }
+        }
+
+        return null;
+    }
+
+    private Object findClassOrResourceByDelegation(String name, boolean isClass)
         throws ClassNotFoundException, ResourceNotFoundException
     {
         // First, try to resolve the originating module.
@@ -1007,7 +515,7 @@
                 // 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 = getResourceFromModule(name);
+                URL url = getResourceLocal(name);
                 if (url != null)
                 {
                     return url;
@@ -1084,8 +592,8 @@
         if (result == null)
         {
             result = (isClass)
-                ? (Object) getClassFromModule(name)
-                : (Object) getResourceFromModule(name);
+                ? (Object) getClassLoader().findClass(name)
+                : (Object) getResourceLocal(name);
 
             // If still not found, then try the module's dynamic imports.
             if (result == null)
@@ -1109,6 +617,559 @@
         return result;
     }
 
+    private URL getResourceLocal(String name)
+    {
+        URL url = null;
+
+        // Remove leading slash, if present, but special case
+        // "/" so that it returns a root URL...this isn't very
+        // clean or meaninful, but the Spring guys want it.
+        if (name.equals("/"))
+        {
+            // Just pick a class path index since it doesn't really matter.
+            url = getURLPolicy().createURL(1, name);
+        }
+        else if (name.startsWith("/"))
+        {
+            name = name.substring(1);
+        }
+
+        // Check the module class path.
+        IContent[] contentPath = getContentPath();
+        for (int i = 0;
+            (url == null) &&
+            (i < contentPath.length); i++)
+        {
+            if (contentPath[i].hasEntry(name))
+            {
+                url = getURLPolicy().createURL(i + 1, name);
+            }
+        }
+
+        return url;
+    }
+
+    public Enumeration getResourcesByDelegation(String name)
+    {
+        Set pkgCycleSet = (Set) m_cycleCheck.get();
+        if (pkgCycleSet == null)
+        {
+            pkgCycleSet = new HashSet();
+            m_cycleCheck.set(pkgCycleSet);
+        }
+        if (!pkgCycleSet.contains(name))
+        {
+            pkgCycleSet.add(name);
+            try
+            {
+                return findResourcesByDelegation(name);
+            }
+            finally
+            {
+                pkgCycleSet.remove(name);
+            }
+        }
+
+        return null;
+    }
+
+    private Enumeration findResourcesByDelegation(String name)
+    {
+        Enumeration urls = null;
+        List completeUrlList = new ArrayList();
+
+        // First, try to resolve the originating module.
+// TODO: FRAMEWORK - Consider opimizing this call to resolve, since it is called
+// for each class load.
+        try
+        {
+            m_resolver.resolve(this);
+        }
+        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.
+            urls = getResourcesLocal(name);
+            return urls;
+        }
+
+        // Get the package of the target class/resource.
+        String pkgName = Util.getResourcePackage(name);
+
+        // Delegate any packages listed in the boot delegation
+        // property to the parent class loader.
+        // NOTE for the default package:
+        // 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 (pkgName.length() > 0)
+        {
+            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 ((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)))
+                {
+                    try
+                    {
+                        urls = getClass().getClassLoader().getResources(name);
+                    }
+                    catch (IOException ex)
+                    {
+                        // This shouldn't happen and even if it does, there
+                        // is nothing we can do, so just ignore it.
+                    }
+                    // If this is a java.* package, then always terminate the
+                    // search; otherwise, continue to look locally.
+                    if (m_bootPkgs[i].startsWith("java."))
+                    {
+                        return urls;
+                    }
+
+                    completeUrlList.add(urls);
+                    break;
+                }
+            }
+        }
+
+        // Look in the module's imports.
+        // We delegate to the module's wires for the resources.
+        // If any resources are found, this means that the package of these
+        // resources is imported, we must not keep looking since we do not
+        // support split-packages.
+
+        // Note that the search may be aborted if this method throws an
+        // exception, otherwise it continues if a null is returned.
+        IWire[] wires = getWires();
+        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        {
+            if (wires[i] instanceof R4Wire)
+            {
+                try
+                {
+                    // If we find the class or resource, then return it.
+                    urls = wires[i].getResources(name);
+                }
+                catch (ResourceNotFoundException ex)
+                {
+                    urls = null;
+                }
+                if (urls != null)
+                {
+                    completeUrlList.add(urls);
+                    return new CompoundEnumeration((Enumeration[])
+                        completeUrlList.toArray(new Enumeration[completeUrlList.size()]));
+                }
+            }
+        }
+
+        // See whether we can get the resource from the required bundles and
+        // regardless of whether or not this is the case continue to the next
+        // step potentially passing on the result of this search (if any).
+        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        {
+            if (wires[i] instanceof R4WireModule)
+            {
+                try
+                {
+                    // If we find the class or resource, then add it.
+                    urls = wires[i].getResources(name);
+                }
+                catch (ResourceNotFoundException ex)
+                {
+                    urls = null;
+                }
+                if (urls != null)
+                {
+                    completeUrlList.add(urls);
+                }
+            }
+        }
+
+        // Try the module's own class path. If we can find the resource then
+        // return it together with the results from the other searches else
+        // try to look into the dynamic imports.
+        urls = getResourcesLocal(name);
+        if (urls != null)
+        {
+            completeUrlList.add(urls);
+        }
+        else
+        {
+            // If not found, then try the module's dynamic imports.
+            // 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/resource via a dynamic import, if possible.
+            IWire wire = null;
+            try
+            {
+                wire = m_resolver.resolveDynamicImport(this, pkgName);
+            }
+            catch (ResolveException ex)
+            {
+                // Ignore this since it is likely normal.
+            }
+            if (wire != null)
+            {
+                try
+                {
+                    urls = wire.getResources(name);
+                }
+                catch (ResourceNotFoundException ex)
+                {
+                    urls = null;
+                }
+                if (urls != null)
+                {
+                    completeUrlList.add(urls);
+                }
+            }
+        }
+
+        return new CompoundEnumeration((Enumeration[])
+            completeUrlList.toArray(new Enumeration[completeUrlList.size()]));
+    }
+
+    private Enumeration getResourcesLocal(String name)
+    {
+        Vector v = new Vector();
+
+        // Special case "/" so that it returns a root URLs for
+        // each bundle class path entry...this isn't very
+        // clean or meaningful, but the Spring guys want it.
+        final IContent[] contentPath = getContentPath();
+        if (name.equals("/"))
+        {
+            for (int i = 0; i < contentPath.length; i++)
+            {
+                v.addElement(getURLPolicy().createURL(i + 1, name));
+            }
+        }
+        else
+        {
+            // Remove leading slash, if present.
+            if (name.startsWith("/"))
+            {
+                name = name.substring(1);
+            }
+
+            // Check the module class path.
+            for (int i = 0; i < contentPath.length; i++)
+            {
+                if (contentPath[i].hasEntry(name))
+                {
+                    // Use the class path index + 1 for creating the path so
+                    // that we can differentiate between module content URLs
+                    // (where the path will start with 0) and module class
+                    // path URLs.
+                    v.addElement(getURLPolicy().createURL(i + 1, name));
+                }
+            }
+        }
+
+        return v.elements();
+    }
+
+    // TODO: API: Investigate how to handle this better, perhaps we need
+    // multiple URL policies, one for content -- one for class path.
+    public URL getEntry(String name)
+    {
+        URL url = null;
+
+        // Check for the special case of "/", which represents
+        // the root of the bundle according to the spec.
+        if (name.equals("/"))
+        {
+            url = getURLPolicy().createURL(0, "/");
+        }
+
+        if (url == null)
+        {
+            // Remove leading slash, if present.
+            if (name.startsWith("/"))
+            {
+                name = name.substring(1);
+            }
+
+            // Check the module content.
+            if (getContent().hasEntry(name))
+            {
+                // Module content URLs start with 0, whereas module
+                // class path URLs start with the index into the class
+                // path + 1.
+                url = getURLPolicy().createURL(0, name);
+            }
+        }
+
+        return url;
+    }
+
+    public boolean hasInputStream(int index, String urlPath)
+    {
+        if (urlPath.startsWith("/"))
+        {
+            urlPath = urlPath.substring(1);
+        }
+        if (index == 0)
+        {
+            return m_content.hasEntry(urlPath);
+        }
+        return getContentPath()[index - 1].hasEntry(urlPath);
+    }
+
+    public InputStream getInputStream(int index, String urlPath)
+        throws IOException
+    {
+        if (urlPath.startsWith("/"))
+        {
+            urlPath = urlPath.substring(1);
+        }
+        if (index == 0)
+        {
+            return m_content.getEntryAsStream(urlPath);
+        }
+        return getContentPath()[index - 1].getEntryAsStream(urlPath);
+    }
+
+    //
+    // Fragment and dependency management methods.
+    //
+
+    public synchronized IModule[] getFragments()
+    {
+        return m_fragments;
+    }
+
+    public synchronized void attachFragments(IModule[] fragments) throws Exception
+    {
+        // Remove module from old fragment dependencies.
+        // We will generally only remove module fragment
+        // dependencies when we are uninstalling the module.
+        for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+        {
+            ((ModuleImpl) m_fragments[i]).removeDependentHost(this);
+        }
+
+        // Update the dependencies on the new fragments.
+        m_fragments = fragments;
+
+        // We need to add ourself as a dependent of each fragment
+        // module. We also need to create an array of fragment contents
+        // to attach to our content loader.
+        if (m_fragments != null)
+        {
+            IContent[] fragmentContents = new IContent[m_fragments.length];
+            for (int i = 0; (m_fragments != null) && (i < m_fragments.length); i++)
+            {
+                ((ModuleImpl) m_fragments[i]).addDependentHost(this);
+                fragmentContents[i] =
+                    m_fragments[i].getContent()
+                        .getEntryAsContent(FelixConstants.CLASS_PATH_DOT);
+            }
+            // Now attach the fragment contents to our content loader.
+            attachFragmentContents(fragmentContents);
+        }
+    }
+
+    private void attachFragmentContents(IContent[] fragmentContents)
+        throws Exception
+    {
+        // Close existing fragment contents.
+        if (m_fragmentContents != null)
+        {
+            for (int i = 0; i < m_fragmentContents.length; i++)
+            {
+                m_fragmentContents[i].close();
+            }
+        }
+        m_fragmentContents = fragmentContents;
+
+        if (m_contentPath != null)
+        {
+            for (int i = 0; i < m_contentPath.length; i++)
+            {
+                m_contentPath[i].close();
+            }
+        }
+        m_contentPath = initializeContentPath();
+    }
+
+    public synchronized IModule[] getDependentHosts()
+    {
+        return m_dependentHosts;
+    }
+
+    public synchronized void addDependentHost(IModule module)
+    {
+        m_dependentHosts = addDependent(m_dependentHosts, module);
+    }
+
+    public synchronized void removeDependentHost(IModule module)
+    {
+        m_dependentHosts = removeDependent(m_dependentHosts, module);
+    }
+
+    public synchronized IModule[] getDependentImporters()
+    {
+        return m_dependentImporters;
+    }
+
+    public synchronized void addDependentImporter(IModule module)
+    {
+        m_dependentImporters = addDependent(m_dependentImporters, module);
+    }
+
+    public synchronized void removeDependentImporter(IModule module)
+    {
+        m_dependentImporters = removeDependent(m_dependentImporters, module);
+    }
+
+    public synchronized IModule[] getDependentRequirers()
+    {
+        return m_dependentRequirers;
+    }
+
+    public synchronized void addDependentRequirer(IModule module)
+    {
+        m_dependentRequirers = addDependent(m_dependentRequirers, module);
+    }
+
+    public synchronized void removeDependentRequirer(IModule module)
+    {
+        m_dependentRequirers = removeDependent(m_dependentRequirers, module);
+    }
+
+    public synchronized IModule[] getDependents()
+    {
+        IModule[] dependents = new IModule[
+            m_dependentHosts.length + m_dependentImporters.length + m_dependentRequirers.length];
+        System.arraycopy(
+            m_dependentHosts,
+            0,
+            dependents,
+            0,
+            m_dependentHosts.length);
+        System.arraycopy(
+            m_dependentImporters,
+            0,
+            dependents,
+            m_dependentHosts.length,
+            m_dependentImporters.length);
+        System.arraycopy(
+            m_dependentRequirers,
+            0,
+            dependents,
+            m_dependentHosts.length + m_dependentImporters.length,
+            m_dependentRequirers.length);
+        return dependents;
+    }
+
+    private static IModule[] addDependent(IModule[] modules, IModule module)
+    {
+        // Make sure the dependent module is not already present.
+        for (int i = 0; i < modules.length; i++)
+        {
+            if (modules[i].equals(module))
+            {
+                return modules;
+            }
+        }
+        IModule[] tmp = new IModule[modules.length + 1];
+        System.arraycopy(modules, 0, tmp, 0, modules.length);
+        tmp[modules.length] = module;
+        return tmp;
+    }
+
+    private static IModule[] removeDependent(IModule[] modules, IModule module)
+    {
+        IModule[] tmp = modules;
+
+        // Make sure the dependent module is present.
+        for (int i = 0; i < modules.length; i++)
+        {
+            if (modules[i].equals(module))
+            {
+                // If this is the module, then point to empty list.
+                if ((modules.length - 1) == 0)
+                {
+                    tmp = new IModule[0];
+                }
+                // Otherwise, we need to do some array copying.
+                else
+                {
+                    tmp = new IModule[modules.length - 1];
+                    System.arraycopy(modules, 0, tmp, 0, i);
+                    if (i < tmp.length)
+                    {
+                        System.arraycopy(modules, i + 1, tmp, i, tmp.length - i);
+                    }
+                }
+                break;
+            }
+        }
+
+        return tmp;
+    }
+
+    public synchronized void close()
+    {
+        m_content.close();
+        for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++)
+        {
+            m_contentPath[i].close();
+        }
+        for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
+        {
+            m_fragmentContents[i].close();
+        }
+        m_classLoader = null;
+    }
+
+    public synchronized void setURLPolicy(IURLPolicy urlPolicy)
+    {
+        m_urlPolicy = urlPolicy;
+    }
+
+    public synchronized IURLPolicy getURLPolicy()
+    {
+        return m_urlPolicy;
+    }
+
+    public synchronized void setSecurityContext(Object securityContext)
+    {
+        m_protectionDomain = (ProtectionDomain) securityContext;
+    }
+
+    public synchronized Object getSecurityContext()
+    {
+        return m_protectionDomain;
+    }
+
+    public String toString()
+    {
+        return m_id;
+    }
+
+    private synchronized ModuleClassLoader getClassLoader()
+    {
+        if (m_classLoader == null)
+        {
+// TODO: REFACTOR - SecureAction fix needed.
+              m_classLoader = new ModuleClassLoader();
+//            m_classLoader = m_secureAction.createModuleClassLoader(
+//                this, m_protectionDomain);
+        }
+        return m_classLoader;
+    }
+
     private Object searchImports(String name, boolean isClass)
         throws ClassNotFoundException, ResourceNotFoundException
     {
@@ -1244,4 +1305,592 @@
 
         return null;
     }
+
+    private static final Constructor m_dexFileClassConstructor;
+    private static final Method m_dexFileClassLoadClass;
+    static
+    {
+        Constructor dexFileClassConstructor = null;
+        Method dexFileClassLoadClass = null;
+        try
+        {
+            Class dexFileClass;
+            try
+            {
+                dexFileClass = Class.forName("dalvik.system.DexFile");
+            }
+            catch (Exception ex)
+            {
+                dexFileClass = Class.forName("android.dalvik.DexFile");
+            }
+
+            dexFileClassConstructor = dexFileClass.getConstructor(
+                new Class[] { java.io.File.class });
+            dexFileClassLoadClass = dexFileClass.getMethod("loadClass",
+                new Class[] { String.class, ClassLoader.class });
+        }
+        catch (Exception ex)
+        {
+           dexFileClassConstructor = null;
+           dexFileClassLoadClass = null;
+        }
+        m_dexFileClassConstructor = dexFileClassConstructor;
+        m_dexFileClassLoadClass = dexFileClassLoadClass;
+    }
+
+    public class ModuleClassLoader extends SecureClassLoader
+    {
+        private final Map m_jarContentToDexFile;
+
+        public ModuleClassLoader()
+        {
+            if (m_dexFileClassConstructor != null)
+            {
+                m_jarContentToDexFile = new HashMap();
+            }
+            else
+            {
+                m_jarContentToDexFile = null;
+            }
+        }
+
+        public IModule getModule()
+        {
+            return ModuleImpl.this;
+        }
+
+        protected Class loadClass(String name, boolean resolve)
+            throws ClassNotFoundException
+        {
+            Class clazz = null;
+
+            // Make sure the class was not already loaded.
+            synchronized (this)
+            {
+                clazz = findLoadedClass(name);
+            }
+
+            if (clazz == null)
+            {
+                try
+                {
+                    return (Class) findClassOrResourceByDelegation(name, true);
+                }
+                catch (ResourceNotFoundException ex)
+                {
+                    // This should never happen since we are asking for a class,
+                    // so just ignore it.
+                }
+                catch (ClassNotFoundException cnfe)
+                {
+                    ClassNotFoundException ex = cnfe;
+                    String msg = name;
+                    if (m_logger.getLogLevel() >= Logger.LOG_DEBUG)
+                    {
+                        msg = diagnoseClassLoadError(m_resolver, ModuleImpl.this, name);
+                        ex = new ClassNotFoundException(msg, cnfe);
+                    }
+                    throw ex;
+                }
+            }
+
+            // Resolve the class and return it.
+            if (resolve)
+            {
+                resolveClass(clazz);
+            }
+            return clazz;
+        }
+
+        protected Class findClass(String name) throws ClassNotFoundException
+        {
+            // Do a quick check here to see if we can short-circuit this
+            // entire process if the class was already loaded.
+            Class clazz = null;
+            synchronized (this)
+            {
+                clazz = findLoadedClass(name);
+            }
+
+            // Search for class in module.
+            if (clazz == null)
+            {
+                String actual = name.replace('.', '/') + ".class";
+
+                byte[] bytes = null;
+
+                // Check the module class path.
+                IContent[] contentPath = getContentPath();
+                IContent content = null;
+                for (int i = 0;
+                    (bytes == null) &&
+                    (i < contentPath.length); i++)
+                {
+                    bytes = contentPath[i].getEntryAsBytes(actual);
+                    content = contentPath[i];
+                }
+
+                if (bytes != null)
+                {
+                    // Before we actually attempt to define the class, grab
+                    // the lock for this class loader and make sure than no
+                    // other thread has defined this class in the meantime.
+                    synchronized (this)
+                    {
+                        clazz = findLoadedClass(name);
+
+                        if (clazz == null)
+                        {
+                            // We need to try to define a Package object for the class
+                            // before we call defineClass(). Get the package name and
+                            // see if we have already created the package.
+                            String pkgName = Util.getClassPackage(name);
+                            if (pkgName.length() > 0)
+                            {
+                                if (getPackage(pkgName) == null)
+                                {
+                                    Object[] params = definePackage(pkgName);
+                                    if (params != null)
+                                    {
+                                        definePackage(
+                                            pkgName,
+                                            (String) params[0],
+                                            (String) params[1],
+                                            (String) params[2],
+                                            (String) params[3],
+                                            (String) params[4],
+                                            (String) params[5],
+                                            null);
+                                    }
+                                    else
+                                    {
+                                        definePackage(pkgName, null, null,
+                                            null, null, null, null, null);
+                                    }
+                                }
+                            }
+
+                            // If we can load the class from a dex file do so
+                            if (content instanceof JarContent)
+                            {
+                                try
+                                {
+                                    clazz = getDexFileClass((JarContent) content, name, this);
+                                }
+                                catch (Exception ex)
+                                {
+                                    // Looks like we can't
+                                }
+                            }
+
+                            if (clazz == null)
+                            {
+                                // If we have a security context, then use it to
+                                // define the class with it for security purposes,
+                                // otherwise define the class without a protection domain.
+                                if (m_protectionDomain != null)
+                                {
+                                    clazz = defineClass(name, bytes, 0, bytes.length,
+                                        m_protectionDomain);
+                                }
+                                else
+                                {
+                                    clazz = defineClass(name, bytes, 0, bytes.length);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return clazz;
+        }
+
+        private Object[] definePackage(String pkgName)
+        {
+            String spectitle = (String) m_headerMap.get("Specification-Title");
+            String specversion = (String) m_headerMap.get("Specification-Version");
+            String specvendor = (String) m_headerMap.get("Specification-Vendor");
+            String impltitle = (String) m_headerMap.get("Implementation-Title");
+            String implversion = (String) m_headerMap.get("Implementation-Version");
+            String implvendor = (String) m_headerMap.get("Implementation-Vendor");
+            if ((spectitle != null)
+                || (specversion != null)
+                || (specvendor != null)
+                || (impltitle != null)
+                || (implversion != null)
+                || (implvendor != null))
+            {
+                return new Object[] {
+                    spectitle, specversion, specvendor, impltitle, implversion, implvendor
+                };
+            }
+            return null;
+        }
+
+        private Class getDexFileClass(JarContent content, String name, ClassLoader loader)
+            throws Exception
+        {
+            if (m_jarContentToDexFile == null)
+            {
+                return null;
+            }
+
+            Object dexFile = null;
+
+            if (!m_jarContentToDexFile.containsKey(content))
+            {
+                try
+                {
+                    dexFile = m_dexFileClassConstructor.newInstance(
+                        new Object[] { content.getFile() });
+                }
+                finally
+                {
+                    m_jarContentToDexFile.put(content, dexFile);
+                }
+            }
+            else
+            {
+                dexFile = m_jarContentToDexFile.get(content);
+            }
+
+            if (dexFile != null)
+            {
+                return (Class) m_dexFileClassLoadClass.invoke(dexFile,
+                    new Object[] { name.replace('.','/'), loader });
+            }
+            return null;
+        }
+
+        public URL getResource(String name)
+        {
+            return ModuleImpl.this.getResourceByDelegation(name);
+        }
+
+        protected URL findResource(String name)
+        {
+            return getResourceLocal(name);
+        }
+
+        // The findResources() method should only look at the module itself, but
+        // instead it tries to delegate because in Java version prior to 1.5 the
+        // getResources() method was final and could not be overridden. We should
+        // override getResources() like getResource() to make it delegate, but we
+        // can't. As a workaround, we make findResources() delegate instead.
+        protected Enumeration findResources(String name)
+        {
+            return getResourcesByDelegation(name);
+        }
+
+        protected String findLibrary(String name)
+        {
+            // Remove leading slash, if present.
+            if (name.startsWith("/"))
+            {
+                name = name.substring(1);
+            }
+
+            R4Library[] libs = getNativeLibraries();
+            for (int i = 0; (libs != null) && (i < libs.length); i++)
+            {
+                if (libs[i].match(name))
+                {
+                    return getContent().getEntryAsNativeLibrary(libs[i].getEntryName());
+                }
+            }
+
+            return null;
+        }
+
+        public String toString()
+        {
+            return ModuleImpl.this.toString();
+        }
+    }
+
+    private static String diagnoseClassLoadError(
+        FelixResolver resolver, ModuleImpl module, String name)
+    {
+        // We will try to do some diagnostics here to help the developer
+        // deal with this exception.
+
+        // 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());
+
+        // Next, check to see if the module imports the package.
+        IWire[] wires = module.getWires();
+        for (int i = 0; (wires != null) && (i < wires.length); i++)
+        {
+            if (wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE) &&
+                wires[i].getCapability().getProperties().get(ICapability.PACKAGE_PROPERTY).equals(pkgName))
+            {
+                long expId = Util.getBundleIdFromModuleId(wires[i].getExporter().getId());
+
+                StringBuffer sb = new StringBuffer("*** Package '");
+                sb.append(pkgName);
+                sb.append("' is imported by bundle ");
+                sb.append(impId);
+                sb.append(" from bundle ");
+                sb.append(expId);
+                sb.append(", but the exported package from bundle ");
+                sb.append(expId);
+                sb.append(" does not contain the requested class '");
+                sb.append(name);
+                sb.append("'. Please verify that the class name is correct in the importing bundle ");
+                sb.append(impId);
+                sb.append(" and/or that the exported package is correctly bundled in ");
+                sb.append(expId);
+                sb.append(". ***");
+
+                return sb.toString();
+            }
+        }
+
+        // Next, check to see if the package was optionally imported and
+        // whether or not there is an exporter available.
+        IRequirement[] reqs = module.getRequirements();
+/*
+* TODO: RB - Fix diagnostic message for optional imports.
+        for (int i = 0; (reqs != null) && (i < reqs.length); i++)
+        {
+            if (reqs[i].getName().equals(pkgName) && reqs[i].isOptional())
+            {
+                // Try to see if there is an exporter available.
+                IModule[] exporters = getResolvedExporters(reqs[i], true);
+                exporters = (exporters.length == 0)
+                    ? getUnresolvedExporters(reqs[i], true) : exporters;
+
+                // An exporter might be available, but it may have attributes
+                // that do not match the importer's required attributes, so
+                // check that case by simply looking for an exporter of the
+                // desired package without any attributes.
+                if (exporters.length == 0)
+                {
+                    IRequirement pkgReq = new Requirement(
+                        ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
+                    exporters = getResolvedExporters(pkgReq, true);
+                    exporters = (exporters.length == 0)
+                        ? getUnresolvedExporters(pkgReq, true) : exporters;
+                }
+
+                long expId = (exporters.length == 0)
+                    ? -1 : Util.getBundleIdFromModuleId(exporters[0].getId());
+
+                StringBuffer sb = new StringBuffer("*** Class '");
+                sb.append(name);
+                sb.append("' was not found, but this is likely normal since package '");
+                sb.append(pkgName);
+                sb.append("' is optionally imported by bundle ");
+                sb.append(impId);
+                sb.append(".");
+                if (exporters.length > 0)
+                {
+                    sb.append(" However, bundle ");
+                    sb.append(expId);
+                    if (reqs[i].isSatisfied(
+                        Util.getExportPackage(exporters[0], reqs[i].getName())))
+                    {
+                        sb.append(" does export this package. Bundle ");
+                        sb.append(expId);
+                        sb.append(" must be installed before bundle ");
+                        sb.append(impId);
+                        sb.append(" is resolved or else the optional import will be ignored.");
+                    }
+                    else
+                    {
+                        sb.append(" does export this package with attributes that do not match.");
+                    }
+                }
+                sb.append(" ***");
+
+                return sb.toString();
+            }
+        }
+*/
+        // Next, check to see if the package is dynamically imported by the module.
+/* TODO: RESOLVER: Need to fix this too.
+        IRequirement[] dynamics = module.getDefinition().getDynamicRequirements();
+        for (int dynIdx = 0; dynIdx < dynamics.length; dynIdx++)
+        {
+            IRequirement target = createDynamicRequirement(dynamics[dynIdx], pkgName);
+            if (target != null)
+            {
+                // Try to see if there is an exporter available.
+                PackageSource[] exporters = getResolvedCandidates(target);
+                exporters = (exporters.length == 0)
+                    ? getUnresolvedCandidates(target) : exporters;
+
+                // An exporter might be available, but it may have attributes
+                // that do not match the importer's required attributes, so
+                // check that case by simply looking for an exporter of the
+                // desired package without any attributes.
+                if (exporters.length == 0)
+                {
+                    try
+                    {
+                        IRequirement pkgReq = new Requirement(
+                            ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
+                        exporters = getResolvedCandidates(pkgReq);
+                        exporters = (exporters.length == 0)
+                            ? getUnresolvedCandidates(pkgReq) : exporters;
+                    }
+                    catch (InvalidSyntaxException ex)
+                    {
+                        // This should never happen.
+                    }
+                }
+
+                long expId = (exporters.length == 0)
+                    ? -1 : Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
+
+                StringBuffer sb = new StringBuffer("*** Class '");
+                sb.append(name);
+                sb.append("' was not found, but this is likely normal since package '");
+                sb.append(pkgName);
+                sb.append("' is dynamically imported by bundle ");
+                sb.append(impId);
+                sb.append(".");
+                if (exporters.length > 0)
+                {
+                    try
+                    {
+                        if (!target.isSatisfied(
+                            Util.getSatisfyingCapability(exporters[0].m_module,
+                                new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"))))
+                        {
+                            sb.append(" However, bundle ");
+                            sb.append(expId);
+                            sb.append(" does export this package with attributes that do not match.");
+                        }
+                    }
+                    catch (InvalidSyntaxException ex)
+                    {
+                        // This should never happen.
+                    }
+                }
+                sb.append(" ***");
+
+                return sb.toString();
+            }
+        }
+*/
+        IRequirement pkgReq = null;
+        try
+        {
+            pkgReq = new Requirement(ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")");
+        }
+        catch (InvalidSyntaxException ex)
+        {
+            // This should never happen.
+        }
+        PackageSource[] exporters =
+            resolver.getResolvedCandidates(pkgReq);
+        exporters = (exporters.length == 0)
+            ? resolver.getUnresolvedCandidates(pkgReq)
+            : exporters;
+        if (exporters.length > 0)
+        {
+            boolean classpath = false;
+            try
+            {
+                ModuleClassLoader.class.getClassLoader().loadClass(name);
+                classpath = true;
+            }
+            catch (NoClassDefFoundError err)
+            {
+                // Ignore
+            }
+            catch (Exception ex)
+            {
+                // Ignore
+            }
+
+            long expId = Util.getBundleIdFromModuleId(exporters[0].m_module.getId());
+
+            StringBuffer sb = new StringBuffer("*** Class '");
+            sb.append(name);
+            sb.append("' was not found because bundle ");
+            sb.append(impId);
+            sb.append(" does not import '");
+            sb.append(pkgName);
+            sb.append("' even though bundle ");
+            sb.append(expId);
+            sb.append(" does export it.");
+            if (classpath)
+            {
+                sb.append(" Additionally, the class is also available from the system class loader. There are two fixes: 1) Add an import for '");
+                sb.append(pkgName);
+                sb.append("' to bundle ");
+                sb.append(impId);
+                sb.append("; imports are necessary for each class directly touched by bundle code or indirectly touched, such as super classes if their methods are used. ");
+                sb.append("2) Add package '");
+                sb.append(pkgName);
+                sb.append("' to the '");
+                sb.append(Constants.FRAMEWORK_BOOTDELEGATION);
+                sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity.");
+            }
+            else
+            {
+                sb.append(" To resolve this issue, add an import for '");
+                sb.append(pkgName);
+                sb.append("' to bundle ");
+                sb.append(impId);
+                sb.append(".");
+            }
+            sb.append(" ***");
+
+            return sb.toString();
+        }
+
+        // Next, try to see if the class is available from the system
+        // class loader.
+        try
+        {
+            ModuleClassLoader.class.getClassLoader().loadClass(name);
+
+            StringBuffer sb = new StringBuffer("*** Package '");
+            sb.append(pkgName);
+            sb.append("' is not imported by bundle ");
+            sb.append(impId);
+            sb.append(", nor is there any bundle that exports package '");
+            sb.append(pkgName);
+            sb.append("'. However, the class '");
+            sb.append(name);
+            sb.append("' is available from the system class loader. There are two fixes: 1) Add package '");
+            sb.append(pkgName);
+            sb.append("' to the '");
+            sb.append(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
+            sb.append("' property and modify bundle ");
+            sb.append(impId);
+            sb.append(" to import this package; this causes the system bundle to export class path packages. 2) Add package '");
+            sb.append(pkgName);
+            sb.append("' to the '");
+            sb.append(Constants.FRAMEWORK_BOOTDELEGATION);
+            sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity.");
+            sb.append(" ***");
+
+            return sb.toString();
+        }
+        catch (Exception ex2)
+        {
+        }
+
+        // Finally, if there are no imports or exports for the package
+        // and it is not available on the system class path, simply
+        // log a message saying so.
+        StringBuffer sb = new StringBuffer("*** Class '");
+        sb.append(name);
+        sb.append("' was not found. Bundle ");
+        sb.append(impId);
+        sb.append(" does not import package '");
+        sb.append(pkgName);
+        sb.append("', nor is the package exported by any other bundle or available from the system class loader.");
+        sb.append(" ***");
+
+        return sb.toString();
+    }
 }
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
index 0ddaa93..136f98f 100644
--- a/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
+++ b/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
@@ -97,32 +97,20 @@
         ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
         if (rp != null)
         {
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            try
             {
-                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
-// TODO: REFACTOR - Module's shouldn't depend on themself.
-                if ((ps.m_module == m_importer) ||
-                    ((ps.m_capability instanceof Capability) &&
-                    ((Capability) ps.m_capability).isIncluded(name)))
+                Class clazz = m_exporter.getClassByDelegation(name);
+                if (clazz != null)
                 {
-// TODO: REFACTOR - It seems like we should be able to use getClassByDelegation()
-//       here once we don't allow modules to require themself above.
-                    try
-                    {
-                        Class clazz = ps.m_module.getClassFromModule(name);
-                        if (clazz != null)
-                        {
-                            return clazz;
-                        }
-                    }
-                    catch (ClassNotFoundException ex)
-                    {
-                        // Do not throw the exception here, since we want
-                        // to continue search other package sources and
-                        // ultimately the module's own content.
-                    }
+                    return clazz;
                 }
             }
+            catch (ClassNotFoundException ex)
+            {
+                // Do not throw the exception here, since we want
+                // to continue search other package sources and
+                // ultimately the module's own content.
+            }
         }
 
         return null;
@@ -139,16 +127,10 @@
         ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
         if (rp != null)
         {
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            URL url = m_exporter.getResourceByDelegation(name);
+            if (url != null)
             {
-                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
-// TODO: REFACTOR - It seems like we should be able to use getClassByDelegation()
-//       here once we don't allow modules to require themself above.
-                URL url = ps.m_module.getResourceFromModule(name);
-                if (url != null)
-                {
-                    return url;
-                }
+                return url;
             }
 
             // Don't throw ResourceNotFoundException because module
@@ -163,9 +145,6 @@
      */
     public Enumeration getResources(String name) throws ResourceNotFoundException
     {
-        // List to hold all enumerations from all package sources.
-        List enums = new ArrayList();
-
         // Get the package of the target class.
         String pkgName = Util.getResourcePackage(name);
 
@@ -175,27 +154,17 @@
         ResolvedPackage rp = (ResolvedPackage) m_pkgMap.get(pkgName);
         if (rp != null)
         {
-            for (int srcIdx = 0; srcIdx < rp.m_sourceList.size(); srcIdx++)
+            Enumeration urls = m_exporter.getResourcesByDelegation(name);
+            if (urls != null)
             {
-                PackageSource ps = (PackageSource) rp.m_sourceList.get(srcIdx);
-// TODO: REFACTOR - It seems like we should be able to use getClassByDelegation()
-//       here once we don't allow modules to require themself above.
-                Enumeration urls = ps.m_module.getResourcesFromModule(name);
-                if (urls != null)
-                {
-                    enums.add(urls);
-                }
+                return urls;
             }
 
             // Don't throw ResourceNotFoundException because module
             // dependencies support split packages.
         }
 
-        return (enums.size() == 0)
-            ? null
-            : new CompoundEnumeration(
-                (Enumeration[]) enums.toArray(new Enumeration[enums.size()]));
-
+        return null;
     }
 
     public String toString()
diff --git a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
index a495394..a660234 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
@@ -25,7 +25,6 @@
 import java.util.Hashtable;
 import java.util.jar.JarFile;
 
-import org.apache.felix.framework.searchpolicy.ModuleClassLoader;
 import org.apache.felix.framework.searchpolicy.ModuleImpl;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -540,7 +539,8 @@
             return new JarFileX(file);
         }
     }
-
+// TODO: REFACTOR - SecureAction fix needed.
+/*
     public ModuleClassLoader createModuleClassLoader(ModuleImpl impl)
     {
         return createModuleClassLoader(impl, null);
@@ -567,7 +567,7 @@
             return new ModuleClassLoader(impl, protectionDomain);
         }
     }
-
+*/
     public void startActivator(BundleActivator activator, BundleContext context)
         throws Exception
     {
@@ -1104,10 +1104,11 @@
             {
                 return ((URLConnection) arg1).getInputStream();
             }
-            else if (action == CREATE_MODULECLASSLOADER_ACTION)
-            {
-                return new ModuleClassLoader((ModuleImpl) arg1, (ProtectionDomain) arg2);
-            }
+// TODO: REFACTOR - SecureAction fix needed.
+//            else if (action == CREATE_MODULECLASSLOADER_ACTION)
+//            {
+//                return new ModuleClassLoader((ModuleImpl) arg1, (ProtectionDomain) arg2);
+//            }
             else if (action == START_ACTIVATOR_ACTION)
             {
                 ((BundleActivator) arg1).start((BundleContext) arg2);
diff --git a/framework/src/main/java/org/apache/felix/moduleloader/IModule.java b/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
index b6e5e6f..91d6b5d 100644
--- a/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
+++ b/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
@@ -28,35 +28,31 @@
 
 public interface IModule
 {
-    Bundle getBundle();
-
     void setURLPolicy(IURLPolicy urlPolicy);
     IURLPolicy getURLPolicy();
     void setSecurityContext(Object securityContext);
     Object getSecurityContext();
 
-    // Metadata access
+    // Metadata access methods.
     Map getHeaders();
+    String getSymbolicName();
     ICapability[] getCapabilities();
     IRequirement[] getRequirements();
     IRequirement[] getDynamicRequirements();
     R4Library[] getNativeLibraries();
 
-    // Run-time data access.
+    // Run-time data access methods.
+    Bundle getBundle();
     String getId();
-    String getSymbolicName();
     IWire[] getWires();
     boolean isResolved();
 
-    // Content access.
+    // Content access methods.
     IContent getContent();
     Class getClassByDelegation(String name) throws ClassNotFoundException;
     URL getResourceByDelegation(String name);
     Enumeration getResourcesByDelegation(String name);
-    Class getClassFromModule(String name) throws ClassNotFoundException;
-    URL getResourceFromModule(String name);
-    Enumeration getResourcesFromModule(String name);
-    URL getResourceFromContent(String name);
+    URL getEntry(String name);
 
     // TODO: ML - For expediency, the index argument was added to these methods
     // but it is not clear that this makes sense in the long run. This needs to