domenica 11 marzo 2012

JBoss Drools, studio e prototipo


Qualche anno fa mi sono trovato a studiare la piattaforma JBoss Drools 5.0 per realizzare un prototipo e valutarne le potenzialità.
Oggi, leggendo un pò in giro, ho visto che al momento siamo quasi arrivati alle versione 5.4.

Dato che il salto di versione non è ancora evidente, vorrei condividere alcune informazioni sul prodotto recuperandole dal mio studio del 2009 in modo da provare a dare una panoramica generale che può sempre essere utile.

La suite JBoss Drools

Drools è un motore a regole orientato al Business Process Management (BPM), ecco un insieme di elementi salienti che lo contraddistinguono:


  • Esecuzione “piatta” delle regole. Lo scopo è non preoccuparsi di un flusso in particolare. Il controllo delle regole avviene "a tappeto" quindi le regole scattano solo se si verificano le condizioni a cui sono legate. Ovviamente occorre bilanciare il numero di regole per evitare l'eccessiva frammentazione.
  • Pianificazione e risoluzione conflitti tra regole mediante l’uso dell’agenda.
  • Possibilità di definire la priorità di esecuzione di determinate regole. E' sempre possibile definire per grandi linee l'ordine di importanza delle regole che devono scattare per prime rispetto alle altre.
  • Raggruppamento e definizione del flusso di esecuzione tramite modulo Flow.
  • Definizione di regole a tempo in funzione della data di attivazione.
  • Stateless vs. Statefull. Regole slegate dal contesto e quindi "on-demand" oppure regole che mantengono "la storia" di quello che sta succedendo facendo evolvere lo stato della nostra richiesta.


Drools è organizzato in quattro moduli fondamentali:


  • Drools Expert: Nucleo centrale dell’API, rappresenta il vero e proprio motore a regole. Consente la gestione di gruppi di regole e tavole di decisione a partire da file sorgenti in formato Excel. Lo sviluppo dei modelli legati alla base di conoscenza risulta semplificato grazie all’utilizzo di un apposito plugin per l’ambiente IDE Eclipse.
  • Drools Guvnor: Tecnicamente si parla di BRMS (Business Rules Management System), di fatto è un repository centralizzato per la gestione di regole, funzioni e processi. Attraverso un’interfaccia web based è possibile configurare e ampliare rapidamente le regole legate ad una particolare base di conoscenza. E’ possibile la sincronizzazione del codice attraverso un plugin di eclipse.
    • Drools Server: applicazione web che svolge il ruolo di bridge applicativo tra il repository di Guvnor ed il mondo esterno. Grazie ad essa è possibile contattare il motore a regole utilizzando semplici chiamate http in formato JSON o XML.
  • Drools Flow: offre la possibilità di gestire workflow di business attraverso il motore a regole e raggruppando le regole in flussi di regole (RoleFlow). Questo modulo si contrappone al più generale progetto jBPM di JBoss. Quest’ultimo permette di definire processi di business in un’ottica process-oriented mentre Flow si pone in un ottica rules/event-oriented. In ogni caso la versione 5.3 di Drools consente l'integrazione anche con jBPM.
  • Drools Fusion: è un CEP (Complex Event Processing), l’identificazione di un Evento all’interno di una nuvola (insieme apparentemente scomposto di eventi facenti parte di una base di conoscenza) viene effettuata grazie a questo strumento mediante pattern complessi quali relazioni di astrazione, correlazione, appartenenza, gerarchia e processi legati agli eventi.


Il prototipo

Vediamo qualcosa di pratico per capirci.
Il mio prototipo riguardava il calcolo del preventivo auto/moto in uno scenario semplificato ma sufficente per una verificare di base su API e architettura generale.
In soldoni si lavora con oggetti e classi Java all'interno di un framework dedicato che è quello del motore a regole.

Il modello dati

Occorre avere in mente il dominio applicativo con il quale si lavora in modo da definire il modello dati, nel mio caso specifico:

  • Preventivo (data, costo, Polizza)
  • Polizza (Contraente, Veicolo, Garanzie)
  • Contraente (dati anagrafici, FattoreRischio)
  • Veicolo (dati tecnici, FattoreRischio)
  • Garanzia (nome, peso, costo, FattoreRischio)
  • FattoreRischio (coefficiente_FR)
  • Promo (sconto)

Queste di fatto non sono altro che semplici classi Java di tipo POJO.

