Simple example loops ad infinitum if executed. If I add "no-loop true" it works. But why? There is no loop hole...
package spikes;
import org.springframework.roo.addon.javabean.RooJavaBean;
@RooJavaBean
public class Applicant {
private final String string;
private final int age;
public boolean valid=true;
public Applicant(String string, int i) {
this.string = string;
this.age = i;
}
}
DroolsSpikeTest
package spikes;
import static org.junit.Assert.*;
import org.drools.KnowledgeBase;
import org.drools.runtime.StatelessKnowledgeSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:**/applicationContext-drools.xml"})
public class DroolsSpikeTest {
@Autowired
private KnowledgeBase kbase;
@Test
public void testspikeDroolRule() {
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
Applicant a = new Applicant("Mr John Smith", 16);
assertTrue(a.isValid());
ksession.execute(a);
assertFalse(a.isValid());
}
}
applicationContext-drools.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--INFO: http://architects.dzone.com/articles/drools-51-expands-spring -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:drools="http://drools.org/schema/drools-spring"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://drools.org/schema/drools-spring http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.0.0.xsd">
<drools:kbase id="kbase1">
<drools:resources>
<drools:resource id="licenseRule" type="DRL" source="classpath:spikes/licenseApplication.drl"/>
</drools:resources>
<drools:configuration>
<drools:mbeans enabled="true" />
</drools:configuration>
</drools:kbase>
<drools:ksession kbase="kbase1" type="stateless" id="ksessionStateless" name="stateless1" >
</drools:ksession>
</beans>
licenseApplication.drl
import spikes.Applicant
rule "Is of valid age" when
$a : Applicant( age < 18 )
then
modify( $a ) { valid = false };
end
The line beginning with modify($a)
tells the engine that the Applicant fact has been updated. This causes the engine to reevaluate all rule conditions. Since the Applicant's age is still under 18, this causes this rule to activate again. Rinse and repeat, forever.
Adding no-loop
tells the engine that the consequence of a rule should not cause the same rule to reactivate. Please note that no-loop
is not a silver bullet against infinite loops; if the consequence of Rule A causes Rule B to activate, and the consequence of Rule B causes Rule A to activate, no-loop
will not prevent the infinite loop.
Personally, I think no-loop
is a cheat to get around writing better conditions. The better solution to this is to write your conditions in such a way that they do not reactivate when they shouldn't. Sometimes this involves inserting "control facts" that your conditions reference, but you can often simply update the pattern to be more specific. In your case, the solution is simple:
rule "Is of valid age" when
$a : Applicant( age < 18, valid != false )
then
modify( $a ) { valid = false };
end
By adding valid != false
to your pattern, the modification of the fact will not cause this rule to reactivate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With