You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2009/01/08 20:35:09 UTC

svn commit: r732800 [1/4] - in /felix/trunk/framework/src/main/java/org/apache/felix: framework/ framework/cache/ framework/searchpolicy/ framework/util/ moduleloader/

Author: rickhall
Date: Thu Jan  8 11:35:07 2009
New Revision: 732800

URL: http://svn.apache.org/viewvc?rev=732800&view=rev
Log:
Major refactoring of module layer. Removed IModuleDefition and IContentLoader,
merged functionality into IModule/ModuleImpl. Removed IModuleFactory. Removed
ISearchPolicy merged functionality into ContentClassLoader, now called
ModuleClassLoader. Merged BundleInfo with BundleImpl, Felix now extends
BundleImpl. Still needs much more clean up. (FELIX-851)

Added:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleClassLoader.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleImpl.java
Removed:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleInfo.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixBundle.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/RegularBundleInfo.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/SystemBundleInfo.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentClassLoader.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ContentLoaderImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/ModuleDefinition.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicy.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ObjectInputStreamX.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IContentLoader.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModuleDefinition.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModuleFactory.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/ISearchPolicy.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/ModuleFactoryImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/ModuleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/ModuleListener.java
Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/FindEntriesEnumeration.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/GetEntryPathsEnumeration.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/PackageAdminImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/RequiredBundleImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/ServiceReferenceImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/StartLevelImpl.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersServiceTracker.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Wire.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4WireModule.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/Resolver.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/IModule.java
    felix/trunk/framework/src/main/java/org/apache/felix/moduleloader/ModuleEvent.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java?rev=732800&r1=732799&r2=732800&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleContextImpl.java Thu Jan  8 11:35:07 2009
@@ -29,10 +29,10 @@
 {
     private Logger m_logger = null;
     private Felix m_felix = null;
-    private FelixBundle m_bundle = null;
+    private BundleImpl m_bundle = null;
     private boolean m_valid = true;
 
-    protected BundleContextImpl(Logger logger, Felix felix, FelixBundle bundle)
+    protected BundleContextImpl(Logger logger, Felix felix, BundleImpl bundle)
     {
         m_logger = logger;
         m_felix = felix;
@@ -381,7 +381,7 @@
     {
         if (m_valid)
         {
-            switch (m_bundle.getInfo().getState())
+            switch (m_bundle.getState())
             {
                 case Bundle.ACTIVE:
                 case Bundle.STARTING:

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java?rev=732800&r1=732799&r2=732800&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.java Thu Jan  8 11:35:07 2009
@@ -21,45 +21,122 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.security.ProtectionDomain;
 import java.util.*;
 
+import org.apache.felix.framework.cache.BundleArchive;
+import org.apache.felix.framework.searchpolicy.ModuleImpl;
+import org.apache.felix.framework.searchpolicy.URLPolicyImpl;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.apache.felix.framework.util.manifestparser.R4Library;
+import org.apache.felix.moduleloader.IModule;
 import org.osgi.framework.*;
 
-class BundleImpl extends FelixBundle
+class BundleImpl implements Bundle
 {
-    private final long m_id;
-    private final Felix m_felix;
-    private volatile RegularBundleInfo m_info = null;
+    private final Felix m_feli;
 
-    protected BundleImpl(Felix felix, RegularBundleInfo info)
+    private final BundleArchive m_archive;
+    private IModule[] m_modules = new IModule[0];
+    private int m_state;
+    private BundleActivator m_activator = null;
+    private BundleContext m_context = null;
+    private final Map m_cachedHeaders = new HashMap();
+    private long m_cachedHeadersTimestamp;
+
+    // Indicates whether the bundle has been updated/uninstalled
+    // and is waiting to be refreshed.
+    private boolean m_removalPending = false;
+    // Indicates whether the bundle is stale, meaning that it has
+    // been refreshed and completely removed from the framework.
+    private boolean m_stale = false;
+
+    // Indicates whether the bundle is an extension, meaning that it is
+    // installed as an extension bundle to the framework (i.e., can not be
+    // removed or updated until a framework restart.
+    private boolean m_extension = false;
+
+    // Used for bundle locking.
+    private int m_lockCount = 0;
+    private Thread m_lockThread = null;
+
+    BundleImpl(Felix felix, BundleArchive archive) throws Exception
+    {
+        m_feli = felix;
+        m_archive = archive;
+        m_state = Bundle.INSTALLED;
+        m_stale = false;
+        m_activator = null;
+        m_context = null;
+
+        // TODO: REFACTOR - Null check is a hHack due to system bundle.
+        if (m_archive != null)
+        {
+            createAndAddModule();
+        }
+    }
+
+    // TODO: REFACTOR - We need this method so the system bundle can override it.
+    Felix getFramework()
     {
-        m_felix = felix;
-        m_info = info;
-        m_id = info.getBundleId();
+        return m_feli;
     }
 
-    /* package private */ BundleInfo getInfo()
+    void reset() throws Exception
     {
-        return m_info;
+        m_modules = new IModule[0];
+        createAndAddModule();
+        m_state = Bundle.INSTALLED;
+        m_stale = false;
+        m_cachedHeaders.clear();
+        m_cachedHeadersTimestamp = 0;
+        m_removalPending = false;
     }
 
-    /*
-     * Only used when refreshing a bundle.
-    **/
-    /* package private */ void setInfo(RegularBundleInfo info)
+    // TODO: REFACTOR - This method is sort of a hack. Since the system bundle
+    //       doesn't have an archive, it can override this method to return its
+    //       manifest.
+    Map getCurrentManifestFromArchive() throws Exception
+    {
+        return m_archive.getRevision(
+            m_archive.getRevisionCount() - 1).getManifestHeader();
+    }
+
+    synchronized BundleActivator getActivator()
+    {
+        return m_activator;
+    }
+
+    synchronized void setActivator(BundleActivator activator)
     {
-        m_info = info;
+        m_activator = activator;
     }
 
-    public BundleContext getBundleContext()
+    public synchronized BundleContext getBundleContext()
     {
 // TODO: SECURITY - We need a security check here.
-        return m_info.getBundleContext();
+        return m_context;
+    }
+
+    synchronized void setBundleContext(BundleContext context)
+    {
+        m_context = context;
     }
 
     public long getBundleId()
     {
-        return m_id;
+        try
+        {
+            return m_archive.getId();
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error getting the identifier from bundle archive.",
+                ex);
+            return -1;
+        }
     }
 
     public URL getEntry(String name)
@@ -79,7 +156,7 @@
             }
         }
 
-        return m_felix.getBundleEntry(this, name);
+        return getFramework().getBundleEntry(this, name);
     }
 
     public Enumeration getEntryPaths(String path)
@@ -99,7 +176,7 @@
             }
         }
 
