[jboss-svn-commits] JBL Code SVN: r32483 - in labs/jbossrules/trunk: drools-compiler/src/main/java/org/drools/compiler and 6 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Apr 8 23:08:58 EDT 2010


Author: tirelli
Date: 2010-04-08 23:08:57 -0400 (Thu, 08 Apr 2010)
New Revision: 32483

Modified:
   labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/ClassLoaderUtil.java
   labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/CompositeClassLoader.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilderConfiguration.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/RuleBaseConfiguration.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/SessionConfiguration.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ClassPathResource.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/DroolsCompositeClassLoader.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectRuntimeData.java
Log:
JBRULES-2067: adding support to class resolution caching on user and system classloaders to improve compilation performance.

Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/ClassLoaderUtil.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/ClassLoaderUtil.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/ClassLoaderUtil.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -1,39 +1,37 @@
 package org.drools.util;
 
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map.Entry;
-
 public class ClassLoaderUtil {
-    public static ClassLoader getClassLoader(final ClassLoader classLoader, Class cls) {
+    public static CompositeClassLoader getClassLoader(final ClassLoader classLoader,
+                                                      final Class< ? > cls,
+                                                      final boolean enableCache) {
         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
-        ClassLoader currentClassLoader = ( cls != null ) ? cls.getClassLoader() : ClassLoaderUtil.class.getClassLoader();
-        ClassLoader systemClassLoader = Class.class.getClassLoader().getSystemClassLoader();
-        
-        CompositeClassLoader cl = new CompositeClassLoader( null );        
-        
-        if (classLoader != null ) {
+        ClassLoader currentClassLoader = (cls != null) ? cls.getClassLoader() : ClassLoaderUtil.class.getClassLoader();
+        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+
+        CompositeClassLoader cl = new CompositeClassLoader( null );
+
+        if ( classLoader != null ) {
             // the user specified classloader
-        	cl.addClassLoader(classLoader); 
+            cl.addClassLoader( classLoader );
         }
-        
-        if (currentClassLoader != null ) {
+
+        if ( currentClassLoader != null ) {
             // the current classloader, typically from a drools-core or drools-compiler class
-            cl.addClassLoader(currentClassLoader); 
-        }         
-        
-        if (contextClassLoader != null ) {
+            cl.addClassLoader( currentClassLoader );
+        }
+
+        if ( contextClassLoader != null ) {
             // context classloader
-        	cl.addClassLoader(contextClassLoader); 
-        }       
-        
-        if (systemClassLoader != null ) {
+            cl.addClassLoader( contextClassLoader );
+        }
+
+        if ( systemClassLoader != null ) {
             // system classloader
-        	cl.addClassLoader(systemClassLoader); 
-        }        
-        
+            cl.addClassLoader( systemClassLoader );
+        }
+
+        cl.setCachingEnabled( enableCache );
+
         return cl;
-                       
-    } 
+    }
 }

Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/CompositeClassLoader.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/CompositeClassLoader.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/util/CompositeClassLoader.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -5,19 +5,32 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicReference;
 
 public class CompositeClassLoader extends ClassLoader {
     /* Assumption: modifications are really rare, but iterations are frequent. */
-    private final List<ClassLoader> classLoaders = new CopyOnWriteArrayList<ClassLoader>();
+    private final List<ClassLoader>       classLoaders = new CopyOnWriteArrayList<ClassLoader>();
+    private final AtomicReference<Loader> loader       = new AtomicReference<Loader>();
 
     public CompositeClassLoader(final ClassLoader parentClassLoader) {
         super( null );
+        loader.set( new DefaultLoader() );
     }
 
+    public synchronized void setCachingEnabled(boolean enabled) {
+        if ( enabled && loader.get() instanceof DefaultLoader ) {
+            loader.set( new CachingLoader() );
+        } else if ( !enabled && loader.get() instanceof CachingLoader ) {
+            loader.set( DefaultLoader.INSTANCE );
+        }
+    }
+
     public synchronized void addClassLoader(final ClassLoader classLoader) {
         /* 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
@@ -30,6 +43,7 @@
             }
         }
         this.classLoaders.add( classLoader );
+        this.loader.get().reset();
     }
 
     public synchronized void removeClassLoader(final ClassLoader classLoader) {
@@ -37,6 +51,7 @@
          * addClassLoader(x) and removeClassLoader(x).
          */
         classLoaders.remove( classLoader );
+        this.loader.get().reset();
     }
 
     /**
@@ -45,25 +60,9 @@
      */
     public Class< ? > loadClass(final String name,
                                 final boolean resolve) throws ClassNotFoundException {
-        // search the child ClassLoaders
-        Class< ? > cls = null;
-
-        for ( final ClassLoader classLoader : this.classLoaders ) {
-            try {            	
-                cls = Class.forName( name, true, classLoader );
-            } catch ( ClassNotFoundException e ) {
-                // swallow as we need to check more classLoaders
-            }
-            if ( cls != null ) {
-                break;
-            }
-        }
-
-        if ( resolve ) {
-            resolveClass( cls );
-        }
-
-        return cls;
+        return loader.get().load( this,
+                                  name,
+                                  resolve );
     }
 
     /**
@@ -111,10 +110,119 @@
         }
     }
 
+    public void dumpStats() {
+        System.out.println( loader.toString() );
+    }
+
+    private static interface Loader {
+        public Class< ? > load(final CompositeClassLoader cl,
+                               final String name,
+                               final boolean resolve);
+
+        public void reset();
+    }
+
+    private static class DefaultLoader
+        implements
+        Loader {
+
+        // this class is stateless, so lets make a singleton of it
+        public static final DefaultLoader INSTANCE = new DefaultLoader();
+
+        private DefaultLoader() {
+        }
+
+        public Class< ? > load(final CompositeClassLoader cl,
+                               final String name,
+                               final boolean resolve) {
+            // search the child ClassLoaders
+            Class< ? > cls = null;
+
+            for ( final ClassLoader classLoader : cl.classLoaders ) {
+                try {
+                    cls = Class.forName( name,
+                                         true,
+                                         classLoader );
+                } catch ( ClassNotFoundException e ) {
+                    // swallow as we need to check more classLoaders
+                }
+                if ( cls != null ) {
+                    break;
+                }
+            }
+
+            if ( resolve ) {
+                cl.resolveClass( cls );
+            }
+
+            return cls;
+        }
+
+        public void reset() {
+            // nothing to do
+        }
+    }
+
+    private static class CachingLoader
+        implements
+        Loader {
+
+        private final Map<String, Object> classLoaderResultMap = new HashMap<String, Object>();
+        public long                       successfulCalls      = 0;
+        public long                       failedCalls          = 0;
+        public long                       cacheHits            = 0;
+
+        public Class< ? > load(final CompositeClassLoader cl,
+                               final String name,
+                               final boolean resolve) {
+            if ( classLoaderResultMap.containsKey( name ) ) {
+                cacheHits++;
+                return (Class< ? >) classLoaderResultMap.get( name );
+            }
+            // search the child ClassLoaders
+            Class< ? > cls = null;
+
+            for ( final ClassLoader classLoader : cl.classLoaders ) {
+                try {
+                    cls = Class.forName( name,
+                                         true,
+                                         classLoader );
+                } catch ( ClassNotFoundException e ) {
+                    // swallow as we need to check more classLoaders
+                }
+                if ( cls != null ) {
+                    break;
+                }
+            }
+
+            if ( resolve ) {
+                cl.resolveClass( cls );
+            }
+
+            classLoaderResultMap.put( name,
+                                      cls );
+            if ( cls != null ) {
+                this.successfulCalls++;
+            } else {
+                this.failedCalls++;
+            }
+
+            return cls;
+        }
+
+        public void reset() {
+            this.successfulCalls = this.failedCalls = this.cacheHits = 0;
+        }
+
+        public String toString() {
+            return new StringBuilder().append( "TotalCalls: " ).append( successfulCalls + failedCalls + cacheHits ).append( " CacheHits: " ).append( cacheHits ).append( " successfulCalls: " ).append( successfulCalls ).append( " FailedCalls: " ).append( failedCalls ).toString();
+        }
+    }
+
     private static class CompositeEnumeration<URL>
         implements
         Enumeration<URL> {
-        private List<URL> list;
+        private List<URL>     list;
         private Iterator<URL> it;
 
         public void addEnumeration(Enumeration<URL> enumeration) {
@@ -122,15 +230,15 @@
                 // don't add it, if it's empty
                 return;
             }
-            
+
             if ( this.it != null ) {
                 throw new IllegalStateException( "cannot add more enumerations while iterator" );
             }
-            
+
             if ( this.list == null ) {
                 this.list = new ArrayList<URL>();
             }
-            
+
             while ( enumeration.hasMoreElements() ) {
                 this.list.add( enumeration.nextElement() );
             }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -126,7 +126,7 @@
      */
     private final String                      defaultDialect;
 
-    private DroolsCompositeClassLoader              rootClassLoader;
+    private DroolsCompositeClassLoader        rootClassLoader;
 
     private Map<String, Class< ? >>           globals;
 
@@ -135,9 +135,9 @@
     private List<DSLTokenizedMappingFile>     dslFiles;
 
     private TimeIntervalParser                timeParser;
-    
-    protected DateFormats                     dateFormats;    
 
+    protected DateFormats                     dateFormats;
+
     /**
      * Use this when package is starting from scratch.
      */
@@ -182,14 +182,15 @@
         } else {
             this.configuration = configuration;
         }
-        
+
         this.dateFormats = null;//(DateFormats) this.environment.get( EnvironmentName.DATE_FORMATS );
         if ( this.dateFormats == null ) {
             this.dateFormats = new DateFormatsImpl();
             //this.environment.set( EnvironmentName.DATE_FORMATS , this.dateFormats );
-        }        
+        }
 
