Add locking for the bundle cache. (FELIX-2646)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1030463 13f79535-47bb-0310-9956-ffa450edef68
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 94c23ce..37e378c 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -579,8 +579,8 @@
// Create the bundle cache, if necessary, so that we can reload any
// installed bundles.
- m_cache = (BundleCache) m_configMutableMap.get(
- FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL);
+ m_cache = (BundleCache)
+ m_configMutableMap.get(FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL);
if (m_cache == null)
{
try
@@ -4387,6 +4387,10 @@
m_extensionManager.removeExtensions(Felix.this);
}
+ // Dispose of the bundle cache.
+ m_cache.release();
+ m_cache = null;
+
// Set the framework state to resolved.
acquireBundleLock(Felix.this, Bundle.STOPPING);
try
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 a9d5ad6..59644b2 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
@@ -19,6 +19,8 @@
package org.apache.felix.framework.cache;
import java.io.*;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
import java.util.*;
import org.apache.felix.framework.Logger;
@@ -72,17 +74,93 @@
protected static transient int BUFSIZE = 4096;
protected static transient final String CACHE_DIR_NAME = "felix-cache";
protected static transient final String CACHE_ROOTDIR_DEFAULT = ".";
+ protected static transient final String CACHE_LOCK_NAME = "cache.lock";
protected static transient final String BUNDLE_DIR_PREFIX = "bundle";
private static final SecureAction m_secureAction = new SecureAction();
private final Logger m_logger;
private final Map m_configMap;
+ private final FileLock m_lock;
public BundleCache(Logger logger, Map configMap)
+ throws Exception
{
m_logger = logger;
m_configMap = configMap;
+
+ // Create the cache directory, if it does not exist.
+ File cacheDir = determineCacheDir(m_configMap);
+ if (!getSecureAction().fileExists(cacheDir))
+ {
+ if (!getSecureAction().mkdirs(cacheDir))
+ {
+ m_logger.log(
+ Logger.LOG_ERROR,
+ "Unable to create cache directory: " + cacheDir);
+ throw new RuntimeException("Unable to create cache directory.");
+ }
+ }
+
+ File lockFile = new File(cacheDir, CACHE_LOCK_NAME);
+ FileChannel fc = null;
+ FileOutputStream fos = null;
+ FileInputStream fis = null;
+ try
+ {
+ if (!getSecureAction().fileExists(lockFile))
+ {
+ fos = getSecureAction().getFileOutputStream(lockFile);
+ fc = fos.getChannel();
+ }
+ else
+ {
+ fis = getSecureAction().getFileInputStream(lockFile);
+ fc = fis.getChannel();
+ }
+ }
+ catch (Exception ex)
+ {
+ try
+ {
+ if (fos != null) fos.close();
+ if (fis != null) fis.close();
+ if (fc != null) fc.close();
+ }
+ catch (Exception ex2)
+ {
+ // Ignore.
+ }
+ throw new Exception("Unable to create bundle cache lock file: " + ex);
+ }
+ try
+ {
+ m_lock = fc.tryLock();
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Unable to lock bundle cache: " + ex);
+ }
+
+ }
+
+ public synchronized void release()
+ {
+ if (m_lock != null)
+ {
+ try
+ {
+ m_lock.release();
+ m_lock.channel().close();
+ }
+ catch (Exception ex)
+ {
+ // Not much we can do here, just log it.
+ m_logger.log(
+ Logger.LOG_WARNING,
+ "Exception releasing bundle cache.", ex);
+ }
+ }
}
/* package */ static SecureAction getSecureAction()
@@ -114,20 +192,8 @@
// Use the default value.
}
- // Create the cache directory, if it does not exist.
- File cacheDir = determineCacheDir(m_configMap);
- if (!getSecureAction().fileExists(cacheDir))
- {
- if (!getSecureAction().mkdirs(cacheDir))
- {
- m_logger.log(
- Logger.LOG_ERROR,
- "Unable to create cache directory: " + cacheDir);
- throw new RuntimeException("Unable to create cache directory.");
- }
- }
-
// Create the existing bundle archives in the directory, if any exist.
+ File cacheDir = determineCacheDir(m_configMap);
List archiveList = new ArrayList();
File[] children = getSecureAction().listDirectory(cacheDir);
for (int i = 0; (children != null) && (i < children.length); i++)
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 a10ccac..0c140f8 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
@@ -412,7 +412,7 @@
}
}
- public InputStream getFileInputStream(File file) throws IOException
+ public FileInputStream getFileInputStream(File file) throws IOException
{
if (System.getSecurityManager() != null)
{
@@ -420,7 +420,7 @@
{
Actions actions = (Actions) m_actions.get();
actions.set(Actions.GET_FILE_INPUT_ACTION, file);
- return (InputStream) AccessController.doPrivileged(actions, m_acc);
+ return (FileInputStream) AccessController.doPrivileged(actions, m_acc);
}
catch (PrivilegedActionException ex)
{
@@ -437,7 +437,7 @@
}
}
- public OutputStream getFileOutputStream(File file) throws IOException
+ public FileOutputStream getFileOutputStream(File file) throws IOException
{
if (System.getSecurityManager() != null)
{
@@ -445,7 +445,7 @@
{
Actions actions = (Actions) m_actions.get();
actions.set(Actions.GET_FILE_OUTPUT_ACTION, file);
- return (OutputStream) AccessController.doPrivileged(actions, m_acc);
+ return (FileOutputStream) AccessController.doPrivileged(actions, m_acc);
}
catch (PrivilegedActionException ex)
{