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

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Jul 16 21:22:31 EDT 2009


Author: stampy88
Date: 2009-07-16 21:22:31 -0400 (Thu, 16 Jul 2009)
New Revision: 28125

Added:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/compiled/
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeCompiler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AbstractCompilerHandler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AssertHandler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/CompiledNetwork.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/DeclarationsHandler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/HashedAlphasDeclaration.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandlerAdaptor.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeParser.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/SetNodeReferenceHandler.java
Removed:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/AlphaNetworkCompiler.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/manners/MannersBenchmark.java
Log:
Initial version of compiled network 

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeCompiler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeCompiler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeCompiler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,185 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassObjectType;
+import org.drools.base.ValueType;
+import org.drools.compiler.PackageBuilder;
+import org.drools.compiler.PackageRegistry;
+import org.drools.lang.descr.PackageDescr;
+import org.drools.reteoo.ObjectTypeNode;
+import org.drools.rule.builder.dialect.java.JavaDialect;
+
+import java.util.Collection;
+
+/**
+ * todo: document
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+public class ObjectTypeNodeCompiler {
+    private static final String NEWLINE = "\n";
+    private static final String PACKAGE_NAME = "org.drools.reteoo.compiled";
+    private static final String BINARY_PACKAGE_NAME = PACKAGE_NAME.replaceAll("\\.", "/");
+    /**
+     * This field hold the fully qualified class name that the {@link org.drools.reteoo.ObjectTypeNode} is representing.
+     */
+    private String className;
+
+    /**
+     * This field will hold the "simple" name of the generated class
+     */
+    private String generatedClassSimpleName;
+
+    /**
+     * OTN we are creating a compiled network for
+     */
+    private ObjectTypeNode objectTypeNode;
+
+    private StringBuilder builder = new StringBuilder();
+
+    private ObjectTypeNodeCompiler(ObjectTypeNode objectTypeNode) {
+        this.objectTypeNode = objectTypeNode;
+
+        ClassObjectType classObjectType = (ClassObjectType) objectTypeNode.getObjectType();
+        this.className = classObjectType.getClassName();
+        generatedClassSimpleName = "Compiled" + classObjectType.getClassName().replaceAll("\\.", "_") + "Network";
+    }
+
+    private String generateSource() {
+        createClassDeclaration();
+
+        ObjectTypeNodeParser parser = new ObjectTypeNodeParser(objectTypeNode);
+
+        // create declarations
+        DeclarationsHandler declarations = new DeclarationsHandler(builder);
+        parser.accept(declarations);
+
+        // we need the hashed declarations when creating the constructor
+        Collection<HashedAlphasDeclaration> hashedAlphaDeclarations = declarations.getHashedAlphaDeclarations();
+
+        createConstructor(hashedAlphaDeclarations);
+
+        // create set node method
+        SetNodeReferenceHandler setNode = new SetNodeReferenceHandler(builder);
+        parser.accept(setNode);
+
+        // create assert method
+        AssertHandler assertHandler = new AssertHandler(builder, className, hashedAlphaDeclarations.size() > 0);
+        parser.accept(assertHandler);
+
+        // end of class
+        builder.append("}").append(NEWLINE);
+
+        return builder.toString();
+    }
+
+    /**
+     * This method will output the package statement, followed by the opening of the class declaration
+     */
+    private void createClassDeclaration() {
+        builder.append("package ").append(PACKAGE_NAME).append(");").append(NEWLINE);
+        builder.append("public class ").append(generatedClassSimpleName).append(" extends ").
+                append(CompiledNetwork.class.getName()).append("{ ").append(NEWLINE);
+    }
+
+    /**
+     * Creates the constructor for the generated class. If the hashedAlphaDeclarations is empty, it will just
+     * output a empty default constructor; if it is not, the constructor will contain code to fill the hash
+     * alpha maps with the values and node ids.
+     *
+     * @param hashedAlphaDeclarations declarations used for creating statements to populate the hashed alpha
+     *                                maps for the generate class
+     */
+    private void createConstructor(Collection<HashedAlphasDeclaration> hashedAlphaDeclarations) {
+        builder.append("public ").append(generatedClassSimpleName).append("() {").append(NEWLINE);
+
+        // for each hashed alpha, we need to fill in the map member variable with the hashed values to node Ids
+        for (HashedAlphasDeclaration declaration : hashedAlphaDeclarations) {
+            String mapVariableName = declaration.getVariableName();
+
+            for (Object hashedValue : declaration.getHashedValues()) {
+                Object value = hashedValue;
+                // need to quote value if it is a string
+                if (declaration.getValueType() == ValueType.STRING_TYPE) {
+                    value = "\"" + value + "\"";
+                }
+
+                String nodeId = declaration.getNodeId(hashedValue);
+
+                // generate the map.put(hashedValue, nodeId) call
+                builder.append(mapVariableName).append(".put(").append(value).append(", ").append(nodeId).append(");");
+                builder.append(NEWLINE);
+            }
+        }
+
+        builder.append("}").append(NEWLINE);
+    }
+
+    /**
+     * Returns the fully qualified name of the generated subclass of {@link org.drools.reteoo.compiled.CompiledNetwork}
+     *
+     * @return name of generated class
+     */
+    private String getName() {
+        return getPackageName() + "." + generatedClassSimpleName;
+    }
+
+    /**
+     * Returns the fully qualified binary name of the generated subclass of {@link org.drools.reteoo.compiled.CompiledNetwork}
+     *
+     * @return binary name of generated class
+     */
+    private String getBinaryName() {
+        return BINARY_PACKAGE_NAME + "." + generatedClassSimpleName + ".class";
+    }
+
+    private String getPackageName() {
+        return PACKAGE_NAME;
+    }
+
+    /**
+     * Creates a {@link CompiledNetwork} for the specified {@link ObjectTypeNode}. The {@link PackageBuilder} is used
+     * to compile the generated source and load the class.
+     *
+     * @param pkgBuilder     builder used to compile and load class
+     * @param objectTypeNode OTN we are generating a compiled network for
+     * @return CompiledNetwork
+     */
+    public static CompiledNetwork compile(PackageBuilder pkgBuilder, ObjectTypeNode objectTypeNode) {
+        if (objectTypeNode == null) {
+            throw new IllegalArgumentException("ObjectTypeNode cannot be null!");
+        }
+        if (pkgBuilder == null) {
+            throw new IllegalArgumentException("PackageBuilder cannot be null!");
+        }
+        ObjectTypeNodeCompiler compiler = new ObjectTypeNodeCompiler(objectTypeNode);
+
+        String packageName = compiler.getPackageName();
+
+        PackageRegistry pkgReg = pkgBuilder.getPackageRegistry(packageName);
+        if (pkgReg == null) {
+            pkgBuilder.addPackage(new PackageDescr(packageName));
+            pkgReg = pkgBuilder.getPackageRegistry(packageName);
+        }
+
+        String source = compiler.generateSource();
+        String generatedSourceName = compiler.getName();
+
+        JavaDialect dialect = (JavaDialect) pkgReg.getDialectCompiletimeRegistry().getDialect("java");
+        dialect.addSrc(compiler.getBinaryName(), source.getBytes());
+        pkgBuilder.compileAll();
+        pkgBuilder.updateResults();
+
+        CompiledNetwork network;
+        try {
+            network = (CompiledNetwork) Class.forName(generatedSourceName, true, pkgBuilder.getRootClassLoader()).newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException("This is a bug. Please contact the development team", e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException("This is a bug. Please contact the development team", e);
+        } catch (InstantiationException e) {
+            throw new RuntimeException("This is a bug. Please contact the development team", e);
+        }
+
+        return network;
+    }
+}

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/manners/MannersBenchmark.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/manners/MannersBenchmark.java	2009-07-17 01:09:09 UTC (rev 28124)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/manners/MannersBenchmark.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -1,75 +1,78 @@
 package org.drools.integrationtests.manners;
 
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.StringTokenizer;
-
 import org.drools.RuleBase;
 import org.drools.RuleBaseFactory;
