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

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Sat May 24 14:01:51 EDT 2008


Author: tirelli
Date: 2008-05-24 14:01:50 -0400 (Sat, 24 May 2008)
New Revision: 20155

Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java
   labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_GeneratedBeans.drl
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassFieldAccessorFactory.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/ClassDefinition.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/FieldDefinition.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactField.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactType.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectData.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/MapBackedClassLoader.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Package.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/asm/ClassFieldInspector.java
Log:
Fixing type resolution in rule consequences for generated beans

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	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -55,10 +55,7 @@
 import org.drools.lang.descr.TypeDeclarationDescr;
 import org.drools.lang.descr.TypeFieldDescr;
 import org.drools.process.core.Process;
-import org.drools.rule.CompositePackageClassLoader;
 import org.drools.rule.ImportDeclaration;
-import org.drools.rule.JavaDialectData;
-import org.drools.rule.MapBackedClassLoader;
 import org.drools.rule.Package;
 import org.drools.rule.Rule;
 import org.drools.rule.TypeDeclaration;
@@ -98,8 +95,6 @@
 
     private DialectRegistry             dialectRegistry;
 
-	private MapBackedClassLoader generatedBeanClassLoader;
-
     /**
      * Use this when package is starting from scratch.
      */
@@ -555,12 +550,7 @@
     		}
 
 	    	byte[] d = cb.buildClass(def);
-	    	if (this.generatedBeanClassLoader == null) {
-                CompositePackageClassLoader ccl = (CompositePackageClassLoader) this.pkg.getDialectDatas().getClassLoader();
-	    		this.generatedBeanClassLoader = new MapBackedClassLoader(this.configuration.getClassLoader());
-	    		ccl.addClassLoader(this.generatedBeanClassLoader);
-	    	}
-	    	this.generatedBeanClassLoader.addClass( fullName, d);
+	    	this.pkg.getPackageScopeClassLoader().addClass( fullName, d);
 	    	type.setTypeClassDef( def );
     	} catch (Exception e) {
     	    e.printStackTrace();

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	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.ObjectInput;
@@ -24,6 +25,8 @@
 import java.io.StringReader;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.net.URL;
+import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -518,7 +521,9 @@
     }
 
     public void testGeneratedBeans1() throws Exception {
-        final PackageBuilder builder = new PackageBuilder();
+        final PackageBuilderConfiguration pbconf = new PackageBuilderConfiguration();
+        pbconf.setDumpDir( new File("target") );
+        final PackageBuilder builder = new PackageBuilder(pbconf);
         builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_GeneratedBeans.drl" ) ) );
         assertFalse( builder.getErrors().toString(),
                      builder.hasErrors() );
@@ -534,6 +539,9 @@
         RuleBase ruleBase = RuleBaseFactory.newRuleBase( conf );
         ruleBase.addPackage( p );
 
+        // test rulebase serialization
+        ruleBase    = SerializationHelper.serializeObject(ruleBase);
+        
         // Retrieve the generated fact type 
         FactType cheeseFact = ruleBase.getFactType( "org.drools.generatedbeans.Cheese" );
 
@@ -599,7 +607,7 @@
         // checking results
         assertEquals( 2,
                       result.size() );
-        assertEquals( "OK",
+        assertEquals( person,
                       result.get( 1 ) );
 
     }
@@ -5305,5 +5313,32 @@
                       list.size() );
 
     }
+    
+    public class SubvertedClassLoader extends URLClassLoader {
 
+        private static final long serialVersionUID = 400L;
+
+        public SubvertedClassLoader(final URL[] urls,
+                                    final ClassLoader parentClassLoader) {
+            super( urls,
+                   parentClassLoader );
+        }
+
+        protected synchronized Class loadClass(String name,
+                                               boolean resolve) throws ClassNotFoundException {
+            // First, check if the class has already been loaded
+            Class c = findLoadedClass( name );
+            if ( c == null ) {
+                try {
+                    c = findClass( name );
+                } catch ( ClassNotFoundException e ) {
+                    c = super.loadClass( name,
+                                         resolve );
+                }
+            }
+            return c;
+        }
+    }
+    
+
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_GeneratedBeans.drl
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_GeneratedBeans.drl	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_GeneratedBeans.drl	2008-05-24 18:01:50 UTC (rev 20155)
@@ -23,5 +23,5 @@
         $cheese : Cheese( type == "stilton" )
      	$person : Person( age== 7, likes == $cheese )
     then
