DroolsEn las notas anteriores dimos los primeros pasos con Drools y vimos como utilizar un DSL con Drools. En esta tercer nota vamos a ver cómo usar una planilla de cálculo Excel para albergar las reglas de nuestro negocio.

Ésta es una característica muy interesante que provee Drools, ya que como muchos de ustedes saben el Excel es una de las herramientas favoritas de los usuarios.

Lo que tenemos que hacer es crear una planilla de cálculo siguiendo algunas convenciones, y poner en ésta las condiciones y acciones a ejecutar y los datos (valores) con los que operarán éstas.

La planilla de cálculo

La planilla de cálculo con las reglas es la siguiente (click en la imágen para ver a tamaño completo):

PoliticaRrhh_Ej3.xls:

Excel para Drools

Como puede observarse la planilla está encabezada por una serie de palabras reservadas que le indican a Drools como interpretar la misma.

La palabra RuleSet justamente indica que la planilla contiene un conjunto de reglas, y el nombre de éste es el que está en la celda contigua. No es obligatorio que pongamos ésta directiva en la planilla.

En realidad RuleSet va a ser traducido en la declaración de un paquete java (package), y como tal las clases de éste paquete van a ser automáticamente accesibles.

Luego de ésto, tál cual teníamos en el DRL, figura la declaración de las clases que vamos a necesitar utilizar desde la planilla. Ésto es a través de la palabra Import. Las clases a importar van en la celda a continuación, y de haber más de una van separadas por coma. la mayoría de las veces no va a ser necesario declarar imports.

A continuación, a través de la directiva RuleTable, indicamos que éste es el inicio de una tabla de reglas. El nombre de la misma va en la misma celda a continuación de la palabra RuleTable (separada por un espacio en blanco). Es obligatorio que figure la directiva RuleTable, aunque su nombre es opcional.

La directiva RuleTable debe aparecer arriba de la primera columna de condición. Todas las columnas a la izquierda de esta columna van a ser ignoradas (en este caso las de color verde).

En una misma hoja de cálculo podemos tener tantas RuleTable como necesitemos, sólo deben estar separadas por una fila en blanco.

Luego de éstos encabezados viene la definición de la regla propiamente dicha. Con la palabra CONDITION indicamos que ésa es una columna de condiciones. Debajo de ésta celda se especifica la plantilla de la regla.

De igual forma, con la directiva ACTION indicamos que la columna es de acciones o consecuencias.

En las filas siguientes especificamos la plantilla de la regla utilizando el lenguaje DRL. En éste caso estamos actuando sobre un hecho de la clase  Empleado aplicando los filtros sobre el atributo promedioConocimientos. Con la palabra $param definimos las variables que serán reemplazadas por los datos (valores) de las celdas.

Y en las acciones se puede ver el código (java en este caso) que se ejecutará.

La fila que sigue debajo es un comentario (es ignorada), pero nos és útil a los efectos de que quede más clara la regla de la planilla.

Luego de ésta fila todas las filas que siguen son datos de la regla hasta que se encuentre un línea vacía.

Cada fila de datos se va a combinar con la plantilla para hacer una condición. Cada fila es una regla en lo que sería un archivo DRL.

Como la leemos desde Java

Para leer las reglas desde la planilla de cálculo necesitamos realizar unos cambios al método leerReglas() de la clase PoliticaRrhhBo.

PoliticaRrhhBo.leerReglas():

    private static RuleBase leerReglas() throws Exception {
        //Leemos el archivo de reglas desde una planilla Excel        
        SpreadsheetCompiler converter = new SpreadsheetCompiler();
        String drl = converter.compile(PoliticaRrhhBo.class.getResourceAsStream(
                                           "PoliticaRrhh_Ej3.xls"), InputType.XLS);

        //Solo mostramos el DRL que se generó del Excel. 
        System.out.println(drl);

        //Construimos un paquete de reglas
        PackageBuilder builder = new PackageBuilder();

        //Leemos el drl del generado del Excel
        builder.addPackageFromDrl(new StringReader(drl));

        // Verificamos el builder para ver si hubo errores
        if (builder.hasErrors()) {
            System.out.println(builder.getErrors().toString());
            throw new RuntimeException("No se pudo compilar el archivo de reglas.");
        }

        //Obtenemos el package de reglas compilado
        Package pkg = builder.getPackage();

        //Agregamos el paquete a la base de reglas 
        //(desplegamos el paquete de reglas)
        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
        ruleBase.addPackage(pkg);
        return ruleBase;
    }

