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/09/21 14:37:02 UTC

svn commit: r817229 - in /felix/trunk/framework/src/main/java/org/apache/felix/framework: ./ cache/ util/

Author: rickhall
Date: Mon Sep 21 12:37:01 2009
New Revision: 817229

URL: http://svn.apache.org/viewvc?rev=817229&view=rev
Log:
Refactoring the bundle cache to try to simplify and consolidate its
management. (FELIX-1625)

Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleImpl.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/cache/BundleArchive.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java

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=817229&r1=817228&r2=817229&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 Mon Sep 21 12:37:01 2009
@@ -44,9 +44,6 @@
     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;
@@ -92,7 +89,41 @@
         return __m_felix;
     }
 
-    synchronized void dispose()
+    BundleArchive getArchive()
+    {
+        return m_archive;
+    }
+
+    synchronized void close()
+    {
+        closeModules();
+        // System bundle has no archive associated with it.
+        if (m_archive != null)
+        {
+            try
+            {
+                m_archive.close();
+            }
+            catch (Exception ex)
+            {
+                getFramework().getLogger().log(
+                    Logger.LOG_ERROR,
+                    "Unable to close archive revisions.", ex);
+            }
+        }
+    }
+
+    synchronized void closeAndDelete() throws Exception
+    {
+        // Mark the bundle as stale, since it is being deleted.
+        m_stale = true;
+        // Close all modules.
+        closeModules();
+        // Delete bundle archive, which will close revisions.
+        m_archive.closeAndDelete();
+    }
+
+    private void closeModules()
     {
         // Remove the bundle's associated modules from the resolver state
         // and close them.
@@ -113,7 +144,7 @@
         else
         {
             // Dispose of the current modules.
-            dispose();
+            closeModules();
 
             // Now we will purge all old revisions, only keeping the newest one.
             m_archive.purge();
@@ -127,7 +158,6 @@
             m_stale = false;
             m_cachedHeaders.clear();
             m_cachedHeadersTimestamp = 0;
-            m_removalPending = false;
         }
     }
 
@@ -804,11 +834,6 @@
         return m_stale;
     }
 