-    	list.add( "OK" );
+    	list.add( $person );
 end
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassFieldAccessorFactory.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassFieldAccessorFactory.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassFieldAccessorFactory.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -139,6 +139,7 @@
         } catch ( final RuntimeDroolsException e ) {
             throw e;
         } catch ( final Exception e ) {
+            e.printStackTrace();
             throw new RuntimeDroolsException( e );
         }
     }

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	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractRuleBase.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -457,11 +457,12 @@
 
             if ( pkg == null ) {
                 pkg = new Package( newPkg.getName(),
-                                   newPkg.getDialectDatas().getParentClassLoader() );
+                                   newPkg.getPackageScopeClassLoader() );
                 pkgs.put( pkg.getName(),
                           pkg );
                 this.packageClassLoader.addClassLoader( pkg.getDialectDatas().getClassLoader() );
             } else {
+                pkg.getPackageScopeClassLoader().getStore().putAll( newPkg.getPackageScopeClassLoader().getStore() );
                 this.packageClassLoader.addClassLoader( newPkg.getDialectDatas().getClassLoader() );
             }
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/ClassDefinition.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/ClassDefinition.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/ClassDefinition.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -18,6 +18,8 @@
 
 import java.beans.IntrospectionException;
 import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -38,7 +40,10 @@
  *
  * @author etirelli
  */