-        this.rootClassLoader = new DroolsCompositeClassLoader( this.configuration.getClassLoader() );
+        this.rootClassLoader = new DroolsCompositeClassLoader( this.configuration.getClassLoader(),
+                                                               this.configuration.isClassLoaderCacheEnabled() );
 
         this.defaultDialect = this.configuration.getDefaultDialect();
 
@@ -216,14 +217,15 @@
         if ( ruleBase != null ) {
             this.rootClassLoader = ((InternalRuleBase) ruleBase).getRootClassLoader();
         } else {
-            this.rootClassLoader = new DroolsCompositeClassLoader( this.configuration.getClassLoader() );
+            this.rootClassLoader = new DroolsCompositeClassLoader( this.configuration.getClassLoader(),
+                                                                   this.configuration.isClassLoaderCacheEnabled() );
         }
-        
+
         this.dateFormats = null;//(DateFormats) this.environment.get( EnvironmentName.DATE_FORMATS );
         if ( this.dateFormats == null ) {
             this.dateFormats = new DateFormatsImpl();
             //this.environment.set( EnvironmentName.DATE_FORMATS , this.dateFormats );
-        }                
+        }
 
         // FIXME, we need to get drools to support "default" namespace.
         //this.defaultNamespace = pkg.getName();        
@@ -341,9 +343,9 @@
         DefaultExpander expander = getDslExpander();
 
         try {
-        	if (expander == null) {
-        		expander = new DefaultExpander();
-        	}
+            if ( expander == null ) {
+                expander = new DefaultExpander();
+            }
             String str = expander.expand( resource.getReader() );
             if ( expander.hasErrors() ) {
                 this.results.addAll( expander.getErrors() );
@@ -371,15 +373,15 @@
         DefaultExpander expander = getDslExpander();
 
         try {
-        	String str;
-        	if (expander != null) {
-        		str = expander.expand( new StringReader( drl ) );
+            String str;
+            if ( expander != null ) {
+                str = expander.expand( new StringReader( drl ) );
                 if ( expander.hasErrors() ) {
                     this.results.addAll( expander.getErrors() );
                 }
-        	} else {
-        		str = drl;
-        	}
+            } else {
+                str = drl;
+            }
 
             final PackageDescr pkg = parser.parse( str );
             this.results.addAll( parser.getErrors() );
@@ -487,7 +489,7 @@
                 addProcessFromXml( resource );
             } else if ( ResourceType.BPMN2.equals( type ) ) {
                 ((InternalResource) resource).setResourceType( type );
-                BPMN2ProcessFactory.configurePackageBuilder(this);
+                BPMN2ProcessFactory.configurePackageBuilder( this );
                 addProcessFromXml( resource );
             } else if ( ResourceType.DTABLE.equals( type ) ) {
                 ((InternalResource) resource).setResourceType( type );
@@ -498,16 +500,19 @@
                 addPackageFromDrl( new StringReader( string ) );
             } else if ( ResourceType.PKG.equals( type ) ) {
                 InputStream is = resource.getInputStream();
-                Package pkg = (Package) DroolsStreamUtils.streamIn( is, this.configuration.getClassLoader() );
+                Package pkg = (Package) DroolsStreamUtils.streamIn( is,
+                                                                    this.configuration.getClassLoader() );
                 is.close();
                 addPackage( pkg );
             } else if ( ResourceType.CHANGE_SET.equals( type ) ) {
                 ((InternalResource) resource).setResourceType( type );
                 XmlChangeSetReader reader = new XmlChangeSetReader( this.configuration.getSemanticModules() );
                 if ( resource instanceof ClassPathResource ) {
-                    reader.setClassLoader( ((ClassPathResource) resource).getClassLoader(),  ((ClassPathResource) resource).getClazz() );
+                    reader.setClassLoader( ((ClassPathResource) resource).getClassLoader(),
+                                           ((ClassPathResource) resource).getClazz() );
                 } else {
-                    reader.setClassLoader( this.configuration.getClassLoader() , null);
+                    reader.setClassLoader( this.configuration.getClassLoader(),
+                                           null );
                 }
                 ChangeSet changeSet = reader.read( resource.getReader() );
                 if ( changeSet == null ) {
@@ -1230,10 +1235,10 @@
     public Map<String, PackageRegistry> getPackageRegistry() {
         return this.pkgRegistryMap;
     }
-    
+
     public DateFormats getDateFormats() {
         return this.dateFormats;
-    }    
+    }
 
     /**
      * Returns an expander for DSLs (only if there is a DSL configured for this package).

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilderConfiguration.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilderConfiguration.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilderConfiguration.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -30,6 +30,7 @@
 import org.drools.base.evaluators.EvaluatorRegistry;
 import org.drools.builder.KnowledgeBuilderConfiguration;
 import org.drools.builder.conf.AccumulateFunctionOption;
+import org.drools.builder.conf.ClassLoaderCacheOption;
 import org.drools.builder.conf.DefaultDialectOption;
 import org.drools.builder.conf.DefaultPackageNameOption;
 import org.drools.builder.conf.DumpDirOption;
@@ -71,6 +72,7 @@
  * drools.accumulate.function.<function name> = <qualified class>
  * drools.evaluator.<ident> = <qualified class>
  * drools.dump.dir = <String>
+ * drools.classLoaderCacheEnabled = true|false
  *
  * default dialect is java.
  * Available preconfigured Accumulate functions are:
@@ -88,28 +90,30 @@
 
     private Map<String, DialectConfiguration> dialectConfigurations;
 
-    private DefaultDialectOption            defaultDialect;
+    private DefaultDialectOption              defaultDialect;
 
-    private ClassLoader                     classLoader;
+    private CompositeClassLoader              classLoader;
 
-    private ChainedProperties               chainedProperties;
+    private ChainedProperties                 chainedProperties;
 
-    private Map<String, AccumulateFunction> accumulateFunctions;
+    private Map<String, AccumulateFunction>   accumulateFunctions;
 
-    private EvaluatorRegistry               evaluatorRegistry;
+    private EvaluatorRegistry                 evaluatorRegistry;
 
-    private SemanticModules                 semanticModules;
+    private SemanticModules                   semanticModules;
 
-    private ProcessNodeBuilderRegistry      nodeBuilderRegistry;
+    private ProcessNodeBuilderRegistry        nodeBuilderRegistry;
 
-    private File                            dumpDirectory;
+    private File                              dumpDirectory;
 
-    private boolean                         allowMultipleNamespaces              = true;
+    private boolean                           allowMultipleNamespaces = true;
 
-    private boolean                         processStringEscapes                 = true;
+    private boolean                           processStringEscapes    = true;
 
-    private String                          defaultPackageName;
+    private boolean                           classLoaderCache        = true;
 
+    private String                            defaultPackageName;
+
     public boolean isAllowMultipleNamespaces() {
         return allowMultipleNamespaces;
     }
@@ -162,12 +166,16 @@
 
         this.chainedProperties = new ChainedProperties( "packagebuilder.conf",
                                                         this.classLoader,
-                                                        true);
+                                                        true );
 
         if ( properties != null ) {
             this.chainedProperties.addProperties( properties );
         }
 
+        setProperty( ClassLoaderCacheOption.PROPERTY_NAME,
+                     this.chainedProperties.getProperty( ClassLoaderCacheOption.PROPERTY_NAME,
+                                                         "true" ) );
+
         this.dialectConfigurations = new HashMap<String, DialectConfiguration>();
 
         buildDialectConfigurationMap();
@@ -181,7 +189,7 @@
         setProperty( ProcessStringEscapesOption.PROPERTY_NAME,
                      this.chainedProperties.getProperty( ProcessStringEscapesOption.PROPERTY_NAME,
                                                          "true" ) );
-        
+
         setProperty( DefaultPackageNameOption.PROPERTY_NAME,
                      this.chainedProperties.getProperty( DefaultPackageNameOption.PROPERTY_NAME,
                                                          "defaultpkg" ) );
@@ -207,6 +215,8 @@
             setDefaultPackageName( value );
         } else if ( name.equals( ProcessStringEscapesOption.PROPERTY_NAME ) ) {
             setProcessStringEscapes( Boolean.parseBoolean( value ) );
+        } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) {
+            setClassLoaderCacheEnabled( Boolean.parseBoolean( value ) );
         }
     }
 
@@ -225,13 +235,15 @@
             AccumulateFunction function = this.accumulateFunctions.get( name.substring( index ) );
             return function != null ? function.getClass().getName() : null;
         } else if ( name.startsWith( EvaluatorOption.PROPERTY_NAME ) ) {
-            String key = name.substring( name.lastIndexOf( '.' )+1 );
-            EvaluatorDefinition evalDef = this.evaluatorRegistry.getEvaluatorDefinition( key ); 
+            String key = name.substring( name.lastIndexOf( '.' ) + 1 );
+            EvaluatorDefinition evalDef = this.evaluatorRegistry.getEvaluatorDefinition( key );
             return evalDef != null ? evalDef.getClass().getName() : null;
         } else if ( name.equals( DumpDirOption.PROPERTY_NAME ) ) {
             return this.dumpDirectory != null ? this.dumpDirectory.toString() : null;
         } else if ( name.equals( ProcessStringEscapesOption.PROPERTY_NAME ) ) {
             return String.valueOf( isProcessStringEscapes() );
+        } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) {
+            return String.valueOf( isClassLoaderCacheEnabled() );
         }
         return null;
     }
@@ -318,7 +330,9 @@
 
     /** Use this to override the classLoader that will be used for the rules. */
     public void setClassLoader(final ClassLoader classLoader) {
-        this.classLoader =  ClassLoaderUtil.getClassLoader( classLoader, getClass() );
+        this.classLoader = ClassLoaderUtil.getClassLoader( classLoader,
+                                                           getClass(),
+                                                           isClassLoaderCacheEnabled() );
     }
 
     public void addSemanticModule(SemanticModule module) {
@@ -616,11 +630,20 @@
     public void setProcessStringEscapes(boolean processStringEscapes) {
         this.processStringEscapes = processStringEscapes;
     }
-    
+
+    public boolean isClassLoaderCacheEnabled() {
+        return classLoaderCache;
+    }
+
+    public void setClassLoaderCacheEnabled(boolean classLoaderCacheEnabled) {
+        this.classLoaderCache = classLoaderCacheEnabled;
+        this.classLoader.setCachingEnabled( this.classLoaderCache );
+    }
+
     public String getDefaultPackageName() {
         return defaultPackageName;
     }
-    
+
     public void setDefaultPackageName(String defaultPackageName) {
         this.defaultPackageName = defaultPackageName;
     }
@@ -632,16 +655,18 @@
         } else if ( DumpDirOption.class.equals( option ) ) {
             return (T) DumpDirOption.get( this.dumpDirectory );
         } else if ( ProcessStringEscapesOption.class.equals( option ) ) {
-            return (T) ( this.processStringEscapes ? ProcessStringEscapesOption.YES : ProcessStringEscapesOption.NO ); 
+            return (T) (this.processStringEscapes ? ProcessStringEscapesOption.YES : ProcessStringEscapesOption.NO);
         } else if ( DefaultPackageNameOption.class.equals( option ) ) {
             return (T) DefaultPackageNameOption.get( this.defaultPackageName );
+        } else if ( ClassLoaderCacheOption.class.equals( option ) ) {
+            return (T) (this.classLoaderCache ? ClassLoaderCacheOption.ENABLED : ClassLoaderCacheOption.DISABLED);
         }
         return null;
     }
 
     @SuppressWarnings("unchecked")
     public <T extends MultiValueKnowledgeBuilderOption> T getOption(Class<T> option,
-                                          String key) {
+                                                                    String key) {
         if ( AccumulateFunctionOption.class.equals( option ) ) {
             return (T) AccumulateFunctionOption.get( key,
                                                      this.accumulateFunctions.get( key ) );
@@ -666,7 +691,8 @@
             this.processStringEscapes = ((ProcessStringEscapesOption) option).isProcessStringEscapes();
         } else if ( option instanceof DefaultPackageNameOption ) {
             setDefaultPackageName( ((DefaultPackageNameOption) option).getPackageName() );
+        } else if ( option instanceof ClassLoaderCacheOption ) {
+            setClassLoaderCacheEnabled( ((ClassLoaderCacheOption) option).isClassLoaderCacheEnabled() );
         }
     }
-
 }
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -1088,7 +1088,8 @@
         assertFalse( builder.hasErrors() );
 
         Package bp = builder.getPackage();
-        DroolsCompositeClassLoader rootClassloader = new DroolsCompositeClassLoader( Thread.currentThread().getContextClassLoader() );
+        DroolsCompositeClassLoader rootClassloader = new DroolsCompositeClassLoader( Thread.currentThread().getContextClassLoader(),
+                                                                                     false );
         JavaDialectRuntimeData dialectData = (JavaDialectRuntimeData) bp.getDialectRuntimeRegistry().getDialectData( "java" );
         dialectData.onAdd( bp.getDialectRuntimeRegistry(),
                            rootClassloader );
@@ -1392,8 +1393,9 @@
         final PackageBuilder builder = new PackageBuilder();
 
         final PackageDescr packageDescr = new PackageDescr( "p1" );
-        final TypeDeclarationDescr typeDeclDescr = new TypeDeclarationDescr(StockTick.class.getName());
-        typeDeclDescr.addMetaAttribute( "role", "event" );
+        final TypeDeclarationDescr typeDeclDescr = new TypeDeclarationDescr( StockTick.class.getName() );
+        typeDeclDescr.addMetaAttribute( "role",
+                                        "event" );
         packageDescr.addTypeDeclaration( typeDeclDescr );
         final RuleDescr ruleDescr = new RuleDescr( "rule-1" );
         packageDescr.addRule( ruleDescr );
@@ -1509,34 +1511,34 @@
         public void setResource(Resource resource) {
         }
 
-		public String[] getGlobalNames() {
-			return null;
-		}
+        public String[] getGlobalNames() {
+            return null;
+        }
 
-		public Map<String, String> getGlobals() {
-			return null;
-		}
+        public Map<String, String> getGlobals() {
+            return null;
+        }
 
-		public List<String> getImports() {
-			return null;
-		}
+        public List<String> getImports() {
+            return null;
+        }
 
-		public void setGlobals(Map<String, String> globals) {
-		}
+        public void setGlobals(Map<String, String> globals) {
+        }
 
-		public void setImports(List<String> imports) {
-		}
+        public void setImports(List<String> imports) {
+        }
 
-		public List<String> getFunctionImports() {
-			// TODO Auto-generated method stub
-			return null;
-		}
+        public List<String> getFunctionImports() {
+            // TODO Auto-generated method stub
+            return null;
+        }
 
-		public void setFunctionImports(List<String> functionImports) {
-			// TODO Auto-generated method stub
-			
-		}
+        public void setFunctionImports(List<String> functionImports) {
+            // TODO Auto-generated method stub
 
+        }
+
     }
 
     class MockActivation

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -92,10 +92,12 @@
 import org.drools.WorkingMemory;
 import org.drools.Cheesery.Maturity;
 import org.drools.builder.KnowledgeBuilder;
