Author: mar...@jb... Date: 2006-05-07 22:51:22 -0400 (Sun, 07 May 2006) New Revision: 4119 Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/CompiledInvoker.java Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/semantics/java/javaInvokers.stg labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java Log: JBRULES-251 Node sharing for compiled Expressions -Predicates, ReturnValue and EvalCondition now all work with node sharing Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/CompiledInvoker.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/CompiledInvoker.java 2006-05-08 02:51:10 UTC (rev 4118) +++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/CompiledInvoker.java 2006-05-08 02:51:22 UTC (rev 4119) @@ -0,0 +1,9 @@ +package org.drools.semantics.java; + +import java.util.List; + +import org.drools.spi.Invoker; + +public interface CompiledInvoker extends Invoker { + public List getMethodBytecode(); +} 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-05-08 02:51:10 UTC (rev 4118) +++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java 2006-05-08 02:51:22 UTC (rev 4119) @@ -158,6 +158,7 @@ pkg.getPackageCompilationData().getClassLoader() ); // make an automatic import for the current package this.typeResolver.addImport( pkg.getName() + ".*" ); + this.typeResolver.addImport( "java.lang.*" ); this.ruleDescr = ruleDescr; @@ -577,8 +578,10 @@ st.setAttribute( "methodName", classMethodName ); + + String returnValueText = functionFixer.fix( returnValueDescr.getText() ); st.setAttribute( "text", - functionFixer.fix( returnValueDescr.getText() ) ); + returnValueText ); this.methods.add( st.toString() ); @@ -597,8 +600,8 @@ declarations, returnValueDescr.getText() ); - st.setAttribute( "text", - returnValueDescr.getText() ); + st.setAttribute( "hashCode", + returnValueText.hashCode() ); String invokerClassName = pkg.getName() + "." + ruleDescr.getClassName() + ucFirst( classMethodName ) + "Invoker"; this.invokers.put( invokerClassName, @@ -668,8 +671,10 @@ st.setAttribute( "methodName", classMethodName ); + + String predicateText = functionFixer.fix( predicateDescr.getText() ); st.setAttribute( "text", - functionFixer.fix( predicateDescr.getText() ) ); + predicateText ); this.methods.add( st.toString() ); @@ -694,8 +699,8 @@ declarations, predicateDescr.getText() ); - st.setAttribute( "text", - predicateDescr.getText() ); + st.setAttribute( "hashCode", + predicateText.hashCode() ); String invokerClassName = pkg.getName() + "." + ruleDescr.getClassName() + ucFirst( classMethodName ) + "Invoker"; this.invokers.put( invokerClassName, @@ -729,8 +734,10 @@ st.setAttribute( "methodName", classMethodName ); + + String evalText = functionFixer.fix( evalDescr.getText() ); st.setAttribute( "text", - functionFixer.fix( evalDescr.getText() ) ); + evalText ); this.methods.add( st.toString() ); @@ -749,8 +756,8 @@ declarations, evalDescr.getText() ); - st.setAttribute( "text", - evalDescr.getText() ); + st.setAttribute( "hashCode", + evalText.hashCode() ); String invokerClassName = pkg.getName() + "." + ruleDescr.getClassName() + ucFirst( classMethodName ) + "Invoker"; this.invokers.put( invokerClassName, Modified: labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/semantics/java/javaInvokers.stg =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/semantics/java/javaInvokers.stg 2006-05-08 02:51:10 UTC (rev 4118) +++ labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/semantics/java/javaInvokers.stg 2006-05-08 02:51:22 UTC (rev 4119) @@ -1,9 +1,62 @@ group javaInvokeable; -returnValueInvoker(package, invokerClassName, ruleClassName, methodName, declarations, declarationTypes, globals, globalTypes, text) ::= << +getMethodBytecode(package, ruleClassName, methodName) ::= << + public java.util.List getMethodBytecode() { + org.drools.util.asm.MethodComparator.Tracer visit = new org.drools.util.asm.MethodComparator.Tracer("<methodName>"); + + + java.io.InputStream is = <ruleClassName>.class.getClassLoader().getResourceAsStream( "<package>.<ruleClassName>".replace( '.', '/' ) + ".class" ); + + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + byte[] data = new byte[1024]; + int byteCount; + try { + while ( (byteCount = is.read( data, + 0, + 1024 )) > -1 ) + { + bos.write(data, 0, byteCount); + } + } catch ( java.io.IOException e ) { + throw new org.drools.RuntimeDroolsException("Unable getResourceAsStream for Class '<ruleClassName>' "); + } + + org.drools.asm.ClassReader classReader = new org.drools.asm.ClassReader( bos.toByteArray() ); + classReader.accept( visit, true ); + org.drools.asm.util.TraceMethodVisitor trace = visit.getTrace(); + return trace.getText(); + } +>> + + +equals() ::= << + public boolean equals(Object object) { + if (object == null ) { + return false; + } else if ( object == this ){ + return true; + } + + if ( ! (object instanceof org.drools.semantics.java.CompiledInvoker) ) { + return false; + } + + org.drools.semantics.java.CompiledInvoker other = ( org.drools.semantics.java.CompiledInvoker ) object; + + return org.drools.util.asm.MethodComparator.compareBytecode( getMethodBytecode(), other.getMethodBytecode() ); + } +>> + +hashCode(hashCode) ::= << + public int hashCode() { + return <hashCode>; + } +>> + +returnValueInvoker(package, invokerClassName, ruleClassName, methodName, declarations, declarationTypes, globals, globalTypes, hashCode) ::= << package <package>; -public class <invokerClassName> implements org.drools.spi.ReturnValueExpression +public class <invokerClassName> implements org.drools.spi.ReturnValueExpression, org.drools.semantics.java.CompiledInvoker { public Object evaluate(org.drools.spi.Tuple tuple, org.drools.rule.Declaration[] declarations, @@ -15,15 +68,21 @@ return <ruleClassName>.<methodName>( <declarations:{ declr | <declr.identifier>}; separator=",\n"><if(globals)>,<endif> <globals:{ identifier | <identifier>}; separator=",\n"> ); - } + } + + <hashCode(hashCode=hashCode)> + + <getMethodBytecode(package=package, ruleClassName=ruleClassName, methodName=methodName)> + + <equals()> } >> predicateInvoker(package, invokerClassName, ruleClassName, methodName, declaration, declarationType, - declarations, declarationTypes, globals, globalTypes, text) ::= << + declarations, declarationTypes, globals, globalTypes, hashCode) ::= << package <package>; -public class <invokerClassName> implements org.drools.spi.PredicateExpression +public class <invokerClassName> implements org.drools.spi.PredicateExpression, org.drools.semantics.java.CompiledInvoker { public boolean evaluate(org.drools.spi.Tuple tuple, org.drools.FactHandle factHandle, @@ -39,14 +98,24 @@ <declarations:{ declr | <declr.identifier>}; separator=",\n"><if(globals)>,<endif> <globals:{ identifier | <identifier>}; separator=",\n"> ); } + + <hashCode(hashCode=hashCode)> + + <getMethodBytecode(package=package, ruleClassName=ruleClassName, methodName=methodName)> + + <equals()> } >> -evalInvoker(package, invokerClassName, ruleClassName, methodName, declarations, declarationTypes, globals, globalTypes, text) ::= << +evalInvoker(package, invokerClassName, ruleClassName, methodName, declarations, declarationTypes, globals, globalTypes, hashCode) ::= << package <package>; -public class <invokerClassName> implements org.drools.spi.EvalExpression +import org.drools.asm.ClassReader; +import org.drools.asm.util.TraceMethodVisitor; +import org.drools.util.asm.MethodComparator.Tracer; + +public class <invokerClassName> implements org.drools.spi.EvalExpression, org.drools.semantics.java.CompiledInvoker { public boolean evaluate(org.drools.spi.Tuple tuple, org.drools.rule.Declaration[] declarations, @@ -59,6 +128,12 @@ <declarations:{ declr | <declr.identifier>}; separator=",\n"><if(globals)>,<endif> <globals:{ identifier | <identifier>}; separator=",\n"> ); } + + <hashCode(hashCode=hashCode)> + + <getMethodBytecode(package=package, ruleClassName=ruleClassName, methodName=methodName)> + + <equals()> } >> 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-05-08 02:51:10 UTC (rev 4118) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java 2006-05-08 02:51:22 UTC (rev 4119) @@ -56,17 +56,22 @@ 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.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; import org.drools.rule.Rule; +import org.drools.semantics.java.CompiledInvoker; import org.drools.spi.Activation; import org.drools.spi.KnowledgeHelper; import org.drools.spi.PropagationContext; import org.drools.spi.Tuple; import org.drools.util.LinkedList; +import org.drools.util.asm.MethodComparator; public class PackageBuilderTest extends DroolsTestCase { @@ -334,7 +339,34 @@ assertLength( 0, builder.getErrors() ); } + + public void testReturnValueMethodCompare() { + PackageBuilder builder1 = new PackageBuilder(); + PackageDescr packageDescr1 = new PackageDescr( "package1" ); + createReturnValueRule( packageDescr1, "new Integer(x.intValue() + y.intValue() )" ); + builder1.addPackage( packageDescr1 ); + Column column1 = (Column) builder1.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + ReturnValueConstraint returnValue1 = (ReturnValueConstraint) column1.getConstraints().get( 2 ); + + PackageBuilder builder2 = new PackageBuilder(); + PackageDescr packageDescr2 = new PackageDescr( "package2" ); + createReturnValueRule( packageDescr2, "new Integer(x.intValue() + y.intValue() )" ); + builder2.addPackage( packageDescr2 ); + Column column2 = (Column) builder2.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + ReturnValueConstraint returnValue2 = (ReturnValueConstraint) column2.getConstraints().get( 2 ); + PackageBuilder builder3 = new PackageBuilder(); + PackageDescr packageDescr3 = new PackageDescr( "package3" ); + createReturnValueRule( packageDescr3, "new Integer(x.intValue() - y.intValue() )" ); + builder3.addPackage( packageDescr3 ); + Column column3 = (Column) builder3.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + ReturnValueConstraint returnValue3 = (ReturnValueConstraint) column3.getConstraints().get( 2 ); + + assertEquals( returnValue1, returnValue2); + assertFalse( returnValue1.equals( returnValue3 ) ); + assertFalse( returnValue2.equals( returnValue3 ) ); + } + public void testPredicate() throws Exception { PackageBuilder builder = new PackageBuilder(); @@ -368,7 +400,34 @@ assertLength( 0, builder.getErrors() ); } + + public void testPredicateMethodCompare() { + PackageBuilder builder1 = new PackageBuilder(); + PackageDescr packageDescr1 = new PackageDescr( "package1" ); + createPredicateRule( packageDescr1, "x==y" ); + builder1.addPackage( packageDescr1 ); + Column column1 = (Column) builder1.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + PredicateConstraint predicate1 = (PredicateConstraint) column1.getConstraints().get( 2 ); + + PackageBuilder builder2 = new PackageBuilder(); + PackageDescr packageDescr2 = new PackageDescr( "package2" ); + createPredicateRule( packageDescr2, "x==y" ); + builder2.addPackage( packageDescr2 ); + Column column2 = (Column) builder2.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + PredicateConstraint predicate2 = (PredicateConstraint) column2.getConstraints().get( 2 ); + PackageBuilder builder3 = new PackageBuilder(); + PackageDescr packageDescr3 = new PackageDescr( "package3" ); + createPredicateRule( packageDescr3, "x!=y" ); + builder3.addPackage( packageDescr3 ); + Column column3 = (Column) builder3.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + PredicateConstraint predicate3 = (PredicateConstraint) column3.getConstraints().get( 2 ); + + assertEquals( predicate1, predicate2); + assertFalse( predicate1.equals( predicate3 ) ); + assertFalse( predicate2.equals( predicate3 ) ); + } + public void testEval() throws Exception { PackageBuilder builder = new PackageBuilder(); @@ -398,12 +457,42 @@ ruleDescr.setConsequence( "modify(stilton);" ); - builder.addPackage( packageDescr ); + builder.addPackage( packageDescr ); assertLength( 0, builder.getErrors() ); + + Package pkg = builder.getPackage(); + Rule rule = pkg.getRule( "rule-1" ); + EvalCondition eval = (EvalCondition) rule.getLhs().getChildren().get( 1 ); + CompiledInvoker invoker = (CompiledInvoker ) eval.getEvalExpression(); + List list = invoker.getMethodBytecode(); } + + public void testEvalMethodCompare() { + PackageBuilder builder1 = new PackageBuilder(); + PackageDescr packageDescr1 = new PackageDescr( "package1" ); + createEvalRule( packageDescr1, "1==1" ); + builder1.addPackage( packageDescr1 ); + EvalCondition eval1 = (EvalCondition) builder1.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + + PackageBuilder builder2 = new PackageBuilder(); + PackageDescr packageDescr2 = new PackageDescr( "package2" ); + createEvalRule( packageDescr2, "1==1" ); + builder2.addPackage( packageDescr2 ); + EvalCondition eval2 = (EvalCondition) builder2.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + PackageBuilder builder3 = new PackageBuilder(); + PackageDescr packageDescr3 = new PackageDescr( "package3" ); + createEvalRule( packageDescr3, "1==3" ); + builder3.addPackage( packageDescr3 ); + EvalCondition eval3 = (EvalCondition) builder3.getPackage().getRules()[0].getLhs().getChildren().get( 0 ); + + assertEquals( eval1, eval2); + assertFalse( eval1.equals( eval3 ) ); + assertFalse( eval2.equals( eval3 ) ); + } + public void testOr() throws Exception { PackageBuilder builder = new PackageBuilder(); Rule rule = createRule( new OrDescr(), @@ -625,8 +714,79 @@ assertLength( 0, builder.getErrors() ); + } + + private void createReturnValueRule(PackageDescr packageDescr, String expression) { + RuleDescr ruleDescr = new RuleDescr( "rule-1" ); + packageDescr.addRule( ruleDescr ); + + AndDescr lhs = new AndDescr(); + ruleDescr.setLhs( lhs ); + + ColumnDescr column = new ColumnDescr( Cheese.class.getName(), + "stilton" ); + lhs.addDescr( column ); + + FieldBindingDescr fieldBindingDescr = new FieldBindingDescr( "price", + "x" ); + column.addDescr( fieldBindingDescr ); + fieldBindingDescr = new FieldBindingDescr( "price", + "y" ); + column.addDescr( fieldBindingDescr ); + + packageDescr.addGlobal( "map", + "java.util.Map" ); + + ReturnValueDescr returnValue = new ReturnValueDescr( "price", + "==", + expression ); + column.addDescr( returnValue ); + + ruleDescr.setConsequence( "modify(stilton);" ); + } + + private void createPredicateRule(PackageDescr packageDescr, String expression) { + RuleDescr ruleDescr = new RuleDescr( "rule-1" ); + packageDescr.addRule( ruleDescr ); + + AndDescr lhs = new AndDescr(); + ruleDescr.setLhs( lhs ); + + ColumnDescr column = new ColumnDescr( Cheese.class.getName(), + "stilton" ); + lhs.addDescr( column ); + + FieldBindingDescr fieldBindingDescr = new FieldBindingDescr( "price", + "x" ); + column.addDescr( fieldBindingDescr ); + + packageDescr.addGlobal( "map", + "java.util.Map" ); + + PredicateDescr predicate = new PredicateDescr( "price", + "y", + expression ); + column.addDescr( predicate ); + + ruleDescr.setConsequence( "modify(stilton);" ); } + + private void createEvalRule(PackageDescr packageDescr, String expression) { + RuleDescr ruleDescr = new RuleDescr( "rule-1" ); + packageDescr.addRule( ruleDescr ); + AndDescr lhs = new AndDescr(); + ruleDescr.setLhs( lhs ); + + packageDescr.addGlobal( "map", + "java.util.Map" ); + + EvalDescr evalDescr = new EvalDescr( expression ); + lhs.addDescr( evalDescr ); + + ruleDescr.setConsequence( "" ); + } + private void createLiteralRule(LiteralDescr literalDescr) { PackageBuilder builder = new PackageBuilder(); |