-    synchronized void setStale()
-    {
-        m_stale = true;
-    }
-
     synchronized boolean isExtension()
     {
         for (int i = (m_modules.length - 1); i > -1; i--)
@@ -962,12 +987,7 @@
 
     synchronized boolean isRemovalPending()
     {
-        return m_removalPending;
-    }
-
-    synchronized void setRemovalPending(boolean removalPending)
-    {
-        m_removalPending = removalPending;
+        return (m_state == Bundle.UNINSTALLED) || (m_modules.length > 1)  || m_stale;
     }
 
     //

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Mon Sep 21 12:37:01 2009
@@ -94,9 +94,6 @@
     // Framework's active start level.
     private volatile int m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
 
-    // Local file system cache.
-    private BundleCache m_cache = null;
-
     // System bundle activator list.
     List m_activatorList = null;
 
@@ -490,6 +487,7 @@
 
                 // Create the bundle cache, if necessary, so that we can reload any
                 // installed bundles.
+/* TODO: CACHE - FIX
                 m_cache = (BundleCache) m_configMutableMap.get(
                     FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL);
                 if (m_cache == null)
@@ -504,18 +502,18 @@
                            throw new BundleException("Error creating bundle cache.", ex);
                        }
                 }
-
+*/
                 // If this is the first time init is called, check to see if
                 // we need to flush the bundle cache.
                 if (getState() == Bundle.INSTALLED)
                 {
-                    String flush = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN);
-                    if ((flush != null)
-                        && flush.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT))
+                    String clean = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN);
+                    if ((clean != null)
+                        && clean.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT))
                     {
                         try
                         {
-                            m_cache.flush();
+                            BundleCache.delete(m_logger, m_configMap);
                         }
                         catch (Exception ex)
                         {
@@ -555,7 +553,7 @@
                 // First get cached bundle identifiers.
                 try
                 {
-                    archives = m_cache.getArchives();
+                    archives = BundleCache.getArchives(m_logger, m_configMap);
                 }
                 catch (Exception ex)
                 {
@@ -580,13 +578,14 @@
                         // it now.
                         if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
                         {
-                            m_cache.remove(archives[i]);
+                            archives[i].closeAndDelete();
                         }
                         // Otherwise re-install the cached bundle.
                         else
                         {
                             // Install the cached bundle.
-                            installBundle(archives[i].getId(), archives[i].getLocation(), null);
+                            installBundle(
+                                archives[i].getId(), archives[i].getLocation(), archives[i], null);
                         }
                     }
                     catch (Exception ex)
@@ -1903,9 +1902,6 @@
 
                 fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
 
-                // Mark the bundle as removal pending.
-                bundle.setRemovalPending(true);
-
                 fireBundleEvent(BundleEvent.UPDATED, bundle);
 
                 // Acquire global lock to check if we should auto-refresh.
@@ -2196,9 +2192,6 @@
                 // Set the bundle's persistent state to uninstalled.
                 bundle.setPersistentStateUninstalled();
 
-                // Mark the bundle as removal pending.
-                bundle.setRemovalPending(true);
-
                 // Put bundle in uninstalled bundle array.
                 rememberUninstalledBundle(bundle);
             }
@@ -2279,10 +2272,10 @@
     Bundle installBundle(String location, InputStream is)
         throws BundleException
     {
-        return installBundle(-1, location, is);
+        return installBundle(-1, location, null, is);
     }
 
-    private Bundle installBundle(long id, String location, InputStream is)
+    private Bundle installBundle(long id, String location, BundleArchive ba, InputStream is)
         throws BundleException
     {
         BundleImpl bundle = null;
@@ -2308,7 +2301,7 @@
             }
 
             // Determine if this is a new or existing bundle.
-            boolean isNew = (id < 0);
+            boolean isNew = (ba == null);
 
             // If the bundle is new we must cache its JAR file.
             if (isNew)
@@ -2319,7 +2312,7 @@
                 try
                 {
                     // Add the bundle to the cache.
-                    m_cache.create(id, location, is);
+                    ba = BundleCache.create(m_logger, m_configMap, id, location, is);
                 }
                 catch (Exception ex)
                 {
@@ -2349,9 +2342,9 @@
                 // due to an error or system crash.
                 try
                 {
-                    if (m_cache.getArchive(id).getRevisionCount() > 1)
+                    if (ba.getRevisionCount() > 1)
                     {
-                        m_cache.getArchive(id).purge();
+                        ba.purge();
                     }
                 }
                 catch (Exception ex)
@@ -2364,8 +2357,6 @@
 
             try
             {
-                BundleArchive archive = m_cache.getArchive(id);
-
                 // Acquire the global lock to create the bundle,
                 // since this impacts the global state.
                 boolean locked = acquireGlobalLock();
@@ -2376,7 +2367,7 @@
                 }
                 try
                 {
-                    bundle = new BundleImpl(this, archive);
+                    bundle = new BundleImpl(this, ba);
                 }
                 finally
                 {
@@ -2407,7 +2398,14 @@
                 {
                     try
                     {
-                        m_cache.remove(m_cache.getArchive(id));
+                        if (bundle != null)
+                        {
+                            bundle.closeAndDelete();
+                        }
+                        else if (ba != null)
+                        {
+                            ba.closeAndDelete();
+                        }
                     }
                     catch (Exception ex1)
                     {
@@ -2417,11 +2415,6 @@
                     }
                 }
 
-                if (bundle != null)
-                {
-                    bundle.setRemovalPending(true);
-                }
-
                 if ((System.getSecurityManager() != null) &&
                     (ex instanceof SecurityException))
                 {
@@ -2899,10 +2892,10 @@
         {
             if (bundle == this)
             {
-                return m_cache.getSystemBundleDataFile(s);
+                return BundleCache.getSystemBundleDataFile(m_logger, m_configMap, s);
             }
 
-            return m_cache.getArchive(bundle.getBundleId()).getDataFile(s);
+            return bundle.getArchive().getDataFile(s);
         }
         catch (Exception ex)
         {
@@ -3557,17 +3550,6 @@
         }
     }
 
-    private void garbageCollectBundle(BundleImpl bundle) throws Exception
-    {
-        // CONCURRENCY NOTE: There is no reason to lock this bundle,
-        // because this method is only called during shutdown or a
-        // refresh operation and these are already guarded by locks.
-
-        // Remove the bundle from memory and the cache.
-        bundle.dispose();
-        m_cache.remove(m_cache.getArchive(bundle.getBundleId()));
-    }
-
     //
     // Event-related methods.
     //
@@ -3694,7 +3676,8 @@
             BufferedReader br = null;
             try
             {
-                File file = m_cache.getSystemBundleDataFile("bundle.id");
+                File file = BundleCache.getSystemBundleDataFile(
+                    m_logger, m_configMap, "bundle.id");
                 is = m_secureAction.getFileInputStream(file);
                 br = new BufferedReader(new InputStreamReader(is));
                 return Long.parseLong(br.readLine());
@@ -3747,7 +3730,8 @@
             BufferedWriter bw = null;
             try
             {
-                File file = m_cache.getSystemBundleDataFile("bundle.id");
+                File file = BundleCache.getSystemBundleDataFile(
+                    m_logger, m_configMap, "bundle.id");
                 os = m_secureAction.getFileOutputStream(file);
                 bw = new BufferedWriter(new OutputStreamWriter(os));
                 String s = Long.toString(m_nextId);
@@ -4176,14 +4160,14 @@
                 }
             }
 
-            // Garbage collect uninstalled bundles.
+            // Delete uninstalled bundles.
             for (int i = 0;
                 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
                 i++)
             {
                 try
                 {
-                    garbageCollectBundle(m_uninstalledBundles[i]);
+                    m_uninstalledBundles[i].closeAndDelete();
                 }
                 catch (Exception ex)
                 {
@@ -4198,7 +4182,7 @@
             bundles = getBundles();
             for (int i = 0; i < bundles.length; i++)
             {
-                ((BundleImpl) bundles[i]).dispose();
+                ((BundleImpl) bundles[i]).close();
             }
 
             // Stop all system bundle activators.
@@ -4281,14 +4265,11 @@
         {
             try
             {
-                // Mark the bundle as stale.
-                m_bundle.setStale();
-
-                // Remove or purge the bundle depending on its
+                // Delete or refresh the bundle depending on its
                 // current state.
                 if (m_bundle.getState() == Bundle.UNINSTALLED)
                 {
-                    garbageCollectBundle(m_bundle);
+                    m_bundle.closeAndDelete();
                     m_bundle = null;
                 }
                 else

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java Mon Sep 21 12:37:01 2009
@@ -468,9 +468,6 @@
             // of its dependent modules.
             ((ModuleImpl) module).setWires(null);
         }
-
-        // Close the module's content.
-        ((ModuleImpl) module).close();
     }
 
     /**

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java Mon Sep 21 12:37:01 2009
@@ -562,9 +562,11 @@
     {
         // Do some sanity checking.
         if ((fileName.length() > 0) && (fileName.charAt(0) == File.separatorChar))
-            throw new IllegalArgumentException("The data file path must be relative, not absolute.");
+            throw new IllegalArgumentException(
+                "The data file path must be relative, not absolute.");
         else if (fileName.indexOf("..") >= 0)
-            throw new IllegalArgumentException("The data file path cannot contain a reference to the \"..\" directory.");
+            throw new IllegalArgumentException(
+                "The data file path cannot contain a reference to the \"..\" directory.");
 
         // Get bundle data directory.
         File dataDir = new File(m_archiveRootDir, DATA_DIRECTORY);
@@ -672,7 +674,7 @@
 
         try
         {
-            m_revisions[m_revisions.length - 1].dispose();
+            m_revisions[m_revisions.length - 1].close();
         }
         catch(Exception ex)
         {
@@ -736,6 +738,51 @@
         }
     }
 
+    public synchronized void close()
+    {
+        // Get the current revision count.
+        int count = getRevisionCount();
+        for (int i = 0; i < count; i++)
+        {
+            // Dispose of the revision, but this might be null in certain
+            // circumstances, such as if this bundle archive was created
+            // for an existing bundle that was updated, but not refreshed
+            // due to a system crash; see the constructor code for details.
+            if (m_revisions[i] != null)
+            {
+                try
+                {
+                    m_revisions[i].close();
+                }
+                catch (Exception ex)
+                {
+                    m_logger.log(
+                        Logger.LOG_ERROR,
+                            "Unable to close revision - "
+                            + m_revisions[i].getRevisionRootDir(), ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * This method closes any revisions and deletes the bundle archive directory.
+     * </p>
+     * @throws Exception if any error occurs.
+    **/
+    public synchronized void closeAndDelete()
+    {
+        // Close the revisions and delete the archive directory.
+        close();
+        if (!BundleCache.deleteDirectoryTree(m_archiveRootDir))
+        {
+            m_logger.log(
+                Logger.LOG_ERROR,
+                "Unable to delete archive directory - " + m_archiveRootDir);
+        }
+    }
+
     /**
      * <p>
      * This method removes all old revisions associated with the archive
@@ -745,23 +792,15 @@
     **/
     public synchronized void purge() throws Exception
     {
-        // Get the current refresh count.
+        // Close the revisions and then delete all but the current revision.
+        // We don't delete it the current revision, because we want to rename it
+        // to the new refresh level.
+        close();
         long refreshCount = getRefreshCount();
-        // Get the current revision count.
         int count = getRevisionCount();
-
-        // Dispose and delete all but the current revision.
         File revisionDir = null;
         for (int i = 0; i < count - 1; i++)
         {
-            // Dispose of the revision, but this might be null in certain
-            // circumstances, such as if this bundle archive was created
-            // for an existing bundle that was updated, but not refreshed
-            // due to a system crash; see the constructor code for details.
-            if (m_revisions[i] != null)
-            {
-                m_revisions[i].dispose();
-            }
             revisionDir = new File(m_archiveRootDir, REVISION_DIRECTORY + refreshCount + "." + i);
             if (BundleCache.getSecureAction().fileExists(revisionDir))
             {
@@ -769,11 +808,6 @@
             }
         }
 
-        // We still need to dispose the current revision, but we
-        // don't want to delete it, because we want to rename it
-        // to the new refresh level.
-        m_revisions[count - 1].dispose();
-
         // Save the current revision location for use later when
         // we recreate the revision.
         String location = getRevisionLocation(count -1);
@@ -797,24 +831,6 @@
 
     /**
      * <p>
-     * This method disposes removes the bundle archive directory.
-     * </p>
-     * @throws Exception if any error occurs.
-    **/
-    /* package */ void dispose() throws Exception
-    {
-        if (!BundleCache.deleteDirectoryTree(m_archiveRootDir))
-        {
-            m_logger.log(
-                Logger.LOG_ERROR,
-                getClass().getName()
-                    + ": Unable to delete archive directory - "
-                    + m_archiveRootDir);
-        }
-    }
-
-    /**
-     * <p>
      * Initializes the bundle archive object by creating the archive
      * root directory and saving the initial state.
      * </p>
@@ -1120,4 +1136,4 @@
             if (os != null) os.close();
         }
     }
-}
+}
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java Mon Sep 21 12:37:01 2009
@@ -80,87 +80,93 @@
     protected static transient final String CACHE_ROOTDIR_DEFAULT = ".";
     protected static transient final String BUNDLE_DIR_PREFIX = "bundle";
 
-    private final Logger m_logger;
-    private final Map m_configMap;
-    private File m_cacheDir = null;
-    private BundleArchive[] m_archives = null;
-
-    private static SecureAction m_secureAction = new SecureAction();
-
-    public BundleCache(Logger logger, Map configMap)
-        throws Exception
-    {
-        m_logger = logger;
-        m_configMap = configMap;
-        initialize();
-    }
+    private static final SecureAction m_secureAction = new SecureAction();
 
     /* package */ static SecureAction getSecureAction()
     {
         return m_secureAction;
     }
 
-    public synchronized void flush() throws Exception
+    public static void delete(Logger logger, Map configMap) throws Exception
     {
-        // Dispose of all existing archives.
-        for (int i = 0; (m_archives != null) && (i < m_archives.length); i++)
-        {
-            m_archives[i].dispose();
-        }
         // Delete the cache directory.
-        deleteDirectoryTree(m_cacheDir);
-        // Reinitialize the cache.
-        initialize();
+        File cacheDir = determineCacheDir(configMap);
+        deleteDirectoryTree(cacheDir);
     }
 
-    public synchronized BundleArchive[] getArchives()
+    public static BundleArchive[] getArchives(Logger logger, Map configMap)
         throws Exception
     {
-        return m_archives;
-    }
+        // Get buffer size value.
+        try
+        {
+            String sBufSize = (String) configMap.get(CACHE_BUFSIZE_PROP);
+            if (sBufSize != null)
+            {
+                BUFSIZE = Integer.parseInt(sBufSize);
+            }
+        }
+        catch (NumberFormatException ne)
+        {
+            // Use the default value.
+        }
 
-    public synchronized BundleArchive getArchive(long id)
-        throws Exception
-    {
-        for (int i = 0; i < m_archives.length; i++)
+        // Create the cache directory, if it does not exist.
+        File cacheDir = determineCacheDir(configMap);
+        if (!getSecureAction().fileExists(cacheDir))
         {
-            if (m_archives[i].getId() == id)
+            if (!getSecureAction().mkdirs(cacheDir))
             {
-                return m_archives[i];
+                logger.log(
+                    Logger.LOG_ERROR,
+                    "Unable to create cache directory: " + cacheDir);
+                throw new RuntimeException("Unable to create cache directory.");
             }
         }
-        return null;
-    }
 
-    public synchronized int getArchiveIndex(BundleArchive ba)
-    {
-        for (int i = 0; i < m_archives.length; i++)
+        // Create the existing bundle archives in the directory, if any exist.
+        List archiveList = new ArrayList();
+        File[] children = getSecureAction().listDirectory(cacheDir);
+        for (int i = 0; (children != null) && (i < children.length); i++)
         {
-            if (m_archives[i] == ba)
+            // Ignore directories that aren't bundle directories or
+            // is the system bundle directory.
+            if (children[i].getName().startsWith(BUNDLE_DIR_PREFIX) &&
+                !children[i].getName().equals(BUNDLE_DIR_PREFIX + Long.toString(0)))
             {
-                return i;
+                // Recreate the bundle archive.
+                try
+                {
+                    archiveList.add(new BundleArchive(logger, configMap, children[i]));
+                }
+                catch (Exception ex)
+                {
+                    // Log and ignore.
+                    logger.log(Logger.LOG_ERROR,
+                        "Error creating archive.", ex);
+                }
             }
         }
-        return -1;
+
+        return (BundleArchive[])
+            archiveList.toArray(new BundleArchive[archiveList.size()]);
     }
 
-    public synchronized BundleArchive create(
+    public static BundleArchive create(Logger logger, Map configMap,
         long id, String location, InputStream is)
         throws Exception
     {
+        File cacheDir = determineCacheDir(configMap);
+
         // Construct archive root directory.
         File archiveRootDir =
-            new File(m_cacheDir, BUNDLE_DIR_PREFIX + Long.toString(id));
+            new File(cacheDir, BUNDLE_DIR_PREFIX + Long.toString(id));
 
         try
         {
             // Create the archive and add it to the list of archives.
             BundleArchive ba =
-                new BundleArchive(m_logger, m_configMap, archiveRootDir, id, location, is);
-            BundleArchive[] tmp = new BundleArchive[m_archives.length + 1];
-            System.arraycopy(m_archives, 0, tmp, 0, m_archives.length);
-            tmp[m_archives.length] = ba;
-            m_archives = tmp;
+                new BundleArchive(logger, configMap, archiveRootDir, id, location, is);
             return ba;
         }
         catch (Exception ex)
@@ -169,10 +175,9 @@
             {
                 if (!BundleCache.deleteDirectoryTree(archiveRootDir))
                 {
-                    m_logger.log(
+                    logger.log(
                         Logger.LOG_ERROR,
-                        getClass().getName()
-                            + ": Unable to delete the archive directory - "
+                        "Unable to delete the archive directory: "
                             + archiveRootDir);
                 }
             }
@@ -180,30 +185,6 @@
         }
     }
 
-    public synchronized void remove(BundleArchive ba)
-        throws Exception
-    {
-        if (ba != null)
-        {
-            // Remove the archive.
-            ba.dispose();
-            // Remove the archive from the cache.
-            int idx = getArchiveIndex(ba);
-            if (idx >= 0)
-            {
-                BundleArchive[] tmp =
-                    new BundleArchive[m_archives.length - 1];
-                System.arraycopy(m_archives, 0, tmp, 0, idx);
-                if (idx < tmp.length)
-                {
-                    System.arraycopy(m_archives, idx + 1, tmp, idx,
-                        tmp.length - idx);
-                }
-                m_archives = tmp;
-            }
-        }
-    }
-
     /**
      * Provides the system bundle access to its private storage area; this
      * special case is necessary since the system bundle is not really a
@@ -212,10 +193,11 @@
      * @return a <tt>File</tt> object corresponding to the specified file name.
      * @throws Exception if any error occurs.
     **/
-    public synchronized File getSystemBundleDataFile(String fileName) throws Exception
+    public static File getSystemBundleDataFile(Logger logger, Map configMap, String fileName)
+        throws Exception
     {
         // Make sure system bundle directory exists.
-        File sbDir = new File(m_cacheDir, BUNDLE_DIR_PREFIX + Long.toString(0));
+        File sbDir = new File(determineCacheDir(configMap), BUNDLE_DIR_PREFIX + Long.toString(0));
 
         // If the system bundle directory exists, then we don't
         // need to initialize since it has already been done.
@@ -224,9 +206,9 @@
             // Create system bundle directory, if it does not exist.
             if (!getSecureAction().mkdirs(sbDir))
             {
-                m_logger.log(
+                logger.log(
                     Logger.LOG_ERROR,
-                    getClass().getName() + ": Unable to create system bundle directory.");
+                    "Unable to create system bundle directory.");
                 throw new IOException("Unable to create system bundle directory.");
             }
         }
@@ -250,7 +232,7 @@
      * @param is the input stream to copy.
      * @param outputFile the file to which the input stream should be copied.
     **/
-    protected static void copyStreamToFile(InputStream is, File outputFile)
+    static void copyStreamToFile(InputStream is, File outputFile)
         throws IOException
     {
         OutputStream os = null;
@@ -273,7 +255,7 @@
         }
     }
 
-    protected static boolean deleteDirectoryTree(File target)
+    static boolean deleteDirectoryTree(File target)
     {
         if (!deleteDirectoryTreeRecursive(target))
         {
@@ -289,107 +271,56 @@
         return true;
     }
 
-    private static boolean deleteDirectoryTreeRecursive(File target)
-    {
-    	if (!getSecureAction().fileExists(target))
-        {
-            return true;
-        }
-
-        if (getSecureAction().isFileDirectory(target))
-        {
-            File[] files = getSecureAction().listDirectory(target);
-            for (int i = 0; i < files.length; i++)
-            {
-                deleteDirectoryTreeRecursive(files[i]);
-            }
-        }
-
-        return getSecureAction().deleteFile(target);
-    }
-
     //
     // Private methods.
     //
 
-    private void initialize() throws Exception
+    private static File determineCacheDir(Map configMap)
     {
-        // Get buffer size value.
-        try
-        {
-            String sBufSize = (String) m_configMap.get(CACHE_BUFSIZE_PROP);
-            if (sBufSize != null)
-            {
-                BUFSIZE = Integer.parseInt(sBufSize);
-            }
-        }
-        catch (NumberFormatException ne)
-        {
-            // Use the default value.
-        }
+        File cacheDir;
 
         // Check to see if the cache directory is specified in the storage
         // configuration property.
-        String cacheDirStr = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE);
+        String cacheDirStr = (String) configMap.get(Constants.FRAMEWORK_STORAGE);
         // Get the cache root directory for relative paths; the default is ".".
-        String rootDirStr = (String) m_configMap.get(CACHE_ROOTDIR_PROP);
+        String rootDirStr = (String) configMap.get(CACHE_ROOTDIR_PROP);
         rootDirStr = (rootDirStr == null) ? CACHE_ROOTDIR_DEFAULT : rootDirStr;
         if (cacheDirStr != null)
         {
             // If the specified cache directory is relative, then use the
             // root directory to calculate the absolute path.
-            m_cacheDir = new File(cacheDirStr);
-            if (!m_cacheDir.isAbsolute())
+            cacheDir = new File(cacheDirStr);
+            if (!cacheDir.isAbsolute())
             {
-                m_cacheDir = new File(rootDirStr, cacheDirStr);
+                cacheDir = new File(rootDirStr, cacheDirStr);
             }
         }
         else
         {
             // If no cache directory was specified, then use the default name
             // in the root directory.
-            m_cacheDir = new File(rootDirStr, CACHE_DIR_NAME);
+            cacheDir = new File(rootDirStr, CACHE_DIR_NAME);
         }
 
-        // Create the cache directory, if it does not exist.
-        if (!getSecureAction().fileExists(m_cacheDir))
+        return cacheDir;
+    }
+
+    private static boolean deleteDirectoryTreeRecursive(File target)
+    {
+    	if (!getSecureAction().fileExists(target))
         {
-            if (!getSecureAction().mkdirs(m_cacheDir))
-            {
-                m_logger.log(
-                    Logger.LOG_ERROR,
-                    getClass().getName() + ": Unable to create cache directory: "
-                        + m_cacheDir);
-                throw new RuntimeException("Unable to create cache directory.");
-            }
+            return true;
         }
 
-        // Create the existing bundle archives in the profile directory,
-        // if any exist.
-        List archiveList = new ArrayList();
-        File[] children = getSecureAction().listDirectory(m_cacheDir);
-        for (int i = 0; (children != null) && (i < children.length); i++)
+        if (getSecureAction().isFileDirectory(target))
         {
-            // Ignore directories that aren't bundle directories or
-            // is the system bundle directory.
-            if (children[i].getName().startsWith(BUNDLE_DIR_PREFIX) &&
-                !children[i].getName().equals(BUNDLE_DIR_PREFIX + Long.toString(0)))
+            File[] files = getSecureAction().listDirectory(target);
+            for (int i = 0; i < files.length; i++)
             {
-                // Recreate the bundle archive.
-                try
-                {
-                    archiveList.add(new BundleArchive(m_logger, m_configMap, children[i]));
-                }
-                catch (Exception ex)
-                {
-                    // Log and ignore.
-                    m_logger.log(Logger.LOG_ERROR,
-                        getClass().getName() + ": Error creating archive.", ex);
-                }
+                deleteDirectoryTreeRecursive(files[i]);
             }
         }
 
-        m_archives = (BundleArchive[])
-            archiveList.toArray(new BundleArchive[archiveList.size()]);
+        return getSecureAction().deleteFile(target);
     }
 }
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java Mon Sep 21 12:37:01 2009
@@ -139,5 +139,5 @@
      * </p>
      * @throws Exception if any error occurs.
     **/
-    public abstract void dispose() throws Exception;
+    protected abstract void close() throws Exception;
 }
\ No newline at end of file

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java Mon Sep 21 12:37:01 2009
@@ -174,7 +174,7 @@
                     }
                 }
             }
-            return new JarContent(m_logger, m_configMap, m_revisionLock, extractDir, file);
+            return new JarContent(m_logger, m_configMap, m_revisionLock, extractDir, file, null);
         }
 
         // The entry could not be found, so return null.

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java Mon Sep 21 12:37:01 2009
@@ -99,9 +99,9 @@
         return new DirectoryContent(getLogger(), getConfig(), this, getRevisionRootDir(), m_refDir);
     }
 