-        return m_felix.getBundleEntryPaths(this, path);
+        return getFramework().getBundleEntryPaths(this, path);
     }
 
     public Enumeration findEntries(String path, String filePattern, boolean recurse)
@@ -119,7 +196,7 @@
             }
         }
 
-        return m_felix.findBundleEntries(this, path, filePattern, recurse);
+        return getFramework().findBundleEntries(this, path, filePattern, recurse);
     }
 
     public Dictionary getHeaders()
@@ -142,12 +219,161 @@
             locale = Locale.getDefault().toString();
         }
 
-        return m_felix.getBundleHeaders(this, locale);
+        return getFramework().getBundleHeaders(this, locale);
+    }
+
+    Map getCurrentLocalizedHeader(String locale)
+    {
+        synchronized (m_cachedHeaders)
+        {
+            // If the bundle has been updated, clear the cached headers
+            if (getLastModified() > m_cachedHeadersTimestamp)
+            {
+                m_cachedHeaders.clear();
+            }
+            else
+            {
+                // Check if headers for this locale have already been resolved
+                if (m_cachedHeaders.containsKey(locale))
+                {
+                    return (Map) m_cachedHeaders.get(locale);
+                }
+            }
+        }
+
+        Map rawHeaders = getCurrentModule().getHeaders();
+        Map headers = new HashMap(rawHeaders.size());
+        headers.putAll(rawHeaders);
+
+        // Check to see if we actually need to localize anything
+        boolean needsLocalization = false;
+        for (Iterator it = headers.values().iterator(); it.hasNext(); )
+        {
+            if (((String) it.next()).startsWith("%"))
+            {
+                needsLocalization = true;
+                break;
+            }
+        }
+
+        if (!needsLocalization)
+        {
+            // If localization is not needed, just cache the headers and return them as-is
+            // Not sure if this is useful
+            updateHeaderCache(locale, headers);
+            return headers;
+        }
+
+        // Do localization here and return the localized headers
+        String basename = (String) headers.get(Constants.BUNDLE_LOCALIZATION);
+        if (basename == null)
+        {
+            basename = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME;
+        }
+
+        // Create ordered list of files to load properties from
+        List resourceList = createResourceList(basename, locale);
+
+        // Create a merged props file with all available props for this locale
+        Properties mergedProperties = new Properties();
+        for (Iterator it = resourceList.iterator(); it.hasNext(); )
+        {
+            URL temp = this.getCurrentModule().getResourceFromModule(it.next() + ".properties");
+            if (temp == null)
+            {
+                continue;
+            }
+            try
+            {
+                mergedProperties.load(temp.openConnection().getInputStream());
+            }
+            catch (IOException ex)
+            {
+                // File doesn't exist, just continue loop
+            }
+        }
+
+        // Resolve all localized header entries
+        for (Iterator it = headers.entrySet().iterator(); it.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry) it.next();
+            String value = (String) entry.getValue();
+            if (value.startsWith("%"))
+            {
+                String newvalue;
+                String key = value.substring(value.indexOf("%") + 1);
+                newvalue = mergedProperties.getProperty(key);
+                if (newvalue==null)
+                {
+                    newvalue = key;
+                }
+                entry.setValue(newvalue);
+            }
+        }
+
+        updateHeaderCache(locale, headers);
+        return headers;
+    }
+
+    private void updateHeaderCache(String locale, Map localizedHeaders)
+    {
+        synchronized (m_cachedHeaders)
+        {
+            m_cachedHeaders.put(locale, localizedHeaders);
+            m_cachedHeadersTimestamp = System.currentTimeMillis();
+        }
+    }
+
+    private List createResourceList(String basename, String locale)
+    {
+        List result = new ArrayList(4);
+
+        StringTokenizer tokens;
+        StringBuffer tempLocale = new StringBuffer(basename);
+
+        result.add(tempLocale.toString());
+
+        if (locale.length() > 0)
+        {
+            tokens = new StringTokenizer(locale, "_");
+            while (tokens.hasMoreTokens())
+            {
+                tempLocale.append("_").append(tokens.nextToken());
+                result.add(tempLocale.toString());
+            }
+        }
+        return result;
     }
 
     public long getLastModified()
     {
-        return m_info.getLastModified();
+        try
+        {
+            return m_archive.getLastModified();
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error reading last modification time from bundle archive.",
+                ex);
+            return 0;
+        }
+    }
+
+    void setLastModified(long l)
+    {
+        try
+        {
+            m_archive.setLastModified(l);
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error writing last modification time to bundle archive.",
+                ex);
+        }
     }
 
     public String getLocation()