+import org.drools.builder.KnowledgeBuilderConfiguration;
 import org.drools.builder.KnowledgeBuilderError;
 import org.drools.builder.KnowledgeBuilderErrors;
 import org.drools.builder.KnowledgeBuilderFactory;
 import org.drools.builder.ResourceType;
+import org.drools.builder.conf.ClassLoaderCacheOption;
 import org.drools.common.AbstractWorkingMemory;
 import org.drools.common.DefaultAgenda;
 import org.drools.common.DefaultFactHandle;
@@ -145,6 +147,7 @@
 import org.drools.runtime.rule.WorkingMemoryEntryPoint;
 import org.drools.spi.ConsequenceExceptionHandler;
 import org.drools.spi.GlobalResolver;
+import org.drools.util.CompositeClassLoader;
 
 /** Run all the tests with the ReteOO engine implementation */
 public class MiscTest extends TestCase {
@@ -6935,7 +6938,22 @@
         session.setGlobal( "list", list );
         session.fireAllRules();   
         assertEquals(1, list.size() );
+    }
+    
+    public void testClassLoaderHits() throws Exception {
+        final KnowledgeBuilderConfiguration conf = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration();
+        //conf.setOption( ClassLoaderCacheOption.DISABLED );
+        final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder( conf );
+        kbuilder.add( ResourceFactory.newInputStreamResource( getClass().getResourceAsStream( "test_GeneratedBeansMVEL.drl" ) ),
+                      ResourceType.DRL );
+        kbuilder.add( ResourceFactory.newInputStreamResource( getClass().getResourceAsStream( "test_GeneratedBeans.drl" ) ),
+                      ResourceType.DRL );
+        kbuilder.add( ResourceFactory.newInputStreamResource( getClass().getResourceAsStream( "test_NullFieldOnCompositeSink.drl" ) ),
+                      ResourceType.DRL );
+        assertFalse( kbuilder.getErrors().toString(),
+                     kbuilder.hasErrors() );
+
+        //((CompositeClassLoader)((PackageBuilderConfiguration)conf).getClassLoader()).dumpStats();
         
     }
