import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
public static boolean useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache", "true").equalsIgnoreCase("true");
+ //Cache not found classes as well to prevent unnecessary file I/O operations
+ public static final boolean useUnavailableClassesCache =
+ System.getProperty("org.aspectj.apache.bcel.useUnavailableClassesCache", "true").equalsIgnoreCase("true");
+ //Ignore cache clear requests to not build up the cache over and over again
+ public static final boolean ignoreCacheClearRequests =
+ System.getProperty("org.aspectj.apache.bcel.ignoreCacheClearRequests", "true").equalsIgnoreCase("true");
+
+ //Second cache for the unavailable classes
+ private static Set<String> unavailableClasses = new HashSet<String>();
+
private static int cacheHitsShared = 0;
private static int missSharedEvicted = 0; // Misses in shared cache access due to reference GC
private long timeManipulatingURLs = 0L;
@Override
public void clear() {
- processQueue();
- map.clear();
+ if (!ignoreCacheClearRequests) {
+ processQueue();
+ map.clear();
+ }
}
@Override
*/
public JavaClass loadClass(String className) throws ClassNotFoundException {
+ //Quick evaluation of unavailable classes to prevent unnecessary file I/O
+ if (useUnavailableClassesCache && unavailableClasses.contains(className))
+ throw new ClassNotFoundException(className + " not found.");
+
// translate to a URL
long time = System.currentTimeMillis();
java.net.URL url = toURL(className);
timeManipulatingURLs += (System.currentTimeMillis() - time);
- if (url == null)
+ if (url == null) {
+ if (useUnavailableClassesCache)
+ unavailableClasses.add(className);
throw new ClassNotFoundException(className + " not found - unable to determine URL");
+ }
JavaClass clazz = null;
InputStream is = (useSharedCache ? url.openStream() : loaderRef.getClassLoader().getResourceAsStream(
classFile + ".class"));
if (is == null) {
+ if (useUnavailableClassesCache) {
+ unavailableClasses.add(className);
+ }
throw new ClassNotFoundException(className + " not found using url " + url);
}
ClassParser parser = new ClassParser(is, className);
classesLoadedCount++;
return clazz;
} catch (IOException e) {
+ unavailableClasses.add(className);
throw new ClassNotFoundException(e.toString());
}
}
/** Clear all entries from the local cache */
public void clear() {
- if (useSharedCache)
- sharedCache.clear();
- else
- localCache.clear();
+ if (!ignoreCacheClearRequests) {
+ if (useSharedCache)
+ sharedCache.clear();
+ else
+ localCache.clear();
+ }
}
}
private Repository bcelRepository;
private BcelWeakClassLoaderReference classLoaderRef;
+
+ private static Repository staticBcelRepository;
+ private static BcelWeakClassLoaderReference staticClassLoaderRef;
+
private World world;
private static boolean useCachingClassLoaderRepository;
+ //Use single instance of Repository and ClassLoader
+ public static final boolean useSingleInstances =
+ System.getProperty("org.aspectj.apache.bcel.useSingleRepositoryInstance", "true").equalsIgnoreCase("true");
+
static {
try {
useCachingClassLoaderRepository = System.getProperty("Xset:bcelRepositoryCaching","true").equalsIgnoreCase("true");
}
public void setClassLoader(ClassLoader aLoader) {
- this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
+ //Set class loader ref
+ if (useSingleInstances && staticClassLoaderRef == null)
+ staticClassLoaderRef = new BcelWeakClassLoaderReference(aLoader);
+ else
+ this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
+
+ //Set repository
if (useCachingClassLoaderRepository) {
- this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
- } else {
- this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
+ if (useSingleInstances && staticBcelRepository == null)
+ staticBcelRepository = new ClassLoaderRepository(getClassLoader());
+ else
+ this.bcelRepository = new ClassLoaderRepository(getClassLoader());
+ }
+ else {
+ if (useSingleInstances && staticBcelRepository == null)
+ staticBcelRepository = new NonCachingClassLoaderRepository(getClassLoader());
+ else
+ this.bcelRepository = new NonCachingClassLoaderRepository(getClassLoader());
}
}
+ private Repository getBcelRepository() {
+ return useSingleInstances ? staticBcelRepository : bcelRepository;
+ }
+
public void setWorld(World aWorld) {
this.world = aWorld;
}
}
private ClassLoader getClassLoader() {
- return classLoaderRef.getClassLoader();
+ return useSingleInstances ? staticClassLoaderRef.getClassLoader() : classLoaderRef.getClassLoader();
}
public AnnotationAJ getAnnotationOfType(UnresolvedType ofType, Member onMember) {
anns = bcelField.getAnnotations();
}
// the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
+ getBcelRepository().clear();
// OPTIMIZE make constant 0 size array for sharing
if (anns == null)
anns = AnnotationGen.NO_ANNOTATIONS;
public String getAnnotationDefaultValue(Member onMember) {
try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
+ JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
// we can just use reflection.
if (!areRuntimeAnnotationsSufficient) {
try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
+ JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = null;
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
anns = bcelField.getAnnotations();
}
// the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
+ getBcelRepository().clear();
if (anns == null || anns.length == 0) {
return ResolvedType.NONE;
}
// annotations so we bail out to Bcel and then chuck away the JavaClass so that we
// don't hog memory.
try {
- JavaClass jc = bcelRepository.loadClass(forClass);
+ JavaClass jc = getBcelRepository().loadClass(forClass);
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[] anns = jc.getAnnotations();
- bcelRepository.clear();
+ getBcelRepository().clear();
if (anns == null) {
return ResolvedType.NONE;
} else {
return null;
try {
- JavaClass jc = bcelRepository.loadClass(forMember.getDeclaringClass());
+ JavaClass jc = getBcelRepository().loadClass(forMember.getDeclaringClass());
LocalVariableTable lvt = null;
int numVars = 0;
if (forMember instanceof Method) {
// don't hog
// memory.
try {
- JavaClass jc = bcelRepository.loadClass(onMember.getDeclaringClass());
+ JavaClass jc = getBcelRepository().loadClass(onMember.getDeclaringClass());
org.aspectj.apache.bcel.classfile.annotation.AnnotationGen[][] anns = null;
if (onMember instanceof Method) {
org.aspectj.apache.bcel.classfile.Method bcelMethod = jc.getMethod((Method) onMember);
// anns = null;
}
// the answer is cached and we don't want to hold on to memory
- bcelRepository.clear();
+ getBcelRepository().clear();
if (anns == null)
return NO_PARAMETER_ANNOTATIONS;
ResolvedType[][] result = new ResolvedType[anns.length][];