[jboss-svn-commits] JBL Code SVN: r8218 - in labs/jbossrules/trunk: drools-compiler/src/main/java/org/drools/semantics/java drools-compiler/src/test/java/org/drools/compiler drools-core/src/main/java/org/drools/reteoo drools-core/src/main/java/org/drools/rule drools-core/src/test/java/org/drools/examples/manners drools-core/src/test/java/org/drools/rule drools-core/src/test/resources

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Dec 11 06:58:13 EST 2006


Author: tirelli
Date: 2006-12-11 06:57:51 -0500 (Mon, 11 Dec 2006)
New Revision: 8218

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElementFactory.java
Removed:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/And.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Exists.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Not.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Or.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Column.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElement.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/LogicTransformer.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Rule.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/examples/manners/BaseMannersTest.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/GroupElementTest.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/LogicTransformerTest.java
   labs/jbossrules/trunk/drools-core/src/test/resources/correct_processTree1.dat
   labs/jbossrules/trunk/drools-core/src/test/resources/correct_transform1.dat
Log:
JBRULES-218: refactoring logical transformation to allow future development of forall

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -28,16 +28,13 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.antlr.runtime.ANTLRReaderStream;
 import org.antlr.runtime.ANTLRStringStream;
-import org.antlr.runtime.CharStream;
 import org.antlr.runtime.CommonTokenStream;
 import org.antlr.runtime.TokenStream;
 import org.antlr.stringtemplate.StringTemplate;
 import org.antlr.stringtemplate.StringTemplateGroup;
 import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
 import org.codehaus.jfdi.interpreter.TypeResolver;
-import org.codehaus.jfdi.interpreter.operations.Expr;
 import org.codehaus.jfdi.parser.JFDILexer;
 import org.codehaus.jfdi.parser.JFDIParser;
 import org.drools.RuntimeDroolsException;
@@ -49,12 +46,6 @@
 import org.drools.base.ValueType;
 import org.drools.base.dataproviders.JFDIDataProvider;
 import org.drools.base.evaluators.Operator;
-import org.drools.base.resolvers.DeclarationVariable;
-import org.drools.base.resolvers.GlobalVariable;
-import org.drools.base.resolvers.ListValue;
-import org.drools.base.resolvers.LiteralValue;
-import org.drools.base.resolvers.MapValue;
-import org.drools.base.resolvers.ValueHandler;
 import org.drools.compiler.RuleError;
 import org.drools.facttemplates.FactTemplate;
 import org.drools.facttemplates.FactTemplateFieldExtractor;
@@ -83,20 +74,17 @@
 import org.drools.lang.descr.RuleDescr;
 import org.drools.lang.descr.VariableRestrictionDescr;
 import org.drools.rule.Accumulate;
-import org.drools.rule.And;
 import org.drools.rule.AndCompositeRestriction;
 import org.drools.rule.Collect;
 import org.drools.rule.Column;
 import org.drools.rule.Declaration;
 import org.drools.rule.EvalCondition;
-import org.drools.rule.Exists;
 import org.drools.rule.From;
 import org.drools.rule.GroupElement;
+import org.drools.rule.GroupElementFactory;
 import org.drools.rule.LiteralConstraint;
 import org.drools.rule.LiteralRestriction;
 import org.drools.rule.MultiRestrictionFieldConstraint;
-import org.drools.rule.Not;
-import org.drools.rule.Or;
 import org.drools.rule.OrCompositeRestriction;
 import org.drools.rule.Package;
 import org.drools.rule.PredicateConstraint;