-
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/RuleBaseConfiguration.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/RuleBaseConfiguration.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/RuleBaseConfiguration.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -28,6 +28,7 @@
 import java.util.Set;
 import java.util.Map.Entry;
 
+import org.drools.builder.conf.ClassLoaderCacheOption;
 import org.drools.common.AgendaGroupFactory;
 import org.drools.common.ArrayAgendaGroupFactory;
 import org.drools.common.PriorityQueueAgendaGroupFactory;
@@ -115,6 +116,7 @@
  * drools.maxThreads = &lt;-1|1..n&gt;
  * drools.multithreadEvaluation = &lt;true|false&gt;
  * drools.mbeans = &lt;enabled|disabled&gt;
+ * drools.classLoaderCacheEnabled = &lt;true|false&gt; 
  * </pre>
  */
 public class RuleBaseConfiguration
@@ -143,6 +145,7 @@
     private String                         executorService;
     private String                         consequenceExceptionHandler;
     private String                         ruleBaseUpdateHandler;
+    private boolean                        classLoaderCacheEnabled;
 
     private EventProcessingOption          eventProcessingMode;
 
@@ -164,7 +167,7 @@
     private ProcessInstanceFactoryRegistry processInstanceFactoryRegistry;
     private NodeInstanceFactoryRegistry    processNodeInstanceFactoryRegistry;
 