@@ -159,7 +385,23 @@
             ((SecurityManager) sm).checkPermission(new AdminPermission(this,
                 AdminPermission.METADATA));
         }
-        return m_felix.getBundleLocation(this);
+        return _getLocation();
+    }
+
+    String _getLocation()
+    {
+        try
+        {
+            return m_archive.getLocation();
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error getting location from bundle archive.",
+                ex);
+            return null;
+        }
     }
 
     /**
@@ -184,7 +426,7 @@
             }
         }
 
-        return m_felix.getBundleResource(this, name);
+        return getFramework().getBundleResource(this, name);
     }
 
     public Enumeration getResources(String name) throws IOException
@@ -204,7 +446,7 @@
             }
         }
 
-        return m_felix.getBundleResources(this, name);
+        return getFramework().getBundleResources(this, name);
     }
 
     /**
@@ -219,7 +461,7 @@
 
         if (sm != null)
         {
-            ServiceReference[] refs = m_felix.getBundleRegisteredServices(this);
+            ServiceReference[] refs = getFramework().getBundleRegisteredServices(this);
 
             if (refs == null)
             {
@@ -228,7 +470,7 @@
 
             List result = new ArrayList();
 
-            for (int i = 0;i < refs.length;i++)
+            for (int i = 0; i < refs.length; i++)
             {
                 String[] objectClass = (String[]) refs[i].getProperty(
                     Constants.OBJECTCLASS);
@@ -238,7 +480,7 @@
                     continue;
                 }
 
-                for (int j = 0;j < objectClass.length;j++)
+                for (int j = 0; j < objectClass.length; j++)
                 {
                     try
                     {
@@ -265,7 +507,7 @@
         }
         else
         {
-            return m_felix.getBundleRegisteredServices(this);
+            return getFramework().getBundleRegisteredServices(this);
         }
     }
 
@@ -275,7 +517,7 @@
 
         if (sm != null)
         {
-            ServiceReference[] refs = m_felix.getBundleServicesInUse(this);
+            ServiceReference[] refs = getFramework().getBundleServicesInUse(this);
 
             if (refs == null)
             {
@@ -284,7 +526,7 @@
 
             List result = new ArrayList();
 
-            for (int i = 0;i < refs.length;i++)
+            for (int i = 0; i < refs.length; i++)
             {
                 String[] objectClass = (String[]) refs[i].getProperty(
                     Constants.OBJECTCLASS);
@@ -294,7 +536,7 @@
                     continue;
                 }
 
-                for (int j = 0;j < objectClass.length;j++)
+                for (int j = 0; j < objectClass.length; j++)
                 {
                     try
                     {
@@ -320,22 +562,143 @@
             return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
         }
 
-        return m_felix.getBundleServicesInUse(this);
+        return getFramework().getBundleServicesInUse(this);
     }
 
-    public int getState()
+    public synchronized int getState()
     {
-        return m_info.getState();
+        return m_state;
+    }
+
+    synchronized void setState(int i)
+    {
+        m_state = i;
+    }
+
+    int getPersistentState()
+    {
+        try
+        {
+            return m_archive.getPersistentState();
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error reading persistent state from bundle archive.",
+                ex);
+            return Bundle.INSTALLED;
+        }
+    }
+
+    void setPersistentStateInactive()
+    {
+        try
+        {
+            m_archive.setPersistentState(Bundle.INSTALLED);
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(Logger.LOG_ERROR,
+                "Error writing persistent state to bundle archive.",
+                ex);
+        }
+    }
+
+    void setPersistentStateActive()
+    {
+        try
+        {
+            m_archive.setPersistentState(Bundle.ACTIVE);
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error writing persistent state to bundle archive.",
+                ex);
+        }
+    }
+
+    void setPersistentStateUninstalled()
+    {
+        try
+        {
+            m_archive.setPersistentState(Bundle.UNINSTALLED);
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error writing persistent state to bundle archive.",
+                ex);
+        }
+    }
+
+    int getStartLevel(int defaultLevel)
+    {
+        try
+        {
+            return m_archive.getStartLevel();
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error reading start level from bundle archive.",
+                ex);
+            return defaultLevel;
+        }
+    }
+
+    void setStartLevel(int i)
+    {
+        try
+        {
+            m_archive.setStartLevel(i);
+        }
+        catch (Exception ex)
+        {
+            getFramework().getLogger().log(
+                Logger.LOG_ERROR,
+                "Error writing start level to bundle archive.",
+                ex);
+        }
+    }
+
+    synchronized boolean isStale()
+    {
+        return m_stale;
+    }
+
+    synchronized void setStale()
+    {
+        m_stale = true;
+    }
+
+    synchronized boolean isExtension()
+    {
+        return m_extension;
+    }
+
+    synchronized void setExtension(boolean extension)
+    {
+        m_extension = extension;
     }
 
     public String getSymbolicName()
     {
-        return m_info.getSymbolicName();
+        return getCurrentModule().getSymbolicName();
     }
 
     public boolean hasPermission(Object obj)
     {
-        return m_felix.bundleHasPermission(this, obj);
+        return getFramework().bundleHasPermission(this, obj);
+    }
+
+    Object getSignerMatcher()
+    {
+        return getFramework().getSignerMatcher(this);
     }
 
     public Class loadClass(String name) throws ClassNotFoundException
@@ -349,13 +712,13 @@
                 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
                     AdminPermission.CLASS));
             }
-            catch (Exception e)
+            catch (Exception ex)
             {
-                throw new ClassNotFoundException("No permission.", e);
+                throw new ClassNotFoundException("No permission.", ex);
             }
         }
 
-        return m_felix.loadBundleClass(this, name);
+        return getFramework().loadBundleClass(this, name);
     }
 
     public void start() throws BundleException
@@ -379,7 +742,7 @@
                 AdminPermission.EXECUTE));
         }
 
-        m_felix.startBundle(this, ((options & Bundle.START_TRANSIENT) == 0));
+        getFramework().startBundle(this, ((options & Bundle.START_TRANSIENT) == 0));
     }
 
     public void update() throws BundleException
@@ -397,7 +760,7 @@
                 AdminPermission.LIFECYCLE));
         }
 
-        m_felix.updateBundle(this, is);
+        getFramework().updateBundle(this, is);
     }
 
     public void stop() throws BundleException
@@ -415,7 +778,7 @@
                 AdminPermission.EXECUTE));
         }
 
-        m_felix.stopBundle(this, ((options & Bundle.STOP_TRANSIENT) == 0));
+        getFramework().stopBundle(this, ((options & Bundle.STOP_TRANSIENT) == 0));
     }
 
     public void uninstall() throws BundleException
@@ -428,12 +791,12 @@
                 AdminPermission.LIFECYCLE));
         }
 
-        m_felix.uninstallBundle(this);
+        getFramework().uninstallBundle(this);
     }
 
     public String toString()
     {
-        String sym = m_info.getSymbolicName();
+        String sym = getCurrentModule().getSymbolicName();
         if (sym != null)
         {
             return sym + " [" + getBundleId() +"]";
@@ -441,8 +804,250 @@
         return "[" + getBundleId() +"]";
     }
 
-    Object getSignerMatcher()
+    synchronized boolean isRemovalPending()
+    {
+        return m_removalPending;
+    }
+
+    synchronized void setRemovalPending(boolean removalPending)
+    {
+        m_removalPending = removalPending;
+    }
+
+    //
+    // Module management.
+    //
+
+    /**
+     * Returns an array of all modules associated with the bundle represented by
+     * this <tt>BundleInfo</tt> object. A module in the array corresponds to a
+     * revision of the bundle's JAR file and is ordered from oldest to newest.
+     * Multiple revisions of a bundle JAR file might exist if a bundle is
+     * updated, without refreshing the framework. In this case, exports from
+     * the prior revisions of the bundle JAR file are still offered; the
+     * current revision will be bound to packages from the prior revision,
+     * unless the packages were not offered by the prior revision. There is
+     * no limit on the potential number of bundle JAR file revisions.
+     * @return array of modules corresponding to the bundle JAR file revisions.
+    **/
+    synchronized IModule[] getModules()
+    {
+        return m_modules;
+    }
+
+    /**
+     * Determines if the specified module is associated with this bundle.
+     * @param module the module to determine if it is associate with this bundle.
+     * @return <tt>true</tt> if the specified module is in the array of modules
+     *         associated with this bundle, <tt>false</tt> otherwise.
+    **/
+    synchronized boolean hasModule(IModule module)
+    {
+        for (int i = 0; i < m_modules.length; i++)
+        {
+            if (m_modules[i] == module)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the newest module, which corresponds to the last module
+     * in the module array.
+     * @return the newest module.
+    **/
+    synchronized IModule getCurrentModule()
+    {
+        return m_modules[m_modules.length - 1];
+    }
+
+    synchronized boolean isUsed()
+    {
+        boolean used = false;
+        for (int i = 0; !used && (i < m_modules.length); i++)
+        {
+            IModule[] dependents = ((ModuleImpl) m_modules[i]).getDependents();
+            for (int j = 0; (dependents != null) && (j < dependents.length) && !used; j++)
+            {
+                if (dependents[j] != m_modules[i])
+                {
+                    used = true;
+                }
+            }
+        }
+        return used;
+    }
+
+    synchronized void revise(String location, InputStream is) throws Exception
+    {
+        // This operation will increase the revision count for the bundle.
+        m_archive.revise(location, is);
+        createAndAddModule();
+    }
+
+    synchronized boolean rollbackRevise() throws Exception
+    {
+        return m_archive.rollbackRevise();
+    }
+
+    // TODO: REFACTOR - Hack for the system bundle.
+    synchronized void addModule(IModule module)
+    {
+        ((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;
+        m_modules = dest;
+    }
+
+    synchronized void createAndAddModule() throws Exception
+    {
+        // Get and parse the manifest from the most recent revision to
+        // create an associated module for it.
+        Map headerMap = getCurrentManifestFromArchive();
+        ManifestParser mp = new ManifestParser(
+            getFramework().getLogger(), getFramework().getConfig(), headerMap);
+
+        // Verify that the bundle symbolic name and version is unique.
+        if (mp.getManifestVersion().equals("2"))
+        {
+            Version bundleVersion = mp.getBundleVersion();
+            bundleVersion = (bundleVersion == null) ? Version.emptyVersion : bundleVersion;
+            String symName = mp.getSymbolicName();
+
+            Bundle[] bundles = getFramework().getBundles();
+            for (int i = 0; (bundles != null) && (i < bundles.length); i++)
+            {
+                long id = ((BundleImpl) bundles[i]).getBundleId();
+                if (id != getBundleId())
+                {
+                    String sym = bundles[i].getSymbolicName();
+                    Version ver = Version.parseVersion((String) ((BundleImpl) bundles[i])
+                        .getCurrentModule().getHeaders().get(Constants.BUNDLE_VERSION));
+                    if (symName.equals(sym) && bundleVersion.equals(ver))
+                    {
+                        throw new BundleException("Bundle symbolic name and version are not unique: " + sym + ':' + ver);
+                    }
+                }
+            }
+        }
+
+        // Now that we have parsed and verified the module metadata, we
+        // can actually create the module. Note, if this is an extension
+        // bundle it's exports are removed, aince they will be added to
+        // the system bundle directly later on.
+        final int revision = m_archive.getRevisionCount() - 1;
+        IModule module = new ModuleImpl(
+            getFramework().getLogger(),
+            getFramework().getConfig(),
+            getFramework().getResolver(),
+            Long.toString(getBundleId()) + "." + Integer.toString(revision),
+            m_archive.getRevision(revision).getContent(),
+            headerMap,
+// TODO: REFACTOR - Karl, does this work correctly if the module is updated to
+//       an extension bundle or vice versa?
+            (ExtensionManager.isExtensionBundle(headerMap)) ? null : mp.getCapabilities(),
+            mp.getRequirements(),
+            mp.getDynamicRequirements(),
+            mp.getLibraries());
+
+        // Set the content loader's URL policy.
+        module.setURLPolicy(
+// TODO: REFACTOR - SUCKS NEEDING URL POLICY PER MODULE.
+            new URLPolicyImpl(
+                getFramework().getLogger(),
+                getFramework().getBundleStreamHandler(),
+                module));
+
+        // Verify that all native libraries exist in advance; this will
+        // throw an exception if the native library does not exist.
+        // TODO: CACHE - It would be nice if this check could be done
+        //               some place else in the module, perhaps.
+        R4Library[] libs = module.getNativeLibraries();
+        for (int i = 0; (libs != null) && (i < libs.length); i++)
+        {
+            String entryName = libs[i].getEntryName();
+            if (entryName != null)
+            {
+                if (module.getContent().getEntryAsNativeLibrary(entryName) == null)
+                {
+                    throw new BundleException("Native library does not exist: " + entryName);
+// TODO: REFACTOR - We have a memory leak here since we added a module above
+//                  and then don't remove it in case of an error; this may also
+//                  be a general issue for installing/updating bundles, so check.
+//                  This will likely go away when we refactor out the module
+//                  factory, but we will track it under FELIX-835 until then.
+                }
+            }
+        }
+
+        ((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;
+        m_modules = dest;
+    }
+
+    void setProtectionDomain(ProtectionDomain pd)
+    {
+        getCurrentModule().setSecurityContext(pd);
+    }
+
+    synchronized ProtectionDomain getProtectionDomain()
+    {
+        ProtectionDomain pd = null;
+
+        for (int i = m_modules.length - 1; (i >= 0) && (pd == null); i--)
+        {
+            pd = (ProtectionDomain) m_modules[i].getSecurityContext();
+        }
+
+        return pd;
+    }
+
+    //
+    // Locking related methods.
+    //
+
+    synchronized boolean isLockable()
+    {
+        return (m_lockCount == 0) || (m_lockThread == Thread.currentThread());
+    }
+
+    synchronized void lock()
+    {
+        if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread()))
+        {
+            throw new IllegalStateException("Bundle is locked by another thread.");
+        }
+        m_lockCount++;
+        m_lockThread = Thread.currentThread();
+    }
+
+    synchronized void unlock()
+    {
+        if (m_lockCount == 0)
+        {
+            throw new IllegalStateException("Bundle is not locked.");
+        }
+        if ((m_lockCount > 0) && (m_lockThread != Thread.currentThread()))
+        {
+            throw new IllegalStateException("Bundle is locked by another thread.");
+        }
+        m_lockCount--;
+        if (m_lockCount == 0)
+        {
+            m_lockThread = null;
+        }
+    }
+
+    synchronized void syncLock(BundleImpl impl)
     {
-        return m_felix.getSignerMatcher(this);
+        m_lockCount = impl.m_lockCount;
+        m_lockThread = impl.m_lockThread;
     }
 }
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java?rev=732800&r1=732799&r2=732800&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java Thu Jan  8 11:35:07 2009
@@ -28,13 +28,13 @@
 public class BundleProtectionDomain extends ProtectionDomain
 {
     private final Felix m_felix;
-    private final FelixBundle m_bundle;
+    private final BundleImpl m_bundle;
 
-    public BundleProtectionDomain(Felix felix, FelixBundle bundle) 
+    BundleProtectionDomain(Felix felix, BundleImpl bundle)
         throws MalformedURLException
     {
         super(new CodeSource(new URL(new URL(null, "location:", 
-            new FakeURLStreamHandler()), felix.getBundleLocation(bundle), 
+            new FakeURLStreamHandler()), bundle._getLocation(),
             new FakeURLStreamHandler()), (Certificate[]) null), null);
         m_felix = felix;
         m_bundle = bundle;
@@ -50,7 +50,7 @@
         return m_felix.impliesBundlePermission(this, permission, true);
     }
 
-    FelixBundle getBundle()
+    BundleImpl getBundle()
     {
         return m_bundle;
     }
@@ -73,4 +73,4 @@
     {
         return "[" + m_bundle + "]";
     }
-}
+}
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java?rev=732800&r1=732799&r2=732800&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExportedPackageImpl.java Thu Jan  8 11:35:07 2009
@@ -27,14 +27,14 @@
 class ExportedPackageImpl implements ExportedPackage
 {
     private final Felix m_felix;
-    private final FelixBundle m_exportingBundle;
+    private final BundleImpl m_exportingBundle;
     private final IModule m_exportingModule;
     private final Capability m_export;
     private String m_toString = null;
     private String m_versionString = null;
 
     public ExportedPackageImpl(
-        Felix felix, FelixBundle exporter, IModule module, Capability export)
+        Felix felix, BundleImpl exporter, IModule module, Capability export)
     {
         m_felix = felix;
         m_exportingBundle = exporter;
@@ -45,7 +45,7 @@
     public Bundle getExportingBundle()
     {
         // If the package is stale, then return null per the spec.
-        if (m_exportingBundle.getInfo().isStale())
+        if (m_exportingBundle.isStale())
         {
             return null;
         }
@@ -55,7 +55,7 @@
     public Bundle[] getImportingBundles()
     {
         // If the package is stale, then return null per the spec.
-        if (m_exportingBundle.getInfo().isStale())
+        if (m_exportingBundle.isStale())
         {
             return null;
         }
@@ -87,7 +87,7 @@
 
     public boolean isRemovalPending()
     {
-        return m_exportingBundle.getInfo().isRemovalPending();
+        return m_exportingBundle.isRemovalPending();
     }
 
     public String toString()

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=732800&r1=732799&r2=732800&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java Thu Jan  8 11:35:07 2009
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.io.InputStream;
-import java.net.JarURLConnection;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
@@ -37,21 +36,20 @@
 import java.util.Properties;
 import java.util.Set;
 
+import org.apache.felix.framework.Felix.FelixResolver;
+import org.apache.felix.framework.searchpolicy.ModuleImpl;
 import org.apache.felix.framework.util.FelixConstants;
-import org.apache.felix.framework.util.SecurityManagerEx;
+import org.apache.felix.framework.util.StringMap;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.framework.util.manifestparser.Capability;
 import org.apache.felix.framework.util.manifestparser.ManifestParser;
 import org.apache.felix.framework.util.manifestparser.R4Attribute;
 import org.apache.felix.framework.util.manifestparser.R4Directive;
-import org.apache.felix.framework.util.manifestparser.R4Library;
 import org.apache.felix.moduleloader.ICapability;
 import org.apache.felix.moduleloader.IContent;
-import org.apache.felix.moduleloader.IContentLoader;
-import org.apache.felix.moduleloader.IModuleDefinition;
-import org.apache.felix.moduleloader.IRequirement;
-import org.apache.felix.moduleloader.ISearchPolicy;
+import org.apache.felix.moduleloader.IModule;
 import org.apache.felix.moduleloader.IURLPolicy;
+import org.apache.felix.moduleloader.ResourceNotFoundException;
 import org.osgi.framework.AdminPermission;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
@@ -82,7 +80,7 @@
 // with the parent classloader and one instance per framework instance that
 // keeps track of extension bundles and systembundle exports for that framework
 // instance.
-class ExtensionManager extends URLStreamHandler implements IModuleDefinition, IContentLoader, IContent
+class ExtensionManager extends URLStreamHandler implements IContent
 {
     // The private instance that is added to Felix.class.getClassLoader() -
     // will be null if extension bundles are not supported (i.e., we are not
@@ -110,10 +108,10 @@
     }
 
     private Logger m_logger = null;
-    private BundleInfo m_sbi = null;
+    private final Map m_headerMap = new StringMap(false);
+    private final IModule m_module;
     private ICapability[] m_capabilities = null;
     private Set m_exportNames = null;
-    private ISearchPolicy m_searchPolicy = null;
     private IURLPolicy m_urlPolicy = null;
     private Object m_securityContext = null;
     private final List m_extensions;
@@ -124,6 +122,8 @@
     // classloader.
     private ExtensionManager()
     {
+// TODO: REFACTOR - Karl, is this correct?
+        m_module = new ExtensionManagerModule();
         m_extensions = new ArrayList();
         m_names = new HashSet();
         m_sourceToExtensions = new HashMap();
@@ -140,28 +140,24 @@
      * @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, BundleInfo sbi)
+    ExtensionManager(Logger logger, Map configMap)
     {
+        m_module = new ExtensionManagerModule();
         m_extensions = null;
         m_names = null;
         m_sourceToExtensions = null;
         m_logger = logger;
-        m_sbi = sbi;
 
 // TODO: FRAMEWORK - Not all of this stuff really belongs here, probably only exports.
         // Populate system bundle header map.
-        // Note: This is a reference to the actual header map,
-        // so these changes are saved. Kind of hacky.
-        Map map = m_sbi.getCurrentHeader();
-        // Initialize header map as a case insensitive map.
-        map.put(FelixConstants.BUNDLE_VERSION,
+        m_headerMap.put(FelixConstants.BUNDLE_VERSION,
             configMap.get(FelixConstants.FELIX_VERSION_PROPERTY));
-        map.put(FelixConstants.BUNDLE_SYMBOLICNAME,
+        m_headerMap.put(FelixConstants.BUNDLE_SYMBOLICNAME,
             FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME);
-        map.put(FelixConstants.BUNDLE_NAME, "System Bundle");
-        map.put(FelixConstants.BUNDLE_DESCRIPTION,
+        m_headerMap.put(FelixConstants.BUNDLE_NAME, "System Bundle");
+        m_headerMap.put(FelixConstants.BUNDLE_DESCRIPTION,
             "This bundle is system specific; it implements various system services.");
-        map.put(FelixConstants.EXPORT_SERVICE,
+        m_headerMap.put(FelixConstants.EXPORT_SERVICE,
             "org.osgi.service.packageadmin.PackageAdmin," +
             "org.osgi.service.startlevel.StartLevel," +
             "org.osgi.service.url.URLHandlers");
@@ -180,7 +176,7 @@
         try
         {
             setCapabilities(
-                addModuleCapability(map,
+                addModuleCapability(m_headerMap,
                     ManifestParser.parseExportHeader(syspkgs)));
         }
         catch (Exception ex)
@@ -193,6 +189,11 @@
         }
     }
 
+    public IModule getModule()
+    {
+        return m_module;
+    }
+
     private ICapability[] addModuleCapability(Map headerMap, ICapability[] caps)
     {
         try
@@ -245,7 +246,7 @@
     /**
      * Check whether the given manifest headers are from an extension bundle.
      */
-    boolean isExtensionBundle(Map headers)
+    static boolean isExtensionBundle(Map headers)
     {
         return (ManifestParser.parseExtensionBundleHeader((String)
                 headers.get(Constants.FRAGMENT_HOST)) != null);
@@ -265,7 +266,7 @@
      *          AdminPermission.EXTENSIONLIFECYCLE and security is enabled.
      * @throws Exception in case something goes wrong.
      */
-    void addExtensionBundle(Felix felix, FelixBundle bundle)
+    void addExtensionBundle(Felix felix, BundleImpl bundle)
         throws SecurityException, BundleException, Exception
     {
         Object sm = System.getSecurityManager();
@@ -275,13 +276,13 @@
                 new AdminPermission(bundle, AdminPermission.EXTENSIONLIFECYCLE));
         }
 
-        if (!((BundleProtectionDomain) bundle.getInfo().getProtectionDomain()).impliesDirect(new AllPermission()))
+        if (!((BundleProtectionDomain) bundle.getProtectionDomain()).impliesDirect(new AllPermission()))
         {
             throw new SecurityException("Extension Bundles must have AllPermission");
         }
 
         R4Directive dir = ManifestParser.parseExtensionBundleHeader((String)
-            bundle.getInfo().getCurrentHeader().get(Constants.FRAGMENT_HOST));
+            bundle.getCurrentModule().getHeaders().get(Constants.FRAGMENT_HOST));
 
         // We only support classpath extensions (not bootclasspath).
         if (!Constants.EXTENSION_FRAMEWORK.equals(dir.getValue()))
@@ -296,21 +297,21 @@
 
         try
         {
-            bundle.getInfo().setExtension(true);
+            bundle.setExtension(true);
 
             // Merge the exported packages with the exported packages of the systembundle.
             ICapability[] exports = null;
             try
             {
                 exports = ManifestParser.parseExportHeader((String)
-                    bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE));
+                    bundle.getCurrentModule().getHeaders().get(Constants.EXPORT_PACKAGE));
             }
             catch (Exception ex)
             {
                 m_logger.log(
                     Logger.LOG_ERROR,
                     "Error parsing extension bundle export statement: "
-                    + bundle.getInfo().getCurrentHeader().get(Constants.EXPORT_PACKAGE), ex);
+                    + bundle.getCurrentModule().getHeaders().get(Constants.EXPORT_PACKAGE), ex);
                 return;
             }
 
@@ -328,14 +329,14 @@
                 throw new UnsupportedOperationException(
                     "Unable to add extension bundle to FrameworkClassLoader - Maybe not an URLClassLoader?");
             }
-            ICapability[] temp = new ICapability[getCapabilities().length + exports.length];
-            System.arraycopy(getCapabilities(), 0, temp, 0, getCapabilities().length);
-            System.arraycopy(exports, 0, temp, getCapabilities().length, exports.length);
+            ICapability[] temp = new ICapability[m_capabilities.length + exports.length];
+            System.arraycopy(m_capabilities, 0, temp, 0, m_capabilities.length);
+            System.arraycopy(exports, 0, temp, m_capabilities.length, exports.length);
             setCapabilities(temp);
         }
         catch (Exception ex)
         {
-            bundle.getInfo().setExtension(false);
+            bundle.setExtension(false);
             throw ex;
         }
         finally
@@ -343,7 +344,7 @@
             felix.releaseBundleLock(felix);
         }
 
-        bundle.getInfo().setState(Bundle.RESOLVED);
+        bundle.setState(Bundle.RESOLVED);
     }
 
     /**
@@ -353,10 +354,10 @@
      * @param felix the framework instance the extension bundle is installed in.
      * @param bundle the extension bundle to start if it has a Felix specific activator.
      */
-    void startExtensionBundle(Felix felix, FelixBundle bundle)
+    void startExtensionBundle(Felix felix, BundleImpl bundle)
     {
         String activatorClass = (String)
-        bundle.getInfo().getCurrentHeader().get(
+        bundle.getCurrentModule().getHeaders().get(
             FelixConstants.FELIX_EXTENSION_ACTIVATOR);
 
         if (activatorClass != null)
@@ -370,11 +371,11 @@
 // TODO: KARL - This is kind of hacky, can we improve it?
                 felix.m_activatorList.add(activator);
 
-                BundleContext context = m_sbi.getBundleContext();
+                BundleContext context = felix.getBundleContext();
 
-                bundle.getInfo().setBundleContext(context);
+                bundle.setBundleContext(context);
 
-                if (felix.getInfo().getState() == Bundle.ACTIVE)
+                if (felix.getState() == Bundle.ACTIVE)
                 {
                     Felix.m_secureAction.startActivator(activator, context);
                 }
@@ -403,37 +404,13 @@
         }
     }
 
-    //
-    // IModuleDefinition
-    //
-    public ICapability[] getCapabilities()
-    {
-        return m_capabilities;
-    }
-
     void setCapabilities(ICapability[] capabilities)
     {
         m_capabilities = capabilities;
 
         // Note: This is a reference to the actual header map,
         // so these changes are saved. Kind of hacky.
-        Map map = m_sbi.getCurrentHeader();
-        map.put(Constants.EXPORT_PACKAGE, convertCapabilitiesToHeaders(map));
-    }
-
-    public IRequirement[] getDynamicRequirements()
-    {
-        return null;
-    }
-
-    public R4Library[] getLibraries()
-    {
-        return null;
-    }
-
-    public IRequirement[] getRequirements()
-    {
-        return null;
+        m_headerMap.put(Constants.EXPORT_PACKAGE, convertCapabilitiesToHeaders(m_headerMap));
     }
 
     private String convertCapabilitiesToHeaders(Map headers)
@@ -468,105 +445,6 @@
     }
 
     //
-    // IContentLoader
-    //
-
-    public void open()
-    {
-        // Nothing needed here.
-    }
-
-    public void close()
-    {
-        // Nothing needed here.
-    }
-
-    public IContent getContent()
-    {
-        return this;
-    }
-
-    public ISearchPolicy getSearchPolicy()
-    {
-        return m_searchPolicy;
-    }
-
-    public void setSearchPolicy(ISearchPolicy searchPolicy)
-    {
-        m_searchPolicy = searchPolicy;
-    }
-
-    public IURLPolicy getURLPolicy()
-    {
-        return m_urlPolicy;
-    }
-
-    public void setURLPolicy(IURLPolicy urlPolicy)
-    {
-        m_urlPolicy = urlPolicy;
-    }
-
-    public Class getClass(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 getResource(String name)
-    {
-        return getClass().getClassLoader().getResource(name);
-    }
-
-    public Enumeration getResources(String name)
-    {
-       try
-       {
-           return getClass().getClassLoader().getResources(name);
-       }
-       catch (IOException ex)
-       {
-           return null;
-       }
-    }
-
-    public URL getResourceFromContent(String name)
-    {
-        // There is no content for the system bundle, so return null.
-        return null;
-    }
-
-    public boolean hasInputStream(int index, String urlPath)
-    {
-        return (getClass().getClassLoader().getResource(urlPath) != null);
-    }
-
-    public InputStream getInputStream(int index, String urlPath)
-    {
-        return getClass().getClassLoader().getResourceAsStream(urlPath);
-    }
-
-    public String findLibrary(String name)
-    {
-        // No native libs associated with the system bundle.
-        return null;
-    }
-
-    //
     // Classpath Extension
     //
 
@@ -585,7 +463,7 @@
 
         for (Iterator iter = m_extensions.iterator(); iter.hasNext();)
         {
-            URL result = ((FelixBundle) iter.next()).getInfo().getCurrentModule().getContentLoader().getResourceFromContent(path);
+            URL result = ((BundleImpl) iter.next()).getCurrentModule().getResourceFromContent(path);
 
             if (result != null)
             {
@@ -647,6 +525,11 @@
         }
     }
 
+    public void close()
+    {
+        // Do nothing on close, since we have nothing open.
+    }
+
     public Enumeration getEntries()
     {
         return new Enumeration()
@@ -737,4 +620,170 @@
             return "";
         }
     }
+
+    class ExtensionManagerModule extends ModuleImpl
+    {
+        ExtensionManagerModule()
+        {
+            super(m_logger, null, null, "0", null, null, null, null, null, null);
+        }
+
+        public Map getHeaders()
+        {
+            return m_headerMap;
+        }
+
+        public ICapability[] getCapabilities()
+        {
+            return m_capabilities;
+        }
+
+        public String getSymbolicName()
+        {
+            return FelixConstants.SYSTEM_BUNDLE_SYMBOLICNAME;
+        }
+
+        public Class getClassByDelegation(String name) throws ClassNotFoundException
+        {
+            // System bundle does not delegate to other modules.
+            return getClassFromModule(name);
+        }
+
+        public URL getResourceByDelegation(String name)
+        {
+            // System bundle does not delegate to other modules.
+            return getResourceFromModule(name);
+        }
+
+        public Enumeration getResourcesByDelegation(String name)
+        {
+            // System bundle does not delegate to other modules.
+            return getResourcesFromModule(name);
+        }
+
+        public Logger getLogger()
+        {
+            return m_logger;
+        }
+
+        public Map getConfig()
+        {
+            return null;
+        }
+
+        public FelixResolver getResolver()
+        {
+            return null;
+        }
+
+        public synchronized IContent[] getClassPath()
+        {
+            throw new UnsupportedOperationException("Should not be used!");
+        }
+
+        public synchronized void attachFragmentContents(IContent[] fragmentContents)
+            throws Exception
+        {
+            throw new UnsupportedOperationException("Should not be used!");
+        }
+
+        public void close()
+        {
+            // Nothing needed here.
+        }
+
+        public IContent getContent()
+        {
+            return ExtensionManager.this;
+        }
+
+        public synchronized void setURLPolicy(IURLPolicy urlPolicy)
+        {
+            m_urlPolicy = urlPolicy;
+        }
+
+        public synchronized IURLPolicy getURLPolicy()
+        {
+            return m_urlPolicy;
+        }
+
+        public void setSecurityContext(Object securityContext)
+        {
+            throw new UnsupportedOperationException("Should not be used!");
+        }
+
+        public Object getSecurityContext()
+        {
+            throw new UnsupportedOperationException("Should not be used!");
+        }
+
+        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)
+        {
+            // There is no content for the system bundle, so return null.
+            return null;
+        }
+
+        public boolean hasInputStream(int index, String urlPath)
+        {
+            return (getClass().getClassLoader().getResource(urlPath) != null);
+        }
+
+        public InputStream getInputStream(int index, String urlPath)
+        {
+            return getClass().getClassLoader().getResourceAsStream(urlPath);
+        }
+    }
 }
\ No newline at end of file