-    public void dispose() throws Exception
+    protected void close() throws Exception
     {
-        // Nothing to dispose of, since we don't maintain any state outside
+        // Nothing to close since we don't maintain any state outside
         // of the revision directory, which will be automatically deleted
         // by the parent bundle archive.
     }

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java Mon Sep 21 12:37:01 2009
@@ -23,7 +23,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.Enumeration;
 import java.util.Map;
 import java.util.Properties;
@@ -46,16 +45,20 @@
     private final Object m_revisionLock;
     private final File m_rootDir;
     private final File m_file;
-    private JarFileX m_jarFile = null;
+    private final JarFileX m_jarFile;
+    private final boolean m_isJarFileOwner;
     private int m_libCount = 0;
 
-    public JarContent(Logger logger, Map configMap, Object revisionLock, File rootDir, File file)
+    public JarContent(Logger logger, Map configMap, Object revisionLock, File rootDir,
+        File file, JarFileX jarFile)
     {
         m_logger = logger;
         m_configMap = configMap;
         m_revisionLock = revisionLock;
         m_rootDir = rootDir;
         m_file = file;
+        m_jarFile = (jarFile == null) ? openJarFile(m_file) : jarFile;
+        m_isJarFileOwner = (jarFile == null);
     }
 
     protected void finalize()