-    private transient ClassLoader          classLoader;
+    private transient CompositeClassLoader classLoader;
 
     public void writeExternal(ObjectOutput out) throws IOException {
         out.writeObject( chainedProperties );
@@ -190,6 +193,7 @@
         out.writeBoolean( multithread );
         out.writeInt( maxThreads );
         out.writeObject( eventProcessingMode );
+        out.writeBoolean( classLoaderCacheEnabled );
     }
 
     public void readExternal(ObjectInput in) throws IOException,
@@ -217,6 +221,7 @@
         multithread = in.readBoolean();
         maxThreads = in.readInt();
         eventProcessingMode = (EventProcessingOption) in.readObject();
+        classLoaderCacheEnabled = in.readBoolean();
     }
 
     /**
@@ -307,6 +312,8 @@
             setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( StringUtils.isEmpty( value ) ? "cloud" : value ) );
         } else if ( name.equals( MBeansOption.PROPERTY_NAME ) ) {
             setMBeansEnabled( MBeansOption.isEnabled( value ) );
+        } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) {
+            setClassLoaderCacheEnabled( StringUtils.isEmpty( value ) ? true : Boolean.valueOf( value ) );
         }
     }
 
@@ -358,6 +365,8 @@
             return getEventProcessingMode().getMode();
         } else if ( name.equals( MBeansOption.PROPERTY_NAME ) ) {
             return isMBeansEnabled() ? "enabled" : "disabled";
+        } else if ( name.equals( ClassLoaderCacheOption.PROPERTY_NAME ) ) {
+            return Boolean.toString( isClassLoaderCacheEnabled() );
         }
 
         return null;
@@ -383,7 +392,9 @@
 
         setClassLoader( classLoader );
 
-        this.chainedProperties = new ChainedProperties( "rulebase.conf", this.classLoader, true );
+        this.chainedProperties = new ChainedProperties( "rulebase.conf",
+                                                        this.classLoader,
+                                                        true );
 
         if ( properties != null ) {
             this.chainedProperties.addProperties( properties );
@@ -443,12 +454,15 @@
 
         setMaxThreads( Integer.parseInt( this.chainedProperties.getProperty( MaxThreadsOption.PROPERTY_NAME,
                                                                              "3" ) ) );
-        
+
         setEventProcessingMode( EventProcessingOption.determineEventProcessingMode( this.chainedProperties.getProperty( EventProcessingOption.PROPERTY_NAME,
                                                                                                                         "cloud" ) ) );
-        
+
         setMBeansEnabled( MBeansOption.isEnabled( this.chainedProperties.getProperty( MBeansOption.PROPERTY_NAME,
                                                                                       "disabled" ) ) );
+
+        setClassLoaderCacheEnabled( Boolean.valueOf( this.chainedProperties.getProperty( ClassLoaderCacheOption.PROPERTY_NAME,
+                                                                                         "true" ) ) );
     }
 
     /**
@@ -690,6 +704,16 @@
         return this.maxThreads;
     }
 
+    public boolean isClassLoaderCacheEnabled() {
+        return this.classLoaderCacheEnabled;
+    }
+
+    public void setClassLoaderCacheEnabled(final boolean classLoaderCacheEnabled) {
+        checkCanChange(); // throws an exception if a change isn't possible;
+        this.classLoaderCacheEnabled = classLoaderCacheEnabled;
+        this.classLoader.setCachingEnabled( this.classLoaderCacheEnabled );
+    }
+
     private void initProcessNodeInstanceFactoryRegistry() {
         this.processNodeInstanceFactoryRegistry = new NodeInstanceFactoryRegistry();
 
@@ -967,7 +991,9 @@
     }
 
     public void setClassLoader(ClassLoader classLoader) {
-        this.classLoader =  ClassLoaderUtil.getClassLoader( classLoader, getClass() );
+        this.classLoader = ClassLoaderUtil.getClassLoader( classLoader,
+                                                           getClass(),
+                                                           isClassLoaderCacheEnabled() );
     }
 
     /**
@@ -1223,6 +1249,8 @@
             return (T) (this.multithread ? MultithreadEvaluationOption.YES : MultithreadEvaluationOption.NO);
         } else if ( MBeansOption.class.equals( option ) ) {
             return (T) (this.isMBeansEnabled() ? MBeansOption.ENABLED : MBeansOption.DISABLED);
+        } else if ( ClassLoaderCacheOption.class.equals( option ) ) {
+            return (T) (this.isClassLoaderCacheEnabled() ? ClassLoaderCacheOption.ENABLED : ClassLoaderCacheOption.DISABLED);
         }
         return null;
 
@@ -1263,6 +1291,8 @@
             setMultithreadEvaluation( ((MultithreadEvaluationOption) option).isMultithreadEvaluation() );
         } else if ( option instanceof MBeansOption ) {
             setMBeansEnabled( ((MBeansOption) option).isEnabled() );
+        } else if ( option instanceof ClassLoaderCacheOption ) {
+            setClassLoaderCacheEnabled( ((ClassLoaderCacheOption) option).isClassLoaderCacheEnabled() );
         }
 
     }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/SessionConfiguration.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/SessionConfiguration.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/SessionConfiguration.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -118,7 +118,9 @@
     }
 
     private void init(ClassLoader classLoader, Properties properties) {
-    	this.classLoader =  ClassLoaderUtil.getClassLoader( classLoader, getClass() );
+    	this.classLoader =  ClassLoaderUtil.getClassLoader( classLoader, 
+    	                                                    getClass(),
+    	                                                    false );
     	
         this.immutable = false;
         this.chainedProperties = new ChainedProperties( "session.conf",  this.classLoader );

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -32,7 +32,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -50,8 +49,8 @@
 import org.drools.impl.EnvironmentFactory;
 import org.drools.management.DroolsManagementAgent;
 import org.drools.process.core.Process;
+import org.drools.rule.DialectRuntimeRegistry;
 import org.drools.rule.DroolsCompositeClassLoader;
-import org.drools.rule.DialectRuntimeRegistry;
 import org.drools.rule.Function;
 import org.drools.rule.ImportDeclaration;
 import org.drools.rule.InvalidPatternException;
@@ -59,7 +58,6 @@
 import org.drools.rule.Rule;
 import org.drools.rule.TypeDeclaration;
 import org.drools.spi.FactHandleFactory;
-import org.drools.time.Calendar;
 
 /**
  * Implementation of <code>RuleBase</code>.
@@ -87,14 +85,14 @@
 
     private Map                                        agendaGroupRuleTotals;
 
-    private transient DroolsCompositeClassLoader             rootClassLoader;
+    private transient DroolsCompositeClassLoader       rootClassLoader;
 
     /**
      * The fact handle factory.
      */
     private FactHandleFactory                          factHandleFactory;
 
