/* * 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.beliefsystem.jtms; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.drools.compiler.Person; import org.drools.core.BeliefSystemType; import org.drools.core.SessionConfiguration; import org.drools.core.beliefsystem.jtms.JTMSBeliefSetImpl; import org.drools.core.beliefsystem.jtms.JTMSBeliefSystem; import org.drools.core.common.EqualityKey; import org.drools.core.common.NamedEntryPoint; import org.drools.core.impl.StatefulKnowledgeSessionImpl; import org.drools.core.util.ObjectHashMap; import org.drools.core.util.ObjectHashMap.ObjectEntry; import org.junit.Ignore; import org.junit.Test; import org.kie.api.io.ResourceType; import org.kie.api.runtime.KieSessionConfiguration; import org.kie.api.runtime.rule.FactHandle; import org.kie.api.runtime.rule.Match; import org.kie.internal.KnowledgeBase; import org.kie.internal.KnowledgeBaseFactory; import org.kie.internal.builder.KnowledgeBuilder; import org.kie.internal.builder.KnowledgeBuilderFactory; import org.kie.internal.event.rule.RuleEventListener; import org.kie.internal.event.rule.RuleEventManager; import org.kie.internal.io.ResourceFactory; import org.kie.internal.runtime.StatefulKnowledgeSession; import static org.junit.Assert.*; public class JTMSTest { protected StatefulKnowledgeSession getSessionFromString( String drlString) { KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); try { System.setProperty("drools.negatable", "on"); kBuilder.add(ResourceFactory.newByteArrayResource(drlString.getBytes()), ResourceType.DRL); if (kBuilder.hasErrors()) { System.err.println(kBuilder.getErrors()); fail(); } } finally { System.setProperty("drools.negatable", "off"); } KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase( ); kBase.addKnowledgePackages( kBuilder.getKnowledgePackages() ); KieSessionConfiguration ksConf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration(); ((SessionConfiguration) ksConf).setBeliefSystemType( BeliefSystemType.JTMS ); StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession( ksConf, null ); return kSession; } protected StatefulKnowledgeSession getSessionFromFile( String ruleFile ) { KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kBuilder.add( ResourceFactory.newClassPathResource( ruleFile, getClass() ), ResourceType.DRL ); if ( kBuilder.hasErrors() ) { System.err.println( kBuilder.getErrors() ); fail(); } KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase( ); kBase.addKnowledgePackages( kBuilder.getKnowledgePackages() ); KieSessionConfiguration ksConf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration(); ((SessionConfiguration) ksConf).setBeliefSystemType( BeliefSystemType.JTMS ); StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession( ksConf, null ); return kSession; } @Test(timeout = 10000 ) public void testPosNegNonConflictingInsertions() { String s = "package org.drools.core.beliefsystem.jtms;\n" + "\n" + "import java.util.List \n" + "import org.drools.core.common.AgendaItem;" + "global java.util.List list;\n" + "\n" + "rule \"go1\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " insertLogical( 'neg', 'neg' );\n" + "end\n" + "\n" + "rule \"go2\"\n" + "when\n" + " String( this == 'go2' )\n" + "then\n" + " insertLogical( 'pos' );\n" + "end\n" + "\n" + "rule \"Positive\"\n" + "when\n" + " $n : String( this != 'go1' || == 'go2' ) \n" + "then\n" + " final String s = '+' + $n;" + " final List l = list;" + " l.add( s );\n" + "end\n" + "rule \"Negative\"\n" + "when\n" + " $n : String( _.neg, this != 'go1' || == 'go2' ) \n" + "then\n" + " final String s = '-' + $n; \n" + " final List l = list; \n" + " l.add( s ); \n" + "end\n"; StatefulKnowledgeSession kSession = getSessionFromString( s ); List list = new ArrayList(); kSession.setGlobal( "list", list ); ( (RuleEventManager) kSession ).addEventListener( new RuleEventListener() { @Override public void onDeleteMatch( Match match ) { String rule = match.getRule().getName(); if (rule.equals( "Positive" )) { list.remove("+" + match.getDeclarationValue( "$n" )); } else if (rule.equals( "Negative" )) { list.remove("-" + match.getDeclarationValue( "$n" )); } } } ); FactHandle fhGo1 = kSession.insert( "go1" ); kSession.fireAllRules(); assertTrue( list.contains( "-neg" ) ); assertEquals( 1, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); //just go1 assertEquals( 1, getNegativeObjects(kSession).size() ); FactHandle fhGo2 = kSession.insert( "go2" ); kSession.fireAllRules(); assertTrue( list.contains( "-neg" ) ); assertTrue( list.contains( "+pos" ) ); assertEquals( 3, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); //go1, go2, pos assertEquals( 1, getNegativeObjects(kSession).size() ); kSession.retract( fhGo1 ); kSession.fireAllRules(); assertFalse( list.contains( "-neg" ) ); assertTrue( list.contains( "+pos" ) ); assertEquals( 2, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); //go2, pos assertEquals( 0, getNegativeObjects(kSession).size() ); kSession.retract( fhGo2 ); kSession.fireAllRules(); assertFalse( list.contains( "-neg" ) ); assertFalse( list.contains( "+pos" ) ); assertEquals( 0, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); assertEquals( 0, getNegativeObjects(kSession).size() ); } @Test(timeout = 10000 ) public void testConflictToggleWithoutGoingEmpty() { String s = "package org.drools.core.beliefsystem.jtms;\n" + "\n" + "import java.util.List \n" + "import org.drools.core.common.AgendaItem;" + "global java.util.List list;\n" + "\n" + "rule \"go1\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " insertLogical( 'xxx' );\n" + "end\n" + "rule \"go2\"\n" + "when\n" + " String( this == 'go2' )\n" + "then\n" + " insertLogical( 'xxx');\n" + "end\n" + "rule \"go3\"\n" + "when\n" + " String( this == 'go3' )\n" + "then\n" + " insertLogical( 'xxx');\n" + "end\n" + "\n" + "rule \"go4\"\n" + "when\n" + " String( this == 'go4' )\n" + "then\n" + " insertLogical( 'xxx', 'neg' );\n" + "end\n" + "\n" + "rule \"Positive\"\n" + "when\n" + " $n : String( this == 'xxx' ) \n" + "then\n" + " final String s = '+' + $n;" + " final List l = list;" + " l.add( s );\n" + "end\n" + "rule \"Negative\"\n" + "when\n" + " $n : String( _.neg, this == 'xxx' )\n" + "then\n" + " final String s = '-' + $n; \n" + " final List l = list; \n" + " l.add( s ); \n" + "end\n" + ""; StatefulKnowledgeSession kSession = getSessionFromString( s ); List list = new ArrayList(); kSession.setGlobal( "list", list ); ( (RuleEventManager) kSession ).addEventListener( new RuleEventListener() { @Override public void onDeleteMatch( Match match ) { String rule = match.getRule().getName(); if (rule.equals( "Positive" )) { list.remove("+" + match.getDeclarationValue( "$n" )); } else if (rule.equals( "Negative" )) { list.remove("-" + match.getDeclarationValue( "$n" )); } } } ); FactHandle fhGo1 = kSession.insert( "go1" ); FactHandle fhGo2 = kSession.insert( "go2" ); FactHandle fhGo3 = kSession.insert( "go3" ); kSession.fireAllRules(); System.out.println( list ); assertTrue(list.contains("+xxx")); FactHandle fhGo4 = kSession.insert( "go4" ); kSession.fireAllRules(); assertTrue( list.isEmpty()); kSession.delete(fhGo4); kSession.fireAllRules(); assertTrue( list.contains( "+xxx" ) ); } @Test(timeout = 10000 ) @Ignore("Currently cannot support updates") public void testChangeInPositivePrime() { String s = "package org.drools.core.beliefsystem.jtms;\n" + "\n" + "import org.kie.internal.event.rule.ActivationUnMatchListener;\n" + "import java.util.List \n" + "import org.drools.core.common.AgendaItem;" + "import org.drools.compiler.Person;" + "global java.util.List list;\n" + "\n" + "rule \"go1\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(1); \n" + " insertLogical( p );\n" + "end\n" + "rule \"go2\"\n" + "when\n" + " String( this == 'go2' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(2); \n" + " insertLogical( p );\n" + "end\n" + "rule \"go3\"\n" + "when\n" + " String( this == 'go3' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(3); \n" + " insertLogical( p );\n" + "end\n" + "\n"; StatefulKnowledgeSession kSession = getSessionFromString( s ); List list = new ArrayList(); kSession.setGlobal( "list", list ); // We want to make sure go1 is prime, and then that it switches to go2 FactHandle fhGo1 = kSession.insert( "go1" ); kSession.fireAllRules(); FactHandle fhGo2 = kSession.insert( "go2" ); kSession.fireAllRules(); FactHandle fhGo3 = kSession.insert( "go3" ); kSession.fireAllRules(); NamedEntryPoint ep = ( NamedEntryPoint ) ((StatefulKnowledgeSessionImpl)kSession).getEntryPoint( "DEFAULT" ); assertEquals( 4, ep.getObjects().size() ); //just go1, go2, go3, Person(darth) int count = 0; for ( Object object : ep.getObjects() ) { if ( object instanceof Person ) { assertEquals( new Integer(1), ((Person)object).getNotInEqualTestObject() ); count++; } } assertEquals( 1, count ); ObjectHashMap equalityMap = ep.getTruthMaintenanceSystem().getEqualityKeyMap(); assertEquals( 1, equalityMap.size() ); // Only Person type is logical org.drools.core.util.Iterator it = equalityMap.iterator(); EqualityKey key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 3, key.getBeliefSet().size() ); assertEquals( new Integer(1), ((Person)key.getBeliefSet().getFactHandle().getObject()).getNotInEqualTestObject() ); kSession.retract( fhGo1 ); kSession.fireAllRules(); it = equalityMap.iterator(); key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 2, key.getBeliefSet().size() ); assertEquals( new Integer(3), ((Person)key.getBeliefSet().getFactHandle().getObject()).getNotInEqualTestObject() ); kSession.retract( fhGo3 ); kSession.fireAllRules(); it = equalityMap.iterator(); key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 1, key.getBeliefSet().size() ); assertEquals( new Integer(2), ((Person)key.getBeliefSet().getFactHandle().getObject()).getNotInEqualTestObject() ); } @Test(timeout = 10000 ) @Ignore("Currently cannot support updates") public void testChangeInNegativePrime() { String s = "package org.drools.core.beliefsystem.jtms;\n" + "\n" + "import org.kie.internal.event.rule.ActivationUnMatchListener;\n" + "import java.util.List \n" + "import org.drools.core.common.AgendaItem;" + "import org.drools.compiler.Person;" + "global java.util.List list;\n" + "\n" + "declare entry-point 'neg' end \n" + "" + "rule \"go1\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(1); \n" + " insertLogical( p, 'neg' );\n" + "end\n" + "rule \"go2\"\n" + "when\n" + " String( this == 'go2' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(2); \n" + " insertLogical( p, 'neg' );\n" + "end\n" + "rule \"go3\"\n" + "when\n" + " String( this == 'go3' )\n" + "then\n" + " Person p = new Person( 'darth' ); \n" + " p.setNotInEqualTestObject(3); \n" + " insertLogical( p, 'neg' );\n" + "end\n" + "\n"; StatefulKnowledgeSession kSession = getSessionFromString( s ); List list = new ArrayList(); kSession.setGlobal( "list", list ); // We want to make sure go1 is prime, and then that it switches to go2 FactHandle fhGo1 = kSession.insert( "go1" ); kSession.fireAllRules(); FactHandle fhGo2 = kSession.insert( "go2" ); kSession.fireAllRules(); FactHandle fhGo3 = kSession.insert( "go3" ); kSession.fireAllRules(); NamedEntryPoint ep = ( NamedEntryPoint ) ((StatefulKnowledgeSessionImpl)kSession).getEntryPoint( "DEFAULT" ); assertEquals( 3, ep.getObjects().size() ); //just go1, go2, go3 assertEquals( 1, getNegativeObjects(kSession).size() ); // Person(darth) int count = 0; for ( Object object : getNegativeObjects(kSession) ) { if ( object instanceof Person ) { assertEquals( new Integer(1), ((Person)object).getNotInEqualTestObject() ); count++; } } assertEquals( 1, count ); ObjectHashMap equalityMap = ep.getTruthMaintenanceSystem().getEqualityKeyMap(); assertEquals( 1, equalityMap.size() ); // Only Person type is logical org.drools.core.util.Iterator it = equalityMap.iterator(); EqualityKey key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 3, key.getBeliefSet().size() ); assertEquals( new Integer(1), ((Person)((JTMSBeliefSetImpl)key.getBeliefSet()).getFactHandle().getObject()).getNotInEqualTestObject() ); kSession.retract( fhGo1 ); kSession.fireAllRules(); it = equalityMap.iterator(); key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 2, key.getBeliefSet().size() ); assertEquals( new Integer(3), ((Person)((JTMSBeliefSetImpl)key.getBeliefSet()).getFactHandle().getObject()).getNotInEqualTestObject() ); kSession.retract( fhGo3 ); kSession.fireAllRules(); it = equalityMap.iterator(); key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( new Person( "darth") ) ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 1, key.getBeliefSet().size() ); assertEquals( new Integer(2), ((Person)((JTMSBeliefSetImpl)key.getBeliefSet()).getFactHandle().getObject()).getNotInEqualTestObject() ); } @Test(timeout = 10000 ) @Ignore("Currently cannot support updates") public void testRetractHandleWhenOnlyNeg() { String s = "package org.drools.core.beliefsystem.jtms;\n" + "\n" + "import java.util.List \n" + "import org.drools.core.common.AgendaItem;" + "global java.util.List list;\n" + "\n" + "rule \"go1_1\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " insertLogical( new String( 'neg' ), 'neg' );\n" + "end\n" + "rule \"go1_2\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " insertLogical( new String( 'neg' ), 'neg' );\n" + "end\n" + "rule \"go1_3\"\n" + "when\n" + " String( this == 'go1' )\n" + "then\n" + " insertLogical( new String( 'neg' ), 'neg' );\n" + "end\n" + "\n" + "rule \"Negative\"\n" + "when\n" + " $n : String( _.neg, this != 'go1' || == 'go2' ) \n" + "then\n" + " final String s = '-' + $n; \n" + " final List l = list; \n" + " l.add( s ); \n" + "end\n"; StatefulKnowledgeSession kSession = getSessionFromString( s ); List list = new ArrayList(); kSession.setGlobal( "list", list ); ( (RuleEventManager) kSession ).addEventListener( new RuleEventListener() { @Override public void onDeleteMatch( Match match ) { String rule = match.getRule().getName(); if (rule.equals( "Negative" )) { list.remove("-" + match.getDeclarationValue( "$n" )); } } } ); FactHandle fhGo1 = kSession.insert( "go1" ); kSession.fireAllRules(); assertTrue( list.contains( "-neg" ) ); assertEquals( 1, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); //just go1 assertEquals( 1, getNegativeObjects(kSession).size() ); NamedEntryPoint ep = ( NamedEntryPoint ) ((StatefulKnowledgeSessionImpl)kSession).getEntryPoint( "DEFAULT" ); ObjectHashMap equalityMap = ep.getTruthMaintenanceSystem().getEqualityKeyMap(); assertEquals( 2, equalityMap.size() ); // go1, neg are two different strings. org.drools.core.util.Iterator it = equalityMap.iterator(); EqualityKey key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); while ( !key.getFactHandle().getObject().equals( "neg") ) { key = ( EqualityKey ) (( ObjectEntry ) it.next() ).getValue(); } assertEquals( 3, key.getBeliefSet().size() ); ep.getTruthMaintenanceSystem().delete( key.getLogicalFactHandle() ); assertEquals( 0, key.getBeliefSet().size() ); assertEquals( 1, kSession.getEntryPoint( "DEFAULT" ).getObjects().size() ); //just go1 assertEquals( 0, getNegativeObjects(kSession).size() ); assertEquals( 0, key.getBeliefSet().size() ); assertEquals( 1, ep.getTruthMaintenanceSystem().getEqualityKeyMap().size() ); } @Test(timeout = 10000 ) public void testConflictStrict() { StatefulKnowledgeSession kSession = getSessionFromFile( "posNegConflict.drl" ); ArrayList list = new ArrayList(); kSession.setGlobal( "list", list ); NamedEntryPoint ep = ( NamedEntryPoint ) ((StatefulKnowledgeSessionImpl)kSession).getEntryPoint( "DEFAULT" ); JTMSBeliefSystem bs = ( JTMSBeliefSystem ) ep.getTruthMaintenanceSystem().getBeliefSystem(); bs.STRICT = true; try { kSession.fireAllRules(); fail( "A fact and its negation should have been asserted, but no exception was trhown in strict mode" ); } catch ( Exception e ) { } finally { bs.STRICT = false; } } @Test(timeout = 10000 ) @Ignore("Currently cannot support updates") public void testConflictTMS() { StatefulKnowledgeSession kSession = getSessionFromFile( "posNegTms.drl" ); ArrayList list = new ArrayList(); kSession.setGlobal( "list", list ); FactHandle a = kSession.insert( "a" ); FactHandle b = kSession.insert( "b" ); FactHandle c = kSession.insert( "c" ); FactHandle d = kSession.insert( "d" ); try { kSession.fireAllRules(); assertEquals( 4, kSession.getFactCount() ); assertEquals( 0, list.size() ); kSession.retract( a ); kSession.fireAllRules(); assertEquals( 3, kSession.getFactCount() ); assertEquals( 0, list.size() ); kSession.retract( b ); kSession.fireAllRules(); assertEquals( 2, kSession.getFactCount() ); assertEquals(1, getNegativeObjects(kSession).size()); assertEquals( 1, list.size() ); a = kSession.insert( "a" ); kSession.fireAllRules(); assertEquals( 3, kSession.getFactCount()); assertEquals( 0, getNegativeObjects(kSession).size() ); assertEquals( 1, list.size() ); kSession.retract( c ); kSession.fireAllRules(); assertEquals( 2, kSession.getFactCount() ); assertEquals( 0, getNegativeObjects(kSession).size() ); assertEquals( 1, list.size() ); kSession.retract( d ); kSession.fireAllRules(); assertEquals( 2, kSession.getFactCount() ); assertEquals( 0, getNegativeObjects(kSession).size() ); assertEquals( 2, list.size() ); kSession.retract( a ); kSession.fireAllRules(); assertEquals( 0, kSession.getFactCount() ); assertEquals( 0, getNegativeObjects(kSession).size() ); assertEquals( 2, list.size() ); c = kSession.insert( "c" ); kSession.fireAllRules(); assertEquals( 1, kSession.getFactCount() ); assertEquals( 1, getNegativeObjects(kSession).size() ); assertEquals( 3, list.size() ); } catch ( Exception e ) { e.printStackTrace(); fail( "No exception should have been thrown" ); } } public List getNegativeObjects(StatefulKnowledgeSession kSession) { List list = new ArrayList(); Iterator it = ((StatefulKnowledgeSessionImpl) kSession).getObjectStore().iterateNegObjects(null); while ( it.hasNext() ) { list.add( it.next() ); } return list; } @Test public void testPrimeJustificationWithEqualityMode() { String droolsSource = "package org.drools.tms.test; \n" + "declare Bar end \n" + "" + "declare Holder x : Bar end \n" + "" + "" + "rule Init \n" + "when \n" + "then \n" + " insert( new Holder( new Bar() ) ); \n" + "end \n" + "rule Justify \n" + "when \n" + " $s : Integer() \n" + " $h : Holder( $b : x ) \n" + "then \n" + " insertLogical( $b ); \n" + "end \n" + "rule React \n" + "when \n" + " $b : Bar( ) \n" + "then \n" + " System.out.println( $b ); \n" + "end \n" ; StatefulKnowledgeSession session = getSessionFromString( droolsSource ); FactHandle handle1 = session.insert( 10 ); FactHandle handle2 = session.insert( 20 ); assertEquals( 4, session.fireAllRules() ); session.delete( handle1 ); assertEquals( 0, session.fireAllRules() ); } }