/******************************************************************************* * 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; } }