@@ -63,11 +66,11 @@
         close();
     }
 
-    public synchronized void close()
+    public void close()
     {
         try
         {
-            if (m_jarFile != null)
+            if (m_isJarFileOwner)
             {
                 m_jarFile.close();
             }
@@ -76,20 +79,12 @@
         {
             m_logger.log(
                 Logger.LOG_ERROR,
-                "JarContent: Unable to open JAR file.", ex);
+                "JarContent: Unable to close JAR file.", ex);
         }
-
-        m_jarFile = null;
     }
 
-    public synchronized boolean hasEntry(String name) throws IllegalStateException
+    public boolean hasEntry(String name) throws IllegalStateException
     {
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-        }
-
         try
         {
             ZipEntry ze = m_jarFile.getEntry(name);
@@ -104,14 +99,8 @@
         }
     }
 
-    public synchronized Enumeration getEntries()
+    public Enumeration getEntries()
     {
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-        }
-
         // Wrap entries enumeration to filter non-matching entries.
         Enumeration e = new EntriesEnumeration(m_jarFile.entries());
 
@@ -119,14 +108,8 @@
         return (e.hasMoreElements()) ? e : null;
     }
 
-    public synchronized byte[] getEntryAsBytes(String name) throws IllegalStateException
+    public byte[] getEntryAsBytes(String name) throws IllegalStateException
     {
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-        }
-
         // Get the embedded resource.
         InputStream is = null;
         ByteArrayOutputStream baos = null;