Lo que modificamos aquí es la forma de leer las reglas, leyendolas desde un excel con las siguientes líneas:

        //Leemos el archivo de reglas desde una planilla Excel        
        SpreadsheetCompiler converter = new SpreadsheetCompiler();
        String drl = converter.compile(PoliticaRrhhBo.class.getResourceAsStream(
                                           "PoliticaRrhh_Ej3.xls"), InputType.XLS);

En realidad el motor de reglas de Drools no interpreta la planilla de cálculo, sino que la convertimos en un DRL y compilamos el mismo.

La instrucción que sigue a continuación sólo sirve para ver cuál es el DRL que se generó, y se puede obviar. No obstante es muy interesante verlo para fines didácticos, y de debug dado el caso.

        //Solo mostramos el DRL que se generó del Excel.
        System.out.println(drl);

Por último una pequeña modificaciónen  la línea donde parseamos y compilamos las reglas:

        //Leemos el drl del generado del Excel
        builder.addPackageFromDrl(new StringReader(drl));

El resto de la clase, como la clase Empleado siguen igual.

La salida resultante

En la salida del programa lo primero que destacamos es el DRL generado. Como dijimos ésto se puede obviar, pero se los dejo para que lo analicen y lo comparen con la planilla de cálculo:

package com.dosideas.drools.ejemplo3.rrhh;
#generated from Decision Table
import java.math.BigDecimal;
#From row number: 10
rule "AscensosPorConocimientos_10"
when
    empleado: Empleado(promedioConocimientos >= 0, promedioConocimientos <= 3)
then
    empleado.setCargo("Gerente"); 
    System.out.println("Gerente" + ": " + empleado.getNombre());
    empleado.setSalario(BigDecimal.valueOf(3000));
end

#From row number: 11
rule "AscensosPorConocimientos_11"
when
    empleado: Empleado(promedioConocimientos >= 4, promedioConocimientos <= 7)
then
    empleado.setCargo("Lider de Proyecto"); 
    System.out.println("Lider de Proyecto" + ": " + empleado.getNombre());
    empleado.setSalario(BigDecimal.valueOf(2000));
end

#From row number: 12
rule "AscensosPorConocimientos_12"
when
    empleado: Empleado(promedioConocimientos >= 8, promedioConocimientos <= 10)
then
    empleado.setCargo("Programador"); 
    System.out.println("Programador" + ": " + empleado.getNombre());
    empleado.setSalario(BigDecimal.valueOf(1000));
end

Y finalmente tenemos la impresión que definimos en las reglas, que como pueden ver es la misma que en las notas anteriores:

Gerente: Pedro
Lider de Proyecto: Jose
Programador: Juan
Empleado: Juan promedio=9 cargo=Programador salario=1000
Empleado: Jose promedio=6 cargo=Lider de Proyecto salario=2000
Empleado: Pedro promedio=2 cargo=Gerente salario=3000

Con ésto finalizamos el ejemplo de uso de Drools con una planilla de cálculo. Es un ejemplo sencillo, que espero se haya entendido.

Como se imaginarán hay mucho más de Drools por ver y aprender.

Descargar el proyecto de ejemploDescargar el proyecto de ejemplo

Pueden descargar un proyecto de ejemplo de Drools, que incluye el código completo de este artículo (y también los 2 ejemplos de las notas anteriores) y todas las librerías necesarias para ejecutarlo.

Inspiración.

"Si tú tienes una manzana y yo tengo una manzana e intercambiamos las manzanas, entonces tanto tú como yo seguiremos teniendo una manzana cada uno. Pero si tú tienes una idea y yo tengo una idea, e intercambiamos las ideas, entonces ambos tendremos dos ideas"

Bernard Shaw