2012-01-20 3 views
5

Semplice loop di esempio all'infinito se eseguito. Se aggiungo "no-loop true", funziona. Ma perché? Non v'è alcuna scappatoia ...Drools spara in un loop

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 
+0

Non ho mai visto "foro di loop" che significa "causa di un loop inaspettato". – aitchnyu

risposta

10

La linea che inizia con modify($a) dice al motore che il fatto del Richiedente è stato aggiornato. Ciò fa sì che il motore rivaluti tutte le condizioni delle regole. Poiché l'età del richiedente è ancora sotto i 18 anni, questa regola si attiva nuovamente. Risciacquare e ripetere, per sempre.

L'aggiunta di no-loop indica al motore che la conseguenza di una regola non dovrebbe causare la riattivazione della stessa regola. Si prega di notare che no-loop non è un proiettile d'argento contro i loop infiniti; se la conseguenza della Regola A fa attivare la Regola B, e la conseguenza della Regola B fa attivare la Regola A, no-loop non impedirà il ciclo infinito.

Personalmente, penso che no-loop sia un trucco per aggirare le condizioni migliori. La soluzione migliore è scrivere le condizioni in modo che non si riattivino quando non dovrebbero. A volte ciò comporta l'inserimento di "fatti di controllo" a cui si riferiscono le condizioni, ma spesso è sufficiente aggiornare il modello per essere più specifici. Nel tuo caso, la soluzione è semplice:

rule "Is of valid age" when 
    $a : Applicant(age < 18, valid != false) 
then 
    modify($a) { valid = false }; 
end 

Aggiungendo valid != false al vostro modello, la modifica della realtà non causerà questa regola per riattivare.