@@ -270,7 +258,7 @@
             final Object object = it.next();
             if ( object instanceof ConditionalElementDescr ) {
                 if ( object.getClass() == AndDescr.class ) {
-                    final And and = new And();
+                    final GroupElement and = GroupElementFactory.newAndInstance();
                     build( this.rule,
                            (ConditionalElementDescr) object,
                            and,
@@ -278,7 +266,7 @@
                            false ); // do not decrement first offset
                     this.rule.addPattern( and );
                 } else if ( object.getClass() == OrDescr.class ) {
-                    final Or or = new Or();
+                    final GroupElement or = GroupElementFactory.newOrInstance();
                     build( this.rule,
                            (ConditionalElementDescr) object,
                            or,
@@ -288,7 +276,7 @@
                 } else if ( object.getClass() == NotDescr.class ) {
                     // We cannot have declarations created inside a not visible outside it, so track no declarations so they can be removed
                     this.innerDeclarations = new HashMap();
-                    final Not not = new Not();
+                    final GroupElement not = GroupElementFactory.newNotInstance();
                     build( this.rule,
                            (ConditionalElementDescr) object,
                            not,
@@ -306,7 +294,7 @@
                     // We cannot have declarations created inside exists visible outside it, 
                     // so track declarations in a way they can be removed
                     this.innerDeclarations = new HashMap();
-                    final Exists exists = new Exists();
+                    final GroupElement exists = GroupElementFactory.newExistsInstance();
                     build( this.rule,
                            (ConditionalElementDescr) object,
                            exists,
@@ -360,7 +348,7 @@
             final Object object = it.next();
             if ( object instanceof ConditionalElementDescr ) {
                 if ( object.getClass() == AndDescr.class ) {
-                    final And and = new And();
+                    final GroupElement and = GroupElementFactory.newAndInstance();
                     build( rule,
                            (ConditionalElementDescr) object,
                            and,
@@ -368,7 +356,7 @@
                            false ); // do not decrement first offset
                     ce.addChild( and );
                 } else if ( object.getClass() == OrDescr.class ) {
-                    final Or or = new Or();
+                    final GroupElement or = GroupElementFactory.newOrInstance();
                     build( rule,
                            (ConditionalElementDescr) object,
                            or,
@@ -376,7 +364,7 @@
                            false ); // do not decrement first offset
                     ce.addChild( or );
                 } else if ( object.getClass() == NotDescr.class ) {
-                    final Not not = new Not();
+                    final GroupElement not = GroupElementFactory.newNotInstance();
                     build( rule,
                            (ConditionalElementDescr) object,
                            not,
@@ -384,7 +372,7 @@
                            true ); // when NOT is used, offset MUST be decremented for first column
                     ce.addChild( not );
                 } else if ( object.getClass() == ExistsDescr.class ) {
-                    final Exists exists = new Exists();
+                    final GroupElement exists = GroupElementFactory.newExistsInstance();
                     build( rule,
                            (ConditionalElementDescr) object,
                            exists,

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -62,14 +62,11 @@
 import org.drools.lang.descr.ReturnValueRestrictionDescr;
 import org.drools.lang.descr.RuleDescr;
 import org.drools.reteoo.ReteooRuleBase;
-import org.drools.rule.And;
 import org.drools.rule.Column;
 import org.drools.rule.Declaration;
 import org.drools.rule.EvalCondition;
-import org.drools.rule.Exists;
+import org.drools.rule.GroupElement;
 import org.drools.rule.LiteralConstraint;
-import org.drools.rule.Not;
-import org.drools.rule.Or;
 import org.drools.rule.Package;
 import org.drools.rule.PredicateConstraint;
 import org.drools.rule.ReturnValueConstraint;
@@ -569,11 +566,11 @@
         assertLength( 0,
                       builder.getErrors() );
 
-        final And lhs = rule.getLhs();
+        final GroupElement lhs = rule.getLhs();
         assertLength( 1,
                       lhs.getChildren() );
 
-        final Or or = (Or) lhs.getChildren().get( 0 );
+        final GroupElement or = (GroupElement) lhs.getChildren().get( 0 );
         assertLength( 1,
                       or.getChildren() );
         final Column column = (Column) or.getChildren().get( 0 );
@@ -589,11 +586,11 @@
         assertLength( 0,
                       builder.getErrors() );
 
-        final And lhs = rule.getLhs();
+        final GroupElement lhs = rule.getLhs();
         assertLength( 1,
                       lhs.getChildren() );
 
-        final And and = (And) lhs.getChildren().get( 0 );
+        final GroupElement and = (GroupElement) lhs.getChildren().get( 0 );
         assertLength( 1,
                       and.getChildren() );
         final Column column = (Column) and.getChildren().get( 0 );
@@ -618,11 +615,11 @@
         assertEquals( 0,
                       builder.getErrors().length );
 
-        final And lhs = rule.getLhs();
+        final GroupElement lhs = rule.getLhs();
         assertLength( 1,
                       lhs.getChildren() );
 
-        final Not not = (Not) lhs.getChildren().get( 0 );
+        final GroupElement not = (GroupElement) lhs.getChildren().get( 0 );
         assertLength( 1,
                       not.getChildren() );
         final Column column = (Column) not.getChildren().get( 0 );
@@ -647,11 +644,11 @@
         assertEquals( 0,
                       builder.getErrors().length );
 
-        final And lhs = rule.getLhs();
+        final GroupElement lhs = rule.getLhs();
         assertLength( 1,
                       lhs.getChildren() );
 
-        final Exists exists = (Exists) lhs.getChildren().get( 0 );
+        final GroupElement exists = (GroupElement) lhs.getChildren().get( 0 );
         assertLength( 1,
                       exists.getChildren() );
         final Column column = (Column) exists.getChildren().get( 0 );

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ReteooBuilder.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -43,17 +43,14 @@
 import org.drools.common.SingleBetaConstraints;
 import org.drools.common.TripleBetaConstraints;
 import org.drools.rule.Accumulate;
-import org.drools.rule.And;
 import org.drools.rule.Collect;
 import org.drools.rule.Column;
 import org.drools.rule.Declaration;
 import org.drools.rule.EvalCondition;
-import org.drools.rule.Exists;
 import org.drools.rule.From;
 import org.drools.rule.GroupElement;
 import org.drools.rule.InvalidPatternException;
 import org.drools.rule.LiteralConstraint;
-import org.drools.rule.Not;
 import org.drools.rule.Query;
 import org.drools.rule.Rule;
 import org.drools.spi.AlphaNodeFieldConstraint;
@@ -165,7 +162,7 @@
         this.currentOffsetAdjustment = 0;
 
         final List nodes = new ArrayList();
-        final And[] and = rule.getTransformedLhs();
+        final GroupElement[] and = rule.getTransformedLhs();
 
         for ( int i = 0; i < and.length; i++ ) {
             if ( !hasColumns( and[i] ) ) {
@@ -216,12 +213,12 @@
         return false;
     }
 
-    private void addInitialFactMatch(final And and) {
-        And temp = null;
+    private void addInitialFactMatch(final GroupElement and) {
+        GroupElement temp = null;
 
         // If we have children we know there are no columns but we need to make sure that InitialFact is first
         if ( !and.getChildren().isEmpty() ) {
-            temp = (And) and.clone();
+            temp = (GroupElement) and.clone();
             and.getChildren().clear();
         }
         final Column column = new Column( 0,
@@ -235,7 +232,7 @@
         this.currentOffsetAdjustment = 1;
     }
 
-    private void addRule(final And and,
+    private void addRule(final GroupElement and,
                          final Rule rule) throws InvalidPatternException {
         this.objectSource = null;
         this.tupleSource = null;
@@ -317,16 +314,16 @@
                                        this.removeIdentities );
             }
 
-            if ( object.getClass() == Not.class ) {
+            if (( object instanceof GroupElement ) && (((GroupElement)object).isNot())) {
                 attachNot( this.tupleSource,
-                           (Not) object,
+                           (GroupElement) object,
                            this.objectSource,
                            binder,
                            column );
                 binder = null;
-            } else if ( object.getClass() == Exists.class ) {
+            } else if (( object instanceof GroupElement ) && (((GroupElement)object).isExists())) {
                 attachExists( this.tupleSource,
-                              (Exists) object,
+                              (GroupElement) object,
                               this.objectSource,
                               binder,
                               column );
@@ -470,7 +467,7 @@
     }
 
     private void attachNot(final TupleSource tupleSource,
-                           final Not not,
+                           final GroupElement not,
                            final ObjectSource ObjectSource,
                            final BetaConstraints binder,
                            final Column column) {
@@ -482,7 +479,7 @@
     }
 
     private void attachExists(final TupleSource tupleSource,
-                              final Exists exists,
+                              final GroupElement exists,
                               final ObjectSource ObjectSource,
                               final BetaConstraints binder,
                               final Column column) {
@@ -597,7 +594,7 @@
     }
 
     private void attachAccumulate(final TupleSource tupleSource,
-                                  final And parent,
+                                  final GroupElement parent,
                                   final Accumulate accumulate) {
         // If a tupleSource does not exist then we need to adapt an
         // InitialFact into a a TupleSource using LeftInputAdapterNode
@@ -668,7 +665,7 @@
     }
 
     private void attachCollect(final TupleSource tupleSource,
-                               final And parent,
+                               final GroupElement parent,
                                final Collect collect) {
         // If a tupleSource does not exist then we need to adapt an
         // InitialFact into a a TupleSource using LeftInputAdapterNode

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/And.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/And.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/And.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -1,26 +0,0 @@
-package org.drools.rule;
-
-/*
- * Copyright 2005 JBoss Inc
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class And extends GroupElement {
-
-    /**
-     * 
-     */
-    private static final long serialVersionUID = -218170444675103882L;
-
-}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Column.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Column.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Column.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -146,7 +146,7 @@
     }
 
     public String toString() {
-        return "Column type='" + this.objectType + "', index='" + this.index + "', offset='" + this.getOffset() + "', identifer='" + this.declaration.getIdentifier() + "'";
+        return "Column type='" + ((this.objectType == null) ? "null" : this.objectType.toString()) + "', index='" + this.index + "', offset='" + this.getOffset() + "', identifer='" + ((this.declaration == null) ? "" : this.declaration.toString()) + "'";
     }
 
     public int hashCode() {
@@ -155,7 +155,7 @@
         result = PRIME * result + this.constraints.hashCode();
         result = PRIME * result + ((this.declaration == null) ? 0 : this.declaration.hashCode());
         result = PRIME * result + this.index;
-        result = PRIME * result + this.objectType.hashCode();
+        result = PRIME * result + ((this.objectType == null) ? 0 : this.objectType.hashCode());
         result = PRIME * result + this.offset;
         return result;
     }

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Exists.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Exists.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Exists.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -1,28 +0,0 @@
-package org.drools.rule;
-
-/*
- * Copyright 2005 JBoss Inc
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Exists extends GroupElement {
-    /**
-     * 
-     */
-    private static final long serialVersionUID = 320;
-
-    public Object getChild() {
-        return getChildren().get( 0 );
-    }
-}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElement.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElement.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElement.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -16,77 +16,46 @@
  * limitations under the License.
  */
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
-public abstract class GroupElement extends ConditionalElement {
-    private final List children = new ArrayList();
+import org.drools.RuntimeDroolsException;
 
+public class GroupElement extends ConditionalElement {
+
+    private static final long serialVersionUID = 125354210439500614L;
+
+    public static final Type  AND              = new AndType();
+    public static final Type  OR               = new OrType();
+    public static final Type  EXISTS           = new ExistsType();
+    public static final Type  NOT              = new NotType();
+
+    private Type              type             = null;
+    private final List        children         = new ArrayList();
+
+    public GroupElement() {
+        this( AND );
+    }
+
+    public GroupElement(Type type) {
+        this.type = type;
+    }
+
     /**
-     * This removes single branch 'and' and 'or'
-     * It also does basic nested removal, where an 'and' is
-     * nested inside an 'and' and when an 'or' is nested inside an 'or'
+     * Adds a child to the current GroupElement.
      * 
-     *  LogicTransformer does further, more complicated, transformations
+     * Restrictions are:
+     * NOT/EXISTS: can have only one child, either a single Pattern or another CE
+     * 
      * @param child
      */
     public void addChild(final Object child) {
-        // @todo : I've commented this out for 3.0, but we want this working for 3.1
-        //        if ( child instanceof Not ) {
-        //            Not not = ( Not )  child;
-        //            Object notChild = not.getChild();
-        //            if ( notChild instanceof Or ) {
-        //                Or or = (Or) notChild;
-        //                And and = new And();
-        //                for ( Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
-        //                    Not newNot = new Not();
-        //                    newNot.addChild( it.next() );
-        //                    and.addChild( newNot );
-        //                }                
-        //                child = and;
-        //            } else if ( notChild instanceof And ) {
-        //                
-        //            }            
-        //        }
-
-        //@todo make this work for 3.1
-        //        if ( child instanceof GroupElement && ( child instanceof And || child instanceof Or ) ) {
-        //            GroupElement group = ( GroupElement )  child;
-        //            
-        //            // Removal single branch group elements 
-        //            // If the child is a GroupElement iterate down until we either
-        //            // find a GroupElement that has more than one children, or its not a GroupElement            
-        //            if (  group.getChildren().size() == 1 ) {
-        //                child = group.getChildren().get( 0 );
-        //            }            
-        //        }
-        //        
-        //        if ( child instanceof GroupElement && ( child instanceof And || child instanceof Or ) ) {
-        //            GroupElement group = ( GroupElement )  child;
-        //            
-        //            // Remove nested Ands/Ors            
-        //            if ( group.getClass() == this.getClass() ) {
-        //                    
-        //                    GroupElement newGroup = null;
-        //                    if ( group instanceof And) {
-        //                        newGroup = new And();
-        //                    } else {
-        //                        newGroup =  new Or();
-        //                    }
-        //                    
-        //                    for ( Iterator it = group.getChildren().iterator(); it.hasNext(); ) {
-        //                        this.children.add( it.next() );
-        //                    }
-        //            } else {
-        //                this.children.add( child );
-        //            }
-        //        }   else {        
-        //            this.children.add( child );
-        //        }
-
+        if ( (this.isNot() || this.isExists()) && (this.children.size() > 0) ) {
+            throw new RuntimeDroolsException( this.type.toString() + " can have only a single child element. Either a single Pattern or another CE." );
+        }
         this.children.add( child );
-
     }
 
     public List getChildren() {
@@ -94,6 +63,84 @@
     }
 
     /**
+     * Optimize the group element subtree by removing redundancies
+     * like an AND inside another AND, OR inside OR, single branches
+     * AND/OR, etc.
+     * 
+     * LogicTransformer does further, more complicated, transformations
+     */
+    public void pack() {
+        Object[] clone = this.children.toArray();
+        for ( int i = 0; i < clone.length; i++ ) {
+            // if child is also a group element, there may be 
+            // some possible clean up / optimizations to be done
+            if ( clone[i] instanceof GroupElement ) {
+                GroupElement childGroup = (GroupElement) clone[i];
+                childGroup.pack( this );
+            }
+        }
+
+        // if after packing, this is an AND or OR GE with a single
+        // child GE, then clone child into current node eliminating child
+        if ( (this.isAnd() || this.isOr()) && (this.children.size() == 1) ) {
+            Object child = this.getChildren().get( 0 );
+            if( child instanceof GroupElement ) {
+                GroupElement group = (GroupElement) child;
+                this.type = group.getType();
+                this.children.clear();
+                this.children.addAll( group.getChildren() );
+            }
+        } 
+    }
+
+    /**
+     * @param parent
+     */
+    private void pack(GroupElement parent) {
+        if( this.children.size() == 0 ) {
+            // if there is no child, just remove this node
+            parent.children.remove( this );
+            return;
+        }
+        
+        // If this is  an AND or OR or EXISTS, there are some possible merges
+        if ( this.isAnd() || this.isOr() || this.isExists()) {
+
+            // if parent is of the same type as current node,
+            // then merge this childs with parent childs
+            if ( parent.getType() == this.getType() ) {
+
+                parent.getChildren().remove( this );
+                // for each child, pack it and add it to parent
+                for ( Iterator childIt = this.children.iterator(); childIt.hasNext(); ) {
+                    Object child = childIt.next();
+                    parent.addChild( child );
+                    if ( child instanceof GroupElement ) {
+                        ((GroupElement) child).pack( parent );
+                    }
+                }
+
+                // if current node has a single child, then move it to parent and pack it
+            } else if ( ( ! this.isExists() ) && ( this.children.size() == 1 ) ) {
+                Object child = this.children.get( 0 );
+                parent.addChild( child );
+                parent.getChildren().remove( this );
+                if ( child instanceof GroupElement ) {
+                    ((GroupElement) child).pack( parent );
+                }
+
+                // otherwise pack itself
+            } else {
+                this.pack();
+            }
+
+        // also pack itself if it is a NOT 
+        } else {
+            this.pack();
+        }
+    }
+
+    /**
      * Traverses two trees and checks that they are structurally equal at all
      * levels
      * 
@@ -114,6 +161,10 @@
 
         // Now try a recurse manual check
         final GroupElement e2 = (GroupElement) object;
+        if ( ! this.type.equals( e2.type ) ) {
+            return false;
+        }
+
         final List e1Children = this.getChildren();
         final List e2Children = e2.getChildren();
         if ( e1Children.size() != e2Children.size() ) {
@@ -126,20 +177,20 @@
             if ( e1Object1 instanceof GroupElement ) {
                 if ( e1Object1.getClass().isInstance( e2Object1 ) ) {
                     if ( !e1Object1.equals( e2Object1 ) ) {
-                        System.out.println( e1Object1.getClass().getName() + " did not have identical children" );
+                        //System.out.println( e1Object1.getClass().getName() + " did not have identical children" );
                         return false;
                     }
                 } else {
-                    System.out.println( "Should be the equal Conditionalelements but instead was '" + e1Object1.getClass().getName() + "', '" + e2Object1.getClass().getName() + "'" );
+                    //System.out.println( "Should be the equal Conditionalelements but instead was '" + e1Object1.getClass().getName() + "', '" + e2Object1.getClass().getName() + "'" );
                     return false;
                 }
             } else if ( e1Object1 instanceof String ) {
                 if ( !e1Object1.equals( e2Object1 ) ) {
-                    System.out.println( "Should be the equal Strings but instead was '" + e1Object1 + "', '" + e2Object1 + "'" );
+                    //System.out.println( "Should be the equal Strings but instead was '" + e1Object1 + "', '" + e2Object1 + "'" );
                     return false;
                 }
             } else {
-                System.out.println( "Objects are neither instances of ConditionalElement or String" );
+                //System.out.println( "Objects are neither instances of ConditionalElement or String" );
                 return false;
             }
         }
@@ -148,7 +199,7 @@
     }
 
     public int hashCode() {
-        return this.children.hashCode();
+        return this.type.hashCode() + this.children.hashCode();
     }
 
     /**
@@ -169,6 +220,8 @@
         } catch ( final IllegalAccessException e ) {
             throw new RuntimeException( "Could not clone '" + this.getClass().getName() + "'" );
         }
+        
+        cloned.setType( this.getType() );
 
         for ( final Iterator it = this.children.iterator(); it.hasNext(); ) {
             Object object = it.next();
@@ -182,4 +235,235 @@
         return cloned;
     }
 
+    public Type getType() {
+        return type;
+    }
+
+    public void setType(Type type) {
+        this.type = type;
+    }
+
+    public boolean isAnd() {
+        return this.type.isAnd();
+    }
+
+    public boolean isOr() {
+        return this.type.isOr();
+    }
+
+    public boolean isNot() {
+        return this.type.isNot();
+    }
+
+    public boolean isExists() {
+        return this.type.isExists();
+    }
+    
+    public String toString() {
+        return this.type.toString()+this.children.toString();
+    }
+
+    /**
+     * A public interface for CE types
+     */
+    public static interface Type extends Serializable {
+
+        /**
+         * Returns true if this CE type is an AND
+         */
+        public boolean isAnd();
+
+        /**
+         * Returns true if this CE type is an OR
+         */
+        public boolean isOr();
+
+        /**
+         * Returns true if this CE type is an NOT
+         */
+        public boolean isNot();
+
+        /**
+         * Returns true if this CE type is an EXISTS
+         */
+        public boolean isExists();
+    }
+
+    /**
+     * An AND CE type
+     */
+    private static class AndType
+        implements
+        Type {
+
+        private static final long serialVersionUID = -669797012452495460L;
+
+        AndType() {
+        }
+
+        public boolean isAnd() {
+            return true;
+        }
+
+        public boolean isExists() {
+            return false;
+        }
+
+        public boolean isNot() {
+            return false;
+        }
+
+        public boolean isOr() {
+            return false;
+        }
+
+        public boolean equals(Object obj) {
+            if ( !(obj instanceof AndType) ) {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode() {
+            return 11;
+        }
+
+        public String toString() {
+            return "AND";
+        }
+    }
+
+    /**
+     * An OR CE type
+     */
+    private static class OrType
+        implements
+        Type {
+
+        private static final long serialVersionUID = 8108203371968455372L;
+
+        OrType() {
+        }
+
+        public boolean isAnd() {
+            return false;
+        }
+
+        public boolean isExists() {
+            return false;
+        }
+
+        public boolean isNot() {
+            return false;
+        }
+
+        public boolean isOr() {
+            return true;
+        }
+
+        public boolean equals(Object obj) {
+            if ( !(obj instanceof OrType) ) {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode() {
+            return 17;
+        }
+
+        public String toString() {
+            return "OR";
+        }
+    }
+
+    /**
+     * A NOT CE type
+     */
+    private static class NotType
+        implements
+        Type {
+
+        private static final long serialVersionUID = -7873159668081968617L;
+
+        NotType() {
+        }
+
+        public boolean isAnd() {
+            return false;
+        }
+
+        public boolean isExists() {
+            return false;
+        }
+
+        public boolean isNot() {
+            return true;
+        }
+
+        public boolean isOr() {
+            return false;
+        }
+
+        public boolean equals(Object obj) {
+            if ( !(obj instanceof NotType) ) {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode() {
+            return 23;
+        }
+
+        public String toString() {
+            return "NOT";
+        }
+
+    }
+
+    /**
+     * An EXISTS CE type
+     */
+    private static class ExistsType
+        implements
+        Type {
+
+        private static final long serialVersionUID = -1528071451996382861L;
+
+        ExistsType() {
+        }
+
+        public boolean isAnd() {
+            return false;
+        }
+
+        public boolean isExists() {
+            return true;
+        }
+
+        public boolean isNot() {
+            return false;
+        }
+
+        public boolean isOr() {
+            return false;
+        }
+
+        public boolean equals(Object obj) {
+            if ( !(obj instanceof ExistsType) ) {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode() {
+            return 31;
+        }
+
+        public String toString() {
+            return "EXISTS";
+        }
+    }
+
 }
\ No newline at end of file

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElementFactory.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElementFactory.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElementFactory.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2006 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.drools.rule;
+
+/**
+ * A simple factory for GroupElements
+ * 
+ * @author etirelli
+ */
+public class GroupElementFactory {
+    
+    private GroupElementFactory() {}
+    
+    public static GroupElement newAndInstance() {
+        return new GroupElement( GroupElement.AND );
+    }
+
+    public static GroupElement newOrInstance() {
+        return new GroupElement( GroupElement.OR );
+    }
+
+    public static GroupElement newNotInstance() {
+        return new GroupElement( GroupElement.NOT );
+    }
+
+    public static GroupElement newExistsInstance() {
+        return new GroupElement( GroupElement.EXISTS );
+    }
+
+}


Property changes on: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/GroupElementFactory.java
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + id author date revision
Name: svn:eol-style
   + native

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/LogicTransformer.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/LogicTransformer.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/LogicTransformer.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -18,12 +18,10 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * LogicTransformation is reponsible for removing redundant nodes and move Or
@@ -36,10 +34,9 @@
  * 
  */
 class LogicTransformer {
-    private final Map               duplicateTransformations = new HashMap();
-    private final Map               orTransformations        = new HashMap();
+    private final Map               orTransformations = new HashMap();
 
-    private static LogicTransformer INSTANCE                 = null;
+    private static LogicTransformer INSTANCE          = null;
 
     static LogicTransformer getInstance() {
         if ( LogicTransformer.INSTANCE == null ) {
@@ -58,92 +55,35 @@
      * 
      */
     private void initialize() {
-        // these pairs will have their duplciates removed
-        addTransformationPair( And.class,
-                               And.class );
-        addTransformationPair( Or.class,
-                               Or.class );
-        addTransformationPair( Exists.class,
-                               Exists.class );
-
         // these pairs will be transformed
-        addTransformationPair( Not.class,
-                               Or.class,
+        addTransformationPair( GroupElement.NOT,
                                new NotOrTransformation() );
-        addTransformationPair( Exists.class,
-                               Or.class,
+        addTransformationPair( GroupElement.EXISTS,
                                new ExistOrTransformation() );
-        addTransformationPair( And.class,
-                               Or.class,
+        addTransformationPair( GroupElement.AND,
                                new AndOrTransformation() );
     }
 
-    private void addTransformationPair(final Class parent,
-                                       final Class child) {
-        final Map map = this.duplicateTransformations;
-        Set childSet = (Set) map.get( child );
-        if ( childSet == null ) {
-            childSet = new HashSet();
-            map.put( parent,
-                     childSet );
-        }
-        childSet.add( child );
+    private void addTransformationPair(final GroupElement.Type parent,
+                                       final Transformation method) {
+        this.orTransformations.put( parent,
+                                    method );
     }
 
-    private void addTransformationPair(final Class parent,
-                                       final Class child,
-                                       final Object method) {
-        final Map map = this.orTransformations;
-        Map childMap = (Map) map.get( parent );
-        if ( childMap == null ) {
-            childMap = new HashMap();
-            map.put( parent,
-                     childMap );
-        }
-        childMap.put( child,
-                      method );
-    }
+    public GroupElement[] transform(final GroupElement and) throws InvalidPatternException {
+        GroupElement cloned = (GroupElement) and.clone();
 
-    And[] transform(final And and) throws InvalidPatternException {
-        final And cloned = (And) and.clone();
-
         processTree( cloned );
+        cloned.pack();
 
-        // Scan for any Child Ors, if found we need apply the
-        // AndOrTransformation
-        // And assign the result to the null declared or
-        Or or = null;
-        for ( final Iterator it = cloned.getChildren().iterator(); it.hasNext(); ) {
-            final Object object = it.next();
-            if ( object instanceof Or ) {
-                or = (Or) applyOrTransformation( cloned,
-                                                 (GroupElement) object );
-                break;
-            }
-        }
-
-        And[] ands = null;
-        // Or will be null if there are no Ors in our tree
-        if ( or == null ) {
-            // No or so just assign
-            ands = new And[]{cloned};
-            checkForAndRemoveDuplicates( ands[0] );
+        GroupElement[] ands = null;
+        // is top element an AND?
+        if ( cloned.getType() == GroupElement.AND ) {
+            // Yes, so just return it
+            ands = new GroupElement[]{cloned};
         } else {
-            ands = new And[or.getChildren().size()];
-            int i = 0;
-            for ( final Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
-                final Object object = it.next();
-                if ( object.getClass() == And.class ) {
-                    ands[i] = (And) object;
-                } else {
-                    final And newAnd = new And();
-                    newAnd.addChild( and );
-                    ands[i] = newAnd;
-                }
-
-                checkForAndRemoveDuplicates( ands[i++] );
-            }
-
+            // No, so each child is an AND branch
+            ands = (GroupElement[]) cloned.getChildren().toArray( new GroupElement[cloned.getChildren().size()] );
         }
         return ands;
     }
@@ -163,90 +103,39 @@
      */
     void processTree(final GroupElement ce) throws InvalidPatternException {
 
+        boolean hasChildOr = false;
+        
+        // first we eliminicate any redundancy
+        ce.pack();
+        
         for ( final ListIterator it = ce.getChildren().listIterator(); it.hasNext(); ) {
             final Object object = it.next();
             if ( object instanceof GroupElement ) {
-                final GroupElement parent = (GroupElement) object;
+                final GroupElement child = (GroupElement) object;
 
-                processTree( parent );
+                processTree( child );
 
-                checkForAndRemoveDuplicates( parent );
-
-                // Scan for any Child Ors, if found we need to move the Or
-                // upwards
-                for ( final Iterator orIter = parent.getChildren().iterator(); orIter.hasNext(); ) {
-                    final Object object2 = orIter.next();
-                    if ( object2 instanceof Or ) {
-                        it.remove();
-                        it.add( applyOrTransformation( parent,
-                                                       (GroupElement) object2 ) );
-                        break;
-                    }
+                if ( child.isOr() ) {
+                    hasChildOr = true;
                 }
-
             }
         }
-    }
-
-    /**
-     * Given a parent and child checks if they are duplicates and that they set
-     * to have duplicates removed
-     * 
-     * @param parent
-     * @param child
-     * @return
-     */
-    boolean removeDuplicate(final GroupElement parent,
-                            final GroupElement child) {
-        if ( this.duplicateTransformations.get( parent.getClass() ) != null ) {
-            return ((HashSet) this.duplicateTransformations.get( parent.getClass() )).contains( child.getClass() );
+        if ( hasChildOr ) {
+            applyOrTransformation( ce );
         }
-
-        return false;
     }
 
-    /**
-     * Removes duplicates, children of the duplicate added to the parent and the
-     * duplicate child is removed by the parent method.
-     * 
-     */
-    void checkForAndRemoveDuplicates(final GroupElement parent) {
-        for ( final ListIterator it = parent.getChildren().listIterator(); it.hasNext(); ) {
-            final Object object = it.next();
-            // Remove the duplicate if the classes are the same and
-            // removeDuplicate method returns true
-            if ( parent.getClass().isInstance( object ) && removeDuplicate( parent,
-                                                                            (GroupElement) object ) ) {
-                final List newList = new ArrayList();
-                final GroupElement child = (GroupElement) object;
-                for ( final Iterator childIter = child.getChildren().iterator(); childIter.hasNext(); ) {
-                    newList.add( childIter.next() );
-                }
-                it.remove();
-                for ( final Iterator childIter = newList.iterator(); childIter.hasNext(); ) {
-                    it.add( childIter.next() );
-                }
-            }
-        }
-    }
+    void applyOrTransformation(final GroupElement parent) throws InvalidPatternException {
+        Transformation transformation = (Transformation) this.orTransformations.get( parent.getType() );
 
-    GroupElement applyOrTransformation(final GroupElement parent,
-                                       final GroupElement child) throws InvalidPatternException {
-        Transformation transformation = null;
-        final Map map = (HashMap) this.orTransformations.get( parent.getClass() );
-        if ( map != null ) {
-            transformation = (Transformation) map.get( child.getClass() );
-        }
-
         if ( transformation == null ) {
-            throw new RuntimeException( "applyOrTransformation could not find transformation for parent '" + parent.getClass().getName() + "' and child '" + child.getClass().getName() + "'" );
+            throw new RuntimeException( "applyOrTransformation could not find transformation for parent '" + parent.getType() + "' and child 'OR'" );
         }
-
-        return transformation.transform( parent );
+        transformation.transform( parent );
     }
 
     interface Transformation {
-        GroupElement transform(GroupElement element) throws InvalidPatternException;
+        void transform(GroupElement element) throws InvalidPatternException;
     }
 
     /**
@@ -280,94 +169,52 @@
         implements
         Transformation {
 
-        public GroupElement transform(final GroupElement and) throws InvalidPatternException {
-            final Or or = new Or();
-            determinePermutations( 0,
-                                   (And) and,
-                                   null,
-                                   or );
-            return or;
-        }
+        public void transform(final GroupElement parent) throws InvalidPatternException {
+            List orsList = new ArrayList();
+            List others = new ArrayList();
 
-        /**
-         * Recursive method that determins all unique combinations of children
-         * for the given parent and.
-         * 
-         * @param currentLevel
-         * @param and
-         * @param combination
-         * @param or
-         */
-        private void determinePermutations(final int currentLevel,
-                                           final And and,
-                                           And combination,
-                                           final Or or) {
-            final Object entry = and.getChildren().get( currentLevel );
-            if ( entry instanceof Or ) {
-                // Only OR nodes need to be iterated over
-                final Or childOr = (Or) entry;
-                for ( final Iterator it = childOr.getChildren().iterator(); it.hasNext(); ) {
-                    // Make a temp copy of combinations+new entry which will be
-                    // sent forward
-                    final And temp = new And();
-                    if ( currentLevel == 0 ) {
-                        // Always start with a clean combination
-                        combination = new And();
-                    } else {
-                        temp.getChildren().addAll( combination.getChildren() );
-                    }
+            // first we split children as OR or not OR
+            int permutations = 1;
+            for ( Iterator it = parent.getChildren().iterator(); it.hasNext(); ) {
+                Object child = it.next();
+                if ( (child instanceof GroupElement) && ((GroupElement) child).isOr() ) {
+                    permutations *= ((GroupElement) child).getChildren().size();
+                    orsList.add( child );
+                } else {
+                    others.add( child );
+                }
+            }
 
-                    // now check for and remove duplicates
-                    final Object object = it.next();
-                    if ( object instanceof And ) {
-                        // Can't have duplicate Ands so move up the children
-                        final And childAnd = (And) object;
-                        for ( final Iterator childIter = childAnd.getChildren().iterator(); childIter.hasNext(); ) {
-                            temp.addChild( childIter.next() );
-                        }
-                    } else {
-                        // no duplicates so just add
-                        temp.addChild( object );
-                    }
+            // transform parent into an OR
+            parent.setType( GroupElement.OR );
+            parent.getChildren().clear();
 
-                    if ( currentLevel < and.getChildren().size() - 1 ) {
-                        // keep recursing to build up the combination until we
-                        // are at the end where it will be added to or
-                        determinePermutations( currentLevel + 1,
-                                               and,
-                                               temp,
-                                               or );
-                    } else {
-                        // we are at the end so just attach the combination to
-                        // the or node
-                        or.addChild( temp );
+            // prepare arrays and indexes to calculate permutation
+            GroupElement[] ors = (GroupElement[]) orsList.toArray( new GroupElement[orsList.size()] );
+            int[] indexes = new int[ors.length];
+
+            // now we know how many permutations we will have, so create it
+            for ( int i = 1; i <= permutations; i++ ) {
+                GroupElement and = GroupElementFactory.newAndInstance();
+
+                // elements originally outside OR will be in every permutation, so add them
+                and.getChildren().addAll( others );
+
+                // create the actual permutations
+                int mod = 1;
+                for ( int j = ors.length - 1; j >= 0; j-- ) {
+                    and.addChild( ors[j].getChildren().get( indexes[j] ) );
+                    if ( (i % mod) == 0 ) {
+                        indexes[j] = (indexes[j] + 1) % ors[j].getChildren().size();
                     }
+                    mod *= ors[j].getChildren().size();
                 }
-            } else {
-                // Make a temp copy of combinations+new entry which will be sent
-                // forward
-                final And temp = new And();
-                if ( currentLevel == 0 ) {
-                    // Always start with a clean combination
-                    combination = new And();
-                } else {
-                    temp.getChildren().addAll( combination.getChildren() );
-                }
-                temp.addChild( entry );
 
-                if ( currentLevel < and.getChildren().size() - 1 ) {
-                    // keep recursing to build up the combination until we are
-                    // at the end where it will be added to or
-                    determinePermutations( currentLevel + 1,
-                                           and,
-                                           temp,
-                                           or );
-                } else {
-                    // we are at the end so just attach the combination to the
-                    // or node
-                    or.addChild( temp );
-                }
+                parent.addChild( and );
             }
+
+            // remove duplications
+            parent.pack();
         }
     }
 
@@ -385,35 +232,35 @@
      * (Exist ( Not (a) Not (b)) )
      * 
      * <pre>
-     *        Exist   
+     *          Or   
      *        /   \
-     *       Not  Not
-     *       |     |
-     *       a     b
+     *    Exists  Exists
+     *      |       |
+     *      a       b
      * </pre>
      */
     class ExistOrTransformation
         implements
         Transformation {
 
-        public GroupElement transform(final GroupElement exist) throws InvalidPatternException {
-            throw new InvalidPatternException( "You cannot nest an OR within an Exists" );
-            //            if ( !(exist.getChildren().get( 0 ) instanceof Or) ) {
-            //                throw new RuntimeException( "ExistOrTransformation expected '" + Or.class.getName() + "' but instead found '" + exist.getChildren().get( 0 ).getClass().getName() + "'" );
-            //            }
-            //
-            //            /*
-            //             * we know a Not only ever has one child, and the previous algorithm
-            //             * has confirmed the child is an OR
-            //             */
-            //            Or or = (Or) exist.getChildren().get( 0 );
-            //            And and = new And();
-            //            for ( Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
-            //                Exists newExist = new Exists();
-            //                newExist.addChild( it.next() );
-            //                and.addChild( newExist );
-            //            }
-            //            return and;
+        public void transform(final GroupElement parent) throws InvalidPatternException {
+            if ( (!(parent.getChildren().get( 0 ) instanceof GroupElement)) && (((GroupElement) parent.getChildren().get( 0 )).isExists()) ) {
+                throw new RuntimeException( "ExistOrTransformation expected 'OR' but instead found '" + parent.getChildren().get( 0 ).getClass().getName() + "'" );
+            }
+
+            /*
+             * we know an Exists only ever has one child, and the previous algorithm
+             * has confirmed the child is an OR
+             */
+            GroupElement or = (GroupElement) parent.getChildren().get( 0 );
+            parent.setType( GroupElement.OR );
+            parent.getChildren().clear();
+            for ( Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
+                GroupElement newExists = GroupElementFactory.newExistsInstance();
+                newExists.addChild( it.next() );
+                parent.addChild( newExists );
+            }
+            parent.pack();
         }
     }
 
@@ -442,26 +289,25 @@
         implements
         Transformation {
 
-        public GroupElement transform(final GroupElement not) throws InvalidPatternException {
+        public void transform(final GroupElement parent) throws InvalidPatternException {
 
-            throw new InvalidPatternException( "You cannot nest an OR within an Not" );
-            // @todo for 3.1
-            //            if ( !(not.getChildren().get( 0 ) instanceof Or) ) {
-            //                throw new RuntimeException( "NotOrTransformation expected '" + Or.class.getName() + "' but instead found '" + not.getChildren().get( 0 ).getClass().getName() + "'" );
-            //            }
-            //
-            //            /*
-            //             * we know a Not only ever has one child, and the previous algorithm
-            //             * has confirmed the child is an OR
-            //             */
-            //            Or or = (Or) not.getChildren().get( 0 );
-            //            And and = new And();
-            //            for ( Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
-            //                Not newNot = new Not();
-            //                newNot.addChild( it.next() );
-            //                and.addChild( newNot );
-            //            }
-            //            return and;
+            if ( (!(parent.getChildren().get( 0 ) instanceof GroupElement)) && (((GroupElement) parent.getChildren().get( 0 )).isOr()) ) {
+                throw new RuntimeException( "NotOrTransformation expected 'OR' but instead found '" + parent.getChildren().get( 0 ).getClass().getName() + "'" );
+            }
+
+            /*
+             * we know a Not only ever has one child, and the previous algorithm
+             * has confirmed the child is an OR
+             */
+            GroupElement or = (GroupElement) parent.getChildren().get( 0 );
+            parent.setType( GroupElement.AND );
+            parent.getChildren().clear();
+            for ( Iterator it = or.getChildren().iterator(); it.hasNext(); ) {
+                GroupElement newNot = GroupElementFactory.newNotInstance();
+                newNot.addChild( it.next() );
+                parent.addChild( newNot );
+            }
+            parent.pack();
         }
     }
 

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Not.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Not.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Not.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -1,29 +0,0 @@
-package org.drools.rule;
-
-/*
- * Copyright 2005 JBoss Inc
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Not extends GroupElement {
-    /**
-     * 
-     */
-    private static final long serialVersionUID = 8315240872099444225L;
-
-    public Object getChild() {
-        return getChildren().get( 0 );
-    }
-
-}
\ No newline at end of file

Deleted: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Or.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Or.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Or.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -1,26 +0,0 @@
-package org.drools.rule;
-
-/*
- * Copyright 2005 JBoss Inc
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class Or extends GroupElement {
-
-    /**
-     * 
-     */
-    private static final long serialVersionUID = 1519832383109314339L;
-
-}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Rule.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Rule.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/rule/Rule.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -64,7 +64,7 @@
 
     private Declaration[]     declarationArray;
 
-    private final And         lhsRoot           = new And();
+    private final GroupElement lhsRoot           = new GroupElement( GroupElement.AND );
 
     private String            agendaGroup;
 
@@ -347,7 +347,7 @@
      * 
      * @return The <code>List</code> of <code>Conditions</code>.
      */
-    public And getLhs() {
+    public GroupElement getLhs() {
         return this.lhsRoot;
     }
 
@@ -361,7 +361,7 @@
      * @return
      * @throws InvalidPatternException
      */
-    public And[] getTransformedLhs() throws InvalidPatternException {
+    public GroupElement[] getTransformedLhs() throws InvalidPatternException {
         return LogicTransformer.getInstance().transform( this.lhsRoot );
     }
 

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/examples/manners/BaseMannersTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/examples/manners/BaseMannersTest.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/examples/manners/BaseMannersTest.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -42,9 +42,10 @@
 import org.drools.base.field.LongFieldImpl;
 import org.drools.rule.Column;
 import org.drools.rule.Declaration;
+import org.drools.rule.GroupElement;
+import org.drools.rule.GroupElementFactory;
 import org.drools.rule.InvalidRuleException;
 import org.drools.rule.LiteralConstraint;
-import org.drools.rule.Not;
 import org.drools.rule.Package;
 import org.drools.rule.Rule;
 import org.drools.rule.VariableConstraint;
@@ -425,7 +426,7 @@
                                                                  "guestName",
                                                                  leftGuestNameDeclaration,
                                                                  this.objectEqualEvaluator ) );
-        final Not notPath = new Not();
+        final GroupElement notPath = GroupElementFactory.newNotInstance();
         notPath.addChild( notPathColumn );
         rule.addPattern( notPath );
         // ------------
@@ -450,7 +451,7 @@
                                                                    rightGuestHobbyDeclaration,
                                                                    this.objectEqualEvaluator ) );
 
-        final Not notChosen = new Not();
+        final GroupElement notChosen = GroupElementFactory.newNotInstance();
         notChosen.addChild( notChosenColumn );
 
         rule.addPattern( notChosen );
@@ -640,7 +641,7 @@
                                                                  pathGuestNameDeclaration,
                                                                  this.objectEqualEvaluator ) );
 
-        final Not not = new Not();
+        final GroupElement not = GroupElementFactory.newNotInstance();
 
         not.addChild( notPathColumn );
 

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/GroupElementTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/GroupElementTest.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/GroupElementTest.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -1,98 +1,336 @@
 package org.drools.rule;
 
+import org.drools.RuntimeDroolsException;
+
+import junit.framework.Assert;
 import junit.framework.TestCase;
 
 public class GroupElementTest extends TestCase {
-    public void test1() {
-        //dummy test
-        assertTrue( true );
+
+    public void testPackNestedAnd() {
+        GroupElement and1 = GroupElementFactory.newAndInstance();
+        Column column1 = new Column( 0,
+                                     null );
+        and1.addChild( column1 );
+
+        Column column2 = new Column( 0,
+                                     null );
+        and1.addChild( column2 );
+
+        assertEquals( 2,
+                      and1.getChildren().size() );
+        assertSame( column1,
+                    and1.getChildren().get( 0 ) );
+        assertSame( column2,
+                    and1.getChildren().get( 1 ) );
+
+        GroupElement and2 = GroupElementFactory.newAndInstance();
+        and2.addChild( and1 );
+
+        and2.pack();
+        assertEquals( 2,
+                      and2.getChildren().size() );
+        assertSame( column1,
+                    and2.getChildren().get( 0 ) );
+        assertSame( column2,
+                    and2.getChildren().get( 1 ) );
     }
-    //    public void testAddNestedAnd() {
-    //        And and1 = new And();
-    //        Column column1 = new Column(0, null);
-    //        and1.addChild( column1 );
-    //        
-    //        Column column2 = new Column(0, null);
-    //        and1.addChild( column2 );
-    //        
-    //        assertEquals( 2, and1.getChildren().size() );
-    //        assertSame( column1, and1.getChildren().get( 0 ) );
-    //        assertSame( column2, and1.getChildren().get( 1 ) );
-    //        
-    //        And and2 = new And();
-    //        and2.addChild( and1 );
-    //        assertEquals( 2, and2.getChildren().size() );
-    //        assertSame( column1, and2.getChildren().get( 0 ) );
-    //        assertSame( column2, and2.getChildren().get( 1 ) );
-    //    }
-    //    
-    //    public void testAddNestedOr() {
-    //        Or or1 = new Or();
-    //        Column column1 = new Column(0, null);
-    //        or1.addChild( column1 );
-    //        
-    //        Column column2 = new Column(0, null);
-    //        or1.addChild( column2 );
-    //        
-    //        assertEquals( 2, or1.getChildren().size() );
-    //        assertSame( column1, or1.getChildren().get( 0 ) );
-    //        assertSame( column2, or1.getChildren().get( 1 ) );
-    //        
-    //        Or or2 = new Or();
-    //        or2.addChild( or1 );
-    //        assertEquals( 2, or2.getChildren().size() );
-    //        assertSame( column1, or2.getChildren().get( 0 ) );
-    //        assertSame( column2, or2.getChildren().get( 1 ) );
-    //    }    
-    //    
-    //    public void testAddSingleBranchAnd() {
-    //        And and1 = new And();
-    //        Column column = new Column(0, null);
-    //        and1.addChild( column );
-    //        assertEquals( 1, and1.getChildren().size() );
-    //        assertSame( column, and1.getChildren().get( 0 ) );
-    //        
-    //        Or or1= new Or();
-    //        or1.addChild( and1 );
-    //        assertEquals( 1, or1.getChildren().size() );
-    //        assertSame( column, or1.getChildren().get( 0 ) );
-    //    }        
-    //    
-    //    public void testAddSingleBranchOr() {
-    //        Or or1 = new Or();
-    //        Column column = new Column(0, null);
-    //        or1.addChild( column );
-    //        assertEquals( 1, or1.getChildren().size() );
-    //        assertSame( column, or1.getChildren().get( 0 ) );
-    //        
-    //        And and1= new And();
-    //        and1.addChild( or1 );
-    //        assertEquals( 1, and1.getChildren().size() );
-    //        assertSame( column, and1.getChildren().get( 0 ) );
-    //    }        
-    //    
-    //    public void testX() {
-    //        Or or1 = new Or();
-    //        Column column1 = new Column(0, null);
-    //        or1.addChild( column1 );
-    //        
-    //        Column column2 = new Column(0, null);
-    //        or1.addChild( column2 );
-    //        
-    //        And and1 = new And();
-    //        and1.addChild( or1 );
-    //        assertEquals( 1, and1.getChildren().size() );
-    //        assertSame( or1, and1.getChildren().get( 0 ) );
-    //        
-    //        assertSame( column1, or1.getChildren().get( 0 ) );
-    //        assertSame( column2, or1.getChildren().get( 1 ) );        
-    //        
-    //        Or or2 = new Or();
-    //        or2.addChild( and1 );
-    //        
-    //        assertEquals( 2, or1.getChildren().size() );
-    //        assertSame( column1, or1.getChildren().get( 0 ) );
-    //        assertSame( column2, or2.getChildren().get( 1 ) );          
-    //        
-    //    }      
+
+    public void testPackNestedOr() {
+        GroupElement or1 = GroupElementFactory.newOrInstance();
+        Column column1 = new Column( 0,
+                                     null );
+        or1.addChild( column1 );
+
+        Column column2 = new Column( 0,
+                                     null );
+        or1.addChild( column2 );
+
+        assertEquals( 2,
+                      or1.getChildren().size() );
+        assertSame( column1,
+                    or1.getChildren().get( 0 ) );
+        assertSame( column2,
+                    or1.getChildren().get( 1 ) );
+
+        GroupElement or2 = GroupElementFactory.newOrInstance();
+        or2.addChild( or1 );
+
+        or2.pack();
+
+        assertEquals( 2,
+                      or2.getChildren().size() );
+        assertSame( column1,
+                    or2.getChildren().get( 0 ) );
+        assertSame( column2,
+                    or2.getChildren().get( 1 ) );
+    }
+
+    public void testPackNestedExists() {
+        GroupElement exists1 = GroupElementFactory.newExistsInstance();
+        Column column1 = new Column( 0,
+                                     null );
+        exists1.addChild( column1 );
+
+        assertEquals( 1,
+                      exists1.getChildren().size() );
+        assertSame( column1,
+                    exists1.getChildren().get( 0 ) );
+
+        GroupElement exists2 = GroupElementFactory.newExistsInstance();
+        exists2.addChild( exists1 );
+
+        exists2.pack();
+
+        assertEquals( 1,
+                      exists2.getChildren().size() );
+        assertSame( column1,
+                    exists2.getChildren().get( 0 ) );
+    }
+
+    public void testAddMultipleChildsIntoNot() {
+        GroupElement not = GroupElementFactory.newNotInstance();
+
+        Column column1 = new Column( 0,
+                                     null );
+        try {
+            not.addChild( column1 );
+        } catch ( RuntimeDroolsException rde ) {
+            Assert.fail( "Adding a single child is not supposed to throw Exception for NOT GE: " + rde.getMessage() );
+        }
+
+        Column column2 = new Column( 0,
+                                     null );
+        try {
+            not.addChild( column2 );
+            Assert.fail( "Adding a second child into a NOT GE should throw Exception" );
+        } catch ( RuntimeDroolsException rde ) {
+            // everything is fine
+        }
+    }
+
+    public void testAddSingleBranchAnd() {
+        GroupElement and1 = GroupElementFactory.newAndInstance();
+        Column column = new Column( 0,
+                                    null );
+        and1.addChild( column );
+        assertEquals( 1,
+                      and1.getChildren().size() );
+        assertSame( column,
+                    and1.getChildren().get( 0 ) );
+
+        GroupElement or1 = GroupElementFactory.newOrInstance();
+        or1.addChild( and1 );
+
+        or1.pack();
+        assertEquals( 1,
+                      or1.getChildren().size() );
+        assertSame( column,
+                    or1.getChildren().get( 0 ) );
+    }
+
+    public void testAddSingleBranchOr() {
+        GroupElement or1 = GroupElementFactory.newOrInstance();
+        Column column = new Column( 0,
+                                    null );
+        or1.addChild( column );
+        assertEquals( 1,
+                      or1.getChildren().size() );
+        assertSame( column,
+                    or1.getChildren().get( 0 ) );
+
+        GroupElement and1 = GroupElementFactory.newAndInstance();
+        and1.addChild( or1 );
+
+        and1.pack();
+        assertEquals( 1,
+                      and1.getChildren().size() );
+        assertSame( column,
+                    and1.getChildren().get( 0 ) );
+    }
+
+    /**
+     * This test tests deep nested structures, and shall transform this:
+     * 
+     *    AND2
+     *     |
+     *    OR3
+     *     |
+     *    OR2
+     *     |
+     *    AND1
+     *     |
+     *    OR1
+     *    / \
+     *   C1  C2
+     *   
+     * Into this:
+     * 
+     *   OR1
+     *   / \
+     *  C1 C2
+     *
+     */
+    public void testDeepNestedStructure() {
+        GroupElement or1 = GroupElementFactory.newOrInstance();
+        Column column1 = new Column( 0,
+                                     null );
+        or1.addChild( column1 );
+
+        Column column2 = new Column( 0,
+                                     null );
+        or1.addChild( column2 );
+
+        GroupElement and1 = GroupElementFactory.newAndInstance();
+        and1.addChild( or1 );
+        assertEquals( 1,
+                      and1.getChildren().size() );
+        assertSame( or1,
+                    and1.getChildren().get( 0 ) );
+
+        assertSame( column1,
+                    or1.getChildren().get( 0 ) );
+        assertSame( column2,
+                    or1.getChildren().get( 1 ) );
+
+        GroupElement or2 = GroupElementFactory.newOrInstance();
+        or2.addChild( and1 );
+
+        assertEquals( 1,
+                      or2.getChildren().size() );
+        assertSame( and1,
+                    or2.getChildren().get( 0 ) );
+
+        GroupElement or3 = GroupElementFactory.newOrInstance();
+        or3.addChild( or2 );
+
+        assertEquals( 1,
+                      or2.getChildren().size() );
+        assertSame( or2,
+                    or3.getChildren().get( 0 ) );
+
+        GroupElement and2 = GroupElementFactory.newAndInstance();
+        and2.addChild( or3 );
+
+        assertEquals( 1,
+                      and2.getChildren().size() );
+        assertSame( or3,
+                    and2.getChildren().get( 0 ) );
+        
+        // Now pack the structure
+        and2.pack();
+        
+        // and2 now is in fact transformed into an OR
+        assertEquals( GroupElement.OR, and2.getType() );
+        
+        assertEquals( 2,
+                      and2.getChildren().size() );
+        
+        assertSame( column1,
+                    and2.getChildren().get( 0 ) );
+        assertSame( column2,
+                    and2.getChildren().get( 1 ) );
+
+    }
+    
+    /**
+     * This test tests deep nested structures, and shall transform this:
+     * 
+     *      AND2
+     *      / \ 
+     *    OR3  C3
+     *     |
+     *    OR2
+     *     |
+     *    AND1
+     *     |
+     *    OR1
+     *    / \
+     *   C1  C2
+     *   
+     * Into this:
+     * 
+     *     AND2
+     *     /  \
+     *   OR1  C3
+     *   / \
+     *  C1 C2
+     *
+     */
+    public void testDeepNestedStructureWithMultipleElementsInRoot() {
+        GroupElement or1 = GroupElementFactory.newOrInstance();
+        Column column1 = new Column( 0,
+                                     null );
+        or1.addChild( column1 );
+
+        Column column2 = new Column( 0,
+                                     null );
+        or1.addChild( column2 );
+
+        GroupElement and1 = GroupElementFactory.newAndInstance();
+        and1.addChild( or1 );
+        assertEquals( 1,
+                      and1.getChildren().size() );
+        assertSame( or1,
+                    and1.getChildren().get( 0 ) );
+
+        assertSame( column1,
+                    or1.getChildren().get( 0 ) );
+        assertSame( column2,
+                    or1.getChildren().get( 1 ) );
+
+        GroupElement or2 = GroupElementFactory.newOrInstance();
+        or2.addChild( and1 );
+
+        assertEquals( 1,
+                      or2.getChildren().size() );
+        assertSame( and1,
+                    or2.getChildren().get( 0 ) );
+
+        GroupElement or3 = GroupElementFactory.newOrInstance();
+        or3.addChild( or2 );
+
+        assertEquals( 1,
+                      or2.getChildren().size() );
+        assertSame( or2,
+                    or3.getChildren().get( 0 ) );
+
+        GroupElement and2 = GroupElementFactory.newAndInstance();
+        and2.addChild( or3 );
+
+        Column column3 = new Column( 0,
+                                     null );
+        and2.addChild( column3 );
+
+        assertEquals( 2,
+                      and2.getChildren().size() );
+        assertSame( or3,
+                    and2.getChildren().get( 0 ) );
+        assertSame( column3,
+                    and2.getChildren().get( 1 ) );
+        
+        // Now pack the structure
+        and2.pack();
+        
+        // and2 now is in fact transformed into an OR
+        assertEquals( GroupElement.AND, and2.getType() );
+        
+        assertEquals( 2,
+                      and2.getChildren().size() );
+        
+        assertSame( column3,
+                    and2.getChildren().get( 0 ) );
+        assertSame( or1,
+                    and2.getChildren().get( 1 ) );
+
+        
+        assertEquals( 2,
+                      or1.getChildren().size() );
+        assertSame( column1,
+                    or1.getChildren().get( 0 ) );
+        assertSame( column2,
+                    or1.getChildren().get( 1 ) );
+
+    }
+    
 }

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/LogicTransformerTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/LogicTransformerTest.java	2006-12-11 05:19:32 UTC (rev 8217)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/rule/LogicTransformerTest.java	2006-12-11 11:57:51 UTC (rev 8218)
@@ -54,30 +54,29 @@
         final String b = "b";
         final String c = "c";
 
-        final And and = new And();
-        and.addChild( c );
-        final Or or = new Or();
+        final GroupElement parent = GroupElementFactory.newAndInstance();
+        parent.addChild( c );
+        final GroupElement or = GroupElementFactory.newOrInstance();
         or.addChild( a );
         or.addChild( b );
-        and.addChild( or );
+        parent.addChild( or );
 
-        final Or newOr = (Or) LogicTransformer.getInstance().applyOrTransformation( and,
-                                                                                    or );
+        LogicTransformer.getInstance().applyOrTransformation( parent );
 
         assertLength( 2,
-                      newOr.getChildren() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 0 ).getClass() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 1 ).getClass() );
+                      parent.getChildren() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 0 ).getClass() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 1 ).getClass() );
 
-        final And and1 = (And) newOr.getChildren().get( 0 );
+        final GroupElement and1 = (GroupElement) parent.getChildren().get( 0 );
         assertContains( c,
                         and1.getChildren() );
         assertContains( a,
                         and1.getChildren() );
 
-        final And and2 = (And) newOr.getChildren().get( 1 );
+        final GroupElement and2 = (GroupElement) parent.getChildren().get( 1 );
         assertContains( c,
                         and2.getChildren() );
         assertContains( b,
@@ -123,38 +122,42 @@
         final String e = "e";
         final String f = "f";
 
-        final And and = new And();
-        final Or or = new Or();
+        final GroupElement parent = GroupElementFactory.newAndInstance();
+        final GroupElement or = GroupElementFactory.newOrInstance();
         or.addChild( a );
         or.addChild( b );
-        and.addChild( or );
-        and.addChild( c );
+        parent.addChild( or );
+        parent.addChild( c );
 
-        final Or or2 = new Or();
+        final GroupElement or2 = GroupElementFactory.newOrInstance();
 
         or2.addChild( d );
         or2.addChild( e );
-        and.addChild( or2 );
+        parent.addChild( or2 );
 
-        final Not not = new Not();
+        final GroupElement not = GroupElementFactory.newNotInstance();
         not.addChild( f );
-        and.addChild( not );
+        parent.addChild( not );
 
-        final Or newOr = (Or) LogicTransformer.getInstance().applyOrTransformation( and,
-                                                                                    or );
+        LogicTransformer.getInstance().applyOrTransformation( parent );
 
+        assertEquals( GroupElement.OR,
+                      parent.getType() );
+
         assertLength( 4,
-                      newOr.getChildren() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 0 ).getClass() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 1 ).getClass() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 2 ).getClass() );
-        assertEquals( And.class,
-                      newOr.getChildren().get( 3 ).getClass() );
+                      parent.getChildren() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 0 ).getClass() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 1 ).getClass() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 2 ).getClass() );
+        assertEquals( GroupElement.class,
+                      parent.getChildren().get( 3 ).getClass() );
 
-        And and1 = (And) newOr.getChildren().get( 0 );
+        GroupElement and1 = (GroupElement) parent.getChildren().get( 0 );
+        assertEquals( GroupElement.AND,
+                      and1.getType() );
         assertLength( 4,
                       and1.getChildren() );
         assertContains( a,
@@ -166,7 +169,9 @@
         assertContains( not,
                         and1.getChildren() );
 
-        and1 = (And) newOr.getChildren().get( 1 );
+        and1 = (GroupElement) parent.getChildren().get( 1 );
+        assertEquals( GroupElement.AND,
+                      and1.getType() );
         assertLength( 4,
                       and1.getChildren() );
         assertContains( a,
@@ -178,7 +183,9 @@
         assertContains( not,
                         and1.getChildren() );
 
-        and1 = (And) newOr.getChildren().get( 2 );
+        and1 = (GroupElement) parent.getChildren().get( 2 );
+        assertEquals( GroupElement.AND,
+                      and1.getType() );
         assertLength( 4,
                       and1.getChildren() );
         assertContains( b,
@@ -190,7 +197,9 @@
         assertContains( not,
                         and1.getChildren() );
 
-        and1 = (And) newOr.getChildren().get( 3 );
+        and1 = (GroupElement) parent.getChildren().get( 3 );
+        assertEquals( GroupElement.AND,
+                      and1.getType() );
         assertLength( 4,
                       and1.getChildren() );
         assertContains( b,
@@ -206,7 +215,7 @@
     /**
      * This data structure is now valid
      * 
-     * (Not (OR (A B)
+     * (Not (OR (A B) ) )
      * 
      * <pre>
      *             Not
@@ -216,29 +225,53 @@
      *           a    b
      * </pre>
      * 
+     * Should become:
+     * 
+     * <pre>
+     *             And
+     *             / \ 
+     *           Not Not   
+     *            |   |
+     *            a   b
+     * </pre>
+     * 
+     * 
      */
-    public void xxxtestNotOrTransformation() throws InvalidPatternException {
+    public void testNotOrTransformation() throws InvalidPatternException {
         final String a = "a";
         final String b = "b";
 
-        final Not not = new Not();
-        final Or or = new Or();
-        not.addChild( or );
+        final GroupElement parent = GroupElementFactory.newNotInstance();
+        final GroupElement or = GroupElementFactory.newOrInstance();
+        parent.addChild( or );
 
         or.addChild( a );
         or.addChild( b );
 
-        try {
-            final And newAnd = (And) LogicTransformer.getInstance().applyOrTransformation( not,
-                                                                                           or );
-            fail( "This should fail as you cannot nest Ors under Nots" );
-        } catch ( final InvalidPatternException e ) {
-            //
-        }
+        LogicTransformer.getInstance().applyOrTransformation( parent );
+
+        assertTrue( parent.isAnd() );
+        assertEquals( 2,
+                      parent.getChildren().size() );
+
+        GroupElement b1 = (GroupElement) parent.getChildren().get( 0 );
+        GroupElement b2 = (GroupElement) parent.getChildren().get( 1 );
+        assertTrue( b1.isNot() );
+        assertTrue( b2.isNot() );
+
+        assertEquals( 1,
+                      b1.getChildren().size() );
+        assertEquals( a,
+                      b1.getChildren().get( 0 ) );
+
+        assertEquals( 1,
+                      b2.getChildren().size() );
+        assertEquals( b,
+                      b2.getChildren().get( 0 ) );
     }
 
     /**
-     * This data structure is not valid (Exists (OR (A B)
+     * This data structure is now valid (Exists (OR (A B) ) )
      * 
      * <pre>
      *             Exists
@@ -248,62 +281,83 @@
      *           a    b
      * </pre>
      * 
+     * Should become:
+     * 
+     * <pre>
+     *              Or
+     *             /  \ 
+     *        Exists  Exists   
+     *            |    |
+     *            a    b
+     * </pre>
      */
-    public void xxxtestExistOrTransformation() throws InvalidPatternException {
+    public void testExistOrTransformation() throws InvalidPatternException {
         final String a = "a";
         final String b = "b";
 
-        final Exists exist = new Exists();
-        final Or or = new Or();
-        exist.addChild( or );
+        final GroupElement parent = GroupElementFactory.newExistsInstance();
+        final GroupElement or = GroupElementFactory.newOrInstance();
+        parent.addChild( or );
 
         or.addChild( a );
         or.addChild( b );
 
-        try {
-            final And newAnd = (And) LogicTransformer.getInstance().applyOrTransformation( exist,
-                                                                                           or );
+        LogicTransformer.getInstance().applyOrTransformation( parent );
 
-            fail( "This should fail as you cannot nest Ors under Existss" );
-        } catch ( final InvalidPatternException e ) {
-            //
-        }
+        assertTrue( parent.isOr() );
+        assertEquals( 2,
+                      parent.getChildren().size() );
 
+        GroupElement b1 = (GroupElement) parent.getChildren().get( 0 );
+        GroupElement b2 = (GroupElement) parent.getChildren().get( 1 );
+        assertTrue( b1.isExists() );
+        assertTrue( b2.isExists() );
+
+        assertEquals( 1,
+                      b1.getChildren().size() );
+        assertEquals( a,
+                      b1.getChildren().get( 0 ) );
+
+        assertEquals( 1,
+                      b2.getChildren().size() );
+        assertEquals( b,
+                      b2.getChildren().get( 0 ) );
+
     }
 
-    public void testDuplicatTransformation() throws InvalidRuleException {
+    public void testEliminateEmptyBranchesAndDuplications() throws InvalidRuleException {
         final String a = "a";
         final String b = "b";
         final String c = "c";
         final String d = "d";
 
-        final And and1 = new And();
+        final GroupElement and1 = GroupElementFactory.newAndInstance();
         and1.addChild( a );
         and1.addChild( b );
 
-        final And and2 = new And();
+        final GroupElement and2 = GroupElementFactory.newAndInstance();
         and2.addChild( c );
         and2.addChild( d );
 
         and1.addChild( and2 );
 
-        final Or or = new Or();
+        final GroupElement or = GroupElementFactory.newOrInstance();
         and1.addChild( or );
 
-        LogicTransformer.getInstance().checkForAndRemoveDuplicates( and1 );
+        GroupElement[] result = LogicTransformer.getInstance().transform( and1 );
 
-        assertLength( 5,
-                      and1.getChildren() );
+        assertLength( 1,
+                      result );
+        assertLength( 4,
+                      result[0].getChildren() );
         assertContains( a,
-                        and1.getChildren() );
+                        result[0].getChildren() );
         assertContains( b,
-                        and1.getChildren() );
+                        result[0].getChildren() );
         assertContains( c,
-                        and1.getChildren() );
+                        result[0].getChildren() );
         assertContains( d,
-                        and1.getChildren() );
-        assertContains( or,
-                        and1.getChildren() );
+                        result[0].getChildren() );
 
     }
 
@@ -316,29 +370,30 @@
      *                 /         |         \
      *                And       and        Not
      *               / | \      / \         |
-     *             a  And d    e  Or        h
+     *             a  And d    e  Or        i
      *                / \        /  \      
-     *               b  Not     f  Exists    
+     *               b  Not     h  Exists    
      *                   |           |      
      *                  Not          g   
      *                   |           
      *                   c         
      * </pre>
      * <pre>
-     *                           _/|\__
-     *                        __/  |   \___
-     *                       /     |       \__
-     *                    __/      |          \__
-     *                   /         |             \__
-     *                  /          |                \__
-     *                 |           |                   \
-     *                And          Or                 Not
-     *              / | | \       /  \                 |  
-     *            a   b d Not   And   And              i
-     *                     |    / \  / |            
-     *                    Not  e  f e Exists       
-     *                     |           |        
-     *                     c           g        
+     *                            Or 
+     *                           _/ \__
+     *                        __/      \___
+     *                       /             \__
+     *                    __/                 \__
+     *                   /                       \__
+     *                  /                           \__
+     *                 |                               \
+     *                And                             And
+     *            /|||| \  \                       /||| |   \    \
+     *            abdeh Not Not                    abde Not Not Exists
+     *                   |   |                           |   |    |
+     *                  Not  i                          Not  i    g
+     *                   |                               |
+     *                   c                               c
      * </pre>
      * 
      * @throws IOException
@@ -347,70 +402,52 @@
      * 
      * 
      */
-    public void xTestProcessTree() throws IOException,
-                                  ClassNotFoundException,
-                                  InvalidPatternException {
+    public void testProcessTree() throws IOException,
+                                 ClassNotFoundException,
+                                 InvalidPatternException {
         final String a = "a";
         final String b = "b";
         final String c = "c";
         final String d = "d";
         final String e = "e";
-        final String f = "f";
+        //final String f = "f";
         final String g = "g";
         final String h = "h";
         final String i = "i";
-        final String j = "j";
-        final String k = "notAssertObject";
+        //final String j = "j";
+        //final String k = "notAssertObject";
 
-        final And and1 = new And();
-        final And and2 = new And();
+        final GroupElement and1 = GroupElementFactory.newAndInstance();
+        final GroupElement and2 = GroupElementFactory.newAndInstance();
         and1.addChild( a );
         and1.addChild( and2 );
         and2.addChild( b );
-        final Not not1 = new Not();
-        final Not not2 = new Not();
+        final GroupElement not1 = GroupElementFactory.newNotInstance();
+        final GroupElement not2 = GroupElementFactory.newNotInstance();
         not1.addChild( not2 );
         not2.addChild( c );
         and2.addChild( not1 );
         and1.addChild( d );
 
-        final And and3 = new And();
+        final GroupElement and3 = GroupElementFactory.newAndInstance();
         and3.addChild( e );
-        final Or or1 = new Or();
+        final GroupElement or1 = GroupElementFactory.newOrInstance();
         and3.addChild( or1 );
-        final Exists exist1 = new Exists();
+        final GroupElement exist1 = GroupElementFactory.newExistsInstance();
         exist1.addChild( g );
         or1.addChild( exist1 );
         or1.addChild( h );
 
-        final Not not3 = new Not();
+        final GroupElement not3 = GroupElementFactory.newNotInstance();
         not3.addChild( i );
 
-        final And root = new And();
+        final GroupElement root = GroupElementFactory.newAndInstance();
         root.addChild( and1 );
         root.addChild( and3 );
         root.addChild( not3 );
 
-        LogicTransformer.getInstance().processTree( root );
+        GroupElement[] result = LogicTransformer.getInstance().transform( root );
 
-        // --------------------------------------
-        // Test that the treesEqual method works
-        // --------------------------------------
-
-        // Check against itself
-        assertEquals( root,
-                      root );
-
-        // Test against a known false tree
-        final And testAnd1 = new And();
-        testAnd1.addChild( a );
-        testAnd1.addChild( b );
-        final Or testOr2 = new Or();
-        testOr2.addChild( c );
-        testOr2.addChild( d );
-        testAnd1.addChild( testOr2 );
-        assertFalse( root.equals( testAnd1 ) );
-
         // ----------------------------------------------------------------------------------
         // Now construct the result tree so we can test root against what it
         // should look like
@@ -421,17 +458,19 @@
 
         // Uncomment this when you need to output a new known correct tree
         // result
-        // writeTree(root, "correct_processTree1.dat");
+        //writeTree(result, "correct_processTree1.dat");
         final ObjectInputStream ois = new ObjectInputStream( this.getClass().getResourceAsStream( "/correct_processTree1.dat" ) );
 
-        final And correctResultRoot = (And) ois.readObject();
+        final GroupElement[] correctResultRoot = (GroupElement[]) ois.readObject();
 
         // Make sure they are equal
-        assertEquals( correctResultRoot,
-                      root );
+        for ( int j = 0; j < correctResultRoot.length; j++ ) {
+            assertEquals( correctResultRoot[j],
+                          result[j] );
+        }
     }
 
-    public void testCloneable() {
+    public void xxxtestCloneable() {
         final String a = "a";
         final String b = "b";
         final String c = "c";
@@ -442,22 +481,22 @@
         final String h = "h";
 
         // Test against a known false tree
-        final And and = new And();
+        final GroupElement and = GroupElementFactory.newAndInstance();
         and.addChild( a );
         and.addChild( b );
 
-        final Or or = new Or();
+        final GroupElement or = GroupElementFactory.newOrInstance();
         or.addChild( c );
         or.addChild( d );
         and.addChild( or );
-        final And and2 = new And();
+        final GroupElement and2 = GroupElementFactory.newAndInstance();
         and2.addChild( e );
         and2.addChild( f );
         or.addChild( and2 );
 
-        final Not not = new Not();
+        final GroupElement not = GroupElementFactory.newNotInstance();
         and.addChild( not );
-        final Or or2 = new Or();
+        final GroupElement or2 = GroupElementFactory.newOrInstance();
         not.addChild( or2 );
         or2.addChild( g );
         or2.addChild( h );
@@ -516,9 +555,9 @@
      * @throws ClassNotFoundException
      * 
      */
-    public void xTestTransform() throws IOException,
-                                ClassNotFoundException,
-                                InvalidPatternException {
+    public void xxxtestTransform() throws IOException,
+                               ClassNotFoundException,
+                               InvalidPatternException {
         final String a = "a";
         final String b = "b";
         final String c = "c";
@@ -527,74 +566,48 @@
         final String f = "f";
         final String g = "g";
         final String h = "h";
-        final String i = "i";
 
-        final And and = new And();
+        final GroupElement and = GroupElementFactory.newAndInstance();
 
-        final And and1 = new And();
+        final GroupElement and1 = GroupElementFactory.newAndInstance();
         and1.addChild( a );
-        final Or or1 = new Or();
+        final GroupElement or1 = GroupElementFactory.newOrInstance();
         or1.addChild( b );
         or1.addChild( c );
         and1.addChild( or1 );
         and.addChild( and1 );
 
-        final Or or2 = new Or();
+        final GroupElement or2 = GroupElementFactory.newOrInstance();
         or2.addChild( d );
         or2.addChild( e );
         and.addChild( or2 );
 
-        final And and2 = new And();
-        final Not not1 = new Not();
+        final GroupElement and2 = GroupElementFactory.newAndInstance();
+        final GroupElement not1 = GroupElementFactory.newNotInstance();
         not1.addChild( f );
-        final Or or3 = new Or();
+        final GroupElement or3 = GroupElementFactory.newOrInstance();
         or3.addChild( g );
 
-        final Not not2 = new Not();
+        final GroupElement not2 = GroupElementFactory.newNotInstance();
         not2.addChild( h );
         or3.addChild( not2 );
 
-        // ---------------------------------------
-        // Check a simple case no just one branch
-        // ---------------------------------------
-        And[] ands = LogicTransformer.getInstance().transform( and1 );
-        assertLength( 2,
-                      ands );
-        assertTrue( ands[0] instanceof And );
-        assertLength( 2,
-                      ands[0].getChildren() );
+        and2.addChild( not1 );
+        and2.addChild( or3 );
+        and.addChild( and2 );
 
-        assertLength( 2,
-                      ands[0].getChildren() );
-        assertEquals( And.class,
-                      ands[0].getClass() );
-        assertEquals( And.class,
-                      ands[0].getClass() );
+        GroupElement[] ands = LogicTransformer.getInstance().transform( and );
 
-        And newAnd = ands[0];
-        assertContains( a,
-                        newAnd.getChildren() );
-        assertContains( b,
-                        newAnd.getChildren() );
-
-        newAnd = ands[1];
-        assertContains( a,
-                        newAnd.getChildren() );
-        assertContains( c,
-                        newAnd.getChildren() );
-
-        ands = LogicTransformer.getInstance().transform( and );
-
         // Uncomment this when you need to output a new known correct tree
         // result
-        // writeTree(ands, "correct_transform1.dat");
+        //writeTree(ands, "correct_transform1.dat");
 
         // Now check the main tree
 
         // Get known correct tree
         // The binary stream was created from a handchecked correct output
         final ObjectInputStream ois = new ObjectInputStream( this.getClass().getResourceAsStream( "/correct_transform1.dat" ) );
-        final And[] correctResultAnds = (And[]) ois.readObject();
+        final GroupElement[] correctResultAnds = (GroupElement[]) ois.readObject();
 
         for ( int j = 0; j < ands.length; j++ ) {
             assertEquals( correctResultAnds[j],

Modified: labs/jbossrules/trunk/drools-core/src/test/resources/correct_processTree1.dat
===================================================================
(Binary files differ)

Modified: labs/jbossrules/trunk/drools-core/src/test/resources/correct_transform1.dat
===================================================================
(Binary files differ)




More information about the jboss-svn-commits mailing list