@@ -179,15 +162,9 @@
         }
     }
 
-    public synchronized InputStream getEntryAsStream(String name)
+    public InputStream getEntryAsStream(String name)
         throws IllegalStateException, IOException
     {
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-        }
-
         // Get the embedded resource.
         InputStream is = null;
 
@@ -212,20 +189,14 @@
         return is;
     }
 
-    public synchronized IContent getEntryAsContent(String entryName)
+    public IContent getEntryAsContent(String entryName)
     {
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-
-        }
-
         // If the entry name refers to the content itself, then
         // just return it immediately.
         if (entryName.equals(FelixConstants.CLASS_PATH_DOT))
         {
-            return new JarContent(m_logger, m_configMap, m_revisionLock, m_rootDir, m_file);
+            return new JarContent(m_logger, m_configMap, m_revisionLock,
+                m_rootDir, m_file, m_jarFile);
         }
 
         // Remove any leading slash.
@@ -291,7 +262,7 @@
             }
             return new JarContent(
                 m_logger, m_configMap, m_revisionLock,
-                extractJar.getParentFile(), extractJar);
+                extractJar.getParentFile(), extractJar, null);
         }
 
         // The entry could not be found, so return null.
@@ -299,17 +270,11 @@
     }
 
 // TODO: This will need to consider security.
