import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.AbstractMap;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.WeakHashMap;
import org.aspectj.apache.bcel.classfile.ClassParser;
*
* @see org.aspectj.apache.bcel.Repository
*
- * @version $Id: ClassLoaderRepository.java,v 1.7 2006/08/18 14:51:00 acolyer Exp $
+ * @version $Id: ClassLoaderRepository.java,v 1.8 2006/08/21 15:23:58 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @author David Dixon-Peugh
*/
public class ClassLoaderRepository implements Repository {
private static java.lang.ClassLoader bootClassLoader = null;
private java.lang.ClassLoader loader;
- private WeakHashMap /*<String classname,JavaClass>*/loadedClassesLocalCache = new WeakHashMap();
- private static Map /*<URL,JavaClass>*/loadedUrlsSharedCache = new HashMap();
- public static boolean useSharedCache = true;
- private static long timeManipulatingURLs = 0L;
- private static long timeSpentLoading = 0L;
- private static int classesLoadedCount = 0;
+ // Choice of cache...
+ private WeakHashMap /*<URL,SoftRef(JavaClass)>*/localCache = new WeakHashMap();
+ private static SoftHashMap /*<URL,JavaClass>*/sharedCache = new SoftHashMap(Collections.synchronizedMap(new HashMap()));
+
+ // For fast translation of the classname *intentionally not static*
+ private SoftHashMap /*<String,URL>*/ nameMap = new SoftHashMap(new HashMap(), false);
+
+ public static boolean useSharedCache =
+ System.getProperty("org.aspectj.apache.bcel.useSharedCache","true").equalsIgnoreCase("true");
+
private static int cacheHitsShared = 0;
private static int missSharedEvicted = 0; // Misses in shared cache access due to reference GC
- private static int misses = 0;
+ private long timeManipulatingURLs = 0L;
+ private long timeSpentLoading = 0L;
+ private int classesLoadedCount = 0;
+ private int misses = 0;
private int cacheHitsLocal = 0;
private int missLocalEvicted = 0; // Misses in local cache access due to reference GC
- static {
- useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache","true").equalsIgnoreCase("true");
- }
-
public ClassLoaderRepository( java.lang.ClassLoader loader ) {
- this.loader = (loader != null) ? loader : getBootClassLoader();
+ this.loader = (loader != null) ? loader : getBootClassLoader();
}
private static synchronized java.lang.ClassLoader getBootClassLoader() {
}
return bootClassLoader;
}
+
+ // Can track back to its key
+ public static class SoftHashMap extends AbstractMap {
+ private Map map;
+ boolean recordMiss = true; // only interested in recording miss stats sometimes
+ private ReferenceQueue rq = new ReferenceQueue();
+
+ public SoftHashMap(Map map) { this.map = map; }
+ public SoftHashMap() { this(new HashMap()); }
+ public SoftHashMap(Map map, boolean b) { this(map); this.recordMiss=b;}
+
+ class SpecialValue extends SoftReference {
+ private final Object key;
+ SpecialValue(Object k,Object v) {
+ super(v,rq);
+ this.key = k;
+ }
+ }
+
+ private void processQueue() {
+ SpecialValue sv = null;
+ while ((sv = (SpecialValue)rq.poll())!=null) {
+ map.remove(sv.key);
+ }
+ }
+
+ public Object get(Object key) {
+ SpecialValue value = (SpecialValue)map.get(key);
+ if (value==null) return null;
+ if (value.get()==null) {
+ // it got GC'd
+ map.remove(value.key);
+ if (recordMiss) missSharedEvicted++;
+ return null;
+ } else {
+ return value.get();
+ }
+ }
+
+ public Object put(Object k, Object v) {
+ processQueue();
+ return map.put(k, new SpecialValue(k,v));
+ }
+
+ public Set entrySet() {
+ return map.entrySet();
+ }
+
+ public void clear() {
+ processQueue();
+ map.clear();
+ }
+
+ public int size() {
+ processQueue();
+ return map.size();
+ }
+
+ public Object remove(Object k) {
+ processQueue();
+ SpecialValue value = (SpecialValue)map.remove(k);
+ if (value==null) return null;
+ if (value.get()!=null) {
+ return value.get();
+ }
+ return null;
+ }
+ }
/**
* Store a new JavaClass into this repository as a soft reference and return the reference
*/
- private Reference storeClassAsReference( JavaClass clazz ) {
- Reference ref = new SoftReference(clazz);
- loadedClassesLocalCache.put( clazz.getClassName(), ref);
- clazz.setRepository( this );
- return ref;
+ private void storeClassAsReference(URL url, JavaClass clazz ) {
+ if (useSharedCache) {
+ clazz.setRepository(null); // can't risk setting repository, we'll get in a pickle!
+ sharedCache.put(url, clazz);
+ } else {
+ clazz.setRepository(this);
+ localCache.put(url, new SoftReference(clazz));
+ }
}
- /**
- * Store a reference in the shared cache
- */
- private void storeReferenceShared(URL url, Reference ref) {
- if (useSharedCache) loadedUrlsSharedCache.put(url, ref);
- }
-
/**
* Store a new JavaClass into this Repository.
*/
public void storeClass( JavaClass clazz ) {
- storeClassAsReference(clazz);
+ storeClassAsReference(toURL(clazz.getClassName()),clazz);
}
/**
* Remove class from repository
*/
public void removeClass(JavaClass clazz) {
- loadedClassesLocalCache.remove(clazz.getClassName());
+ if (useSharedCache) sharedCache.remove(toURL(clazz.getClassName()));
+ else localCache.remove(toURL(clazz.getClassName()));
}
/**
* Find an already defined JavaClass in the local cache.
*/
public JavaClass findClass( String className ) {
- Object o = loadedClassesLocalCache.get( className );
+ if (useSharedCache) return findClassShared(toURL(className));
+ else return findClassLocal(toURL(className));
+ }
+
+ private JavaClass findClassLocal( URL url ) {
+ Object o = localCache.get(url);
if (o != null) {
o = ((Reference)o).get();
if (o != null) {
* Find an already defined JavaClass in the shared cache.
*/
private JavaClass findClassShared(URL url) {
- if (!useSharedCache) return null;
- Object o = (Reference)loadedUrlsSharedCache.get(url);
- if (o != null) {
- o = ((Reference)o).get();
- if (o != null) {
- return (JavaClass)o;
- } else {
- missSharedEvicted++;
- }
- }
- return null;
+ return (JavaClass)sharedCache.get(url);
}
+ private URL toURL(String className) {
+ URL url = (URL)nameMap.get(className);
+ if (url==null) {
+ String classFile = className.replace('.', '/');
+ url = loader.getResource( classFile + ".class" );
+ nameMap.put(className, url);
+ }
+ return url;
+ }
/**
* Lookup a JavaClass object from the Class Name provided.
*/
public JavaClass loadClass( String className ) throws ClassNotFoundException {
- String classFile = className.replace('.', '/');
-
- // Check the local cache
- JavaClass clazz = findClass(className);
- if (clazz != null) { cacheHitsLocal++; return clazz; }
+
+ // translate to a URL
+ long time = System.currentTimeMillis();
+ java.net.URL url = toURL(className);
+ timeManipulatingURLs += (System.currentTimeMillis() - time);
+ if (url==null) throw new ClassNotFoundException(className + " not found.");
+
+ JavaClass clazz = null;
- try {
- // Work out the URL
- long time = System.currentTimeMillis();
- java.net.URL url = (useSharedCache?loader.getResource( classFile + ".class" ):null);
- if (useSharedCache && url==null) throw new ClassNotFoundException(className + " not found.");
- InputStream is = (useSharedCache?url.openStream():loader.getResourceAsStream( classFile + ".class" ));
- timeManipulatingURLs += (System.currentTimeMillis() - time);
-
- // Check the shared cache
+ // Look in the appropriate cache
+ if (useSharedCache) {
clazz = findClassShared(url);
- if (clazz != null) { cacheHitsShared++; timeSpentLoading+=(System.currentTimeMillis() - time); return clazz; }
+ if (clazz != null) { cacheHitsShared++; return clazz; }
+ } else {
+ clazz = findClassLocal(url);
+ if (clazz != null) { cacheHitsLocal++; return clazz; }
+ }
+
+ // Didn't find it in either cache
+ misses++;
- // Didn't find it in either cache
- misses++;
-
- if (is == null) { // TODO move this up?
- throw new ClassNotFoundException(className + " not found.");
- }
-
- ClassParser parser = new ClassParser( is, className );
+ try {
+ // Load it
+ String classFile = className.replace('.', '/');
+ InputStream is = (useSharedCache?url.openStream():loader.getResourceAsStream( classFile + ".class" ));
+ if (is == null) {
+ throw new ClassNotFoundException(className + " not found.");
+ }
+ ClassParser parser = new ClassParser( is, className );
clazz = parser.parse();
- // Store it in both caches
- Reference ref = storeClassAsReference( clazz );
- storeReferenceShared(url,ref);
+ // Cache it
+ storeClassAsReference(url, clazz );
timeSpentLoading += (System.currentTimeMillis() - time);
classesLoadedCount++;
}
-/**
+ /**
* Produce a report on cache usage.
*/
- public String reportAllStatistics() {
+ public String report() {
StringBuffer sb = new StringBuffer();
sb.append("BCEL repository report.");
- if (!useSharedCache) sb.append(" (Shared cache deactivated)");
+ if (useSharedCache) sb.append(" (shared cache)");
+ else sb.append(" (local cache)");
sb.append(" Total time spent loading: "+timeSpentLoading+"ms.");
- sb.append(" Time manipulating URLs: "+timeManipulatingURLs+"ms.");
+ sb.append(" Time spent manipulating URLs: "+timeManipulatingURLs+"ms.");
sb.append(" Classes loaded: "+classesLoadedCount+".");
- if (useSharedCache) sb.append(" URL cache (hits/missDueToEviction): ("+cacheHitsShared+"/"+missSharedEvicted+").");
- sb.append(" Local cache (hits/missDueToEviction): ("+cacheHitsLocal+"/"+missLocalEvicted+").");
+ if (useSharedCache) {
+ sb.append(" Shared cache size: "+sharedCache.size());
+ sb.append(" Shared cache (hits/missDueToEviction): ("+cacheHitsShared+"/"+missSharedEvicted+").");
+ } else {
+ sb.append(" Local cache size: "+localCache.size());
+ sb.append(" Local cache (hits/missDueToEviction): ("+cacheHitsLocal+"/"+missLocalEvicted+").");
+ }
return sb.toString();
}
- public int reportLocalCacheHits() {
- return cacheHitsLocal;
- }
-
- public static int reportSharedCacheHits() {
- return cacheHitsShared;
+ /**
+ * Returns an array of the stats, for testing, the order is fixed:
+ * 0=time spent loading (static)
+ * 1=time spent manipulating URLs (static)
+ * 2=classes loaded (static)
+ * 3=cache hits shared (static)
+ * 4=misses in shared due to eviction (static)
+ * 5=cache hits local
+ * 6=misses in local due to eviction
+ * 7=shared cache size
+ */
+ public long[] reportStats() {
+ return new long[]{timeSpentLoading,timeManipulatingURLs,classesLoadedCount,
+ cacheHitsShared,missSharedEvicted,cacheHitsLocal,missLocalEvicted,
+ sharedCache.size()};
}
/**
missLocalEvicted = 0;
misses = 0;
clear();
- clearShared();
}
/** Clear all entries from the local cache */
public void clear() {
- loadedClassesLocalCache.clear();
- }
-
- /** Clear all entries from the shared cache */
- public static void clearShared() {
- loadedUrlsSharedCache.clear();
+ if (useSharedCache) sharedCache.clear();
+ else localCache.clear();
}
+
}
+
// Retrieve string 5 times from same repository, 4 hits should be from local cache
public void testLocalCacheWorks() throws ClassNotFoundException {
+ ClassLoaderRepository.useSharedCache=false;
JavaClass jc = rep1.loadClass("java.lang.String");
jc = rep1.loadClass("java.lang.String");
jc = rep1.loadClass("java.lang.String");
jc = rep1.loadClass("java.lang.String");
jc = rep1.loadClass("java.lang.String");
- assertTrue("Should have used local cache 4 times: "+rep1.reportLocalCacheHits(),rep1.reportLocalCacheHits()==4);
+ assertTrue("Should have used local cache 4 times: "+reportLocalCacheHits(rep1),reportLocalCacheHits(rep1)==4);
+ }
+
+ // Retrieve string 5 times from same repository, 4 hits should be from local cache
+ public void testSharedCacheWorksOnOne() throws ClassNotFoundException {
+ ClassLoaderRepository.useSharedCache=true;
+ JavaClass jc = rep1.loadClass("java.lang.String");
+ jc = rep1.loadClass("java.lang.String");
+ jc = rep1.loadClass("java.lang.String");
+ jc = rep1.loadClass("java.lang.String");
+ jc = rep1.loadClass("java.lang.String");
+ assertTrue("Should have used local cache 4 times: "+reportSharedCacheHits(rep1),reportSharedCacheHits(rep1)==4);
}
// Retrieve String through one repository then load again through another, should be shared cache hit
public void testSharedCacheWorks() throws ClassNotFoundException {
+ ClassLoaderRepository.useSharedCache=true;
JavaClass jc = rep1.loadClass("java.lang.String");
jc = rep2.loadClass("java.lang.String");
- assertTrue("Should have retrieved String from shared cache: "+ClassLoaderRepository.reportSharedCacheHits(),
- ClassLoaderRepository.reportSharedCacheHits()==1);
+ assertTrue("Should have retrieved String from shared cache: "+reportSharedCacheHits(rep1),
+ reportSharedCacheHits(rep1)==1);
}
// Shared cache OFF, shouldn't get a shared cache hit
JavaClass jc = rep1.loadClass("java.lang.String");
jc = rep2.loadClass("java.lang.String");
assertTrue("Should not have retrieved String from shared cache: "+
- ClassLoaderRepository.reportSharedCacheHits(),
- ClassLoaderRepository.reportSharedCacheHits()==0);
+ reportSharedCacheHits(rep1),
+ reportSharedCacheHits(rep1)==0);
} finally {
ClassLoaderRepository.useSharedCache=true;
}
public void tearDown() throws Exception {
super.tearDown();
- System.err.println("Rep1: "+rep1.reportAllStatistics());
- System.err.println("Rep2: "+rep2.reportAllStatistics());
+ System.err.println("Rep1: "+rep1.reportStats());
+ System.err.println("Rep2: "+rep2.reportStats());
rep1.reset();
rep2.reset();
}
-
+
+ private long reportLocalCacheHits(ClassLoaderRepository rep) {
+ return rep.reportStats()[5];
+ }
+
+ private long reportSharedCacheHits(ClassLoaderRepository rep) {
+ return rep.reportStats()[3];
+ }
+
}
+
WeaverStateInfo wsi = type.getWeaverState();
if (wsi != null && wsi.isReweavable()) {
BcelObjectType classType = getClassType(type.getName());
- classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes())));
+ JavaClass wovenJavaClass = classType.getJavaClass();
+ JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(),
+ wsi.getUnwovenClassFileData(wovenJavaClass.getBytes()));
+ world.storeClass(unwovenJavaClass);
+ classType.setJavaClass(unwovenJavaClass);
+// classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes())));
}
//TODO AV - happens to reach that a lot of time: for each type flagged reweavable X for each aspect in the weaverstate
public class BcelWorld extends World implements Repository {
private ClassPathManager classPath;
- private Repository delegate;
+ protected Repository delegate;
//private ClassPathManager aspectPath = null;
}
public void storeClass(JavaClass clazz) {
- throw new RuntimeException("Not implemented");
+ // doesn't need to do anything
}
public void removeClass(JavaClass clazz) {
import java.util.List;
import java.util.Map;
+import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.ICrossReferenceHandler;
*/
public class LTWWorld extends BcelWorld implements IReflectionWorld {
-
private AnnotationFinder annotationFinder;
private ClassLoader loader; // weavingContext?
private IWeavingContext weavingContext;
((ReferenceType)ret).setDelegate(rtd);
return ret;
}
+
+ public void storeClass(JavaClass clazz) {
+ delegate.storeClass(clazz);
+ }
+
}
package org.aspectj.weaver.bcel;
import java.io.File;
-import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
+import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/** NOT YET INCLUDED IN A FULL TEST RUN - WORK IN PROGRESS CHECKING CLASSLOADERREPOSITORY OPTIMIZATIONS */
public class ClassLoaderRepositoryTests extends TestCase {
-
- public void testRepositorySharing() throws Exception {
- ClassLoaderRepository.useSharedCache=false;
- File f = new File("../lib/aspectj/lib/aspectjtools.jar");
+ private File f;
+ private ZipFile zf;
+ private Enumeration entries;
+ private Map map;
+
+ public void setUp() throws Exception {
+ f = new File("../lib/aspectj/lib/aspectjtools.jar");
+ assertTrue("Couldn't find aspectjtools to test. Tried: "+f.getAbsolutePath(),f.exists());
+ zf = new ZipFile(f);
+ entries = zf.entries();
+// ClassLoaderRepository.sharedCacheCompactFrequency = 16384;
+ map = getSharedMap();
+ }
+
+ public void tearDown() {
+ new ClassLoaderRepository(null).reset();
+ }
+
+ private ClassLoaderRepository setupRepository() throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
- ClassLoader cl1 = new URLClassLoader(new URL[]{f.toURL()},cl);
- ClassLoader cl2 = new URLClassLoader(new URL[]{f.toURL()},cl);
- ClassLoaderRepository rep1 = new ClassLoaderRepository(cl1);
- ClassLoaderRepository rep2 = new ClassLoaderRepository(cl2);
- try {
- assertTrue("Couldnt find aspectjtools to test. Tried: "+f.getAbsolutePath(),f.exists());
- ZipFile zf = new ZipFile(f);
- int i = 0;
- Enumeration entries = zf.entries();
- while (entries.hasMoreElements()) {
- ZipEntry zfe = (ZipEntry)entries.nextElement();
- String classfileName = zfe.getName();
- if (classfileName.endsWith(".class")) {
- String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.');
-
- // twice by each
- rep1.loadClass(clazzname);
- rep1.loadClass(clazzname);
- rep2.loadClass(clazzname);
- rep2.loadClass(clazzname);
- i++;
- }
+ ClassLoader res = new URLClassLoader(new URL[]{f.toURL()},cl);
+ ClassLoaderRepository rep = new ClassLoaderRepository(res);
+ return rep;
+ }
+
+ private void compareTwoRepositories() throws Exception {
+ ClassLoaderRepository rep1 = setupRepository();
+ ClassLoaderRepository rep2 = setupRepository();
+ int i = 0;
+ while (entries.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry)entries.nextElement();
+ String classfileName = zfe.getName();
+ if (classfileName.endsWith(".class")) {
+ String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.');
+
+ // twice by each
+ rep1.loadClass(clazzname);
+ rep1.loadClass(clazzname);
+ rep2.loadClass(clazzname);
+ rep2.loadClass(clazzname);
+ i++;
+ }
+ }
+ System.err.println("Successfully compared "+i+" entries!!");
+ System.err.println(rep1.report());
+ System.err.println(rep2.report());
+ }
+
+ private void loadOnce() throws Exception {
+ ClassLoaderRepository rep = setupRepository();
+ while (entries.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry) entries.nextElement();
+ String classfileName = zfe.getName();
+ if (classfileName.endsWith(".class")) {
+ String clazzname = classfileName.substring(0,
+ classfileName.length() - 6).replace('/', '.');
+
+ rep.loadClass(clazzname);
+ }
+ }
+ }
+
+ public void testMultiThreaded() throws Throwable {
+ ClassLoaderRepository.useSharedCache=true;
+// ClassLoaderRepository.sharedCacheCompactFrequency = 200;
+ //loadOnce();
+ TestThread threads[] = new TestThread[6];
+ for (int i=0; i<threads.length; i++) {
+ threads[i] = new TestThread((i%3)*1000);
+ threads[i].start();
+ }
+ for (int i=0; i<threads.length; i++) {
+ threads[i].join();
+ if (threads[i].getFailure() != null) {
+ throw threads[i].getFailure();
+ }
+ }
+ }
+
+ private class TestThread extends Thread {
+ public Throwable failure = null;
+ Enumeration entries;
+
+ // ensure the threads are loading DIFFERENT shared classes at the same time...
+ public TestThread(int skip) {
+ entries = zf.entries();
+ for (int i=0; i<skip && entries.hasMoreElements(); i++) {
+ entries.nextElement();
}
- System.err.println("Successfully compared "+i+" entries!!");
- } catch (IOException e) {
- e.printStackTrace();
- fail(e.getMessage());
+ }
+
+ public void run() {
+ try {
+ ClassLoaderRepository rep = setupRepository();
+ int i = 0;
+ while (entries.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry)entries.nextElement();
+ String classfileName = zfe.getName();
+ if (classfileName.endsWith(".class")) {
+ String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.');
+ rep.loadClass(clazzname);
+ rep.loadClass(clazzname);
+ i++;
+ }
+ }
+ System.err.println("Thread finished: "+rep.report());
+ } catch (Throwable t) {
+ failure = t;
+ }
+ }
+ public Throwable getFailure() {
+ return failure;
}
- System.err.println(rep1.reportAllStatistics());
- System.err.println(rep2.reportAllStatistics());
+ }
+
+ public void testNotSharedRepository() throws Exception {
+ ClassLoaderRepository.useSharedCache=false;
+ compareTwoRepositories();
+ }
+
+ public void testSharedUrlRepository() throws Exception {
+ ClassLoaderRepository.useSharedCache=true;
+ compareTwoRepositories();
+// ClassLoaderRepository.compactSharedCache();
}
-
+ public void testPurgeUrlRepository() throws Exception {
+ ClassLoaderRepository.useSharedCache = true;
+ ClassLoaderRepository rep = setupRepository();
+ Reference ref = null;
+
+ while (ref==null && entries.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry)entries.nextElement();
+ String classfileName = zfe.getName();
+ if (classfileName.endsWith(".class")) {
+ String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.');
+
+ rep.loadClass(clazzname);
+ assertEquals("expected one entry in shared URL cache "+map.size(), 1, map.size());
+ ref = (Reference)map.values().iterator().next();
+ ref.clear();
+ ref.enqueue();
+ map.size();//force purge
+ }
+ }
+ assertEquals("expected empty shared URL cache "+map.size(), 0, map.size());
+ }
+
+ public void testAutoPurgeUrlRepository() throws Exception {
+ ClassLoaderRepository.useSharedCache = true;
+ assertEquals("expected empty shared URL cache "+map.size(), 0, map.size());
+ ClassLoaderRepository rep = setupRepository();
+ Reference ref = null;
+ int i = 0;
+
+ while (i<3 && entries.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry)entries.nextElement();
+ String classfileName = zfe.getName();
+ if (classfileName.endsWith(".class")) {
+ String clazzname = classfileName.substring(0,classfileName.length()-6).replace('/','.');
+
+ rep.loadClass(clazzname);
+ ref = (Reference)map.values().iterator().next();
+ ref.clear();
+ ref.enqueue();
+ i++;
+ }
+ }
+ assertTrue("expected smaller shared URL cache "+map.size(), map.size()<3);
+ }
+
+ private Field getSharedMapField() throws Exception {
+ Field field = ClassLoaderRepository.class.getDeclaredField("sharedCache");
+ field.setAccessible(true);
+ return field;
+ }
+ private Map getSharedMap() throws Exception {
+ return (Map)getSharedMapField() .get(null);
+ }
}
+