From: <jbo...@li...> - 2006-04-21 14:48:08
|
Author: tirelli Date: 2006-04-21 10:47:25 -0400 (Fri, 21 Apr 2006) New Revision: 3886 Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Alarm.java labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/EmergencyTeam.java labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Sensor.java labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions2.drl labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsBacking.drl labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsLoop.drl labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsNoLoop.drl labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsSelfreferencing.drl Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Person.java labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/IntegrationCases.java labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions.drl labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/WorkingMemoryImpl.java labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/LogicalAssertionTest.java Log: JBRULES-233: * Fixing problems described in the ticket, related to logical assertions * Adding unit tests and integration tests Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Alarm.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Alarm.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Alarm.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,38 @@ +package org.drools; + +public class Alarm { + private String message; + + public Alarm(String message) { + this.message = message; + } + + public String toString() { + return this.message; + } + + /** + * @inheritDoc + */ + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((message == null) ? 0 : message.hashCode()); + return result; + } + + /** + * @inheritDoc + */ + public boolean equals(Object obj) { + if ( this == obj ) return true; + if ( obj == null ) return false; + if ( getClass() != obj.getClass() ) return false; + final Alarm other = (Alarm) obj; + if ( message == null ) { + if ( other.message != null ) return false; + } else if ( !message.equals( other.message ) ) return false; + return true; + } + +} Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Alarm.java ___________________________________________________________________ Name: svn:executable + * Name: svn:keywords + id author date revision Name: svn:eol-style + native Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/EmergencyTeam.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/EmergencyTeam.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/EmergencyTeam.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,5 @@ +package org.drools; + +public class EmergencyTeam { + +} Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/EmergencyTeam.java ___________________________________________________________________ Name: svn:executable + * Name: svn:keywords + id author date revision Name: svn:eol-style + native Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Person.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Person.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Person.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -84,4 +84,36 @@ public String toString() { return "[Person name='" + this.name + "']"; } + + + /** + * @inheritDoc + */ + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + age; + result = PRIME * result + (alive ? 1231 : 1237); + result = PRIME * result + ((name == null) ? 0 : name.hashCode()); + result = PRIME * result + sex; + return result; + } + + + /** + * @inheritDoc + */ + public boolean equals(Object obj) { + if ( this == obj ) return true; + if ( obj == null ) return false; + if ( getClass() != obj.getClass() ) return false; + final Person other = (Person) obj; + if ( age != other.age ) return false; + if ( alive != other.alive ) return false; + if ( name == null ) { + if ( other.name != null ) return false; + } else if ( !name.equals( other.name ) ) return false; + if ( sex != other.sex ) return false; + return true; + } } \ No newline at end of file Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Sensor.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Sensor.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Sensor.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,44 @@ +package org.drools; + +public class Sensor { + private int temperature; + private int pressure; + + public Sensor(int temp, int press) { + this.temperature = temp; + this.pressure = press; + } + + /** + * @return the pressure + */ + public int getPressure() { + return pressure; + } + + /** + * @param pressure the pressure to set + */ + public void setPressure(int pressure) { + this.pressure = pressure; + } + + /** + * @return the temperature + */ + public int getTemperature() { + return temperature; + } + + /** + * @param temperature the temperature to set + */ + public void setTemperature(int temperature) { + this.temperature = temperature; + } + + public String toString() { + return "Sensor [ temperature = "+this.temperature+", pressure = "+this.pressure+" ]"; + } + +} Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/Sensor.java ___________________________________________________________________ Name: svn:executable + * Name: svn:keywords + id author date revision Name: svn:eol-style + native Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/IntegrationCases.java =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/IntegrationCases.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/IntegrationCases.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -38,7 +38,9 @@ import org.drools.Person; import org.drools.QueryResults; import org.drools.RuleBase; +import org.drools.Sensor; import org.drools.WorkingMemory; +import org.drools.audit.WorkingMemoryFileLogger; import org.drools.compiler.DrlParser; import org.drools.compiler.DroolsError; import org.drools.compiler.PackageBuilder; @@ -1005,37 +1007,6 @@ list.get( 7 ) ); } - public void testLogicalAssertions() throws Exception { - PackageBuilder builder = new PackageBuilder(); - builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertions.drl" ) ) ); - Package pkg = builder.getPackage(); - - RuleBase ruleBase = getRuleBase(); - ruleBase.addPackage( pkg ); - WorkingMemory workingMemory = ruleBase.newWorkingMemory(); - - List list = new ArrayList(); - workingMemory.setGlobal( "list", - list ); - - Cheese brie = new Cheese( "brie", - 12 ); - FactHandle brieHandle = workingMemory.assertObject( brie ); - - workingMemory.fireAllRules(); - - assertEquals( 2, - list.size() ); - - assertEquals( 2, - workingMemory.getObjects().size() ); - - workingMemory.retractObject( brieHandle ); - - assertEquals( 0, - workingMemory.getObjects().size() ); - } - public void testDuration() throws Exception { PackageBuilder builder = new PackageBuilder(); builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_Duration.drl" ) ) ); @@ -1405,6 +1376,200 @@ assertEquals( "match Person 3", rules[2].getName() ); } + public void testLogicalAssertions() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertions.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + List list = new ArrayList(); + workingMemory.setGlobal( "list", + list ); + + Cheese brie = new Cheese( "brie", + 12 ); + FactHandle brieHandle = workingMemory.assertObject( brie ); + + Cheese provolone = new Cheese( "provolone", + 12 ); + FactHandle provoloneHandle = workingMemory.assertObject( provolone ); + + workingMemory.fireAllRules(); + + assertEquals( 3, + list.size() ); + + assertEquals( 3, + workingMemory.getObjects().size() ); + + workingMemory.retractObject( brieHandle ); + + assertEquals( 2, + workingMemory.getObjects().size() ); + + workingMemory.retractObject( provoloneHandle ); + + assertEquals( 0, + workingMemory.getObjects().size() ); + } + + public void xxxtestLogicalAssertionsBacking() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertionsBacking.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + Cheese cheese1 = new Cheese("c", 1); + Cheese cheese2 = new Cheese(cheese1.getType(), 1); + List list; + + FactHandle h1 = workingMemory.assertObject( cheese1 ); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(cheese1.getType().getClass()); + assertEquals(1, list.size()); + //probably dangerous, as contains works with equals, not identity + assertEquals(cheese1.getType(), list.get(0)); + //FactHandle ht = workingMemory.getFactHandle(c1.getType()); + + FactHandle h2 = workingMemory.assertObject( cheese2 ); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(cheese1.getType().getClass()); + assertEquals(1, list.size()); + assertEquals(cheese1.getType(), list.get(0)); + + workingMemory.retractObject(h1); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(cheese1.getType().getClass()); + assertEquals("cheese-type " + cheese1.getType() + " was retracted, but should not. Backed by cheese2 => type.", 1, list.size()); + assertEquals("cheese-type " + cheese1.getType() + " was retracted, but should not. Backed by cheese2 => type.", cheese1.getType(), list.get(0)); + + workingMemory.retractObject(h2); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(cheese1.getType().getClass()); + assertEquals("cheese-type " + cheese1.getType() + " was not retracted, but should have. Neither cheese1 => type nor cheese2 => type is true.", 0, list.size()); + } + + public void xxxtestLogicalAssertionsSelfreferencing() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertionsSelfreferencing.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + List list; + + String b = new String("b"); + String a = new String("a"); + + workingMemory.setGlobal( "b", b ); + + FactHandle h1 = workingMemory.assertObject( a ); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(a.getClass()); + assertEquals(2, list.size()); + assertTrue(list.contains(a)); + assertTrue(list.contains(b)); + + workingMemory.retractObject(h1); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(a.getClass()); + assertEquals("b was retracted, but it should not have. Is backed by b => b being true.", 1, list.size()); + assertEquals("b was retracted, but it should not have. Is backed by b => b being true.", b, list.get(0)); + + h1 = workingMemory.getFactHandle(b); + workingMemory.retractObject(h1); + workingMemory.fireAllRules(); + list = workingMemory.getObjects(a.getClass()); + assertEquals(0, list.size()); + } + + public void xxxtestLogicalAssertionsLoop() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertionsLoop.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + List list; + + List l = new ArrayList(); + String a = new String("a"); + workingMemory.setGlobal( "a", a ); + workingMemory.setGlobal( "l", l ); + + workingMemory.fireAllRules(); + list = workingMemory.getObjects(a.getClass()); + assertEquals("a still asserted.", 0, list.size()); + assertEquals("Rule has not fired (looped) expected number of times", 10, l.size()); + } + + public void xxxtestLogicalAssertionsNoLoop() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertionsNoLoop.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + List list; + + List l = new ArrayList(); + String a = new String("a"); + workingMemory.setGlobal( "a", a ); + workingMemory.setGlobal( "l", l ); + + workingMemory.fireAllRules(); + list = workingMemory.getObjects(a.getClass()); + assertEquals("a not asserted.", 1, list.size()); + assertEquals("a not asserted", a, list.get(0)); + assertEquals("Rule should not loop", 1, l.size()); + } + + public void xxxtestLogicalAssertions2() throws Exception { + PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_LogicalAssertions2.drl" ) ) ); + Package pkg = builder.getPackage(); + + RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + WorkingMemory workingMemory = ruleBase.newWorkingMemory(); + + List events = new ArrayList(); + + workingMemory.setGlobal( "events", events ); + + Sensor sensor = new Sensor(80, 80); + FactHandle handle = workingMemory.assertObject( sensor ); + + // everything should be normal + workingMemory.fireAllRules(); + + List list = workingMemory.getObjects(); + + assertEquals("Only sensor is there", 1, list.size()); + assertEquals("Only one event", 1, events.size()); + + // problems should be detected + sensor.setPressure( 200 ); + sensor.setTemperature( 200 ); + workingMemory.modifyObject( handle, sensor ); + + workingMemory.fireAllRules(); + assertEquals("Only sensor is there", 1, list.size()); + assertEquals("Exactly six events", 6, events.size()); + } + private Object serializeIn(byte[] bytes) throws IOException, ClassNotFoundException { ObjectInput in = new ObjectInputStream( new ByteArrayInputStream( bytes ) ); Modified: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -5,14 +5,22 @@ global java.util.List list; -rule justifier +rule justifier1 when - cheese : Cheese( ) + cheese : Cheese( type == "brie" ) then assertLogical( new Person( "jane" ) ); list.add( cheese ); end +rule justifier2 + when + cheese : Cheese( type == "provolone" ) + then + assertLogical( new Person( "jane" ) ); + list.add( cheese ); +end + rule justified when person : Person( ) Added: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions2.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions2.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions2.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,50 @@ +package org.drools.test; + +import org.drools.Alarm; +import org.drools.EmergencyTeam; +import org.drools.Sensor; + +global java.util.List events; + +rule "Everything is Normal" + when + not Alarm( ) + then + events.add("Everything is Normal"); +end + +rule "Problem detected" salience 10 + when + sensor : Sensor( temperature > 100 ) or Sensor( pressure > 150 ) + then + events.add( "Problem detected: "+sensor.toString() ); + assertLogical( new Alarm( "Call emergency team" ) ); +end + +rule "Call Emergency Team" + when + Alarm ( ) + then + events.add( "Calling Emergency Team" ); + assertLogical( new EmergencyTeam() ); +end + +rule "Emergency Team solves temperature" salience 20 + when + EmergencyTeam() + sensor : Sensor( temperature > 100 ) + then + events.add( "Solving temperature problem" ); + sensor.setTemperature(80); + modify(sensor); +end + +rule "Emergency Team solves pressure" salience 20 + when + EmergencyTeam() + sensor : Sensor( pressure > 150 ) + then + events.add( "Solving pressure problem" ); + sensor.setPressure(80); + modify(sensor); +end Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertions2.drl ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsBacking.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsBacking.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsBacking.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,10 @@ +package org.drools.test; + +import org.drools.Cheese; + +rule "Cheese => type" + when + Cheese( type : type ) + then + assertLogical( type ); +end \ No newline at end of file Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsBacking.drl ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsLoop.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsLoop.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsLoop.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,18 @@ +package org.drools.test; + +import java.lang.String; +import java.util.List; + +global java.lang.String a; +global java.util.List l; + +rule "r" + when + not String() + then + if (l.size() < 10) + { + l.add(new Integer(0)); + assertLogical( a ); + } +end \ No newline at end of file Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsLoop.drl ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsNoLoop.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsNoLoop.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsNoLoop.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,20 @@ +package org.drools.test; + +import java.lang.String; +import java.util.List; + +global java.lang.String a; +global java.util.List l; + +rule "r" + no-loop true + when + not String() + then + l.add(new Integer(0)); + if (l.size() > 2) + { + throw new Exception( "this should not loop" ); + } + assertLogical( a ); +end \ No newline at end of file Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsNoLoop.drl ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native Added: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsSelfreferencing.drl =================================================================== --- labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsSelfreferencing.drl 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsSelfreferencing.drl 2006-04-21 14:47:25 UTC (rev 3886) @@ -0,0 +1,11 @@ +package org.drools.test; + +global java.lang.String b; +import java.lang.String; + +rule "String => b" + when + s : String() + then + assertLogical( b ); +end Property changes on: labs/jbossrules/trunk/drools-compiler/src/test/resources/org/drools/integrationtests/test_LogicalAssertionsSelfreferencing.drl ___________________________________________________________________ Name: svn:executable + * Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/WorkingMemoryImpl.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/WorkingMemoryImpl.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/WorkingMemoryImpl.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -103,7 +103,11 @@ private Map queryResults = Collections.EMPTY_MAP; + /** Support for logical assertions */ private static final String STATED = "STATED"; + private static final String JUSTIFIED = "JUSTIFIED"; + private static final String NEW = "NEW"; + private static final FactStatus STATUS_NEW = new FactStatus(NEW, 0); /** The eventSupport */ private final WorkingMemoryEventSupport workingMemoryEventSupport = new WorkingMemoryEventSupport( this ); @@ -425,27 +429,40 @@ boolean logical, Rule rule, Activation activation) throws FactException { + // check if the object already exists in the WM FactHandleImpl handle = (FactHandleImpl) this.identityMap.get( object ); - // return if the handle exists and this is a logical assertion - if ( (handle != null) && (logical) ) { - return handle; + // lets see if the object is already logical asserted + FactStatus logicalState = (FactStatus) this.equalsMap.get( object ); + if(logicalState == null) { + logicalState = STATUS_NEW; } - // lets see if the object is already logical asserted - Object logicalState = this.equalsMap.get( object ); + // This object is already STATED, we cannot make it justifieable + if ( (logical) && (logicalState.getStatus() == WorkingMemoryImpl.STATED) ) { + return null; + } + // return if there is already a logical handle + if ( (logical) && (logicalState.getStatus() == WorkingMemoryImpl.JUSTIFIED) ) { + addLogicalDependency( logicalState.getHandle(), + activation, + activation.getPropagationContext(), + rule ); + return logicalState.getHandle(); + } + // if we have a handle and this STATED fact was previously STATED - if ( (handle != null) && (!logical) && logicalState == WorkingMemoryImpl.STATED ) { + if ( (handle != null) && (!logical) && ( logicalState.getStatus() == WorkingMemoryImpl.STATED ) ) { return handle; } if ( !logical ) { // If this stated assertion already has justifications then we need // to cancel them - if ( logicalState instanceof FactHandleImpl ) { - handle = (FactHandleImpl) logicalState; + if ( logicalState.getStatus() == WorkingMemoryImpl.JUSTIFIED ) { + handle = logicalState.getHandle(); removeLogicalDependencies( handle ); } else { handle = (FactHandleImpl) newFactHandle(); @@ -454,19 +471,21 @@ putObject( handle, object ); - this.equalsMap.put( object, - WorkingMemoryImpl.STATED ); + if( logicalState != WorkingMemoryImpl.STATUS_NEW) { + // make sure status is stated + logicalState.setStatus( WorkingMemoryImpl.STATED ); + logicalState.incCounter(); + } else { + this.equalsMap.put( object, + new FactStatus(WorkingMemoryImpl.STATED, 1) ); + } if ( dynamic ) { addPropertyChangeListener( object ); } } else { - // This object is already STATED, we cannot make it justifieable - if ( logicalState == WorkingMemoryImpl.STATED ) { - return null; - } - handle = (FactHandleImpl) logicalState; + handle = logicalState.getHandle(); // we create a lookup handle for the first asserted equals object // all future equals objects will use that handle if ( handle == null ) { @@ -476,8 +495,8 @@ object ); this.equalsMap.put( object, - handle ); - } + new FactStatus(WorkingMemoryImpl.JUSTIFIED, handle) ); + } addLogicalDependency( handle, activation, activation.getPropagationContext(), @@ -614,11 +633,17 @@ /* check to see if this was a logical asserted object */ if ( removeLogical ) { removeLogicalDependencies( handle ); - this.equalsMap.remove( oldObject ); + //this.equalsMap.remove( oldObject ); } - if ( updateEqualsMap ) { - this.equalsMap.remove( oldObject ); + if ( removeLogical || updateEqualsMap ) { + FactStatus status = (FactStatus) this.equalsMap.get( oldObject ); + if(status != null) { + status.decCounter(); + if(status.getCounter() <= 0) { + this.equalsMap.remove( oldObject ); + } + } } this.factHandlePool.push( ((FactHandleImpl) handle).getId() ); @@ -661,7 +686,7 @@ if ( this.justified.get( handleImpl.getId() ) != null ) { this.equalsMap.remove( originalObject ); this.equalsMap.put( object, - handle ); + new FactStatus(WorkingMemoryImpl.JUSTIFIED, handleImpl) ); } PropagationContext propagationContext = new PropagationContextImpl( this.propagationIdCounter++, @@ -812,4 +837,78 @@ public void dispose() { this.ruleBase.disposeWorkingMemory( this ); } + + private static class FactStatus { + private int counter; + private String status; + private FactHandleImpl handle; + + public FactStatus() { + this(WorkingMemoryImpl.STATED, 1); + } + + public FactStatus(String status) { + this(status, 1); + } + + public FactStatus(String status, FactHandleImpl handle) { + this.status = status; + this.handle = handle; + } + + public FactStatus(String status, int counter) { + this.status = status; + this.counter = counter; + } + + /** + * @return the counter + */ + public int getCounter() { + return counter; + } + /** + * @param counter the counter to set + */ + public void setCounter(int counter) { + this.counter = counter; + } + + public int incCounter() { + return ++counter; + } + + public int decCounter() { + return --counter; + } + /** + * @return the handle + */ + public FactHandleImpl getHandle() { + return handle; + } + /** + * @param handle the handle to set + */ + public void setHandle(FactHandleImpl handle) { + this.handle = handle; + } + /** + * @return the status + */ + public String getStatus() { + return status; + } + /** + * @param status the status to set + */ + public void setStatus(String status) { + this.status = status; + } + + public String toString() { + return "FactStatus( "+this.status+", handle="+this.handle+", counter="+this.counter+")"; + } + + } } Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/LogicalAssertionTest.java =================================================================== --- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/LogicalAssertionTest.java 2006-04-21 12:19:44 UTC (rev 3885) +++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/LogicalAssertionTest.java 2006-04-21 14:47:25 UTC (rev 3886) @@ -285,7 +285,7 @@ // Alreyad identify same so return previously assigned handle logicalHandle1 = workingMemory.assertObject( logicalString2, false, - true, + false, rule1, tuple1.getActivation() ); // return the matched handle @@ -507,5 +507,96 @@ assertLength( 0, workingMemory.getJustified().values() ); } + + /** + * This tests that when multiple not identical, but equals facts, are asserted + * into WM, only when all are removed, a logical assert will succeed + * + * @throws Exception + */ + public void testMultipleAssert() throws Exception { + // create a RuleBase with a single ObjectTypeNode we attach a + // MockObjectSink so we can detect assertions and retractions + final Rule rule1 = new Rule( "test-rule1" ); + Rete rete = new Rete(); + ObjectTypeNode objectTypeNode = new ObjectTypeNode( 0, + new ClassObjectType( String.class ), + rete ); + objectTypeNode.attach(); + MockObjectSink sink = new MockObjectSink(); + objectTypeNode.addObjectSink( sink ); + final TerminalNode node = new TerminalNode( 2, + new MockTupleSource( 2 ), + rule1 ); + RuleBase ruleBase = new RuleBaseImpl(); + WorkingMemoryImpl workingMemory = (WorkingMemoryImpl) ruleBase.newWorkingMemory(); + final Agenda agenda = workingMemory.getAgenda(); + + Consequence consequence = new Consequence() { + public void evaluate(KnowledgeHelper knowledgeHelper, + WorkingMemory workingMemory) { + // do nothing + } + }; + rule1.setConsequence( consequence ); + + FactHandleImpl handle1 = new FactHandleImpl( 1 ); + ReteTuple tuple1 = new ReteTuple( handle1 ); + + final PropagationContext context1 = new PropagationContextImpl( 0, + PropagationContext.ASSERTION, + null, + null ); + + // Assert multiple stated objects + node.assertTuple( tuple1, + context1, + workingMemory ); + + String statedString1 = new String( "logical" ); + FactHandle statedHandle1 = workingMemory.assertObject( statedString1 ); + + String statedString2 = new String( "logical" ); + FactHandle statedHandle2 = workingMemory.assertObject( statedString2 ); + + // This assertion is logical should fail as there is previous stated objects + String logicalString3 = new String( "logical" ); + FactHandle logicalHandle3 = workingMemory.assertObject( logicalString3, + false, + true, + rule1, + tuple1.getActivation() ); + + // Checks that previous LogicalAssert failed + assertNull( logicalHandle3 ); + + workingMemory.retractObject( statedHandle2 ); + + logicalHandle3 = workingMemory.assertObject( logicalString3, + false, + true, + rule1, + tuple1.getActivation() ); + + // Checks that previous LogicalAssert failed as there is still one + // stated string in the working memory + assertNull( logicalHandle3 ); + + workingMemory.retractObject( statedHandle1 ); + + logicalHandle3 = workingMemory.assertObject( logicalString3, + false, + true, + rule1, + tuple1.getActivation() ); + + // Checks that previous LogicalAssert succeeded as there are no more + // stated strings in the working memory + assertNotNull( logicalHandle3 ); + + } + + + } \ No newline at end of file |