-    private transient Map<String, Class< ? >>          globals;   
+    private transient Map<String, Class< ? >>          globals;
 
     private ReloadPackageCompilationData               reloadPackageCompilationData = null;
 
@@ -153,7 +151,8 @@
             this.agendaGroupRuleTotals = new HashMap();
         }
 
-        this.rootClassLoader = new DroolsCompositeClassLoader( this.config.getClassLoader() );
+        this.rootClassLoader = new DroolsCompositeClassLoader( this.config.getClassLoader(),
+                                                               this.config.isClassLoaderCacheEnabled() );
         this.pkgs = new HashMap<String, Package>();
         this.processes = new HashMap();
         this.globals = new HashMap<String, Class< ? >>();
@@ -199,6 +198,9 @@
             droolsStream = new DroolsObjectOutputStream( bytes );
         }
 
+        // must write this option first in order to properly deserialize later
+        droolsStream.writeBoolean( this.config.isClassLoaderCacheEnabled() );
+        
         droolsStream.writeObject( this.config );
         droolsStream.writeObject( this.pkgs );
 
@@ -250,7 +252,8 @@
             droolsStream = new DroolsObjectInputStream( bytes );
         }
 
-        this.rootClassLoader = new DroolsCompositeClassLoader( droolsStream.getParentClassLoader() );
+        boolean classLoaderCacheEnabled = droolsStream.readBoolean();
+        this.rootClassLoader = new DroolsCompositeClassLoader( droolsStream.getParentClassLoader(), classLoaderCacheEnabled );
         droolsStream.setClassLoader( this.rootClassLoader );
         droolsStream.setRuleBase( this );
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ClassPathResource.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ClassPathResource.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ClassPathResource.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -9,15 +9,12 @@
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.Reader;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
-import org.drools.core.util.ClassUtils;
 import org.drools.core.util.StringUtils;
 import org.drools.io.Resource;
 import org.drools.io.internal.InternalResource;
@@ -29,16 +26,17 @@
  *+
  */
 
-public class ClassPathResource extends BaseResource 
+public class ClassPathResource extends BaseResource
     implements
