Refactoring the bundle cache to try to simplify and consolidate its
management. (FELIX-1625)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@817229 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
index 9ce585a..de0310c 100644
--- a/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/BundleImpl.java
@@ -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;
}
//
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 1cd0f28..38af166 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -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
diff --git a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
index 14b843c..213cdc4 100644
--- a/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
+++ b/framework/src/main/java/org/apache/felix/framework/FelixResolverState.java
@@ -468,9 +468,6 @@
// of its dependent modules.
((ModuleImpl) module).setWires(null);
}
-
- // Close the module's content.
- ((ModuleImpl) module).close();
}
/**
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index e8fbf5e..69e5ab3 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -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
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
index 55e3ca6..fdfa742 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
@@ -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;
- }
-
- public synchronized BundleArchive getArchive(long id)
- throws Exception
- {
- for (int i = 0; i < m_archives.length; i++)
+ // Get buffer size value.
+ try
{
- if (m_archives[i].getId() == id)
+ String sBufSize = (String) configMap.get(CACHE_BUFSIZE_PROP);
+ if (sBufSize != null)
{
- return m_archives[i];
+ BUFSIZE = Integer.parseInt(sBufSize);
}
}
- return null;
- }
-
- public synchronized int getArchiveIndex(BundleArchive ba)
- {
- for (int i = 0; i < m_archives.length; i++)
+ catch (NumberFormatException ne)
{
- if (m_archives[i] == ba)
+ // Use the default value.
+ }
+
+ // Create the cache directory, if it does not exist.
+ File cacheDir = determineCacheDir(configMap);
+ if (!getSecureAction().fileExists(cacheDir))
+ {
+ if (!getSecureAction().mkdirs(cacheDir))
{
- return i;
+ logger.log(
+ Logger.LOG_ERROR,
+ "Unable to create cache directory: " + cacheDir);
+ throw new RuntimeException("Unable to create cache directory.");
}
}
- return -1;
+
+ // 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++)
+ {
+ // 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)))
+ {
+ // 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 (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,6 +271,40 @@
return true;
}
+ //
+ // Private methods.
+ //
+
+ private static File determineCacheDir(Map configMap)
+ {
+ File cacheDir;
+
+ // Check to see if the cache directory is specified in the storage
+ // configuration property.
+ String cacheDirStr = (String) configMap.get(Constants.FRAMEWORK_STORAGE);
+ // Get the cache root directory for relative paths; the default is ".".
+ 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.
+ cacheDir = new File(cacheDirStr);
+ if (!cacheDir.isAbsolute())
+ {
+ cacheDir = new File(rootDirStr, cacheDirStr);
+ }
+ }
+ else
+ {
+ // If no cache directory was specified, then use the default name
+ // in the root directory.
+ cacheDir = new File(rootDirStr, CACHE_DIR_NAME);
+ }
+
+ return cacheDir;
+ }
+
private static boolean deleteDirectoryTreeRecursive(File target)
{
if (!getSecureAction().fileExists(target))
@@ -307,89 +323,4 @@
return getSecureAction().deleteFile(target);
}
-
- //
- // Private methods.
- //
-
- private void initialize() throws Exception
- {
- // 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.
- }
-
- // Check to see if the cache directory is specified in the storage
- // configuration property.
- String cacheDirStr = (String) m_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);
- 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())
- {
- m_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);
- }
-
- // Create the cache directory, if it does not exist.
- if (!getSecureAction().fileExists(m_cacheDir))
- {
- 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.");
- }
- }
-
- // 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++)
- {
- // 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)))
- {
- // 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);
- }
- }
- }
-
- m_archives = (BundleArchive[])
- archiveList.toArray(new BundleArchive[archiveList.size()]);
- }
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java
index 6d8ae36..c07a13c 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleRevision.java
@@ -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
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
index fd42c17..6ef4a56 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
@@ -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.
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
index 24d54d7..716d81a 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/DirectoryRevision.java
@@ -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.
}
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
index 492fb31..4ae3af8 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
@@ -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;
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
index 69b9051..b834c5d 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
@@ -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 (!byReference)
- {
- if (is == null)
+ if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
{
- // 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 ("http".equals(url.getProtocol()) ||
- "https".equals(url.getProtocol()))
- {
- String base64 = Util.base64Encode(auth);
- conn.setRequestProperty(
- "Proxy-Authorization", "Basic " + base64);
- }
- }
- is = BundleCache.getSecureAction().getURLConnectionInputStream(conn);
+ getLogger().log(
+ Logger.LOG_ERROR,
+ getClass().getName() + ": Unable to create revision directory.");
+ throw new IOException("Unable to create archive directory.");
}
- // Save the bundle jar file.
- BundleCache.copyStreamToFile(is, m_bundleFile);
+ if (!byReference)
+ {
+ if (is == null)
+ {
+ // 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 ("http".equals(url.getProtocol()) ||
+ "https".equals(url.getProtocol()))
+ {
+ String base64 = Util.base64Encode(auth);
+ conn.setRequestProperty(
+ "Proxy-Authorization", "Basic " + base64);
+ }
+ }
+ is = BundleCache.getSecureAction().getURLConnectionInputStream(conn);
+ }
+
+ // Save the bundle jar file.
+ BundleCache.copyStreamToFile(is, m_bundleFile);
+ }
}
}
finally
diff --git a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
index 42fe55a..22fda77 100644
--- a/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
+++ b/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
@@ -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 =