package org.mobicents.slee.container.component.deployment.classloading; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * An extension of {@link URLClassLoader} to support multiple parents. * * @author martins * */ public class URLClassLoaderDomain extends java.net.URLClassLoader { /** * the set of dependencies for the domain */ private Set<URLClassLoaderDomain> dependencies = new HashSet<URLClassLoaderDomain>(); /** * local cache of classes, avoids expensive search in dependencies */ private ConcurrentHashMap<String, Class<?>> cache = new ConcurrentHashMap<String, Class<?>>(); /** * the slee class loader */ private ClassLoader sleeClassLoader; /** * * @param urls * @param sleeClassLoader */ public URLClassLoaderDomain(URL[] urls, ClassLoader sleeClassLoader) { super(urls); this.sleeClassLoader = sleeClassLoader; } /** * * Loads a class locally, i.e., from managed URLs or URLs managed by dependencies. * * @param name * @return * @throws ClassNotFoundException */ public Class<?> loadClassLocally(String name) throws ClassNotFoundException { return loadClass(name, false, new HashSet<URLClassLoaderDomain>(),false); } @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { return loadClass(name, resolve, new HashSet<URLClassLoaderDomain>(),true); } /** * Loads the class for the specified name, providing a set of already * visited domains, if the domain was already visited a * {@link ClassNotFoundException} is thrown to prevent loops. * * @param name * @param resolve * @param visited * @param loadFromSlee if true the domain will search for the class in slee class loader too (last to check) * @return * @throws ClassNotFoundException */ protected Class<?> loadClass(String name, boolean resolve, Set<URLClassLoaderDomain> visited, boolean loadFromSlee) throws ClassNotFoundException { // try in cache Class<?> result = cache.get(name); if (result == null) { if (!visited.add(this)) { // cycle throw new ClassNotFoundException(name); } // try slee shared class loader? if (loadFromSlee) { try { result = sleeClassLoader.loadClass(name); } catch (Throwable e) { // ignore } } if (result == null) { // try in dependencies for (URLClassLoaderDomain dependency : dependencies) { try { result = dependency.loadClass(name, resolve, visited,false); } catch (Throwable e) { // ignore } if (result != null) { break; } } if (result == null) { // finally try locally result = super.loadClass(name, resolve); } } cache.put(name, result); } if (resolve) { resolveClass(result); } return result; } /** * Retrieves the non thread safe set of dependencies for the domain. * * @return */ public Set<URLClassLoaderDomain> getDependencies() { return dependencies; } /** * Retrieves the container's class loader * @return */ public ClassLoader getSleeClassLoader() { return sleeClassLoader; } /** * Clears the local classe cache and set of dependencies. */ public void clean() { cache.clear(); dependencies.clear(); } @Override public String toString() { return "URLClassLoaderDomain( urls= "+Arrays.asList(getURLs()) + " )\n"; } }