/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* 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.compiler.integrationtests;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.drools.compiler.Address;
import org.drools.compiler.CommonTestMethodBase;
import org.drools.compiler.Person;
import org.drools.core.factmodel.traits.Traitable;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.io.impl.ByteArrayResource;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.definition.type.Modifies;
import org.kie.api.definition.type.PropertyReactive;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.builder.conf.PropertySpecificOption;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import org.kie.internal.utils.KieHelper;
public class PropertyReactivityTest extends CommonTestMethodBase {
@Test(timeout=10000)
public void testComposedConstraint() {
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass2.class.getCanonicalName() + ";\n" +
"\n" +
"rule R when \n" +
" $k2 : Klass2(b == 0 || c == 0)\n" +
"then" +
" modify($k2) { setD(1) }\n" +
"end\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
Klass2 k2 = new Klass2(0, 0, 0, 0);
ksession.insert(k2);
assertEquals(1, ksession.fireAllRules());
assertEquals(1, k2.getD());
}
@Test(timeout=10000)
public void testScrambleProperties() {
// DROOLS-91
String str =
"package org.drools.test\n" +
" global java.util.List list" +
"\n" +
" declare Parent\n" +
" @propertyReactive\n" +
" a : int\n" +
" k : int\n" +
" z : int\n" +
" end\n" +
"\n" +
" declare Child extends Parent\n" +
" @propertyReactive\n" +
" p : int\n" +
" end\n" +
"\n" +
"\n" +
" rule Init\n" +
" when\n" +
" then\n" +
" insert( new Child( 1, 3, 5, 7 ) );\n" +
" end\n" +
"\n" +
" rule Mod\n" +
" when\n" +
" $p : Parent()\n" +
" then\n" +
" modify( $p ) { setZ( 99 ); }\n" +
" end\n" +
"\n" +
" rule React2\n" +
" when\n" +
" Child( p == 7 )\n" +
" then\n" +
" list.add( \"React2\" );\n" +
" end\n" +
"\n" +
" rule React\n" +
" when\n" +
" Child( z == 99 )\n" +
" then\n" +
" list.add( \"React\" );\n" +
" end";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals(2, list.size());
assertTrue(list.contains("React"));
assertTrue(list.contains("React2"));
}
@PropertyReactive
public static interface Intf1 {
public int getC();
public void setC(int c);
public int getD();
public void setD(int d);
public int getF();
public void setF(int f);
public String getId();
}
@PropertyReactive
public static interface Intf2 {
public int getD();
public void setD(int d);
public int getE();
public void setE(int e);
public String getId();
}
@PropertyReactive
public static class Klass implements Intf1, Intf2 {
private String id = "k1";
private int a;
private int b;
private int c;
private int d;
private int e;
private int f;
public Klass(int a, int b, int c, int d, int e, int f) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
this.f = f;
}
public int getA() { return a; }
public void setA(int a) { this.a = a; }
public int getB() { return b; }
public void setB(int b) { this.b = b; }
public int getC() { return c; }
public void setC(int c) { this.c = c; }
public int getD() { return d; }
public void setD(int d) { this.d = d; }
public int getE() { return e; }
public void setE(int e) { this.e = e; }
public int getF() { return f; }
public void setF(int f) { this.f = f; }
public String getId() { return id; }
}
@PropertyReactive
public static class Klass2 implements Intf2 {
private String id = "k2";
private int b;
private int c;
private int d;
private int e;
public Klass2( int b, int c, int d, int e ) {
this.b = b;
this.c = c;
this.d = d;
this.e = e;
}
public int getB() { return b; }
public void setB(int b) { this.b = b; }
public int getC() { return c; }
public void setC(int c) { this.c = c; }
public int getD() { return d; }
public void setD(int d) { this.d = d; }
public int getE() { return e; }
public void setE(int e) { this.e = e; }
public String getId() { return id; }
}
@Test(timeout=10000)
public void testScrambleWithInterfaces() {
/*
* K1 a b c d e f 1000
* I1 c d f 10
* I2 d e 1
* K2 b c d e 100
*/
// DROOLS-91
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Intf1.class.getCanonicalName() + ";\n" +
"import " + Intf2.class.getCanonicalName() + ";\n" +
"import " + Klass.class.getCanonicalName() + ";\n" +
"import " + Klass2.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass( 1, 2, 3, 4, 5, 6 ) );\n" +
" insert( new Klass2( 2, 3, 4, 5 ) );\n" +
"end\n" +
"\n" +
"rule \"On1\"\n" +
"when\n" +
" $x : Intf1( )\n" +
"then\n" +
" System.out.println( \"Modify by interface \" );\n" +
" modify ( $x ) { setD( 200 ) }\n" +
"end\n" +
"rule \"On2\"\n" +
"when\n" +
" $x : Klass2( )\n" +
"then\n" +
" System.out.println( \"Modify by class \" );\n" +
" modify ( $x ) { setD( 200 ) }\n" +
"end\n" +
"\n" +
"rule \"Log1\"\n" +
"when\n" +
" Klass( d == 200, $id : id ) \n" +
"then\n" +
" System.out.println( \"Log1 - As K1 \" + $id );\n" +
" list.add( $id + \"@K1\" );\n" +
"end\n" +
"\n" +
"rule \"Log2\"\n" +
"when\n" +
" Klass2( d == 200, $id : id ) \n" +
"then\n" +
" System.out.println( \"Log2 - As K2 \" + $id );\n" +
" list.add( $id + \"@K2\" );\n" +
"end\n" +
"\n" +
"rule \"Log3\"\n" +
"when\n" +
" Intf1( d == 200, $id : id ) \n" +
"then\n" +
" System.out.println( \"Log3 - As I1 \" + $id );\n" +
" list.add( $id + \"@I1\" );\n" +
"end\n" +
"\n" +
"rule \"Log4\"\n" +
"when\n" +
" Intf2( d == 200, $id : id ) \n" +
"then\n" +
" System.out.println( \"Log4 - As K2 \" + $id );\n" +
" list.add( $id + \"@I2\" );\n" +
"end";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
System.out.println( list );
assertTrue( list.containsAll( Arrays.asList( "k1@K1", "k1@I1", "k1@I2" ) ) );
assertTrue( list.containsAll( Arrays.asList( "k2@K2", "k2@I2" ) ) );
assertEquals( 5, list.size() );
}
@Test(timeout=10000)
public void testScrambleWithInterfacesAndObject() {
// DROOLS-91
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Intf2.class.getCanonicalName() + ";\n" +
"import " + Klass2.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass2( 2, 3, 4, 5 ) );\n" +
"end\n" +
"rule \"Mod\"\n" +
"when\n" +
" $x : Intf2( )\n" +
"then\n" +
" modify ( $x ) { setD( 200 ) }\n" +
"end\n" +
"\n" +
"rule \"Log\"\n" +
"when\n" +
" Klass2( d == 200, $id : id ) \n" +
"then\n" +
" list.add( \"Klass2\" );\n" +
"end\n" +
"\n" +
"rule \"LogObject\" salience -1\n" +
"when\n" +
" $o : Object( ) \n" +
"then\n" +
" list.add( $o.getClass().getSimpleName() );\n" +
"end\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( "Klass2", list.get(0) );
assertEquals( "Klass2", list.get(1) );
}
@Test(timeout=10000)
public void testWithDeclaredTypeAndTraitInDifferentPackages() {
// DROOLS-91
String str1 =
"package org.pkg1;\n" +
"declare trait Trait " +
" @propertyReactive\n" +
" a : int\n" +
"end";
String str2 =
"package org.pkg2;\n" +
"declare Bean " +
" @propertyReactive\n" +
" @Traitable\n" +
" a : int\n" +
" b : int\n" +
"end";
String str3 =
"package org.pkg3;\n" +
"import org.pkg1.Trait;\n" +
"import org.pkg2.Bean;\n" +
"rule Init\n" +
"when\n" +
"then\n" +
" insert(new Bean(1, 2));\n" +
"end\n" +
"rule R\n" +
"when\n" +
" $b : Bean( b == 2)" +
"then\n" +
" Trait t = don( $b, Trait.class, true );\n" +
" modify(t) { setA(2) };\n" +
"end";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str1, str2, str3);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ksession.fireAllRules();
}
@PropertyReactive @Traitable
public static class Bean {
private int a;
private int b;
public Bean() { }
public Bean(int a, int b) {
this.a = a;
this.b = b;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
@Test(timeout=10000)
public void testWithBeanAndTraitInDifferentPackages() {
// DROOLS-91
String str1 =
"package org.drools.compiler.integrationtests;\n" +
"declare trait Trait " +
" @propertyReactive\n" +
" a : int\n" +
"end";
String str2 =
"package org.drools.test;\n" +
"import org.drools.compiler.integrationtests.Trait;\n" +
"import " + Bean.class.getCanonicalName() + ";\n" +
"rule Init\n" +
"when\n" +
"then\n" +
" insert(new Bean(1, 2));\n" +
"end\n" +
"rule R\n" +
"when\n" +
" $b : Bean( b == 2)" +
"then\n" +
" Trait t = don( $b, Trait.class, true );\n" +
" modify(t) { setA(2) };\n" +
"end";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str1, str2);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ksession.fireAllRules();
}
@Test(timeout=10000)
public void testRepeatedPatternWithPR() {
// JBRULES-3705
String str1 =
"package org.test;\n" +
"global java.util.List list; \n" +
"" +
"declare SampleBean \n" +
"@propertyReactive \n" +
"x : java.math.BigDecimal \n" +
"y : java.math.BigDecimal \n" +
"id : Long @key\n" +
"end \n" +
"" +
" rule \"calculate y\"\n" +
" dialect \"mvel\"\n" +
" when\n" +
" $bean : SampleBean(id == 1L);\n" +
" then\n" +
" modify($bean){\n" +
" y =5B;\n" +
" }\n" +
" list.add( $bean.y ); \n" +
" end\n" +
"\n" +
" rule \"calculate x\"\n" +
" dialect \"mvel\"\n" +
" when\n" +
" $bean : SampleBean(id == 1L);\n" +
" then\n" +
" modify($bean){\n" +
" x =10B;\n" +
" }\n" +
" list.add( $bean.x ); \n" +
" end\n" +
"" +
" rule Init \n" +
" when\n" +
" then\n" +
" insert( new SampleBean( 1L ) ); \n" +
" end";
KnowledgeBase kbase = loadKnowledgeBaseFromString( str1 );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ArrayList list = new ArrayList();
ksession.setGlobal( "list", list );
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertTrue( list.contains( new BigDecimal( 10 ) ) );
assertTrue(list.contains(new BigDecimal(5)));
}
@Test(timeout=10000)
public void testPRWithCollections() {
// DROOLS-135
String str1 = "package org.test;\n" +
"import java.util.*\n" +
"\n" +
"global List list;\n" +
"" +
"declare java.util.ArrayList end \n" +
"" +
"declare MyList extends java.util.ArrayList \n" +
"end\n" +
"\n" +
"declare Bean\n" +
"@propertyReactive\n" +
" id : int\n" +
" num : int\n" +
" values : MyList \n" +
" checks : Map \n" +
" str : String\n" +
"end\n" +
"\n" +
"\n" +
"rule Init\n" +
"when\n" +
"then\n" +
" insert( new Bean( 42, 0, new MyList(), new HashMap(), \"\" ) );\n" +
"end\n" +
"\n" +
"rule M1\n" +
"when\n" +
" $b : Bean( id == 42 )\n" +
"then\n" +
" System.out.println( 1 ); \n" +
" list.add( 1 ); \n" +
" modify ( $b ) { setNum( 1 ); }\n" +
"end\n" +
"\n" +
"rule M2\n" +
"when\n" +
" $b : Bean( num == 1 )\n" +
"then\n" +
" System.out.println( 2 ); \n" +
" list.add( 2 ); \n" +
" modify ( $b ) { getValues().add( \"foo\" ); }\n" +
"end\n" +
"\n" +
"rule M3\n" +
"when\n" +
" $b : Bean( values contains \"foo\" )\n" +
"then\n" +
" System.out.println( 3 ); \n" +
" list.add( 3 ); \n" +
" modify ( $b ) { setStr( \"x\" ); }\n" +
"end\n" +
" \n " +
"rule M4\n" +
"when\n" +
" $b : Bean( str == \"x\" )\n" +
"then\n" +
" System.out.println( 4 ); \n" +
" list.add( 4 ); \n" +
" modify ( $b ) { getChecks().put( \"x\", 13 ); }\n" +
"end\n" +
"\n" +
"rule M5\n" +
"when\n" +
" $b : Bean( checks[ \"x\" ] > 10 )\n" +
"then\n" +
" System.out.println( 5 ); \n" +
" list.add( 5 ); \n" +
" modify ( $b ) { getChecks().clear(); }\n" +
"end\n" +
"\n" +
"rule Log\n" +
"salience 1\n" +
"when\n" +
" $b : Bean() @watch( values, checks ) \n" +
"then\n" +
" System.out.println( \"Log >> \" + $b );\n" +
" list.add( 0 );\n" +
"end";
KnowledgeBase kbase = loadKnowledgeBaseFromString( str1 );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ArrayList list = new ArrayList();
ksession.setGlobal( "list", list );
ksession.fireAllRules();
assertEquals( Arrays.asList( 0, 1, 2, 0, 3, 4, 0, 5, 0 ), list );
}
@Test(timeout=10000)
public void testPRWithPositionalUnification() {
// DROOLS-247
String str1 =
"package org.test;\n" +
"global java.util.List list; \n" +
"" +
"declare Man \n" +
"@propertyReactive \n" +
" name : String \n" +
"end \n" +
"" +
"declare Animal \n" +
"@propertyReactive \n" +
" id : int \n" +
" owner : String \n" +
" age : int \n" +
"end \n" +
"" +
"rule Init \n" +
"when \n" +
"then \n" +
" insert( new Man( \"alan\" ) ); \n" +
" insert( new Animal( 1, \"bob\", 7 ) ); \n" +
"end \n" +
"" +
"rule \"Mod Man\" \n" +
"when \n" +
" $m :Man() \n" +
"then \n" +
" modify ( $m ) { setName( \"bob\" ); } \n" +
"end \n" +
"" +
"rule \"Mod Per\" \n" +
"when \n" +
" $m :Animal() \n" +
"then \n" +
" modify ( $m ) { " +
" setId( 1 ); \n " +
" } \n" +
"end \n" +
"" +
"rule Join_1\n" +
"when\n" +
" Man( $name ; ) \n" +
" Animal( $name := owner ) \n" +
"then\n" +
" list.add( 1 ); \n" +
"end\n" +
"" +
"rule Join_3\n" +
"when\n" +
" Man( $name ; ) \n" +
" Animal( $id, $name; ) \n" +
" Integer( this == $id ) \n" +
"then\n" +
" list.add( 2 ); \n" +
"end\n" +
"";
KnowledgeBase kbase = loadKnowledgeBaseFromString( str1 );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ArrayList list = new ArrayList();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.fireAllRules();
assertTrue( list.contains( 1 ) );
assertTrue( list.contains( 2 ) );
assertEquals( 2, list.size() );
}
/**
* Tests the use of PR on constraints involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* Because getFullName doesn't have a setter, and we are not using
* @watch in the rule nor @Modified in setName() or in setLastName(), there
* are no way that rule 'Find Heisenberg' gets activated because a modification
* or a Klass3 object.
*/
@Test(timeout=10000)
public void testPRConstraintOnAttributesWithoutSetter(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass3.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass3( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Find Heisenberg\"\n" +
"when\n" +
" $x : Klass3( fullName == 'Walter White' )\n" +
"then\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass3( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( Arrays.asList( "XXX -> Walter" ), list );
}
/**
* Tests the use of PR on constraints involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* getFullName doesn't have a setter and Klass3 doesn't state that setName()
* nor setLastName() @Modifies fullName. We are explicitly using @watches
* in the rule involving fullName to be aware of modifications in the name
* and/or lastName of a Klass3 object.
*/
@Test(timeout=10000)
public void testPRConstraintOnAttributesWithoutSetterUsingWatches(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass3.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass3( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Find Heisenberg\"\n" +
"when\n" +
" $x : Klass3( fullName == 'Walter White' ) @watch( name, lastName)\n" +
"then\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass3( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( Arrays.asList( "XXX -> Walter", "Find Heisenberg" ), list );
}
/**
* Tests the use of PR on constraints involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* getFullName doesn't have a setter but Klass4 states that setName()
* and setLastName() both @Modifies fullName.
*/
@Test(timeout=10000)
public void testPRConstraintOnAttributesWithoutSetterUsingModifies(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass4.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass4( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Find Heisenberg\"\n" +
"when\n" +
" $x : Klass4( fullName == 'Walter White' )\n" +
"then\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass4( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
" list.add( drools.getRule().getName() );\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( Arrays.asList( "XXX -> Walter", "Find Heisenberg" ), list );
}
/**
* Tests the use of PR on bindings involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* Because getFullName doesn't have a setter, and we are not using
* @watch in the rule nor @Modified in setName() or in setLastName(), there
* are no way that rule 'Get Person name' gets activated because a modification
* or a Klass3 object.
*/
@Test(timeout=10000)
public void testPRBindingOnAttributesWithoutSetter(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass3.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass3( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Get Person name\"\n" +
"salience 1\n" +
"when\n" +
" $x : Klass3( $fullName: fullName )\n" +
"then\n" +
" list.add( $fullName );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass3( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( Arrays.asList( "XXX White" ), list );
}
/**
* Tests the use of PR on bindings involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* getFullName doesn't have a setter but we are explicitly using @watches
* annotation in 'Get Person name' rule. After the name of Kalss3 instance is
* modified, rule 'Get Person name' must be re-activated.
*/
@Test(timeout=10000)
public void testPRBindingOnAttributesWithoutSetterUsingWatches(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass3.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass3( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Get Person name\"\n" +
"salience 1\n" +
"when\n" +
" $x : Klass3( $fullName: fullName ) @watch( name, lastName)\n" +
"then\n" +
" list.add( $fullName );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass3( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( Arrays.asList( "XXX White", "Walter White" ), list );
}
/**
* Tests the use of PR on bindings involving 'virtual' properties
* of a POJO: calculated properties without a setter.
* getFullName doesn't have a setter but we are explicitly using @Modifies
* in Klass4's setName() and setLastName(). After the name of Kalss4
* instance is modified, rule 'Get Person name' must be re-activated.
*/
@Test(timeout=10000)
public void testPRBindingOnAttributesWithoutSetterUsingModifies(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass4.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new Klass4( \"XXX\", \"White\" ) );\n" +
"end\n" +
"rule \"Get Person name\"\n" +
"salience 1\n" +
"when\n" +
" $x : Klass4( $fullName: fullName )\n" +
"then\n" +
" list.add( $fullName );\n" +
"end\n" +
"rule \"XXX -> Walter\"\n" +
"when\n" +
" $x : Klass4( name == 'XXX' )\n" +
"then\n" +
" modify($x){ setName('Walter') };\n" +
"end\n" +
"\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( Arrays.asList( "XXX White", "Walter White" ), list );
}
@Test(timeout=10000)
public void testPRBindingOnNonexistingAttributes(){
String str =
"package org.drools.test;\n" +
"\n" +
"import " + Klass4.class.getCanonicalName() + ";\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Get Person name\"\n" +
"salience 1\n" +
"when\n" +
" $x : Klass4( $name: nonexistingName )\n" +
"then\n" +
" list.add( $fullName );\n" +
"end\n";
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add( new ByteArrayResource( str.getBytes() ), ResourceType.DRL );
System.out.println( knowledgeBuilder.getErrors() );
assertTrue( knowledgeBuilder.hasErrors() );
}
@Test(timeout=10000)
public void testPRBindingOnNonexistingWatchedAttribute(){
String str =
"package org.drools.test;\n" +
"\n" +
"import org.drools.compiler.integrationtests.PropertyReactivityTest.Klass4;\n" +
"\n" +
"global java.util.List list;\n" +
"\n" +
"rule \"Get Person name\"\n" +
"salience 1\n" +
"when\n" +
" $x : Klass4( ) @watch( nmae )\n" +
"then\n" +
"end\n";
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add( new ByteArrayResource( str.getBytes() ), ResourceType.DRL );
System.out.println( knowledgeBuilder.getErrors() );
assertTrue( knowledgeBuilder.hasErrors() );
}
@Test(timeout=10000)
public void testModifyAfterInsertWithPropertyReactive() {
String rule1 =
"\n" +
"package com.sample;\n" +
"import " + MyClass.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule r0\n" +
"then insert( new MyClass() );\n" +
"end\n" +
"rule r1 salience 1\n" +
"when " +
" MyClass(value == null)\n" +
"then " +
" list.add( 1 );\n" +
"end\n" +
"\n" +
"rule r2 salience 2\n" +
"when " +
" m : MyClass(value == null)\n" +
"then " +
" modify(m) { setData(\"test\") }\n" +
" list.add( 2 );\n" +
"end\n" +
"\n" +
"rule r3 salience 3\n" +
"when " +
" MyClass(value == null)\n" +
"then " +
" list.add( 3 );\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent(rule1, ResourceType.DRL);
KieSession ksession = helper.build().newKieSession();
List list = new ArrayList();
ksession.setGlobal("list", list);
assertEquals(4, ksession.fireAllRules());
assertEquals(3, list.size());
assertEquals(3, list.get(0));
assertEquals(2, list.get(1));
assertEquals(1, list.get(2));
}
@PropertyReactive
public static class Klass3 {
private String name;
private String lastName;
public Klass3(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName(){
return this.name + " "+ this.lastName;
}
}
@PropertyReactive
public static class MyClass {
private String value;
private String data;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
/**
* Same as Klass3 but using @Modifies in setName() and setLastName()
*/
@PropertyReactive
public static class Klass4 {
private String name;
private String lastName;
public Klass4(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public String getName() {
return name;
}
@Modifies("fullName")
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
@Modifies("fullName")
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFullName(){
return this.name + " "+ this.lastName;
}
}
@Test(timeout=10000)
public void testIndexedNotWatchedProperty() {
// DROOLS-569
String rule1 =
"package com.sample;\n" +
"import " + MyClass.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R1 when\n" +
" $s : String()\n" +
" $m : MyClass( data != null, value == $s ) @watch( !* )\n" +
"then \n" +
" list.add($s);\n" +
" modify( $m ) { setValue(\"2\") };\n" +
"end\n" +
"\n" +
"rule R2 when\n" +
" $i : Integer()\n" +
" $m : MyClass( value == $i.toString(), data == \"x\" ) @watch( !value )\n" +
"then \n" +
" modify( $m ) { setValue(\"3\"), setData(\"y\") };\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent(rule1, ResourceType.DRL);
KieSession ksession = helper.build().newKieSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
MyClass myClass = new MyClass();
myClass.setValue("1");
myClass.setData("x");
ksession.insert(myClass);
ksession.insert("1");
ksession.insert(2);
ksession.fireAllRules();
assertEquals(1, list.size());
assertEquals("1", list.get(0));
list.clear();
ksession.insert("3");
ksession.fireAllRules();
assertEquals(1, list.size());
assertEquals("3", list.get(0));
}
@Test
public void testModifyWithGetter() {
String rule1 =
"package foo.bar\n" +
"import " + Person.class.getName() + "\n" +
"declare Person @propertyReactive end\n" +
"rule x\n" +
" when\n" +
" $p : Person( address != null ) @watch(!address) \n" +
" then\n" +
" modify($p){getAddress().setStreet(\"foo\");}\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent(rule1, ResourceType.DRL);
KieSession ksession = helper.build().newKieSession();
Person p = new Person();
p.setAddress(new Address());
ksession.insert(p);
int fired = ksession.fireAllRules(10);
assertEquals(1, fired);
assertEquals("foo", p.getAddress().getStreet());
}
@Test(timeout = 10000L)
public void testMoreThan64Fields() {
StringBuilder fields = new StringBuilder();
for (int i = 10; i < 100; i++) {
fields.append(" a").append(i).append(" : int\n");
}
String str =
"package org.drools.test\n" +
"global java.util.List list;\n" +
"declare BigType @propertyReactive\n" +
fields +
"end\n" +
"rule Init when\n" +
"then\n" +
" insert( new BigType() );" +
"end\n" +
"rule R when\n" +
" $b : BigType( a11 == 0, a98 == 0 )" +
"then\n" +
" modify($b) { setA12(1), setA99(1) };\n" +
" list.add(1);\n" +
"end\n";
KieSession ksession = new KieHelper().addContent(str, ResourceType.DRL)
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals(1, list.size());
}
@Test(timeout = 10000L)
public void testMoreThan64FieldsMultipleFirings() {
StringBuilder fields = new StringBuilder();
for (int i = 10; i < 100; i++) {
fields.append(" a").append(i).append(" : int\n");
}
String str =
"package org.drools.test\n" +
"global java.util.List list;\n" +
"declare BigType @propertyReactive\n" +
fields +
"end\n" +
"rule Init when\n" +
"then\n" +
" insert( new BigType() );" +
"end\n" +
"rule R when\n" +
" $b : BigType( a11 == 0, a12 < 10, a98 == 0 )" +
"then\n" +
" modify($b) { setA12($b.getA12()+1), setA99(1) };\n" +
" list.add(1);\n" +
"end\n";
KieSession ksession = new KieHelper().addContent(str, ResourceType.DRL)
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals(10, list.size());
}
@Test(timeout = 10000L)
public void testMoreThan64FieldsWithWatch() {
StringBuilder fields = new StringBuilder();
for (int i = 10; i < 100; i++) {
fields.append(" a").append(i).append(" : int\n");
}
String str =
"package org.drools.test\n" +
"global java.util.List list;\n" +
"declare BigType @propertyReactive\n" +
fields +
"end\n" +
"rule Init when\n" +
"then\n" +
" insert( new BigType() );" +
"end\n" +
"rule R when\n" +
" $b : BigType( a11 == 0, a99 < 10 ) @watch(!a99)" +
"then\n" +
" modify($b) { setA12(1), setA99(1) };\n" +
" list.add(1);\n" +
"end\n";
KieSession ksession = new KieHelper().addContent(str, ResourceType.DRL)
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal("list", list);
ksession.fireAllRules();
assertEquals(1, list.size());
}
@Test
public void testPropReactiveAnnotationOnDifferentDrl() {
// DROOLS-800
String str1 =
"package org.jboss.ddoyle.drools.propertyreactive;\n" +
"\n" +
"import " + Event1.class.getCanonicalName() + ";\n" +
"\n" +
"declare Event1\n" +
" @role( event )\n" +
" @timestamp( timestamp )\n" +
" @expires( 2d )\n" +
" @propertyReactive\n" +
"end\n";
String str2 =
"package org.jboss.ddoyle.drools.propertyreactive;\n" +
"\n" +
"import " + Event1.class.getCanonicalName() + ";\n" +
"\n" +
"rule \"rule_1\"\n" +
" when\n" +
" Event1() @watch(*, !code)\n" +
" then\n" +
" System.out.println(\"Rule fired.\");\n" +
"end\n";
KieBase kbase = new KieHelper().addContent(str1, "a.drl")
.addContent(str2, "rules.drl")
.build();
}
public static class Event1 {
private int id;
private String code;
private long timestamp;
public Event1( String code, int id ) {
this.code = code;
this.id = id;
}
public String getCode() {
return code;
}
public int getId() {
return id;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp( long timestamp ) {
this.timestamp = timestamp;
}
public void setId( int id ) {
this.id = id;
}
public void setCode( String code ) {
this.code = code;
}
}
public static class ParentDummyBean {
private String id;
public ParentDummyBean(String id) { this.id = id; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
}
@PropertyReactive
public interface DummyBeanInterface {
boolean isActive();
void setActive(boolean active);
}
@PropertyReactive
public static class DummyBean extends ParentDummyBean implements DummyBeanInterface {
private boolean active;
public DummyBean(String id) {
super(id);
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Override
public String toString() {
return "DummyEvent{" + "id='" + getId() + '\'' + ", active=" + active + '}';
}
}
@Test
public void testPropReactiveWithParentClassNotImplementingChildInterface() {
// DROOLS-1090
String str1 =
"import " + DummyBeanInterface.class.getCanonicalName() + "\n" +
"import " + DummyBean.class.getCanonicalName() + "\n" +
"rule \"RG_TEST_1\"\n" +
" when\n" +
" $event: DummyBean (!active)\n" +
" then\n" +
" modify($event){\n" +
" setActive(true)\n" +
" }\n" +
" System.out.println(\"RG_TEST_1 fired\");\n" +
"end\n" +
"\n" +
"rule \"RG_TEST_2\"\n" +
" when\n" +
" $event: DummyBeanInterface (!active)\n" +
" then\n" +
" System.out.println(\"RG_TEST_2 fired, with event \" + $event);\n" +
" throw new IllegalStateException(\"Should not happen since the event is active\");\n" +
"end\n" +
"\n" +
"rule \"RG_TEST_3\"\n" +
" when\n" +
" $event: DummyBean ()\n" +
" then\n" +
" retract($event)\n" +
" System.out.println(\"RG_TEST_3 fired\");\n" +
"end";
KieSession ksession = new KieHelper().addContent( str1, ResourceType.DRL )
.build()
.newKieSession();
ksession.insert(new DummyBean("1"));
ksession.fireAllRules();
ksession.insert(new DummyBean("2"));
ksession.fireAllRules();
}
@Test
public void testPropReactiveUpdate() {
// DROOLS-1275
String str1 =
"import " + Klass.class.getCanonicalName() + "\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" Klass( b == 2 )\n" +
"then\n" +
" list.add(\"fired\");\n" +
"end\n";
KieSession ksession = new KieHelper().addContent( str1, ResourceType.DRL )
.build()
.newKieSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal( "list", list );
Klass bean = new Klass( 1, 2, 3, 4, 5, 6 );
FactHandle fh = ksession.insert( bean );
ksession.fireAllRules();
assertEquals( 1, list.size() );
( (StatefulKnowledgeSessionImpl) ksession ).update( fh, bean, "a", "d" );
ksession.fireAllRules();
assertEquals( 1, list.size() );
( (StatefulKnowledgeSessionImpl) ksession ).update( fh, bean, "c", "b" );
ksession.fireAllRules();
assertEquals( 2, list.size() );
}
@Test
public void testSetterInConcreteClass() {
// DROOLS-1368
String drl = "import " + BaseFact.class.getCanonicalName() + ";\n"
+ "import " + MyFact.class.getCanonicalName() + ";\n"
+ "rule R when\n"
+ " $b : BaseFact( $n : name, name != null )\n"
+ "then end\n";
KieSession ksession = new KieHelper().addContent(drl, ResourceType.DRL).build().newKieSession();
MyFact f = new MyFact();
FactHandle fh = ksession.insert(f);
assertEquals( 0, ksession.fireAllRules() );
f.setName("hello");
ksession.update(fh, f, "name");
assertEquals( 1, ksession.fireAllRules() );
}
public abstract class BaseFact {
public abstract String getName();
}
public class MyFact extends BaseFact {
private String name;
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@PropertyReactive
public interface StopOrHub {
boolean isVisitedByCoach();
}
@PropertyReactive
public static class BusStop implements StopOrHub {
private boolean visitedByCoach;
@Override
public boolean isVisitedByCoach() {
return visitedByCoach;
}
public BusStop setVisitedByCoach(boolean visitedByCoach) {
this.visitedByCoach = visitedByCoach;
return this;
}
}
@PropertyReactive
public static class Shuttle {
private StopOrHub destination;
public StopOrHub getDestination() {
return destination;
}
public Shuttle setDestination(StopOrHub destination) {
this.destination = destination;
return this;
}
}
@Test
public void testSetterInConcreteClass2() {
// DROOLS-1369
String drl = "package org.test;\n"
+ "import " + BusStop.class.getCanonicalName() + ";\n"
+ "import " + Shuttle.class.getCanonicalName() + ";\n"
+ "import " + StopOrHub.class.getCanonicalName() + ";\n"
+ "rule shuttleDestinationIsCoachOrHub\n"
+ " when\n"
+ " $destination : StopOrHub(visitedByCoach == false)\n"
+ " Shuttle(destination == $destination)\n"
+ " then\n"
+ "end";
KieSession kieSession = new KieHelper().addContent(drl, ResourceType.DRL).build().newKieSession();
BusStop busStop = new BusStop();
Shuttle shuttle = new Shuttle();
busStop.setVisitedByCoach(true);
FactHandle fhShuttle = kieSession.insert(shuttle);
FactHandle fhBusStop = kieSession.insert(busStop);
kieSession.update(fhShuttle, shuttle.setDestination(busStop));
assertEquals(0, kieSession.fireAllRules());
// removing the property name from this update will make the test pass
kieSession.update(fhBusStop, busStop.setVisitedByCoach(false), "visitedByCoach");
// LHS is now satisfied, the rule should fire but it doesn't
assertEquals(busStop, shuttle.getDestination());
assertFalse(busStop.isVisitedByCoach());
assertEquals(1, kieSession.fireAllRules()); // change the expected value to 0 to get further
// after this update (without any real fact modification) the rule will fire as expected
kieSession.update(fhBusStop, busStop);
assertEquals(1, kieSession.fireAllRules());
}
@Test
public void testWatchFieldInExternalPattern() {
// DROOLS-1445
String drl =
"import " + Person.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" $p1 : Person( name == \"Mario\" )\n" +
" $p2 : Person( age > $p1.age ) \n" +
"then\n" +
" list.add(\"t0\");\n" +
"end\n" +
"rule Z when\n" +
" $p1 : Person( name == \"Mario\" ) \n" +
"then\n" +
" modify($p1) { setAge(35); } \n" +
"end\n";
// making the default explicit:
KieSession ksession = new KieHelper(PropertySpecificOption.ALWAYS).addContent(drl, ResourceType.DRL)
.build()
.newKieSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
Person mario = new Person("Mario", 40);
Person mark = new Person("Mark", 37);
FactHandle fh_mario = ksession.insert(mario);
ksession.insert(mark);
int x = ksession.fireAllRules();
assertEquals(1, list.size());
assertEquals("t0", list.get(0));
}
@Test
public void testWatchFieldInExternalNotPattern() {
// DROOLS-1445
String drl =
"import " + Person.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" $p1 : Person( name == \"Mario\" )\n" +
" not( Person( age < $p1.age ) )\n" +
"then\n" +
" list.add(\"t0\");\n" +
"end\n" +
"rule Z when\n" +
" $p1 : Person( name == \"Mario\" ) \n" +
"then\n" +
" modify($p1) { setAge(35); } \n" +
"end\n";
// making the default explicit:
KieSession ksession = new KieHelper(PropertySpecificOption.ALWAYS).addContent(drl, ResourceType.DRL)
.build()
.newKieSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
Person mario = new Person("Mario", 40);
Person mark = new Person("Mark", 37);
FactHandle fh_mario = ksession.insert(mario);
ksession.insert(mark);
int x = ksession.fireAllRules();
assertEquals(1, list.size());
assertEquals("t0", list.get(0));
}
}