You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by an...@apache.org on 2010/10/05 23:47:52 UTC
svn commit: r1004820 -
/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
Author: andygumbrecht
Date: Tue Oct 5 21:47:52 2010
New Revision: 1004820
URL: http://svn.apache.org/viewvc?rev=1004820&view=rev
Log:
Both clearSunJarFileFactoryCache and clearSunSoftCache should synchronize on the Class instances.
Internally the reflected classes use 'this', so synchronizing on the Map alone fails to prevent a (albeit rare) ConcurrentModificationException.
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java?rev=1004820&r1=1004819&r2=1004820&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/ClassLoaderUtil.java Tue Oct 5 21:47:52 2010
@@ -34,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;
+import java.util.ConcurrentModificationException;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.jar.JarFile;
@@ -48,14 +49,16 @@ import org.apache.openejb.util.UrlCache;
* @version $Revision$ $Date$
*/
public class ClassLoaderUtil {
- private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, ClassLoaderUtil.class);
- private static final Map<String,List<ClassLoader>> classLoadersByApp = new HashMap<String,List<ClassLoader>>();
- private static final Map<ClassLoader, Set<String>> appsByClassLoader = new HashMap<ClassLoader,Set<String>>();
+ private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, ClassLoaderUtil.class);
+ private static final Map<String, List<ClassLoader>> classLoadersByApp = new HashMap<String, List<ClassLoader>>();
+ private static final Map<ClassLoader, Set<String>> appsByClassLoader = new HashMap<ClassLoader, Set<String>>();
private static final UrlCache urlCache = new UrlCache();
public static ClassLoader getContextClassLoader() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+
+ @Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
@@ -113,7 +116,9 @@ public class ClassLoaderUtil {
for (ClassLoader classLoader : classLoaders) {
// get the apps using the class loader
Set<String> apps = appsByClassLoader.get(classLoader);
- if (apps == null) apps = Collections.emptySet();
+ if (apps == null) {
+ apps = Collections.emptySet();
+ }
// this app is no longer using the class loader
apps.remove(appId);
@@ -154,50 +159,65 @@ public class ClassLoaderUtil {
Introspector.flushCaches();
}
- public static void clearSunJarFileFactoryCache(String jarLocation) {
+ public static void clearSunJarFileFactoryCache(final String jarLocation) {
+ clearSunJarFileFactoryCacheImpl(jarLocation, 5);
+ }
+
+ private static void clearSunJarFileFactoryCacheImpl(final String jarLocation, final int attempt) {
logger.debug("Clearing Sun JarFileFactory cache for directory " + jarLocation);
try {
Class jarFileFactory = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
- Field fileCacheField = jarFileFactory.getDeclaredField("fileCache");
+ synchronized (jarFileFactory) {
- fileCacheField.setAccessible(true);
- Map fileCache = (Map) fileCacheField.get(null);
+ Field fileCacheField = jarFileFactory.getDeclaredField("fileCache");
- Field urlCacheField = jarFileFactory.getDeclaredField("urlCache");
- urlCacheField.setAccessible(true);
- Map urlCache = (Map) urlCacheField.get(null);
-
- List<URL> urls = new ArrayList<URL>();
- for (Object item : fileCache.keySet()) {
- URL url = null;
- if (item instanceof URL) {
- url = (URL) item;
- } else if (item instanceof String) {
- url = new URI((String) item).toURL();
- } else {
- logger.warning("Don't know how to handle object: " + item.toString() + " of type: " + item.getClass().getCanonicalName() + " in Sun JarFileFactory cache, skipping");
- }
+ fileCacheField.setAccessible(true);
+ Map fileCache = (Map) fileCacheField.get(null);
- File file = null;
- try {
- file = URLs.toFile(url);
- } catch (IllegalArgumentException e) {
- //unknown kind of url
- return;
- }
- if (url != null && isParent(jarLocation, file)) {
- urls.add(url);
+ Field urlCacheField = jarFileFactory.getDeclaredField("urlCache");
+ urlCacheField.setAccessible(true);
+ Map ucf = (Map) urlCacheField.get(null);
+
+ List<URL> urls = new ArrayList<URL>();
+ for (Object item : fileCache.keySet()) {
+ URL url = null;
+ if (item instanceof URL) {
+ url = (URL) item;
+ } else if (item instanceof String) {
+ url = new URI((String) item).toURL();
+ } else {
+ logger.warning("Don't know how to handle object: " + item.toString() + " of type: " + item.getClass().getCanonicalName() + " in Sun JarFileFactory cache, skipping");
+ }
+
+ File file = null;
+ try {
+ file = URLs.toFile(url);
+ } catch (IllegalArgumentException e) {
+ //unknown kind of url
+ return;
+ }
+ if (url != null && isParent(jarLocation, file)) {
+ urls.add(url);
+ }
}
- }
- for (URL url : urls) {
- JarFile jarFile = (JarFile) fileCache.remove(url);
- if (jarFile == null) continue;
+ for (URL url : urls) {
+ JarFile jarFile = (JarFile) fileCache.remove(url);
+ if (jarFile == null) {
+ continue;
+ }
- urlCache.remove(jarFile);
- jarFile.close();
+ ucf.remove(jarFile);
+ jarFile.close();
+ }
+ }
+ } catch (ConcurrentModificationException e) {
+ if (attempt > 0) {
+ clearSunJarFileFactoryCacheImpl(jarLocation, (attempt - 1));
+ } else {
+ logger.error("Unable to clear Sun JarFileFactory cache after 5 attempts", e);
}
} catch (ClassNotFoundException e) {
// not a sun vm
@@ -220,25 +240,22 @@ public class ClassLoaderUtil {
}
/**
- * Clears the caches maintained by the SunVM object stream implementation. This method uses reflection and
- * setAccessable to obtain access to the Sun cache. The cache is locked with a synchronize monitor and cleared.
+ * Clears the caches maintained by the SunVM object stream implementation.
+ * This method uses reflection and setAccessable to obtain access to the Sun cache.
+ * The cache Class synchronizes upon itself for access to the cache Map.
* This method completely clears the class loader cache which will impact preformance of object serialization.
* @param clazz the name of the class containing the cache field
* @param fieldName the name of the cache field
*/
public static void clearSunSoftCache(Class clazz, String fieldName) {
- Map cache = null;
- try {
- Field field = clazz.getDeclaredField(fieldName);
- field.setAccessible(true);
- cache = (Map) field.get(null);
- } catch (Throwable ignored) {
- // there is nothing a user could do about this anyway
- }
-
- if (cache != null) {
- synchronized (cache) {
+ synchronized (clazz) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ final Map cache = (Map) field.get(null);
cache.clear();
+ } catch (Throwable ignored) {
+ // there is nothing a user could do about this anyway
}
}
}