-    public synchronized String getEntryAsNativeLibrary(String entryName)
+    public String getEntryAsNativeLibrary(String entryName)
     {
         // Return result.
         String result = null;
 
-        // Open JAR file if not already opened.
-        if (m_jarFile == null)
-        {
-            openJarFile();
-        }
-
         // Remove any leading slash.
         entryName = (entryName.startsWith("/")) ? entryName.substring(1) : entryName;
 
@@ -374,10 +339,13 @@
                                     props.setProperty("abspath", libFile.toString());
                                     command = Util.substVars(command, "command", null, props);
                                     Process p = BundleCache.getSecureAction().exec(command);
-                                    // We have to make sure we read stdout and stderr because otherwise
-                                    // we will block on certain unbuffered os's (like eg. windows)
-                                    Thread stdOut = new Thread(new DevNullRunnable(p.getInputStream()));
-                                    Thread stdErr = new Thread(new DevNullRunnable(p.getErrorStream()));
+                                    // We have to make sure we read stdout and stderr because
+                                    // otherwise we will block on certain unbuffered os's
+                                    // (like eg. windows)
+                                    Thread stdOut = new Thread(
+                                        new DevNullRunnable(p.getInputStream()));
+                                    Thread stdErr = new Thread(
+                                        new DevNullRunnable(p.getErrorStream()));
                                     stdOut.setDaemon(true);
                                     stdErr.setDaemon(true);
                                     stdOut.start();
@@ -426,26 +394,11 @@
         return "JAR " + m_file.getPath();
     }
 