+import org.drools.StatefulSession;
 import org.drools.common.InternalRuleBase;
 import org.drools.compiler.PackageBuilder;
-import org.drools.reteoo.AlphaNetworkCompiler;
 import org.drools.reteoo.ObjectTypeNode;
+import org.drools.reteoo.compiled.CompiledNetwork;
+import org.drools.reteoo.compiled.ObjectTypeNodeCompiler;
 import org.drools.rule.Package;
 
+import java.io.*;
+import java.util.*;
+
 public class MannersBenchmark {
-    /** Number of guests at the dinner (default: 16). */
-    private int numGuests  = 16;
+    /**
+     * Number of guests at the dinner (default: 16).
+     */
+    private int numGuests = 16;
 
-    /** Number of seats at the table (default: 16). */
-    private int numSeats   = 16;
+    /**
+     * Number of seats at the table (default: 16).
+     */
+    private int numSeats = 16;
 
-    /** Minimum number of hobbies each guest should have (default: 2). */
+    /**
+     * Minimum number of hobbies each guest should have (defaJavaCompilerFactoryult: 2).
+     */
     private int minHobbies = 2;
 
-    /** Maximun number of hobbies each guest should have (default: 3). */
+    /**
+     * Maximun number of hobbies each guest should have (default: 3).
+     */
     private int maxHobbies = 3;
 
     public static void main(final String[] args) throws Exception {
         PackageBuilder builder = new PackageBuilder();
-        builder.addPackageFromDrl( new InputStreamReader( MannersBenchmark.class.getResourceAsStream( "manners.drl" ) ) );
+        builder.addPackageFromDrl(new InputStreamReader(MannersBenchmark.class.getResourceAsStream("manners.drl")));
         Package pkg = builder.getPackage();
 
         // add the package to a rulebase
         final RuleBase ruleBase = RuleBaseFactory.newRuleBase();
-        ruleBase.addPackage( pkg );
-        
-        AlphaNetworkCompiler compiler = new  AlphaNetworkCompiler();
-        
-        for(ObjectTypeNode node : ( (InternalRuleBase) ruleBase).getRete().getObjectTypeNodes() ){
-            compiler.compile( node );
+        ruleBase.addPackage(pkg);
+
+        for (ObjectTypeNode node : ((InternalRuleBase) ruleBase).getRete().getObjectTypeNodes()) {
+            CompiledNetwork compiledNetwork = ObjectTypeNodeCompiler.compile(builder, node);
+            node.setCompiledNetwork(compiledNetwork);
         }
 
-//        StatefulSession session = ruleBase.newStatefulSession();
-//
-//        String filename;
-//        if ( args.length != 0 ) {
-//            String arg = args[0];
-//            filename = arg;
-//        } else {
-//            filename = "manners128.dat";
-//        }
-//
-//        InputStream is = MannersBenchmark.class.getResourceAsStream( filename );
-//        List list = getInputObjects( is );
-//        for ( Iterator it = list.iterator(); it.hasNext(); ) {
-//            Object object = it.next();
-//            session.insert( object );
-//        }
-//
-//        session.insert( new Count( 1 ) );
-//
-//        long start = System.currentTimeMillis();
-//        session.fireAllRules();
-//        System.err.println( System.currentTimeMillis() - start );
-//        session.dispose();
+        String filename;
+        if (args.length != 0) {
+            String arg = args[0];
+            filename = arg;
+        } else {
+            filename = "manners128.dat";
+        }
+
+        for (int i = 0; i < 10; ++i) {
+            InputStream is = MannersBenchmark.class.getResourceAsStream(filename);
+            List list = getInputObjects(is);
+            StatefulSession session = ruleBase.newStatefulSession();
+
+            for (Iterator it = list.iterator(); it.hasNext();) {
+                Object object = it.next();
+                session.insert(object);
+            }
+
+            session.insert(new Count(1));
+
+            long start = System.currentTimeMillis();
+            session.fireAllRules();
+            System.err.println(System.currentTimeMillis() - start);
+            session.dispose();
+        }
     }
 
     /**
@@ -79,50 +82,50 @@
     protected static List getInputObjects(InputStream inputStream) throws IOException {
         List list = new ArrayList();
 
-        BufferedReader br = new BufferedReader( new InputStreamReader( inputStream ) );
+        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
 
         String line;
-        while ( (line = br.readLine()) != null ) {
-            if ( line.trim().length() == 0 || line.trim().startsWith( ";" ) ) {
+        while ((line = br.readLine()) != null) {
+            if (line.trim().length() == 0 || line.trim().startsWith(";")) {
                 continue;
             }
-            StringTokenizer st = new StringTokenizer( line,
-                                                      "() " );
+            StringTokenizer st = new StringTokenizer(line,
+                    "() ");
             String type = st.nextToken();
 
-            if ( "guest".equals( type ) ) {
-                if ( !"name".equals( st.nextToken() ) ) {
-                    throw new IOException( "expected 'name' in: " + line );
+            if ("guest".equals(type)) {
+                if (!"name".equals(st.nextToken())) {
+                    throw new IOException("expected 'name' in: " + line);
                 }
                 String name = st.nextToken();
-                if ( !"sex".equals( st.nextToken() ) ) {
-                    throw new IOException( "expected 'sex' in: " + line );
+                if (!"sex".equals(st.nextToken())) {
+                    throw new IOException("expected 'sex' in: " + line);
                 }
                 String sex = st.nextToken();
-                if ( !"hobby".equals( st.nextToken() ) ) {
-                    throw new IOException( "expected 'hobby' in: " + line );
+                if (!"hobby".equals(st.nextToken())) {
+                    throw new IOException("expected 'hobby' in: " + line);
                 }
                 String hobby = st.nextToken();
 
-                Guest guest = new Guest( name,
-                                         Sex.resolve( sex ),
-                                         Hobby.resolve( hobby ) );
+                Guest guest = new Guest(name,
+                        Sex.resolve(sex),
+                        Hobby.resolve(hobby));
 
-                list.add( guest );
+                list.add(guest);
             }
 
-            if ( "last_seat".equals( type ) ) {
-                if ( !"seat".equals( st.nextToken() ) ) {
-                    throw new IOException( "expected 'seat' in: " + line );
+            if ("last_seat".equals(type)) {
+                if (!"seat".equals(st.nextToken())) {
+                    throw new IOException("expected 'seat' in: " + line);
                 }
-                list.add( new LastSeat( new Integer( st.nextToken() ).intValue() ) );
+                list.add(new LastSeat(new Integer(st.nextToken()).intValue()));
             }
 
-            if ( "context".equals( type ) ) {
-                if ( !"state".equals( st.nextToken() ) ) {
-                    throw new IOException( "expected 'state' in: " + line );
+            if ("context".equals(type)) {
+                if (!"state".equals(st.nextToken())) {
+                    throw new IOException("expected 'state' in: " + line);
                 }
-                list.add( new Context( st.nextToken() ) );
+                list.add(new Context(st.nextToken()));
             }
         }
         inputStream.close();
@@ -131,7 +134,7 @@
     }
 
     private InputStream generateData() {
-        final String LINE_SEPARATOR = System.getProperty( "line.separator" );
+        final String LINE_SEPARATOR = System.getProperty("line.separator");
 
         StringWriter writer = new StringWriter();
 
@@ -143,42 +146,42 @@
 
         // init hobbies
         List hobbyList = new ArrayList();
-        for ( int i = 1; i <= maxHobbies; i++ ) {
-            hobbyList.add( "h" + i );
+        for (int i = 1; i <= maxHobbies; i++) {
+            hobbyList.add("h" + i);
         }
 
         Random rnd = new Random();
-        for ( int i = 1; i <= numGuests; i++ ) {
+        for (int i = 1; i <= numGuests; i++) {
             char sex = rnd.nextBoolean() ? 'm' : 'f';
-            if ( sex == 'm' && maleCount == maxMale ) {
+            if (sex == 'm' && maleCount == maxMale) {
                 sex = 'f';
             }
-            if ( sex == 'f' && femaleCount == maxFemale ) {
+            if (sex == 'f' && femaleCount == maxFemale) {
                 sex = 'm';
             }
-            if ( sex == 'm' ) {
+            if (sex == 'm') {
                 maleCount++;
             }
-            if ( sex == 'f' ) {
+            if (sex == 'f') {
                 femaleCount++;
             }
 
-            List guestHobbies = new ArrayList( hobbyList );
+            List guestHobbies = new ArrayList(hobbyList);
 
-            int numHobbies = minHobbies + rnd.nextInt( maxHobbies - minHobbies + 1 );
-            for ( int j = 0; j < numHobbies; j++ ) {
-                int hobbyIndex = rnd.nextInt( guestHobbies.size() );
-                String hobby = (String) guestHobbies.get( hobbyIndex );
-                writer.write( "(guest (name n" + i + ") (sex " + sex + ") (hobby " + hobby + "))" + LINE_SEPARATOR );
-                guestHobbies.remove( hobbyIndex );
+            int numHobbies = minHobbies + rnd.nextInt(maxHobbies - minHobbies + 1);
+            for (int j = 0; j < numHobbies; j++) {
+                int hobbyIndex = rnd.nextInt(guestHobbies.size());
+                String hobby = (String) guestHobbies.get(hobbyIndex);
+                writer.write("(guest (name n" + i + ") (sex " + sex + ") (hobby " + hobby + "))" + LINE_SEPARATOR);
+                guestHobbies.remove(hobbyIndex);
             }
         }
-        writer.write( "(last_seat (seat " + numSeats + "))" + LINE_SEPARATOR );
+        writer.write("(last_seat (seat " + numSeats + "))" + LINE_SEPARATOR);
 
-        writer.write( LINE_SEPARATOR );
-        writer.write( "(context (state start))" + LINE_SEPARATOR );
+        writer.write(LINE_SEPARATOR);
+        writer.write("(context (state start))" + LINE_SEPARATOR);
 
-        return new ByteArrayInputStream( writer.getBuffer().toString().getBytes() );
+        return new ByteArrayInputStream(writer.getBuffer().toString().getBytes());
     }
 
 }

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/AlphaNetworkCompiler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/AlphaNetworkCompiler.java	2009-07-17 01:09:09 UTC (rev 28124)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/AlphaNetworkCompiler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -1,166 +0,0 @@
-package org.drools.reteoo;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import org.drools.util.Iterator;
-import org.drools.util.ObjectHashMap;
-import org.drools.util.ObjectHashMap.ObjectEntry;
-
-public class AlphaNetworkCompiler {
-    private StringBuilder builder;
-
-    public void compile(ObjectTypeNode objectTypeNode) {
-        builder = new StringBuilder();
-        builder.append( "public class Compiled" + objectTypeNode.getObjectType() + "AlphaNetwork implements ObjectSink { \n" );
-        
-        createVars( objectTypeNode.getSinkPropagator().getSinks(), 4  );
-        
-        builder.append( "    public void assertObject(....) { \n");
-
-        compileAlphaNodes( objectTypeNode.getSinkPropagator(),
-                           8 );
-        
-        builder.append( "    } \n" );
-        builder.append( "} \n" );
-
-        System.out.println( builder.toString() );
-    }
-
-    public void createVars(ObjectSink[] sinks,
-                           int indent) {
-        for ( ObjectSink sink : sinks ) {
-            if ( sink instanceof AlphaNode ) {
-                AlphaNode alphaNode = (AlphaNode) sink;
-                builder.append( getIndent( indent ) + "AlphaNodeFieldConstraint alphaNodeConstraint" + alphaNode.getId() + ";\n" );
-                createVars( alphaNode.getSinkPropagator().getSinks(), indent );
-            } else if ( sink instanceof BetaNode ) {
-                BetaNode betaNode = (BetaNode) sink;
-                builder.append( getIndent( indent ) +  "ObjectSink sink" + betaNode.getId() + ";\n" );
-            } else if ( sink instanceof LeftInputAdapterNode ) {
-                LeftInputAdapterNode liaNode = (LeftInputAdapterNode) sink;
-                builder.append( getIndent( indent ) +  "ObjectSink sink" + liaNode.getId() + ";\n" );
-            }
-        }
-    }
-
-    public void compileAlphaNodes(ObjectSinkPropagator adapter,
-                                  int indent) {
-        if ( adapter instanceof SingleObjectSinkAdapter ) {
-            compileAlphaNodeSingleConstraint( (SingleObjectSinkAdapter) adapter,
-                                              indent );
-        } else if ( adapter instanceof CompositeObjectSinkAdapter ) {
-            compileAlphaNodeCompositeConstraint( (CompositeObjectSinkAdapter) adapter,
-                                                 indent );
-        }
-    }
-
-    private void compileAlphaNodeCompositeConstraint(CompositeObjectSinkAdapter adapter,
-                                                     int indent) {
-        ObjectSinkNodeList sinks = adapter.getHashableSinks();
-        if ( sinks != null ) {
-            for ( ObjectSinkNode sink = sinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
-                compileAlphaNodeSingleConstraint( sink,
-                                                  indent );
-            }
-        }
-
-        sinks = adapter.getOthers();
-        if ( sinks != null ) {
-            for ( ObjectSinkNode sink = sinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode() ) {
-                compileAlphaNodeSingleConstraint( sink,
-                                                  indent );
-            }
-        }
-
-        ObjectHashMap map = adapter.getHashedSinkMap();
-        if ( map != null ) {
-            ObjectEntry[] entries = new ObjectEntry[map.size()];
-            Iterator it = map.iterator();
-            int i = 0;
-            for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
-                entries[i++] = entry;
-            }
-
-            // we sort as switch works faster with ordered cases
-            Arrays.sort( entries,
-                         new Comparator() {
-                             public int compare(Object o1,
-                                                Object o2) {
-                                 ObjectEntry entry1 = (ObjectEntry) o1;
-                                 ObjectEntry entry2 = (ObjectEntry) o2;
-                                 return ((ObjectSink) entry1.getValue()).getId() - ((ObjectSink) entry2.getValue()).getId();
-                             }
-
-                         } );
-
-            //final Iterator it = map.newIterator();
-            builder.append( getIndent( indent ) + "HashKey key = new HashKey(handle);\n" );
-            builder.append( getIndent( indent ) + "swtich ((ObjectSink)this.hashedSinkedMap(key)).getId() {\n" );
-            for ( ObjectEntry entry : entries ) {
-                ObjectSink sink = (ObjectSink) entry.getValue();
-                builder.append( getIndent( indent + 4 ) + "case " + sink.getId() + ": {\n" );
-                //builder.append( getIndent( indent + 8 ) + "sink" + sink.getId() + ".assertRight(handle, wm, context);\n" );
-                
-                if (sink instanceof AlphaNode ) {
-                    compileAlphaNodes( ((AlphaNode)sink).getSinkPropagator(),
-                                       indent + 8 );                    
-                }
-                
-                builder.append( getIndent( indent + 4 )+ "};\n" );
-            }
-            builder.append( getIndent( indent ) + "};\n" );
-        }
-
-    }
-
-    public void compileAlphaNodeSingleConstraint(SingleObjectSinkAdapter adapter,
-                                                 int indent) {
-        compileAlphaNodeSingleConstraint( adapter.getSinks()[0],
-                                          indent );
-    }
-
-    public void compileAlphaNodeSingleConstraint(ObjectSink sink,
-                                                 int indent) {
-        if ( sink instanceof AlphaNode ) {
-            AlphaNode alphaNode = (AlphaNode) sink;
-            builder.append( getIndent( indent ) + "if ( alphaNodeConstraint" + alphaNode.getId() + ".isAllowed(handle, wm) ) {\n" );
-            compileAlphaNodes( alphaNode.getSinkPropagator(),
-                               indent + 4 );
-            builder.append( getIndent( indent ) + "}\n" );
-        } else if ( sink instanceof BetaNode ) {
-            BetaNode betaNode = (BetaNode) sink;
-            builder.append( getIndent( indent ) + "sink" + betaNode.getId() + ".assertRight(handle, wm, context);\n" );
-        } else if ( sink instanceof LeftInputAdapterNode ) {
-            LeftInputAdapterNode liaNode = (LeftInputAdapterNode) sink;
-            builder.append( getIndent( indent ) + "sink" + liaNode.getId() + ".assertRight(handle, wm, context);\n" );
-        }
-    }
-
-    public void compileAlphaNodeCompositeConstraint(ObjectSink sink,
-                                                    int indent) {
-        if ( sink instanceof AlphaNode ) {
-            AlphaNode alphaNode = (AlphaNode) sink;
-            builder.append( getIndent( indent ) + "if ( alphaNodeConstraint" + alphaNode.getId() + ".isAllowed(handle, wm) ) {\n" );
-            compileAlphaNodes( alphaNode.getSinkPropagator(),
-                               indent + 4 );
-            builder.append( getIndent( indent ) + "}\n" );
-        } else if ( sink instanceof BetaNode ) {
-            BetaNode betaNode = (BetaNode) sink;
-            builder.append( getIndent( indent ) + "sink" + betaNode.getId() + ".assertRight(handle, wm, context);\n" );
-        } else if ( sink instanceof LeftInputAdapterNode ) {
-            LeftInputAdapterNode liaNode = (LeftInputAdapterNode) sink;
-            builder.append( getIndent( indent ) + "sink" + liaNode.getId() + ".assertRight(handle, wm, context);\n" );
-        }
-    }
-
-    private String getIndent(int indent) {
-        char[] spaces = new char[indent];
-        for ( int i = 0; i < spaces.length; i++ ) {
-            spaces[i] = ' ';
-        }
-
-        return new String( spaces );
-    }
-
-}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AbstractCompilerHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AbstractCompilerHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AbstractCompilerHandler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,59 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.reteoo.AlphaNode;
+import org.drools.reteoo.Sink;
+
+/**
+ * This handler is used as a base class for all {@link org.drools.reteoo.compiled.NetworkHandler}s used for
+ * generating a compiled network. It provides methods to return the variable type and names used for storing
+ * refernces to different {@link org.drools.common.NetworkNode}s and variable names for {@link ClassFieldReader}s.
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+abstract class AbstractCompilerHandler extends NetworkHandlerAdaptor {
+    protected static final String NEWLINE = "\n";
+
+    private static final String MAP_VARIABLE_NAME_SUFFIX = "ToNodeId";
+
+    protected Class<?> getVariableType(AlphaNode alphaNode) {
+
+        // for alphas, we use the constraint of the alpha for the declaration
+        return alphaNode.getConstraint().getClass();
+    }
+
+    protected Class<?> getVariableType(Sink sink) {
+
+        return sink.getClass();
+    }
+
+    protected String getVariableName(AlphaNode alphaNode) {
+        Class<?> variableType = getVariableType(alphaNode);
+
+        return getVariableName(variableType, alphaNode.getId());
+    }
+
+    protected String getVariableName(Sink sink) {
+        Class<?> variableType = getVariableType(sink);
+
+        return getVariableName(variableType, sink.getId());
+    }
+
+    protected String getVariableName(ClassFieldReader fieldReader) {
+        return fieldReader.getFieldName() + MAP_VARIABLE_NAME_SUFFIX;
+    }
+
+    /**
+     * Returns a variable name based on the simple name of the specified class appended with the specified
+     * nodeId.
+     *
+     * @param clazz  class whose simple name is lowercased and user as the prefix of the variable name
+     * @param nodeId id of {@link org.drools.common.NetworkNode}
+     * @return variable name
+     * @see Class#getSimpleName()
+     */
+    private String getVariableName(Class clazz, int nodeId) {
+        String type = clazz.getSimpleName();
+        return Character.toLowerCase(type.charAt(0)) + type.substring(1) + nodeId;
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AssertHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AssertHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/AssertHandler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,145 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.common.InternalFactHandle;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.reteoo.AlphaNode;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.ObjectTypeNode;
+import org.drools.spi.PropagationContext;
+
+/**
+ * todo: document
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+class AssertHandler extends AbstractCompilerHandler {
+    private static final String LOCAL_FACT_VAR_NAME = "fact";
+
+    private static final String FACT_HANDLE_PARAM_TYPE = InternalFactHandle.class.getName();
+    private static final String PROP_CONTEXT_PARAM_TYPE = PropagationContext.class.getName();
+    private static final String WORKING_MEMORY_PARAM_TYPE = InternalWorkingMemory.class.getName();
+
+    private static final String FACT_HANDLE_PARAM_NAME = "handle";
+    private static final String PROP_CONTEXT_PARAM_NAME = "context";
+    private static final String WORKING_MEMORY_PARAM_NAME = "wm";
+
+    private static final String ASSERT_METHOD_SIGNATURE = "public final void assertObject("
+            + FACT_HANDLE_PARAM_TYPE + " " + FACT_HANDLE_PARAM_NAME + ","
+            + PROP_CONTEXT_PARAM_TYPE + " " + PROP_CONTEXT_PARAM_NAME + ","
+            + WORKING_MEMORY_PARAM_TYPE + " " + WORKING_MEMORY_PARAM_NAME + "){";
+
+    /**
+     * This flag is used to instruct the AssertHandler to tell it to generate a local varible
+     * in the {@link org.drools.reteoo.compiled.CompiledNetwork#assertObject} for holding the value returned
+     * from the {@link org.drools.common.InternalFactHandle#getObject()}.
+     *
+     * This is only needed if there is at least 1 set of hashed alpha nodes in the network
+     */
+    private final boolean alphaNetContainsHashedField;
+
+    private final StringBuilder builder;
+    private final String factClassName;    
+
+    AssertHandler(StringBuilder builder, String factClassName) {
+        this(builder, factClassName, false);
+    }
+
+    AssertHandler(StringBuilder builder, String factClassName, boolean alphaNetContainsHashedField) {
+        this.builder = builder;
+        this.factClassName = factClassName;
+        this.alphaNetContainsHashedField = alphaNetContainsHashedField;
+    }
+
+    @Override
+    public void startObjectTypeNode(ObjectTypeNode objectTypeNode) {
+        builder.append(ASSERT_METHOD_SIGNATURE).append(NEWLINE);
+
+        // we only need to create a reference to the object, not handle, if there is a hashed alpha in the network
+        if (alphaNetContainsHashedField) {
+            // example of what this will look like
+            // ExampleFact fact = (ExampleFact) handle.getObject();
+            builder.append(factClassName).append(" ").append(LOCAL_FACT_VAR_NAME).
+                    append(" = (").append(factClassName).append(")").
+                    append(FACT_HANDLE_PARAM_NAME).append(".getObject();").
+                    append(NEWLINE);
+        }
+    }
+
+    @Override
+    public void startBetaNode(BetaNode betaNode) {
+        builder.append(getVariableName(betaNode)).append(".assertObject(").
+                append(FACT_HANDLE_PARAM_NAME).append(",").
+                append(PROP_CONTEXT_PARAM_NAME).append(",").
+                append(WORKING_MEMORY_PARAM_NAME).append(");").append(NEWLINE);
+    }
+
+    @Override
+    public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+        builder.append(getVariableName(leftInputAdapterNode)).append(".assertObject(").
+                append(FACT_HANDLE_PARAM_NAME).append(",").
+                append(PROP_CONTEXT_PARAM_NAME).append(",").
+                append(WORKING_MEMORY_PARAM_NAME).append(");").append(NEWLINE);
+    }
+
+    @Override
+    public void startNonHashedAlphaNode(AlphaNode alphaNode) {
+        builder.append("if ( ").append(getVariableName(alphaNode)).
+                append(".isAllowed(").append(FACT_HANDLE_PARAM_NAME).append(",").
+                append(WORKING_MEMORY_PARAM_NAME).append(", ").
+                append(getVariableName(alphaNode)).append(".createContextEntry()) ) {").append(NEWLINE);
+
+    }
+
+    @Override
+    public void endNonHashedAlphaNode(AlphaNode alphaNode) {
+        // close if statement
+        builder.append("}").append(NEWLINE);
+    }
+
+    @Override
+    public void startHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
+        String attributeName = hashedFieldReader.getFieldName();
+        String localVariableName = attributeName + "NodeId";
+
+        // todo get accessor smarter because of booleans. Note that right now booleans wouldn't be hashed
+        String attributeGetterName = "get" + Character.toTitleCase(attributeName.charAt(0)) + attributeName.substring(1);
+
+        // get the attribute from the fact that we are switching over
+        builder.append("Integer ").append(localVariableName);
+        // todo we are casting to Integer because generics aren't supported
+        builder.append(" = (Integer)").append(getVariableName(hashedFieldReader)).append(".get(").
+                append(LOCAL_FACT_VAR_NAME).append(".").append(attributeGetterName)
+                .append("());").append(NEWLINE);
+
+        // ensure that the value is present in the node map
+        builder.append("if(").append(localVariableName).append(" != null) {").append(NEWLINE);
+        // todo we had the .intValue() because JANINO has a problem with it
+        builder.append("switch(").append(localVariableName).append(".intValue()) {").append(NEWLINE);
+    }
+
+    @Override
+    public void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+        builder.append("case ").append(hashedAlpha.getId()).append(" : ").append(NEWLINE);
+    }
+
+    @Override
+    public void endHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+        builder.append("break;").append(NEWLINE);
+    }
+
+    @Override
+    public void endHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
+        // close switch statement
+        builder.append("}").append(NEWLINE);
+        // and if statement for ensuring non-null
+        builder.append("}").append(NEWLINE);
+    }
+
+    @Override
+    public void endObjectTypeNode(ObjectTypeNode objectTypeNode) {
+        // close the assertObject method
+        builder.append("}").append(NEWLINE);
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/CompiledNetwork.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/CompiledNetwork.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/CompiledNetwork.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,116 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.common.NetworkNode;
+import org.drools.common.RuleBasePartitionId;
+import org.drools.reteoo.*;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * This is the base type for all generated classes that that represent a "compiled" portion of the RETE network.
+ * By compiled we mean IF statements, switch statements, etc. as opposed to nodes, propagators, etc.
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+public abstract class CompiledNetwork implements ObjectSink {
+
+    private ObjectTypeNode objectTypeNode;
+
+    /**
+     * Returns the unique id that represents the node in the Rete network
+     *
+     * @return unique int value
+     */
+    public int getId() {
+        return objectTypeNode.getId();
+    }
+
+    /**
+     * Returns the partition ID to which this node belongs to
+     *
+     * @return partition id
+     */
+    public RuleBasePartitionId getPartitionId() {
+        return objectTypeNode.getPartitionId();
+    }
+
+    /**
+     * The object implements the writeExternal method to save its contents
+     * by calling the methods of DataOutput for its primitive values or
+     * calling the writeObject method of ObjectOutput for objects, strings,
+     * and arrays.
+     *
+     * @param out the stream to write the object to
+     * @throws java.io.IOException Includes any I/O exceptions that may occur
+     * @serialData Overriding methods should use this tag to describe
+     * the data layout of this Externalizable object.
+     * List the sequence of element types and, if possible,
+     * relate the element to a public/protected field and/or
+     * method of this Externalizable class.
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+        // todo is this needed??
+    }
+
+    /**
+     * The object implements the readExternal method to restore its
+     * contents by calling the methods of DataInput for primitive
+     * types and readObject for objects, strings and arrays.  The
+     * readExternal method must read the values in the same sequence
+     * and with the same types as were written by writeExternal.
+     *
+     * @param in the stream to read data from in order to restore the object
+     * @throws java.io.IOException    if I/O errors occur
+     * @throws ClassNotFoundException If the class for an object being
+     *                                restored cannot be found.
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        // todo is this needed??
+    }
+
+    /**
+     * Sets the OTN for this network. Calling this method will set all variables in the generated subclasses
+     * by walking the {@link org.drools.reteoo.ObjectTypeNode} using a {@link ObjectTypeNodeParser}.
+     * @param objectTypeNode node for whom this network was created
+     */
+    public final void setObjectTypeNode(final ObjectTypeNode objectTypeNode) {
+        this.objectTypeNode = objectTypeNode;
+
+        NodeReferenceSetter setter= new NodeReferenceSetter();
+        ObjectTypeNodeParser parser = new ObjectTypeNodeParser(objectTypeNode);
+        parser.accept(setter);
+    }
+
+    /**
+     * Generated subclasses need to implement this method to set member variables based on the specified
+     * NetworkNode.
+     *
+     * @param networkNode node to set to set
+     */
+    protected abstract void setNetworkNodeReference(NetworkNode networkNode);
+
+    /**
+     * Handler implementation to call {@link CompiledNetwork#setNetworkNodeReference} for each node
+     * encountered in the network.
+     */
+    private class NodeReferenceSetter extends NetworkHandlerAdaptor {
+
+        public void startNonHashedAlphaNode(AlphaNode alphaNode) {
+            setNetworkNodeReference(alphaNode);
+        }
+
+        public void startBetaNode(BetaNode betaNode) {
+            setNetworkNodeReference(betaNode);
+        }
+
+        public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+            setNetworkNodeReference(leftInputAdapterNode);
+        }
+
+        public void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+            setNetworkNodeReference(hashedAlpha);
+        }
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/DeclarationsHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/DeclarationsHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/DeclarationsHandler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,112 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.reteoo.AlphaNode;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.Sink;
+
+import java.util.*;
+
+/**
+ * This handler is used to create the member declarations section of a generated subclass of a {@link CompiledNetwork}.
+ * Currently we only create member variables for the following types of nodes:
+ * <p/>
+ * <li>Non-hashed {@link AlphaNode}s</li>
+ * <li>{@link LeftInputAdapterNode}s</li>
+ * <li>{@link BetaNode}s</li>
+ * <li>A {@link Map} for each set of hashed {@link AlphaNode}s. The keys are the hashed values, and the values are
+ * the IDs of the alphas</li>
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+class DeclarationsHandler extends AbstractCompilerHandler {
+    private static final String PRIVATE_MODIFIER = "private";
+
+    /**
+     * This field keeps track of the current set of hashed AlphaNodes for a ClassReader.
+     *
+     * @see #startHashedAlphaNodes(org.drools.base.ClassFieldReader)
+     * @see #startHashedAlphaNode(org.drools.reteoo.AlphaNode, Object)
+     */
+    private HashedAlphasDeclaration currentHashedAlpha;
+
+    private final StringBuilder builder;
+
+    /**
+     * Keeps track of all the ClassFieldReaders for hashed alphas, and the maps that contain hashed values/node ids
+     * for said alphas.
+     */
+    private final Collection<HashedAlphasDeclaration> hashedAlphaDeclarations;
+
+    DeclarationsHandler(StringBuilder builder) {
+        this.builder = builder;
+        this.hashedAlphaDeclarations = new LinkedList<HashedAlphasDeclaration>();
+    }
+
+    private String getVariableDeclaration(AlphaNode alphaNode) {
+        Class<?> variableType = getVariableType(alphaNode);
+        String variableName = getVariableName(alphaNode);
+        // comment for variable declaration is just the toString of the node
+        String comment = alphaNode.toString();
+
+        return PRIVATE_MODIFIER + " " + variableType.getName() + " " + variableName + "; // " + comment;
+    }
+
+    private String getVariableDeclaration(Sink sink) {
+        Class<?> declarationType = getVariableType(sink);
+        String variableName = getVariableName(sink);
+        // comment for variable declaration is just the toString of the node
+        String comment = sink.toString();
+
+        return PRIVATE_MODIFIER + " " + declarationType.getName() + " " + variableName + "; // " + comment;
+    }
+
+    private String getVariableDeclaration(ClassFieldReader fieldReader) {
+        Class<?> declarationType = Map.class;
+        Class<?> createType = HashMap.class;
+        String variableName = getVariableName(fieldReader);
+
+        // todo JANINO doesn't support generics
+        // return "private java.util.Map<Object,Integer> " + variableName + " = new java.util.HashMap<Object,Integer>();";
+        return PRIVATE_MODIFIER + " " + declarationType.getName() + " " + variableName
+                + " = new " + createType.getName() + "();";
+    }
+
+    Collection<HashedAlphasDeclaration> getHashedAlphaDeclarations() {
+        return Collections.unmodifiableCollection(hashedAlphaDeclarations);
+    }
+
+    @Override
+    public void startNonHashedAlphaNode(AlphaNode alphaNode) {
+        builder.append(getVariableDeclaration(alphaNode)).append(NEWLINE);
+    }
+
+    @Override
+    public void startBetaNode(BetaNode betaNode) {
+        builder.append(getVariableDeclaration(betaNode)).append(NEWLINE);
+    }
+
+    @Override
+    public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+        builder.append(getVariableDeclaration(leftInputAdapterNode)).append(NEWLINE);
+    }
+
+    @Override
+    public void startHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
+        // we create a new hashed alpha that will be used to keep track of the hashes values to node ID for each
+        // class field reader.
+        currentHashedAlpha = new HashedAlphasDeclaration(getVariableName(hashedFieldReader),
+                hashedFieldReader.getValueType());
+
+        // add the new declaration
+        hashedAlphaDeclarations.add(currentHashedAlpha);
+
+        builder.append(getVariableDeclaration(hashedFieldReader)).append(NEWLINE);
+    }
+
+    @Override
+    public void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+        currentHashedAlpha.add(hashedValue, String.valueOf(hashedAlpha.getId()));
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/HashedAlphasDeclaration.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/HashedAlphasDeclaration.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/HashedAlphasDeclaration.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,50 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ValueType;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * This class is used to hold information for Hashed {@link org.drools.reteoo.AlphaNode}s for generated subclasses
+ * of {@link CompiledNetwork}.
+ *
+ * @see org.drools.reteoo.compiled.DeclarationsHandler
+ */
+class HashedAlphasDeclaration {
+    private final String variableName;
+    private final ValueType valueType;
+
+    /**
+     * This map contains keys which are different values of the same field and the node id that of the
+     * {@link org.drools.common.NetworkNode} the value is from.
+     */
+    private final Map<Object, String> hashedValuesToNodeIds = new HashMap<Object, String>();
+
+    HashedAlphasDeclaration(String variableName,ValueType valueType) {
+        this.variableName = variableName;
+        this.valueType = valueType;
+    }
+
+    ValueType getValueType() {
+        return valueType;
+    }
+
+    String getVariableName() {
+        return variableName;
+    }
+
+    void add(Object hashedValue, String nodeId) {
+        hashedValuesToNodeIds.put(hashedValue,  nodeId);
+    }
+
+    Collection<Object> getHashedValues() {
+        return Collections.unmodifiableSet(hashedValuesToNodeIds.keySet());
+    }
+
+    String getNodeId(Object hashedValue) {
+        return hashedValuesToNodeIds.get(hashedValue);
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,80 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.reteoo.AlphaNode;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.ObjectTypeNode;
+
+/**
+ * Receive notification of the logical parts of the RETE-OO network.
+ * todo: finish documenting 
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+public interface NetworkHandler {
+
+    /**
+     * Receive notification of the beginning of an {@link org.drools.reteoo.ObjectTypeNode}
+     *
+     * <p>The Network parser will invoke this method only once, before any other event callback.</p>
+     *
+     * @param objectTypeNode the object type node
+     * @see #endObjectTypeNode(org.drools.reteoo.ObjectTypeNode)
+     */
+    void startObjectTypeNode(ObjectTypeNode objectTypeNode);
+
+    /**
+     * Receive notification of the a non-hashed {@link org.drools.reteoo.AlphaNode}.
+     *
+     * <p>The Parser will invoke this method at the beginning of every non-hashed Alpha in the Network;
+     * there will be a corresponding endNonHashedAlphaNode() event for every startNonHashedAlphaNode() event.
+     * All of the node's decendants will be reported, in order, before the corresponding endNonHashedAlphaNode()
+     * event.</p>
+     *
+     * @param alphaNode non-hashed AlphaNode
+     * @see #endNonHashedAlphaNode
+     */
+    void startNonHashedAlphaNode(AlphaNode alphaNode);
+
+    /**
+     * Receive notification of the end of a non-hashed {@link org.drools.reteoo.AlphaNode}.
+     *
+     * <p>The parser will invoke this method at the end of every alpha in the network; there will be a corresponding
+     * {@link #startNonHashedAlphaNode(org.drools.reteoo.AlphaNode)} event for every endNonHashedAlphaNode event.</p>
+     *
+     * @param alphaNode non-hashed AlphaNode
+     */
+    void endNonHashedAlphaNode(AlphaNode alphaNode);
+
+    void startBetaNode(BetaNode betaNode);
+
+    void endBetaNode(BetaNode betaNode);
+
+    void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode);
+
+    void endLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode);
+
+    /**
+     * Receive notification of the a group of hashed {@link org.drools.reteoo.AlphaNode}s.
+     *
+     * <p>The Parser will invoke this method at the beginning of every groups of hashed Alphas in the Network;
+     * there will be a corresponding {@link #endHashedAlphaNodes} event for every startHashedAlphaNodes() event.
+     *
+     * The actual alpha nodes will be reported via the {@link #startHashedAlphaNode} method, along with all of the
+     * node's decendants, in order, before the corresponding {@link #endHashedAlphaNode}
+     * event.</p>
+     *
+     * @param hashedFieldReader field reader that is used to access the hashed attribute
+     * @see #endHashedAlphaNodes
+     * @see #startHashedAlphaNode
+     */
+    void startHashedAlphaNodes(ClassFieldReader hashedFieldReader);
+
+    void endHashedAlphaNodes(ClassFieldReader hashedFieldReader);
+
+    void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue);
+
+    void endHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue);
+
+    void endObjectTypeNode(ObjectTypeNode objectTypeNode);
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandlerAdaptor.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandlerAdaptor.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/NetworkHandlerAdaptor.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,70 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.reteoo.AlphaNode;
+import org.drools.reteoo.BetaNode;
+import org.drools.reteoo.LeftInputAdapterNode;
+import org.drools.reteoo.ObjectTypeNode;
+
+/**
+ * An abstract adapter class for receiving network node events from the {@link org.drools.reteoo.compiled.ObjectTypeNodeParser}.
+ * The methods in this class are empty. This class exists as convenience for creating handler objects.
+ * <P>
+ * Extend this class to create a <code>NetworkHandler</code> and override the methods for the nodes of interest.
+ * (If you implement the {@link NetworkHandler} interface, you have to define all of the methods in it. This
+ * abstract class defines null methods for them all, so you can only have to define methods for events you care about.)
+ * <P>
+ * @see org.drools.reteoo.compiled.NetworkHandler
+ * @see org.drools.reteoo.compiled.ObjectTypeNodeParser
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+public class NetworkHandlerAdaptor implements NetworkHandler {
+    public void startObjectTypeNode(ObjectTypeNode objectTypeNode) {
+
+    }
+
+    public void startNonHashedAlphaNode(AlphaNode alphaNode) {
+
+    }
+
+    public void endNonHashedAlphaNode(AlphaNode alphaNode) {
+
+    }
+
+    public void startBetaNode(BetaNode betaNode) {
+
+    }
+
+    public void endBetaNode(BetaNode betaNode) {
+
+    }
+
+    public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+
+    }
+
+    public void endLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+
+    }
+
+    public void startHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
+
+    }
+
+    public void endHashedAlphaNodes(ClassFieldReader hashedFieldReader) {
+
+    }
+
+    public void startHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+
+    }
+
+    public void endHashedAlphaNode(AlphaNode hashedAlpha, Object hashedValue) {
+
+    }
+
+    public void endObjectTypeNode(ObjectTypeNode objectTypeNode) {
+
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeParser.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeParser.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/ObjectTypeNodeParser.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,202 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.base.ClassFieldReader;
+import org.drools.reteoo.*;
+import org.drools.rule.LiteralConstraint;
+import org.drools.spi.AlphaNodeFieldConstraint;
+import org.drools.util.Iterator;
+import org.drools.util.ObjectHashMap;
+
+/**
+ * This class is used for reading an {@link ObjectTypeNode} using callbacks.
+ * <p/>
+ * The user defines a number of callback methods in a {@link NetworkHandler} that will be called when events occur
+ * during parsing. The events include :
+ * <li>ObjectTypeNode</li>
+ * <li>Non-hashed and hashed AlphaNodes</li>
+ * <li>BetaNodes</li>
+ * <li>LeftInputAdapterNodes</li>
+ * <p/>
+ * Events are fired when each of these network features are encountered, and again when the end of them is encountered.
+ * OTN parsing is unidirectional; previously parsed data cannot be re-read without starting the parsing operation again.
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+public class ObjectTypeNodeParser {
+
+    /**
+     * OTN we are parsing/traversing
+     */
+    private final ObjectTypeNode objectTypeNode;
+
+    /**
+     * Creates a new parser for the specified ObjectTypeNode
+     *
+     * @param objectTypeNode otn to parse
+     */
+    public ObjectTypeNodeParser(ObjectTypeNode objectTypeNode) {
+        this.objectTypeNode = objectTypeNode;
+    }
+
+    /**
+     * Parse the {@link #objectTypeNode}.
+     * <p/>
+     * <p>The application can use this method to instruct the OTN parser to begin parsing an {@link ObjectTypeNode}.</p>
+     * <p/>
+     * Once a parse is complete, an application may reuse the same Parser object, possibly with a different
+     * {@link NetworkHandler}.</p>
+     *
+     * @param handler handler that will receieve the events generated by this parser
+     * @see NetworkHandler
+     */
+    public void accept(NetworkHandler handler) {
+        ObjectSinkPropagator propagator = objectTypeNode.getSinkPropagator();
+
+        handler.startObjectTypeNode(objectTypeNode);
+        traversePropagator(propagator, handler);
+        handler.endObjectTypeNode(objectTypeNode);
+    }
+
+    private void traversePropagator(ObjectSinkPropagator propagator, NetworkHandler handler) {
+        if (propagator instanceof SingleObjectSinkAdapter) {
+            // we know there is only a single child sink for this propagator
+            ObjectSink sink = propagator.getSinks()[0];
+
+            traverseSink(sink, handler);
+        } else if (propagator instanceof CompositeObjectSinkAdapter) {
+            CompositeObjectSinkAdapter composite = (CompositeObjectSinkAdapter) propagator;
+
+            traverseSinkLisk(composite.getHashableSinks(), handler);
+            traverseSinkLisk(composite.getOthers(), handler);
+            traverseHashedAlphaNodes(composite.getHashedSinkMap(), handler);
+        }
+    }
+
+    private void traversePropagator(LeftTupleSinkPropagator propagator, NetworkHandler handler) {
+        if (propagator instanceof SingleLeftTupleSinkAdapter) {
+            // we know there is only a single child sink for this propagator
+            LeftTupleSink sink = propagator.getSinks()[0];
+
+            traverseSink(sink, handler);
+        } else if (propagator instanceof CompositeLeftTupleSinkAdapter) {
+            CompositeLeftTupleSinkAdapter composite = (CompositeLeftTupleSinkAdapter) propagator;
+
+            LeftTupleSink[] sinks = composite.getSinks();
+            traverseSinkLisk(sinks, handler);
+        }
+    }
+
+    private void traverseSinkLisk(ObjectSinkNodeList sinks, NetworkHandler handler) {
+        if (sinks != null) {
+            for (ObjectSinkNode sink = sinks.getFirst(); sink != null; sink = sink.getNextObjectSinkNode()) {
+
+                traverseSink(sink, handler);
+            }
+        }
+    }
+
+    private void traverseSinkLisk(LeftTupleSink[] sinks, NetworkHandler handler) {
+        if (sinks != null) {
+            for (int sinkIndex = 0; sinkIndex < sinks.length; ++sinkIndex) {
+                traverseSink(sinks[sinkIndex], handler);
+            }
+        }
+    }
+
+    private void traverseHashedAlphaNodes(ObjectHashMap hashedAlphaNodes, NetworkHandler handler) {
+        if (hashedAlphaNodes != null && hashedAlphaNodes.size() > 0) {
+            AlphaNode firstAlpha = getFirstAlphaNode(hashedAlphaNodes);
+            ClassFieldReader hashedFieldReader = getClassFieldReaderForHashedAlpha(firstAlpha);
+
+            // start the hashed alphas
+            handler.startHashedAlphaNodes(hashedFieldReader);
+
+            Iterator iter = hashedAlphaNodes.iterator();
+            for (ObjectHashMap.ObjectEntry entry = (ObjectHashMap.ObjectEntry) iter.next(); entry != null; entry = (ObjectHashMap.ObjectEntry) iter.next()) {
+                CompositeObjectSinkAdapter.HashKey hashKey = (CompositeObjectSinkAdapter.HashKey) entry.getKey();
+                AlphaNode alphaNode = (AlphaNode) entry.getValue();
+
+                handler.startHashedAlphaNode(alphaNode, hashKey.getObjectValue());
+                // traverse the propagator for each alpha
+                traversePropagator(alphaNode.getSinkPropagator(), handler);
+
+                handler.endHashedAlphaNode(alphaNode, hashKey.getObjectValue());
+            }
+
+            // end of the hashed alphas
+            handler.endHashedAlphaNodes(hashedFieldReader);
+        }
+    }
+
+    private void traverseSink(ObjectSink sink, NetworkHandler handler) {
+        if (sink instanceof AlphaNode) {
+            AlphaNode alphaNode = (AlphaNode) sink;
+
+            handler.startNonHashedAlphaNode(alphaNode);
+
+            traversePropagator(alphaNode.getSinkPropagator(), handler);
+
+            handler.endNonHashedAlphaNode(alphaNode);
+        } else if (sink instanceof BetaNode) {
+            BetaNode betaNode = (BetaNode) sink;
+
+            handler.startBetaNode(betaNode);
+            // todo traverse beta
+            handler.endBetaNode(betaNode);
+        } else if (sink instanceof LeftInputAdapterNode) {
+            LeftInputAdapterNode leftInputAdapterNode = (LeftInputAdapterNode) sink;
+
+            handler.startLeftInputAdapterNode(leftInputAdapterNode);
+            // todo traverse lia
+            handler.endLeftInputAdapterNode(leftInputAdapterNode);
+        }
+    }
+
+    private void traverseSink(LeftTupleSink sink, NetworkHandler handler) {
+        // todo traverse sink's propagator
+    }
+
+    /**
+     * Returns the first {@link org.drools.reteoo.AlphaNode} from the specified {@link ObjectHashMap}.
+     *
+     * @param hashedAlphaNodes map of hashed AlphaNodes
+     * @return first alpha from the specified map
+     * @throws IllegalArgumentException thrown if the map doesn't contain any alpha nodes
+     */
+    private AlphaNode getFirstAlphaNode(final ObjectHashMap hashedAlphaNodes) throws IllegalArgumentException {
+        AlphaNode firstAlphaNode;
+
+        final Iterator iter = hashedAlphaNodes.iterator();
+        final ObjectHashMap.ObjectEntry entry = (ObjectHashMap.ObjectEntry) iter.next();
+
+        if (entry != null) {
+            firstAlphaNode = (AlphaNode) entry.getValue();
+        } else {
+            throw new IllegalArgumentException("ObjectHashMap does not contain any hashed AlphaNodes!");
+        }
+
+        return firstAlphaNode;
+    }
+
+    /**
+     * Returns the {@link ClassFieldReader} for the hashed AlphaNode. The AlphaNode's constraint has to be a
+     * LiteralConstraint. This is the only type of hashed alpha currently supported.
+     *
+     * @param alphaNode hashed alpha to get reader for
+     * @return ClassFieldReader
+     * @throws IllegalArgumentException thrown if the AlphaNode's {@link org.drools.spi.AlphaNodeFieldConstraint} is not a
+     *                                  {@link org.drools.rule.LiteralConstraint}.
+     */
+    private ClassFieldReader getClassFieldReaderForHashedAlpha(final AlphaNode alphaNode) throws IllegalArgumentException {
+        final AlphaNodeFieldConstraint fieldConstraint = alphaNode.getConstraint();
+
+        if (!(fieldConstraint instanceof LiteralConstraint)) {
+            throw new IllegalArgumentException("Only support LiteralConstraint hashed AlphaNodes, not " + fieldConstraint.getClass());
+        }
+        // we need to get the first alpha in the map to get the attribute name that be use for the prefix of the
+        // generated variable name
+        final LiteralConstraint literalConstraint = (LiteralConstraint) alphaNode.getConstraint();
+
+        return (ClassFieldReader) literalConstraint.getFieldExtractor();
+    }
+}

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/SetNodeReferenceHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/SetNodeReferenceHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/compiled/SetNodeReferenceHandler.java	2009-07-17 01:22:31 UTC (rev 28125)
@@ -0,0 +1,101 @@
+package org.drools.reteoo.compiled;
+
+import org.drools.common.NetworkNode;
+import org.drools.reteoo.*;
+
+/**
+ * This handler is used to create the member variable assignment statements section of a generated subclass of a
+ * {@link CompiledNetwork#setNetworkNodeReference(org.drools.common.NetworkNode)}.
+ * Currently we only need to create member variable assignments for the following types of nodes:
+ * <p/>
+ * <li>Non-hashed {@link AlphaNode}s</li>
+ * <li>{@link LeftInputAdapterNode}s</li>
+ * <li>{@link BetaNode}s</li>
+ *
+ * @author <a href="mailto:stampy88 at yahoo.com">dave sinclair</a>
+ */
+class SetNodeReferenceHandler extends AbstractCompilerHandler {
+
+    private static final String PARAM_TYPE = NetworkNode.class.getName();
+    private static final String PARAM_NAME = "node";
+    private static final String SET_NETWORK_NODE_REFERENCE_SIGNATURE = "protected void setNetworkNodeReference("
+            + PARAM_TYPE + " " + PARAM_NAME + "){";
+
+    private final StringBuilder builder;
+
+    SetNodeReferenceHandler(StringBuilder builder) {
+        this.builder = builder;
+    }
+
+    private String getVariableAssignmentStatement(Sink sink, String nodeVariableName) {
+        Class<?> variableType = getVariableType(sink);
+        String assignmentStatement;
+
+        // for non alphas, we just need to cast to the right variable type
+        assignmentStatement = getVariableName(sink) + " = (" + variableType.getName() + ")" + nodeVariableName + ";";
+
+        return assignmentStatement;
+    }
+
+    private String getVariableAssignmentStatement(AlphaNode alphaNode, String nodeVariableName) {
+        Class<?> variableType = getVariableType(alphaNode);
+        String assignmentStatement;
+
+        // we need the constraint for an alpha node assignment, so generate a cast, plus the method call to get
+        // the constraint
+        assignmentStatement = getVariableName(alphaNode) + " = (" + variableType.getName() + ") ((" + AlphaNode.class.getName() + ")" + nodeVariableName + ").getConstraint();";
+
+        return assignmentStatement;
+    }
+
+
+    @Override
+    public void startObjectTypeNode(ObjectTypeNode objectTypeNode) {
+        builder.append(SET_NETWORK_NODE_REFERENCE_SIGNATURE).append(NEWLINE);
+        // we are switch based on the parameter's node ID
+        builder.append("switch (").append(PARAM_NAME).append(".getId()) {").append(NEWLINE);
+    }
+
+    @Override
+    public void endObjectTypeNode(ObjectTypeNode objectTypeNode) {
+        // close the switch
+        builder.append("}").append(NEWLINE);
+        // and close the setNetworkNodeReference method
+        builder.append("}").append(NEWLINE);
+    }
+
+    @Override
+    public void startNonHashedAlphaNode(AlphaNode alphaNode) {
+        // case statement for the non-hashed alphas looks like the following
+        // case 24:
+        //      variableConstraint24 = (VariableConstraint) ((AlphaNode) node).getConstraint();
+        //      break;
+
+        builder.append("case ").append(alphaNode.getId()).append(": ").append(NEWLINE);
+        builder.append(getVariableAssignmentStatement(alphaNode, PARAM_NAME)).append(NEWLINE);
+        builder.append("break;").append(NEWLINE);
+    }
+
+    @Override
+    public void startBetaNode(BetaNode betaNode) {
+        // case statement for the betas looks like the following
+        // case 65:
+        //      notNode65 = (NodeNode) node;
+        //      break;
+
+        builder.append("case ").append(betaNode.getId()).append(": ").append(NEWLINE);
+        builder.append(getVariableAssignmentStatement(betaNode, PARAM_NAME)).append(NEWLINE);
+        builder.append("break;").append(NEWLINE);
+    }
+
+    @Override
+    public void startLeftInputAdapterNode(LeftInputAdapterNode leftInputAdapterNode) {
+        // case statement for the lias looks like the following
+        // case 5:
+        //      leftInputAdapterNode5 = (LeftInputAdapterNode) node;
+        //      break;
+        builder.append("case ").append(leftInputAdapterNode.getId()).append(": ").append(NEWLINE);
+        builder.append(getVariableAssignmentStatement(leftInputAdapterNode, PARAM_NAME)).append(NEWLINE);
+        builder.append("break;").append(NEWLINE);
+    }
+}



More information about the jboss-svn-commits mailing list