Con el paso del tiempo las aplicaciones que construimos se vuelven cada vez más complicadas, con más reglas de negocio y difíciles de mantener, el uso de motores de reglas permite tener una separación entre las reglas de negocio y el código de nuestra aplicación. En este post hablaremos de un motor muy sencillo pero a la vez completo llamado Easy rules.

Easy rules fue desarrollado por jeasy (http://www.jeasy.org/) el cual es una colección de micro frameworks muy fáciles de utilizar, tan es así que su eslogan es :

The simple stupid rules engine for Java.

Easy rules está inspirado en un artículo de Martin Fowler Should I use a Rules Engine?en el que decía:

Puedes construir un motor de reglas tu mismo, todo lo que necesitas hacer es crear un montón de objetos con condiciones y acciones, almacenarlos en una colección e iterarlos evaluando sis condiciones y ejecutando sus acciones.

Configuración

La configuración de easy rules es muy simple y solo necesitaremos las dependencias descritas en el siguiente archivo pom.xml.

Creación del modelo

Una vez configurada la dependencia de Easy Rules, el siguiente paso será crear una clase sobre la cual ejecutaremos las reglas, veamos la siguiente clase Person.java:


/**
 * @author raidentrance
 *
 */
public class Person {
	private String name;
	private String middleName;
	private String lastName;
	private int age;

	public Person() {
	}

	public Person(String name, String middleName, String lastName, int age) {
		this.name = name;
		this.middleName = middleName;
		this.lastName = lastName;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMiddleName() {
		return middleName;
	}

	public void setMiddleName(String middleName) {
		this.middleName = middleName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", middleName=" + middleName + ", lastName=" + lastName + ", age=" + age + "]";
	}
}

Los objetos de la clase person serán evaluados por el engine de reglas.

Reglas

Una regla en easy rules se compondrá por 2 partes:

  • Condición: Una expresión boolean que en caso de ser verdadera ejecutará la acción definida
  • Acción: Lógica que se ejecutará en caso de que la condición sea verdadera.

Creando nuestra primera regla

La regla que crearemos recibirá un objeto de tipo persona y se llamará «ageValidation«. En caso de que una persona tenga 18 años o más imprimirá en la consola el mensaje :

Allow access to the person «Person information»

En caso contrario la persona será ignorada, veamos el código:


import java.util.logging.Level;
import java.util.logging.Logger;

import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;

import com.devs4j.app.model.Person;

/**
 * @author raidentrance
 *
 */
@Rule(name = "ageValidation", description = "Validates that the person is greater than 18 years")
public class AgeValidation {

	private static Logger log = Logger.getLogger(AgeValidation.class.getName());

	@Condition
	public boolean isGraterThan18(@Fact("person") Person person) {
		return (person.getAge() >= 18);
	}

	@Action
	public void allowAccess(@Fact("person") Person person) {
		log.log(Level.INFO, String.format("Allow access to the person %s", person));
	}
}

En la regla anterior podemos ver lo siguiente:

  • Name: Define el nombre de la regla a ejecutar
  • Description: Define una descripción para la regla, esto es muy útil cuando tenemos muchas reglas dentro de nuestra aplicación
  • Método isGraterThan18 : Condición que define en que casos se ejecutarán las acciones y en que casos no, se debe utilizar la anotación @Condition para que sea reconocida por easy rules.

  • Método allowAccess : Acción que se llevará a cabo para todos los objetos de tipo persona que cumplan con la condición definida en el método isGraterThan18.

Ejecutando las reglas sobre algunos objetos

Una vez que entendimos como crear nuestras reglas el siguiente paso será aplicarlas a un conjunto de objetos, veamos el siguiente código:


import java.util.ArrayList;
import java.util.List;

import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;

import com.devs4j.app.model.Person;
import com.devs4j.app.rules.AgeValidation;

/**
 * @author raidentrance
 *
 */
public class RuleSampleApplication {

	public static Rules getRules() {
		Rules rules = new Rules();
		rules.register(new AgeValidation());
		return rules;
	}

	public static List getPeople() {
		List people = new ArrayList();
		people.add(new Person("Alex", "raiden", "bautista", 18));
		people.add(new Person("Juan", "juan123", "ramírez", 17));
		people.add(new Person("Pedro", "pedro123", "hernandez", 30));
		people.add(new Person("Arturo", "artur2019", "juarez", 15));
		people.add(new Person("Edgar", "edgar1020", "sanchez", 18));
		people.add(new Person("Oscar", "oscar11", "perez", 4));
		people.add(new Person("Hugo", "hugiño", "lopez", 10));
		return people;
	}

	public static void main(String[] args) {
		RulesEngine rulesEngine = new DefaultRulesEngine();
		for (Person person : getPeople()) {
			Facts fact = new Facts();
			fact.put("person", person);
			rulesEngine.fire(getRules(), fact);
		}
	}
}

En la clase anterior veremos lo siguiente:

  • Método getRules:Define un conjunto de reglas a ejecutar sobre un conjunto de objetos.
  • Método getPeople: Define un conjunto de objetos de tipo Person a los que se les aplicará la regla ageValidation.

  • Método main: A través de un objeto de tipo RulesEngine creará una relación entre las reglas a ejecutar y los objetos a los cuales se les aplicarán.

Salida:

sep 28, 2018 11:05:25 AM com.devs4j.app.rules.AgeValidation allowAccess
INFORMACIÓN: Allow access to the person Person [name=Alex, middleName=raiden, lastName=bautista, age=18]
sep 28, 2018 11:05:25 AM com.devs4j.app.rules.AgeValidation allowAccess
INFORMACIÓN: Allow access to the person Person [name=Pedro, middleName=pedro123, lastName=hernandez, age=30]
sep 28, 2018 11:05:25 AM com.devs4j.app.rules.AgeValidation allowAccess
INFORMACIÓN: Allow access to the person Person [name=Edgar, middleName=edgar1020, lastName=sanchez, age=18]

En la salida anterior podemos ver que solo se imprimieron los datos de los objetos que pasaron la condición definida en la regla ageValidation.

Puedes encontrar el código completo en el siguiente repositorio https://github.com/raidentrance/easy-rule-example.

Síguenos en nuestras redes sociales para enterarte sobre nuevo contenido https://www.facebook.com/devs4j/ y https://twitter.com/devs4j.

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com