148 lines
5.3 KiB
Java
148 lines
5.3 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.classLoader;
|
|
|
|
import java.io.IOException;
|
|
import java.lang.reflect.Constructor;
|
|
import java.util.HashMap;
|
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
|
import com.ibm.wala.types.ClassLoaderReference;
|
|
import com.ibm.wala.util.collections.HashMapFactory;
|
|
import com.ibm.wala.util.config.SetOfClasses;
|
|
import com.ibm.wala.util.warnings.Warning;
|
|
import com.ibm.wala.util.warnings.Warnings;
|
|
|
|
/**
|
|
* An implementation of the class loader factory that produces ClassLoaderImpls
|
|
*/
|
|
public class ClassLoaderFactoryImpl implements ClassLoaderFactory {
|
|
|
|
/**
|
|
* Set of classes that class loaders should ignore; classloaders should
|
|
* pretend these classes don't exit.
|
|
*/
|
|
final private SetOfClasses exclusions;
|
|
|
|
/**
|
|
* A Mapping from ClassLoaderReference to IClassLoader
|
|
*/
|
|
final private HashMap<ClassLoaderReference, IClassLoader> map = HashMapFactory.make(3);
|
|
|
|
/**
|
|
* @param exclusions
|
|
* A set of classes that class loaders should pretend don't exist.
|
|
*/
|
|
public ClassLoaderFactoryImpl(SetOfClasses exclusions) {
|
|
this.exclusions = exclusions;
|
|
}
|
|
|
|
/**
|
|
* Return a class loader corresponding to a given class loader identifier.
|
|
* Create one if necessary.
|
|
*
|
|
* @param classLoaderReference
|
|
* identifier for the desired class loader
|
|
*/
|
|
@Override
|
|
public IClassLoader getLoader(ClassLoaderReference classLoaderReference, IClassHierarchy cha, AnalysisScope scope)
|
|
throws IOException {
|
|
if (classLoaderReference == null) {
|
|
throw new IllegalArgumentException("null classLoaderReference");
|
|
}
|
|
IClassLoader result = map.get(classLoaderReference);
|
|
if (result == null) {
|
|
ClassLoaderReference parentRef = classLoaderReference.getParent();
|
|
IClassLoader parent = null;
|
|
if (parentRef != null) {
|
|
parent = getLoader(parentRef, cha, scope);
|
|
}
|
|
IClassLoader cl = makeNewClassLoader(classLoaderReference, cha, parent, scope);
|
|
map.put(classLoaderReference, cl);
|
|
result = cl;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a new class loader for a given key
|
|
*
|
|
* @param classLoaderReference
|
|
* the key
|
|
* @param parent
|
|
* parent classloader to be used for delegation
|
|
* @return a new ClassLoaderImpl
|
|
* @throws IOException
|
|
* if the desired loader cannot be instantiated, usually because the
|
|
* specified module can't be found.
|
|
*/
|
|
protected IClassLoader makeNewClassLoader(ClassLoaderReference classLoaderReference, IClassHierarchy cha, IClassLoader parent,
|
|
AnalysisScope scope) throws IOException {
|
|
String implClass = scope.getLoaderImpl(classLoaderReference);
|
|
IClassLoader cl;
|
|
if (implClass == null) {
|
|
cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, cha);
|
|
} else
|
|
try {
|
|
// this is fragile. why are we doing things this way again?
|
|
Class<?> impl = Class.forName(implClass);
|
|
Constructor<?> ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, IClassLoader.class,
|
|
SetOfClasses.class, IClassHierarchy.class });
|
|
cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, parent, exclusions, cha });
|
|
} catch (Exception e) {
|
|
try {
|
|
Class<?> impl = Class.forName(implClass);
|
|
Constructor<?> ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, ArrayClassLoader.class,
|
|
IClassLoader.class, SetOfClasses.class, IClassHierarchy.class });
|
|
cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, scope.getArrayClassLoader(), parent,
|
|
exclusions, cha });
|
|
} catch (Exception e2) {
|
|
System.err.println("failed to load impl class " + implClass);
|
|
e2.printStackTrace(System.err);
|
|
Warnings.add(InvalidClassLoaderImplementation.create(implClass));
|
|
cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, cha);
|
|
}
|
|
}
|
|
cl.init(scope.getModules(classLoaderReference));
|
|
return cl;
|
|
}
|
|
|
|
/**
|
|
* A waring when we fail to load an appropriate class loader implementation
|
|
*/
|
|
private static class InvalidClassLoaderImplementation extends Warning {
|
|
|
|
final String impl;
|
|
|
|
InvalidClassLoaderImplementation(String impl) {
|
|
super(Warning.SEVERE);
|
|
this.impl = impl;
|
|
}
|
|
|
|
@Override
|
|
public String getMsg() {
|
|
return getClass().toString() + " : " + impl;
|
|
}
|
|
|
|
public static InvalidClassLoaderImplementation create(String impl) {
|
|
return new InvalidClassLoaderImplementation(impl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the set of classes that will be ignored.
|
|
*/
|
|
public SetOfClasses getExclusions() {
|
|
return exclusions;
|
|
}
|
|
}
|