Le regole

Occorre definire tutte le regole che ci interessa gestire all'interno del nostro motore.
Nel mio caso specifico esistono 4 categorie di regole:


  • Controllo, per bloccare il preventivo.
  • Inizializzazione, per impostare i dati polizza.
  • Calcolo, per modificare i fattori di rischio e calcolare il costo finale complessivo.
  • Promozioni a tempo


Le regole vanno inserite all'interno di file di testo con estensione ".drl" e vengono poi date in pasto al motore a regole durante l'inizializzazione dell'applicazione usando delle righe di codice come queste:

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("StandardRules.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("RulesPromozioni.drl"), ResourceType.DRL);


KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

Naturalmente oltre ad istruire il motore con le regole dobbiamo passargli gli oggetti sui quali effettuare i controlli quindi ad esempio:

Veicolo v= new Veicolo();
ksession.insert(v);
Contraente c= new Contraente();
ksession.insert(c);
Garanzia g = new Garanzia();
ksession.insert(g);

Utilizzando a questo punto il metodo "fireAllRules()" scateniamo il controllo e l'esecuzione delle nostre regole sugli oggetti appena creati:

ksession.fireAllRules();

Esempio regola di controllo

rule "garanzia RC - auto non sottoscrivibile"
agenda-group "sottoscrivibile" no-loop 
when
 (c: Contraente(eta  < 18 ) or c: Contraente( eta > 85 )) and g : Garanzia( tipo == "RC" )
then
 g.setNonSottoscrivibile(true);
 retract(g);
end

Esempio regola di Inizializzazione

rule "prezzo base garanzia furto incendio"
agenda-group "baseprice" no-loop 
when
 g : Garanzia(tipo == "INCENDIOFURTO" )
then
 g.setCostobase(250);
 g.getFr().setCoefficienteVeicolo(150);
 g.getFr().setCoefficienteContraente(50);
 g.getFr().setCoefficientePromozionale(1);
 update(g);
end

Esempio regola di Calcolo

rule " aumento incendiofurto auto non in box"
when
 g :Garanzia( tipo =="INCENDIOFURTO" ) and Garanzia(nonSottoscrivibile == false) and Veicolo( tipoRecovery != "IN" )
then
 double actual = g.getFr().getCoefficienteVeicolo();
 g.getFr().setCoefficienteVeicolo(actual+ (actual* 0.20));
end

Esempio regola di Promozione temporale

rule "offerta mese“ salience -100 no-loop
date-effective "09-GIU-2009"
date-expires  "18-GIU-2009" 
when
  pre: Contratto()
then
int percentualeSconto = 30;
double newPrice=pre.getImporto()-pre.getImporto()*((double)percentualeSconto/(double)100);
pre.setImporto( newPrice );
update(pre);
end

Flussi di regole complesse

Fin qui abbiamo solo definito regole slegate tra di loro. Utilizzando il modulo Flow è possibile modellare il flusso di esecuzione delle nostre regole usando un ambiente grafico integrato con Eclipse.
Nel caso del mio prototipo abbiamo definito il flusso legato alla "legge Bersani" la quale prevede uno sconto sulla classe di merito in base ad alcuni eventi che devono verificarsi contemporaneamente.
Drools Flow permette di disegnare il flusso di regole con la stessa semplicità di un diagramma di flusso tradizionale e il risultato è un file xml con estensione rf che passeremo in fase di inizializzazione al nostro motore a regole:

kbuilder.add(ResourceFactory.newClassPathResource("BersaniRules.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("BersaniRuleflow.rf"), ResourceType.DRF);

Naturalmente occorre creare in precedenza il file di regole e poi legarle insieme grazie a Flow, da cui le due righe sopra.
A questo punto non ci resta che lanciare l'esecuzione del flusso e attivare il controllo sulle regole:

ksession.startProcess("it.ruleflow.prototipo.bersani");
ksession.fireAllRules();

Questo termina la breve panoramica sullo studio e il prototipo di cui mi sono occupato. La versione 5.0 usata all'epoca era ancora un pò carente in certi aspetti ma immagino che adesso a 3 anni di distanza la versione 5.4 di prossimo rilascio possa colmare alcune delle lacune che avevo riscontrato.
Sicuramente l'idea del motore a regole non è malvagia e il fatto di poter usare un linguaggio java like la rende ancora più abbordabile.

1 commento: