/** * Copyright 2010 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.rule; import java.io.InputStream; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.drools.core.util.DroolsClassLoader; /** * A classloader that loads from a (dynamic) list of sub-classloaders. */ public class DroolsCompositeClassLoader extends ClassLoader implements DroolsClassLoader { /* Assumption: modifications are really rare, but iterations are frequent. */ private final List<ClassLoader> classLoaders = new CopyOnWriteArrayList<ClassLoader>(); private final boolean hasParent; public DroolsCompositeClassLoader(final ClassLoader parentClassLoader, final boolean cacheParentCalls) { super( parentClassLoader ); this.hasParent = parentClassLoader != null; } public synchronized void addClassLoader(final ClassLoader classLoader) { if ( classLoader == null ) { return; } /* NB: we need synchronized here even though we use a COW list: * two threads may try to add the same new class loader, so we need * to protect over a bigger area than just a single iteration. */ // don't add duplicate ClassLoaders; for ( final ClassLoader cl : this.classLoaders ) { if ( cl == classLoader ) { return; } } this.classLoaders.add( classLoader ); } public synchronized void removeClassLoader(final ClassLoader classLoader) { /* synchronized to protect against concurrent runs of * addClassLoader(x) and removeClassLoader(x). */ classLoaders.remove( classLoader ); } /** * Search the list of child ClassLoaders */ public Class< ? > fastFindClass(final String name) { for ( final ClassLoader classLoader : this.classLoaders ) { final Class< ? > cls = ((DroolsClassLoader) classLoader).fastFindClass( name ); if ( cls != null ) { return cls; } } return null; } /** * This ClassLoader never has classes of it's own, so only search the child ClassLoaders * and the parent ClassLoader if one is provided */ public Class< ? > loadClass(final String name, final boolean resolve) throws ClassNotFoundException { // search the child ClassLoaders Class< ? > cls; cls = fastFindClass( name ); // still not found so search the parent ClassLoader if ( this.hasParent && cls == null ) { cls = Class.forName( name, true, getParent() ); } if ( resolve ) { resolveClass( cls ); } return cls; } /** * This ClassLoader never has classes of it's own, so only search the child ClassLoaders * and the parent ClassLoader if one is provided */ public InputStream getResourceAsStream(final String name) { for ( final ClassLoader classLoader : this.classLoaders ) { InputStream stream = classLoader.getResourceAsStream( name ); if ( stream != null ) { return stream; } } if ( this.hasParent ) { return getParent().getResourceAsStream( name ); } return null; } /** * This ClassLoader never has classes of it's own, so only search the child ClassLoaders */ protected Class< ? > findClass(final String name) throws ClassNotFoundException { final Class< ? > cls = fastFindClass( name ); if ( cls == null ) { throw new ClassNotFoundException( name ); } return cls; } }