-public class ClassDefinition implements FactType {
+public class ClassDefinition
+    implements
+    FactType {
+
     private String                       className;
     private String                       superClass;
     private String[]                     interfaces;
@@ -46,6 +51,12 @@
 
     private Map<String, FieldDefinition> fields = new LinkedHashMap<String, FieldDefinition>();
 
+    public ClassDefinition() {
+        this( null,
+              null,
+              null );
+    }
+
     public ClassDefinition(String className) {
         this( className,
               null,
@@ -74,6 +85,23 @@
         this.setInterfaces( interfaces );
     }
 
+    public void readExternal(ObjectInput in) throws IOException,
+                                            ClassNotFoundException {
+        this.className = (String) in.readObject();
+        this.superClass = (String) in.readObject();
+        this.interfaces = (String[]) in.readObject();
+        this.definedClass = (Class<?>) in.readObject();
+        this.fields = (Map<String, FieldDefinition>) in.readObject();
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject( this.className );
+        out.writeObject( this.superClass );
+        out.writeObject( this.interfaces );
+        out.writeObject( this.definedClass );
+        out.writeObject( this.fields );
+    }
+
     /**
      * @return Returns the name.
      */
@@ -98,7 +126,7 @@
     /**
      * @param className The class to set.
      */
-    public void setDefinedClass(final Class< ? > definedClass)  {
+    public void setDefinedClass(final Class< ? > definedClass) {
 
         this.definedClass = definedClass;
     }
@@ -156,9 +184,14 @@
         ClassFieldAccessorCache cache = ClassFieldAccessorCache.getInstance();
 
         for ( FieldDefinition attrDef : this.fields.values() ) {
-            ClassFieldReader reader = cache.getReader( this.getDefinedClass(), attrDef.getName(), this.getClass().getClassLoader() );
-            ClassFieldWriter writer = cache.getWriter( this.getDefinedClass(), attrDef.getName(), this.getClass().getClassLoader() );
-            ClassFieldAccessor accessor = new ClassFieldAccessor( reader, writer );
+            ClassFieldReader reader = cache.getReader( this.getDefinedClass(),
+                                                       attrDef.getName(),
+                                                       this.getClass().getClassLoader() );
+            ClassFieldWriter writer = cache.getWriter( this.getDefinedClass(),
+                                                       attrDef.getName(),
+                                                       this.getClass().getClassLoader() );
+            ClassFieldAccessor accessor = new ClassFieldAccessor( reader,
+                                                                  writer );
             attrDef.setFieldAccessor( accessor );
         }
     }
@@ -195,7 +228,8 @@
         return getClassName();
     }
 
-    public Object newInstance() throws InstantiationException, IllegalAccessException {
+    public Object newInstance() throws InstantiationException,
+                               IllegalAccessException {
         return this.definedClass.newInstance();
     }
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/FieldDefinition.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/FieldDefinition.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/factmodel/FieldDefinition.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -16,6 +16,9 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
 import java.lang.reflect.InvocationTargetException;
 
 import org.drools.base.ClassFieldAccessor;
@@ -26,13 +29,18 @@
  *
  * @author etirelli
  */
-public class FieldDefinition implements FactField {
-    private String             name         = null;
-    private String             type         = null;
-    private boolean            key          = false;
+public class FieldDefinition
+    implements
+    FactField {
+    private String             name     = null;
+    private String             type     = null;
+    private boolean            key      = false;
 
-    private ClassFieldAccessor accessor     = null;
+    private ClassFieldAccessor accessor = null;
 
+    public FieldDefinition() {
+    }
+    
     /**
      * Default constructor
      * 
@@ -60,6 +68,21 @@
         this.key = key;
     }
 
+    public void readExternal(ObjectInput in) throws IOException,
+                                            ClassNotFoundException {
+        this.name = (String) in.readObject();
+        this.type = (String) in.readObject();
+        this.key = in.readBoolean();
+        this.accessor = (ClassFieldAccessor) in.readObject();
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject( this.name );
+        out.writeObject( this.type );
+        out.writeBoolean( this.key );
+        out.writeObject( this.accessor );
+    }
+
     /**
      * @return Returns the name.
      */

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactField.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactField.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactField.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -25,14 +25,16 @@
  * 
  * @author etirelli
  */
-public interface FactField {
-    
-    public Class<?> getType();
-    
+public interface FactField
+    extends
+    java.io.Externalizable {
+
+    public Class< ? > getType();
+
     public String getName();
-    
+
     public boolean isKey();
 
     public FieldAccessor getFieldAccessor();
-    
+
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactType.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/FactType.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -25,15 +25,18 @@
  * 
  * @author etirelli
  */
-public interface FactType {
-    
+public interface FactType
+    extends
+    java.io.Externalizable {
+
     public String getName();
-    
+
     public List<FactField> getFields();
-    
-    public FactField getField( String name );
-    
-    public Class<?> getFactClass();
 
-    public Object newInstance() throws InstantiationException, IllegalAccessException;
+    public FactField getField(String name);
+
+    public Class< ? > getFactClass();
+
+    public Object newInstance() throws InstantiationException,
+                               IllegalAccessException;
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectData.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectData.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/JavaDialectData.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -320,7 +320,7 @@
                      final Object invoker) throws ClassNotFoundException,
                                           InstantiationException,
                                           IllegalAccessException {
-        final Class clazz = this.classLoader.findClass( className );
+        final Class clazz = ((CompositePackageClassLoader)this.datas.getClassLoader()).findClass( className );
 
         if (clazz != null) {
             if ( invoker instanceof ReturnValueRestriction ) {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/MapBackedClassLoader.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/MapBackedClassLoader.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/MapBackedClassLoader.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -111,7 +111,7 @@
     public InputStream getResourceAsStream(final String name) {
         byte[] bytes = null;
         synchronized ( this.store ) {
-            bytes = this.store.get( name );
+            bytes = this.store.get( convertResourcePathToClassName( name ) );
         }
 
         if ( bytes != null ) {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Package.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Package.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Package.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -36,11 +36,11 @@
 
 /**
  * Collection of related <code>Rule</code>s.
- *
+ * 
  * @see Rule
- *
+ * 
  * @author <a href="mail:bob at werken.com">bob mcwhirter </a>
- *
+ * 
  * @version $Id: Package.java,v 1.1 2005/07/26 01:06:31 mproctor Exp $
  */
 public class Package
@@ -51,7 +51,7 @@
     // ------------------------------------------------------------
 
     /**
-     *
+     * 
      */
     private static final long              serialVersionUID = 400L;
 
@@ -77,24 +77,35 @@
 
     private Map                            ruleFlows;
 
-    //    private JavaDialectData         packageCompilationData;
+    // private JavaDialectData packageCompilationData;
     private DialectDatas                   dialectDatas;
-    
+
     private Map<String, TypeDeclaration>   typeDeclarations;
 
-    /** This is to indicate the the package has no errors during the compilation/building phase */
+    /**
+     * This is to indicate the the package has no errors during the
+     * compilation/building phase
+     */
     private boolean                        valid            = true;
 
-    /** This will keep a summary error message as to why this package is not valid */
+    /**
+     * This will keep a summary error message as to why this package is not
+     * valid
+     */
     private String                         errorSummary;
-    
+
+    /**
+     * A class loader for package scoped artifacts
+     */
+    private transient MapBackedClassLoader packageScopeClassLoader;
+
     // ------------------------------------------------------------
     // Constructors
     // ------------------------------------------------------------
 
     /**
-     * Default constructor - for Externalizable. This should never be used by a user, as it
-     * will result in an invalid state for the instance.
+     * Default constructor - for Externalizable. This should never be used by a
+     * user, as it will result in an invalid state for the instance.
      */
     public Package() {
 
@@ -102,7 +113,7 @@
 
     /**
      * Construct.
-     *
+     * 
      * @param name
      *            The name of this <code>Package</code>.
      */
@@ -113,7 +124,7 @@
 
     /**
      * Construct.
-     *
+     * 
      * @param name
      *            The name of this <code>Package</code>.
      */
@@ -129,35 +140,78 @@
         this.factTemplates = Collections.EMPTY_MAP;
         this.functions = Collections.EMPTY_MAP;
 
-        // This classloader test should only be here for unit testing, too much legacy api to want to change by hand at the moment
+        // This classloader test should only be here for unit testing, too much
+        // legacy api to want to change by hand at the moment
         if ( parentClassLoader == null ) {
             parentClassLoader = Thread.currentThread().getContextClassLoader();
             if ( parentClassLoader == null ) {
                 parentClassLoader = getClass().getClassLoader();
             }
         }
-        //this.packageCompilationData = new JavaDialectData( parentClassLoader );
-        this.dialectDatas = new DialectDatas( parentClassLoader );
+        this.packageScopeClassLoader = new MapBackedClassLoader( parentClassLoader );
+        this.dialectDatas = new DialectDatas( this.packageScopeClassLoader );
     }
+    
+    /**
+     * Construct.
+     * 
+     * @param name
+     *            The name of this <code>Package</code>.
+     */
+    public Package(final String name,
+                   final MapBackedClassLoader packageClassLoader ) {
+        this.name = name;
+        this.imports = new HashMap<String, ImportDeclaration>();
+        this.typeDeclarations = new HashMap<String, TypeDeclaration>();
+        this.staticImports = Collections.EMPTY_SET;
+        this.rules = new LinkedHashMap();
+        this.ruleFlows = Collections.EMPTY_MAP;
+        this.globals = Collections.EMPTY_MAP;
+        this.factTemplates = Collections.EMPTY_MAP;
+        this.functions = Collections.EMPTY_MAP;
 
+        if( packageClassLoader == null ) {
+            ClassLoader parentClassLoader = null;
+            // This classloader test should only be here for unit testing, too much
+            // legacy api to want to change by hand at the moment
+            if ( parentClassLoader == null ) {
+                parentClassLoader = Thread.currentThread().getContextClassLoader();
+                if ( parentClassLoader == null ) {
+                    parentClassLoader = getClass().getClassLoader();
+                }
+            }
+            this.packageScopeClassLoader = new MapBackedClassLoader( parentClassLoader );
+        } else {
+            this.packageScopeClassLoader = packageClassLoader;
+        }
+        this.dialectDatas = new DialectDatas( this.packageScopeClassLoader );
+    }
+    
+
     /**
-     * Handles the write serialization of the Package. Patterns in Rules may reference generated data which cannot be serialized by default methods.
-     * The Package uses PackageCompilationData to hold a reference to the generated bytecode. The generated bytecode must be restored before any Rules.
-     * @param stream out the stream to write the object to; should be an instance of DroolsObjectOutputStream or OutputStream
-     *
+     * Handles the write serialization of the Package. Patterns in Rules may
+     * reference generated data which cannot be serialized by default methods.
+     * The Package uses PackageCompilationData to hold a reference to the
+     * generated bytecode. The generated bytecode must be restored before any
+     * Rules.
+     * 
+     * @param stream
+     *            out the stream to write the object to; should be an instance
+     *            of DroolsObjectOutputStream or OutputStream
+     * 
      */
     public void writeExternal(ObjectOutput stream) throws IOException {
-        boolean                 isDroolsStream    = stream instanceof DroolsObjectOutputStream;
-        ByteArrayOutputStream   bytes = null;
-        ObjectOutput    out;
+        boolean isDroolsStream = stream instanceof DroolsObjectOutputStream;
+        ByteArrayOutputStream bytes = null;
+        ObjectOutput out;
 
-        if (isDroolsStream) {
+        if ( isDroolsStream ) {
             out = stream;
-        }
-        else {
+        } else {
             bytes = new ByteArrayOutputStream();
-            out = new DroolsObjectOutputStream(bytes);
+            out = new DroolsObjectOutputStream( bytes );
         }
+        out.writeObject( this.packageScopeClassLoader.getStore() );
         out.writeObject( this.dialectDatas );
         out.writeObject( this.typeDeclarations );
         out.writeObject( this.name );
@@ -170,30 +224,42 @@
         out.writeBoolean( this.valid );
         out.writeObject( this.rules );
         // writing the whole stream as a byte array
-        if (!isDroolsStream) {
+        if ( !isDroolsStream ) {
             bytes.flush();
             bytes.close();
-            stream.writeObject(bytes.toByteArray());
+            stream.writeObject( bytes.toByteArray() );
         }
     }
 
     /**
-     * Handles the read serialization of the Package. Patterns in Rules may reference generated data which cannot be serialized by default methods.
-     * The Package uses PackageCompilationData to hold a reference to the generated bytecode; which must be restored before any Rules.
-     * A custom ObjectInputStream, able to resolve classes against the bytecode in the PackageCompilationData, is used to restore the Rules.
-     * @param stream, the stream to read data from in order to restore the object; should be an instance of
-     * DroolsObjectInputStream or InputStream
-     *
+     * Handles the read serialization of the Package. Patterns in Rules may
+     * reference generated data which cannot be serialized by default methods.
+     * The Package uses PackageCompilationData to hold a reference to the
+     * generated bytecode; which must be restored before any Rules. A custom
+     * ObjectInputStream, able to resolve classes against the bytecode in the
+     * PackageCompilationData, is used to restore the Rules.
+     * 
+     * @param stream,
+     *            the stream to read data from in order to restore the object;
+     *            should be an instance of DroolsObjectInputStream or
+     *            InputStream
+     * 
      */
     public void readExternal(ObjectInput stream) throws IOException,
-                                                      ClassNotFoundException {
-        boolean     isDroolsStream    = stream instanceof DroolsObjectInputStream;
-        ObjectInput in   = isDroolsStream
-                           ? stream
-                           : new DroolsObjectInputStream(new ByteArrayInputStream((byte[])stream.readObject()));
+                                                ClassNotFoundException {
+        boolean isDroolsStream = stream instanceof DroolsObjectInputStream;
+        DroolsObjectInputStream in = isDroolsStream ? (DroolsObjectInputStream) stream : new DroolsObjectInputStream( new ByteArrayInputStream( (byte[]) stream.readObject() ) );
 
-        this.dialectDatas   = (DialectDatas)in.readObject();
-        this.typeDeclarations   = (Map)in.readObject();
+        // creating package scoped classloader
+        Map store = (Map) in.readObject();
+        this.packageScopeClassLoader = new MapBackedClassLoader( in.getClassLoader(),
+                                                                 store );
+
+        // setting parent classloader for dialect datas
+        in.setClassLoader( this.packageScopeClassLoader );
+        this.dialectDatas = (DialectDatas) in.readObject();
+
+        this.typeDeclarations = (Map) in.readObject();
         this.name = (String) in.readObject();
         this.imports = (Map<String, ImportDeclaration>) in.readObject();
         this.staticImports = (Set) in.readObject();
@@ -204,7 +270,10 @@
         this.valid = in.readBoolean();
         this.rules = (Map) in.readObject();
 
-        if (!isDroolsStream) {
+        // restoring original parent classloader
+        in.setClassLoader( this.packageScopeClassLoader.getParent() );
+
+        if ( !isDroolsStream ) {
             in.close();
         }
     }
@@ -215,7 +284,7 @@
 
     /**
      * Retrieve the name of this <code>Package</code>.
-     *
+     * 
      * @return The name of this <code>Package</code>.
      */
     public String getName() {
@@ -238,20 +307,21 @@
     public Map<String, ImportDeclaration> getImports() {
         return this.imports;
     }
-    
-    public void addTypeDeclaration( final TypeDeclaration typeDecl ) {
-        this.typeDeclarations.put( typeDecl.getTypeName(), typeDecl );
+
+    public void addTypeDeclaration(final TypeDeclaration typeDecl) {
+        this.typeDeclarations.put( typeDecl.getTypeName(),
+                                   typeDecl );
     }
-    
-    public void removeTypeDeclaration( final String type ) {
+
+    public void removeTypeDeclaration(final String type) {
         this.typeDeclarations.remove( type );
     }
-    
+
     public Map<String, TypeDeclaration> getTypeDeclarations() {
         return this.typeDeclarations;
     }
-    
-    public TypeDeclaration getTypeDeclaration( String type ) {
+
+    public TypeDeclaration getTypeDeclaration(String type) {
         return this.typeDeclarations.get( type );
     }
 
@@ -269,7 +339,7 @@
 
         this.functions.put( function.getName(),
                             function );
-        dialectDatas.getDialectData(function.getDialect()).setDirty(true);
+        dialectDatas.getDialectData( function.getDialect() ).setDirty( true );
     }
 
     public Map<String, Function> getFunctions() {
@@ -323,10 +393,10 @@
 
     /**
      * Add a <code>Rule</code> to this <code>Package</code>.
-     *
+     * 
      * @param rule
      *            The rule to add.
-     *
+     * 
      * @throws DuplicateRuleNameException
      *             If the <code>Rule</code> attempting to be added has the
      *             same name as another previously added <code>Rule</code>.
@@ -353,8 +423,8 @@
     }
 
     /**
-     * Get the rule flows for this package. The key is the ruleflow id.
-     * It will be Collections.EMPTY_MAP if none have been added.
+     * Get the rule flows for this package. The key is the ruleflow id. It will
+     * be Collections.EMPTY_MAP if none have been added.
      */
     public Map getRuleFlows() {
         return this.ruleFlows;
@@ -374,54 +444,61 @@
         this.rules.remove( rule.getName() );
         this.dialectDatas.removeRule( this,
                                       rule );
-        //        final String consequenceName = rule.getConsequence().getClass().getName();
+        // final String consequenceName =
+        // rule.getConsequence().getClass().getName();
         //
-        //        Object object = this.dialectData.getDialectData( rule.getDialect() );
+        // Object object = this.dialectData.getDialectData( rule.getDialect() );
         //
-        //        // check for compiled code and remove if present.
-        //        if ( this.packageCompilationData.remove( consequenceName ) ) {
-        //            removeClasses( rule.getLhs() );
+        // // check for compiled code and remove if present.
+        // if ( this.packageCompilationData.remove( consequenceName ) ) {
+        // removeClasses( rule.getLhs() );
         //
-        //            // Now remove the rule class - the name is a subset of the consequence name
-        //            this.packageCompilationData.remove( consequenceName.substring( 0,
-        //                                                                           consequenceName.indexOf( "ConsequenceInvoker" ) ) );
-        //        }
-        //        return this.packageCompilationData;
+        // // Now remove the rule class - the name is a subset of the
+        // consequence name
+        // this.packageCompilationData.remove( consequenceName.substring( 0,
+        // consequenceName.indexOf( "ConsequenceInvoker" ) ) );
+        // }
+        // return this.packageCompilationData;
     }
 
-    //    private void removeClasses(final ConditionalElement ce) {
-    //        if ( ce instanceof GroupElement ) {
-    //            final GroupElement group = (GroupElement) ce;
-    //            for ( final Iterator it = group.getChildren().iterator(); it.hasNext(); ) {
-    //                final Object object = it.next();
-    //                if ( object instanceof ConditionalElement ) {
-    //                    removeClasses( (ConditionalElement) object );
-    //                } else if ( object instanceof Pattern ) {
-    //                    removeClasses( (Pattern) object );
-    //                }
-    //            }
-    //        } else if ( ce instanceof EvalCondition ) {
-    //            this.packageCompilationData.remove( ((EvalCondition) ce).getEvalExpression().getClass().getName() );
-    //        }
-    //    }
+    // private void removeClasses(final ConditionalElement ce) {
+    // if ( ce instanceof GroupElement ) {
+    // final GroupElement group = (GroupElement) ce;
+    // for ( final Iterator it = group.getChildren().iterator(); it.hasNext(); )
+    // {
+    // final Object object = it.next();
+    // if ( object instanceof ConditionalElement ) {
+    // removeClasses( (ConditionalElement) object );
+    // } else if ( object instanceof Pattern ) {
+    // removeClasses( (Pattern) object );
+    // }
+    // }
+    // } else if ( ce instanceof EvalCondition ) {
+    // this.packageCompilationData.remove( ((EvalCondition)
+    // ce).getEvalExpression().getClass().getName() );
+    // }
+    // }
     //
-    //    private void removeClasses(final Pattern pattern) {
-    //        for ( final Iterator it = pattern.getConstraints().iterator(); it.hasNext(); ) {
-    //            final Object object = it.next();
-    //            if ( object instanceof PredicateConstraint ) {
-    //                this.packageCompilationData.remove( ((PredicateConstraint) object).getPredicateExpression().getClass().getName() );
-    //            } else if ( object instanceof ReturnValueConstraint ) {
-    //                this.packageCompilationData.remove( ((ReturnValueConstraint) object).getExpression().getClass().getName() );
-    //            }
-    //        }
-    //    }
+    // private void removeClasses(final Pattern pattern) {
+    // for ( final Iterator it = pattern.getConstraints().iterator();
+    // it.hasNext(); ) {
+    // final Object object = it.next();
+    // if ( object instanceof PredicateConstraint ) {
+    // this.packageCompilationData.remove( ((PredicateConstraint)
+    // object).getPredicateExpression().getClass().getName() );
+    // } else if ( object instanceof ReturnValueConstraint ) {
+    // this.packageCompilationData.remove( ((ReturnValueConstraint)
+    // object).getExpression().getClass().getName() );
+    // }
+    // }
+    // }
 
     /**
      * Retrieve a <code>Rule</code> by name.
-     *
+     * 
      * @param name
      *            The name of the <code>Rule</code> to retrieve.
-     *
+     * 
      * @return The named <code>Rule</code>, or <code>null</code> if not
      *         such <code>Rule</code> has been added to this
      *         <code>Package</code>.
@@ -432,16 +509,16 @@
 
     /**
      * Retrieve all <code>Rules</code> in this <code>Package</code>.
-     *
+     * 
      * @return An array of all <code>Rules</code> in this <code>Package</code>.
      */
     public Rule[] getRules() {
         return (Rule[]) this.rules.values().toArray( new Rule[this.rules.size()] );
     }
 
-    //    public JavaDialectData getPackageCompilationData() {
-    //        return this.packageCompilationData;
-    //    }
+    // public JavaDialectData getPackageCompilationData() {
+    // return this.packageCompilationData;
+    // }
 
     public String toString() {
         return "[Package name=" + this.name + "]";
@@ -494,6 +571,7 @@
 
     /**
      * Returns true if clazz is imported as an Event class in this package
+     * 
      * @param clazz
      * @return true if clazz is imported as an Event class in this package
      */
@@ -503,8 +581,8 @@
         }
 
         // check if clazz is resolved by any of the type declarations
-        for( TypeDeclaration type : this.typeDeclarations.values() ) {
-            if( type.matches( clazz ) && type.getRole() == TypeDeclaration.Role.EVENT ) {
+        for ( TypeDeclaration type : this.typeDeclarations.values() ) {
+            if ( type.matches( clazz ) && type.getRole() == TypeDeclaration.Role.EVENT ) {
                 return true;
             }
         }
@@ -525,12 +603,17 @@
     }
 
     public FactType getFactType(final String typeName) {
-        if( this.name != null && ! typeName.startsWith( this.name ) ) {
+        if ( this.name != null && !typeName.startsWith( this.name ) ) {
             return null;
         }
-        // in case the package name is != null, remove the package name from the beginning of the type name 
-        String key = this.name == null ? typeName : typeName.substring( this.name.length()+1 );
-        TypeDeclaration decl = this.typeDeclarations.get( key ); 
+        // in case the package name is != null, remove the package name from the
+        // beginning of the type name
+        String key = this.name == null ? typeName : typeName.substring( this.name.length() + 1 );
+        TypeDeclaration decl = this.typeDeclarations.get( key );
         return decl != null ? decl.getTypeClassDef() : null;
     }
+
+    public MapBackedClassLoader getPackageScopeClassLoader() {
+        return packageScopeClassLoader;
+    }
 }
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/asm/ClassFieldInspector.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/asm/ClassFieldInspector.java	2008-05-24 13:51:11 UTC (rev 20154)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/asm/ClassFieldInspector.java	2008-05-24 18:01:50 UTC (rev 20155)
@@ -26,6 +26,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.drools.RuntimeDroolsException;
 import org.drools.asm.AnnotationVisitor;
 import org.drools.asm.Attribute;
 import org.drools.asm.ClassReader;
@@ -33,6 +34,7 @@
 import org.drools.asm.FieldVisitor;
 import org.drools.asm.MethodVisitor;
 import org.drools.asm.Opcodes;
+import org.drools.asm.Type;
 
 /**
  * Visit a POJO user class, and extract the property getter methods that are public, in the 
@@ -121,22 +123,22 @@
         for ( int i = 0; i < methods.length; i++ ) {
             // modifiers mask  
             final int mask = includeFinalMethods ? Modifier.PUBLIC : Modifier.PUBLIC | Modifier.FINAL;
-            
-            if ( ((methods[i].getModifiers() & mask) == Opcodes.ACC_PUBLIC ) && (methods[i].getParameterTypes().length == 0) && (!methods[i].getName().equals( "<init>" )) && (!methods[i].getName().equals( "<clinit>" ))
+
+            if ( ((methods[i].getModifiers() & mask) == Opcodes.ACC_PUBLIC) && (methods[i].getParameterTypes().length == 0) && (!methods[i].getName().equals( "<init>" )) && (!methods[i].getName().equals( "<clinit>" ))
                  && (methods[i].getReturnType() != void.class) ) {
-                
+
                 // want public methods that start with 'get' or 'is' and have no args, and return a value
                 final int fieldIndex = this.fieldNames.size();
                 addToMapping( methods[i],
                               fieldIndex );
-                
-            } else if ( ((methods[i].getModifiers() & mask) == Opcodes.ACC_PUBLIC ) && (methods[i].getParameterTypes().length == 1) && (methods[i].getName().startsWith( "set" ))) {
 
+            } else if ( ((methods[i].getModifiers() & mask) == Opcodes.ACC_PUBLIC) && (methods[i].getParameterTypes().length == 1) && (methods[i].getName().startsWith( "set" )) ) {
+
                 // want public methods that start with 'set' and have one arg
                 final int fieldIndex = this.fieldNames.size();
                 addToMapping( methods[i],
                               fieldIndex );
-                
+
             }
         }
     }
@@ -211,7 +213,7 @@
                         fieldName );
             storeGetterSetter( method,
                                fieldName );
-            
+
             if ( offset == 0 ) {
                 // only if it is a non-standard getter method
                 this.nonGetters.add( fieldName );
@@ -240,15 +242,15 @@
      */
     private void storeGetterSetter(final Method method,
                                    final String fieldName) {
-        if( method.getName().startsWith( "set" ) ) {
+        if ( method.getName().startsWith( "set" ) ) {
             this.setterMethods.put( fieldName,
                                     method );
-            if( ! fieldTypes.containsKey( fieldName ) ) {
+            if ( !fieldTypes.containsKey( fieldName ) ) {
                 this.fieldTypes.put( fieldName,
                                      method.getParameterTypes()[0] );
             }
         } else {
-            this.getterMethods.put( fieldName, 
+            this.getterMethods.put( fieldName,
                                     method );
             this.fieldTypes.put( fieldName,
                                  method.getReturnType() );
@@ -290,20 +292,28 @@
             //and have no args, and return a value
             final int mask = this.includeFinalMethods ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL;
             if ( (access & mask) == Opcodes.ACC_PUBLIC ) {
-                if (( desc.startsWith( "()" ) && (!name.equals( "<init>" )) && (!name.equals( "<clinit>" )) ) ||
-                    ( name.startsWith( "set" ) ) ){// && ( name.startsWith("get") || name.startsWith("is") ) ) {
-                    try {
+                try {
+                    if ( desc.startsWith( "()" ) && (!name.equals( "<init>" )) && (!name.equals( "<clinit>" )) ) {// && ( name.startsWith("get") || name.startsWith("is") ) ) {
                         final Method method = this.clazz.getMethod( name,
                                                                     (Class[]) null );
-                        if ( method.getReturnType() != void.class || 
-                             ( method.getName().startsWith( "set" ) && ( method.getParameterTypes().length == 1 ) ) ) {
+                        if ( method.getReturnType() != void.class ) {
                             final int fieldIndex = this.inspector.fieldNames.size();
                             this.inspector.addToMapping( method,
                                                          fieldIndex );
                         }
-                    } catch ( final NoSuchMethodException e ) {
-                        throw new IllegalStateException( "Error in getting field access method." );
+                    } else if ( name.startsWith( "set" ) ) {
+                        // I found no safe way of getting the method object from the descriptor, so doing the other way around
+                        Method[] methods = this.clazz.getMethods();
+                        for( int i = 0; i < methods.length; i++ ) {
+                            if( desc.equals( Type.getMethodDescriptor( methods[i] ) ) ) {
+                                final int fieldIndex = this.inspector.fieldNames.size();
+                                this.inspector.addToMapping( methods[i],
+                                                             fieldIndex );
+                            }
+                        }
                     }
+                } catch ( final Exception e ) {
+                    throw new RuntimeDroolsException( "Error getting field access method: "+name+": "+e.getMessage(), e );
                 }
             }
             return null;




More information about the jboss-svn-commits mailing list