-    InternalResource, Externalizable  {
+    InternalResource,
+    Externalizable {
     private String      path;
     private ClassLoader classLoader;
-    private Class       clazz;
+    private Class< ? >  clazz;
     private long        lastRead;
-    
+
     public ClassPathResource() {
-        
+
     }
 
     public ClassPathResource(String path) {
@@ -48,7 +46,7 @@
     }
 
     public ClassPathResource(String path,
-                             Class clazz) {
+                             Class<?> clazz) {
         this( path,
               clazz,
               null );
@@ -62,16 +60,18 @@
     }
 
     public ClassPathResource(String path,
-                             Class clazz,
+                             Class<?> clazz,
                              ClassLoader classLoader) {
         if ( path == null ) {
             throw new IllegalArgumentException( "path cannot be null" );
         }
         this.path = path;
         this.clazz = clazz;
-        this.classLoader =  ClassLoaderUtil.getClassLoader( classLoader, clazz );        
+        this.classLoader = ClassLoaderUtil.getClassLoader( classLoader,
+                                                           clazz,
+                                                           false );
     }
-    
+
     public void writeExternal(ObjectOutput out) throws IOException {
         out.writeObject( this.path );
     }
@@ -79,7 +79,7 @@
     public void readExternal(ObjectInput in) throws IOException,
                                             ClassNotFoundException {
         this.path = (String) in.readObject();
-    }    
+    }
 
     /**
      * This implementation opens an InputStream for the given class path resource.
@@ -90,8 +90,8 @@
         InputStream is = null;
         if ( this.clazz != null ) {
             is = this.clazz.getResourceAsStream( this.path );
-        } 
-        
+        }
+
         if ( is == null ) {
             is = this.classLoader.getResourceAsStream( this.path );
         }
@@ -112,8 +112,8 @@
         URL url = null;
         if ( this.clazz != null ) {
             url = this.clazz.getResource( this.path );
-        } 
-        
+        }
+
         if ( url == null ) {
             url = this.classLoader.getResource( this.path );
         }
@@ -146,7 +146,7 @@
     public Reader getReader() throws IOException {
         return new InputStreamReader( getInputStream() );
     }
-    
+
     public boolean isDirectory() {
         try {
             URL url = getURL();
@@ -156,7 +156,7 @@
             }
 
             File file = new File( StringUtils.toURI( url.toString() ).getSchemeSpecificPart() );
-            
+
             return file.isDirectory();
         } catch ( Exception e ) {
             return false;
@@ -167,32 +167,32 @@
         try {
             URL url = getURL();
 
-            if ( "file".equals( url.getProtocol() ) ) {                            
+            if ( "file".equals( url.getProtocol() ) ) {
                 File dir = new File( StringUtils.toURI( url.toString() ).getSchemeSpecificPart() );
-                
+
                 List<Resource> resources = new ArrayList<Resource>();
-                
+
                 for ( File file : dir.listFiles() ) {
                     resources.add( new FileSystemResource( file ) );
                 }
-                
+
                 return resources;
             }
         } catch ( Exception e ) {
             // swollow as we'll throw an exception anyway            
         }
-        
+
         throw new RuntimeException( "This Resource cannot be listed, or is not a directory" );
-    }    
+    }
 
     public ClassLoader getClassLoader() {
         return this.classLoader;
     }
-    
-    public Class getClazz() {
+
+    public Class<?> getClazz() {
         return this.clazz;
     }
-    
+
     public boolean equals(Object object) {
         if ( object == null || !(object instanceof ClassPathResource) ) {
             return false;
@@ -214,5 +214,4 @@
         return "[ClassPathResource path='" + this.path + "']";
     }
 
-
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/DroolsCompositeClassLoader.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/DroolsCompositeClassLoader.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/DroolsCompositeClassLoader.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -12,17 +12,15 @@
 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 boolean hasParent = false;
-    
-    public DroolsCompositeClassLoader(final ClassLoader parentClassLoader) {
+    private final boolean           hasParent;
+
+    public DroolsCompositeClassLoader(final ClassLoader parentClassLoader,
+                                      final boolean cacheParentCalls) {
         super( parentClassLoader );
-        if ( parentClassLoader != null ) {
-            this.hasParent = true;
-        }
+        this.hasParent = parentClassLoader != null;
     }
 
     public synchronized void addClassLoader(final ClassLoader classLoader) {
@@ -40,7 +38,6 @@
             }
         }
         this.classLoaders.add( classLoader );
-
     }
 
     public synchronized void removeClassLoader(final ClassLoader classLoader) {
@@ -53,9 +50,9 @@
     /**
      * Search the list of child ClassLoaders
      */
-    public Class<?> fastFindClass(final String name) {
+    public Class< ? > fastFindClass(final String name) {
         for ( final ClassLoader classLoader : this.classLoaders ) {
-            final Class<?> cls = ((DroolsClassLoader) classLoader).fastFindClass( name );
+            final Class< ? > cls = ((DroolsClassLoader) classLoader).fastFindClass( name );
             if ( cls != null ) {
                 return cls;
             }
@@ -66,18 +63,19 @@
     /**
      * 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 {
+     */
+    public Class< ? > loadClass(final String name,
+                                final boolean resolve) throws ClassNotFoundException {
         // search the child ClassLoaders
-        Class<?> cls = fastFindClass( name );
-        
+        Class< ? > cls;
+        cls = fastFindClass( name );
+
         // still not found so search the parent ClassLoader
         if ( this.hasParent && cls == null ) {
             cls = Class.forName( name,
-                           true,
-                           getParent() );
-        }        
+                                 true,
+                                 getParent() );
+        }
 
         if ( resolve ) {
             resolveClass( cls );
@@ -89,30 +87,29 @@
     /**
      * 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) {        
+     */
+    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 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 );
-        
+     */
+    protected Class< ? > findClass(final String name) throws ClassNotFoundException {
+        final Class< ? > cls = fastFindClass( name );
+
         if ( cls == null ) {
             throw new ClassNotFoundException( name );
         }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectRuntimeData.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectRuntimeData.java	2010-04-08 20:43:23 UTC (rev 32482)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectRuntimeData.java	2010-04-09 03:08:57 UTC (rev 32483)
@@ -47,23 +47,23 @@
     /**
      *
      */
-    private static final long              serialVersionUID = 400L;
+    private static final long                    serialVersionUID = 400L;
 
-    private static final ProtectionDomain  PROTECTION_DOMAIN;
+    private static final ProtectionDomain        PROTECTION_DOMAIN;
 
-    private Map                            invokerLookups;
+    private Map                                  invokerLookups;
 
-    private Map                            store;
+    private Map                                  store;
 
-    private DialectRuntimeRegistry         registry;
+    private DialectRuntimeRegistry               registry;
 
-    private transient PackageClassLoader   classLoader;
+    private transient PackageClassLoader         classLoader;
 
     private transient DroolsCompositeClassLoader rootClassLoader;
 
-    private boolean                        dirty;
+    private boolean                              dirty;
 
-    private List<String>                   wireList         = Collections.<String> emptyList();
+    private List<String>                         wireList         = Collections.<String> emptyList();
 
     static {
         PROTECTION_DOMAIN = (ProtectionDomain) AccessController.doPrivileged( new PrivilegedAction() {
@@ -129,7 +129,7 @@
                                                    this.rootClassLoader );
         this.rootClassLoader.addClassLoader( this.classLoader );
     }
-    
+
     public void onRemove() {
         this.rootClassLoader.removeClassLoader( this.classLoader );
     }
@@ -222,7 +222,7 @@
             removeClasses( rule.getLhs() );
 
             // Now remove the rule class - the name is a subset of the consequence name
-            String sufix = StringUtils.ucFirst( rule.getConsequence().getName() )+"ConsequenceInvoker";
+            String sufix = StringUtils.ucFirst( rule.getConsequence().getName() ) + "ConsequenceInvoker";
             remove( consequenceName.substring( 0,
                                                consequenceName.indexOf( sufix ) ) );
         }
@@ -296,7 +296,7 @@
                                             IllegalAccessException {
         final Object invoker = getInvokers().get( className );
         if ( invoker != null ) {
-            wire( className,        
+            wire( className,
                   invoker );
         }
     }
@@ -383,8 +383,8 @@
             throw new RuntimeDroolsException( e );
         } catch ( final InstantiationException e ) {
             throw new RuntimeDroolsException( e );
-        } 
-        
+        }
+
         this.dirty = false;
     }
 
@@ -424,8 +424,13 @@
         implements
         DroolsClassLoader {
         private JavaDialectRuntimeData store;
-        DroolsCompositeClassLoader           rootClassLoader;
+        DroolsCompositeClassLoader     rootClassLoader;
 
+        private Map<String, Object>    cache           = new HashMap<String, Object>();
+        private long                   successfulCalls = 0;
+        private long                   failedCalls     = 0;
+        private long                   cacheHits       = 0;
+
         public PackageClassLoader(JavaDialectRuntimeData store,
                                   DroolsCompositeClassLoader rootClassLoader) {
             super( rootClassLoader );
@@ -433,16 +438,24 @@
             this.store = store;
         }
 
-        public Class<?> fastFindClass(final String name) {
-            Class<?> cls = findLoadedClass( name );
+        public Class< ? > fastFindClass(final String name) {
+            Class< ? > cls = findLoadedClass( name );
 
             if ( cls == null ) {
                 final byte[] clazzBytes = this.store.read( convertClassToResourcePath( name ) );
                 if ( clazzBytes != null ) {
-                	String pkgName = name.substring(0, name.lastIndexOf('.'));
-                	if (getPackage(pkgName) == null) {
-                		definePackage(pkgName, "", "", "", "", "", "", null);
-                	}
+                    String pkgName = name.substring( 0,
+                                                     name.lastIndexOf( '.' ) );
+                    if ( getPackage( pkgName ) == null ) {
+                        definePackage( pkgName,
+                                       "",
+                                       "",
+                                       "",
+                                       "",
+                                       "",
+                                       "",
+                                       null );
+                    }
                     cls = defineClass( name,
                                        clazzBytes,
                                        0,
@@ -454,27 +467,45 @@
             return cls;
         }
 
-        public Class<?> loadClass(final String name,
-                                            final boolean resolve) throws ClassNotFoundException {
-            Class<?> cls = fastFindClass( name );
-
-            if ( cls == null ) {
-                final ClassLoader parent = getParent();
-                if ( parent != null ) {
-                    cls = Class.forName( name,
-                                         true,
-                                         parent );
+        public Class< ? > loadClass(final String name,
+                                    final boolean resolve) throws ClassNotFoundException {
+            try {
+                if( cache.containsKey( name ) ) {
+                    this.cacheHits++;
+                    Object result = cache.get( name );
+                    if( result instanceof ClassNotFoundException ) {
+                        throw (ClassNotFoundException) result;
+                    } else {
+                        return (Class<?>) result;
+                    }
                 }
+                Class< ? > cls = fastFindClass( name );
+                if ( cls == null ) {
+                    final ClassLoader parent = getParent();
+                    if ( parent != null ) {
+                        cls = Class.forName( name,
+                                             true,
+                                             parent );
+                    }
+                }
+                if ( resolve && cls != null ) {
+                    resolveClass( cls );
+                }
+                if ( cls != null ) {
+                    this.successfulCalls++;
+                } else {
+                    this.failedCalls++;
+                }
+                cache.put( name, cls );
+                return cls;
+            } catch ( ClassNotFoundException e ) {
+                this.failedCalls++;
+                cache.put( name, e );
+                throw e;
             }
-
-            if ( resolve && cls != null ) {
-                resolveClass( cls );
-            }
-
-            return cls;
         }
 
-        protected Class<?> findClass(final String name) throws ClassNotFoundException {
+        protected Class< ? > findClass(final String name) throws ClassNotFoundException {
             return fastFindClass( name );
         }
 
@@ -485,6 +516,16 @@
             }
             return null;
         }
+        
+        public void reset() {
+            this.cacheHits = this.failedCalls = this.successfulCalls = 0;
+            this.cache.clear();
+        }
+
+        public void printStats() {
+            System.out.println( "CacheHits = " + this.cacheHits + "\nSuccessful=" + this.successfulCalls + "\nFailed=" + this.failedCalls + "\n" );
+
+        }
     }
 
     /**



More information about the jboss-svn-commits mailing list