-    public synchronized File getFile()
+    public File getFile()
     {
         return m_file;
     }
 
-    private void openJarFile() throws RuntimeException
-    {
-        if (m_jarFile == null)
-        {
-            try
-            {
-                m_jarFile = BundleCache.getSecureAction().openJAR(m_file, false);
-            }
-            catch (IOException ex)
-            {
-                throw new RuntimeException("Unable to open JAR file, probably deleted: " + ex.getMessage());
-            }
-        }
-    }
-
     /**
      * This method extracts an embedded JAR file from the bundle's
      * JAR file.
@@ -509,6 +462,19 @@
         }
     }
 
+    private static JarFileX openJarFile(File file) throws RuntimeException
+    {
+        try
+        {
+            return BundleCache.getSecureAction().openJAR(file, false);
+        }
+        catch (IOException ex)
+        {
+            throw new RuntimeException(
+                "Unable to open JAR file, probably deleted: " + ex.getMessage());
+        }
+    }
+
     private static class EntriesEnumeration implements Enumeration
     {
         private Enumeration m_enumeration = null;

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java Mon Sep 21 12:37:01 2009
@@ -24,10 +24,10 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.Map;
-import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 
 import org.apache.felix.framework.Logger;
+import org.apache.felix.framework.util.JarFileX;
 import org.apache.felix.framework.util.StringMap;
 import org.apache.felix.framework.util.Util;
 import org.apache.felix.moduleloader.IContent;
@@ -48,6 +48,7 @@
     private static final transient String BUNDLE_JAR_FILE = "bundle.jar";
 
     private File m_bundleFile = null;
+    private final JarFileX m_jarFile;
 
     public JarRevision(
         Logger logger, Map configMap, File revisionRootDir,
@@ -77,13 +78,9 @@
 
         // Save and process the bundle JAR.
         initialize(byReference, is);
-    }
-
-    public synchronized Map getManifestHeader() throws Exception
-    {
-        // Get the embedded resource.
-        JarFile jarFile = null;
 
+        // Open shared copy of the JAR file.
+        JarFileX jarFile = null;
         try
         {
             // Open bundle JAR file.
@@ -93,27 +90,32 @@
             {
                 throw new IOException("No JAR file found.");
             }
-            // Get manifest.
-            Manifest mf = jarFile.getManifest();
-            // Create a case insensitive map of manifest attributes.
-            return new StringMap(mf.getMainAttributes(), false);
+            m_jarFile = jarFile;
         }
-        finally
+        catch (Exception ex)
         {
             if (jarFile != null) jarFile.close();
+            throw ex;
         }
     }
 
+    public Map getManifestHeader() throws Exception
+    {
+        // Get the embedded resource.
+        Manifest mf = m_jarFile.getManifest();
+        // Create a case insensitive map of manifest attributes.
+        return new StringMap(mf.getMainAttributes(), false);
+    }
+
     public synchronized IContent getContent() throws Exception
     {
-        return new JarContent(getLogger(), getConfig(), this, getRevisionRootDir(), m_bundleFile);
+        return new JarContent(getLogger(), getConfig(), this, getRevisionRootDir(),
+            m_bundleFile, m_jarFile);
     }
 
-    public void dispose() throws Exception
+    protected void close() throws Exception
     {
-        // Nothing to dispose of, since we don't maintain any state outside
-        // of the revision directory, which will be automatically deleted
-        // by the parent bundle archive.
+        m_jarFile.close();
     }
 
     //
@@ -125,49 +127,45 @@
     {
         try
         {
-            // If the revision directory exists, then we don't
-            // need to initialize since it has already been done.
-            if (BundleCache.getSecureAction().fileExists(getRevisionRootDir()))
+            // If the revision directory does not exist, then create it.
+            if (!BundleCache.getSecureAction().fileExists(getRevisionRootDir()))
             {
-                return;
-            }
-
-            // Create revision directory.
-            if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
-            {
-                getLogger().log(
-                    Logger.LOG_ERROR,
-                    getClass().getName() + ": Unable to create revision directory.");
-                throw new IOException("Unable to create archive directory.");
-            }
+                if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
+                {
+                    getLogger().log(
+                        Logger.LOG_ERROR,
+                        getClass().getName() + ": Unable to create revision directory.");
+                    throw new IOException("Unable to create archive directory.");
+                }
 
-            if (!byReference)
-            {
-                if (is == null)
+                if (!byReference)
                 {
-                    // Do it the manual way to have a chance to
-                    // set request properties such as proxy auth.
-                    URL url = new URL(getLocation());
-                    URLConnection conn = url.openConnection();
-
-                    // Support for http proxy authentication.
-                    String auth = BundleCache.getSecureAction()
-                        .getSystemProperty("http.proxyAuth", null);
-                    if ((auth != null) && (auth.length() > 0))
+                    if (is == null)
                     {
-                        if ("http".equals(url.getProtocol()) ||
-                            "https".equals(url.getProtocol()))
+                        // Do it the manual way to have a chance to
+                        // set request properties such as proxy auth.
+                        URL url = new URL(getLocation());
+                        URLConnection conn = url.openConnection();
+
+                        // Support for http proxy authentication.
+                        String auth = BundleCache.getSecureAction()
+                            .getSystemProperty("http.proxyAuth", null);
+                        if ((auth != null) && (auth.length() > 0))
                         {
-                            String base64 = Util.base64Encode(auth);
-                            conn.setRequestProperty(
-                                "Proxy-Authorization", "Basic " + base64);
+                            if ("http".equals(url.getProtocol()) ||
+                                "https".equals(url.getProtocol()))
+                            {
+                                String base64 = Util.base64Encode(auth);
+                                conn.setRequestProperty(
+                                    "Proxy-Authorization", "Basic " + base64);
+                            }
                         }
+                        is = BundleCache.getSecureAction().getURLConnectionInputStream(conn);
                     }
-                    is = BundleCache.getSecureAction().getURLConnectionInputStream(conn);
-                }
 
-                // Save the bundle jar file.
-                BundleCache.copyStreamToFile(is, m_bundleFile);
+                    // Save the bundle jar file.
+                    BundleCache.copyStreamToFile(is, m_bundleFile);
+                }
             }
         }
         finally

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java?rev=817229&r1=817228&r2=817229&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java Mon Sep 21 12:37:01 2009
@@ -23,7 +23,6 @@
 import java.net.*;
 import java.security.*;
 import java.util.Hashtable;
-import java.util.jar.JarFile;
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -541,33 +540,6 @@
         }
     }
 
-    public JarFile getJarURLConnectionJAR(JarURLConnection connection)
-        throws IOException
-    {
-        if (System.getSecurityManager() != null)
-        {
-            try
-            {
-                Actions actions = (Actions) m_actions.get();
-                actions.set(Actions.GET_JARURLCONNECTION_JAR_ACTION, connection);
-                return (JarFile) AccessController.doPrivileged(actions,
-                    m_acc);
-            }
-            catch (PrivilegedActionException ex)
-            {
-                if (ex.getException() instanceof IOException)
-                {
-                    throw (IOException) ex.getException();
-                }
-                throw (RuntimeException) ex.getException();
-            }
-        }
-        else
-        {
-            return connection.getJarFile();
-        }
-    }
-
     public JarFileX openJAR(File file) throws IOException
     {
         if (System.getSecurityManager() != null)
@@ -1045,7 +1017,6 @@
         public static final int GET_FIELD_ACTION = 15;
         public static final int GET_FILE_INPUT_ACTION = 16;
         public static final int GET_FILE_OUTPUT_ACTION = 17;
-        public static final int GET_JARURLCONNECTION_JAR_ACTION = 18;
         public static final int GET_METHOD_ACTION = 19;
         public static final int GET_POLICY_ACTION = 20;
         public static final int GET_PROPERTY_ACTION = 21;
@@ -1257,10 +1228,6 @@
             {
                 return ((URL) arg1).openConnection();
             }
-            else if (action == GET_JARURLCONNECTION_JAR_ACTION)
-            {
-                return ((JarURLConnection) arg1).getJarFile();
-            }
             else if (action == ADD_EXTENSION_URL)
             {
                 Method addURL =