martes, 19 de diciembre de 2006

OT-Rules. Manejando cambios funcionales

A medida que pasa el tiempo, en el desarrollo de aplicaciones de software, muchas cosas cambian, el equipo de trabajo cambia, las fechas de entrega y también los requerimientos iniciales ya sea porque el usuario final no sabia que quería o porque el funcional no entendio nada o simplemente por el hecho de que todo cambia (evoluciona).
Dada esta necesidad de cambio (casi constante) en los requerimientos de una aplicación se hace necesario hacer que el software que construimos sea flexible y fácil de modificar.

Como se dijo en el post anterior, OT-Rules permite escribir ciertas validaciones (o lógica de negocio) en una forma flexible, donde agregar nuevas reglas, modificar y eliminar reglas existentes y cambiar el comportamiento de como se debe ejecutar estas reglas se hace muy facil y simple.

Aquí utilizaremos el código de ejemplo utilizado para el post anterior y por supuesto, agregaremos algunas cositas.
Categorización de reglas.
OT-Rules contiene una categorización de las reglas que este provee:
* Reglas de soporte: Son aquellas que facilitan el desarrollo por ejemplo (net.sf.opentranquera.rules.support.TrueRule o net.sf.opentranquera.rules.support.FalseRule).
* Reglas lógicas: Ejecutan acciones lógicas como AND, OR, XOR, NOT.
* Reglas condicionales: Ejecutan condiciones, hasta ahora solo net.sf.opentranquera.rules.conditional.IfRule.
* Reglas iterativas: Reglas que iteran e invoquan a otras reglas (FOR, WHILE)

Short circuit
Todas las reglas lógicas tienen el atributo short circuit que debería ser setteado en la creación/construcción de la regla, el cual permite definir el modo de ejecución que tendra ésta y trabaja de la misma manera que lo hace el short circuit de la clausula if de Java.
Veamoslo en un ejemplo usando un AND:

a && b -> short circuit = true: Si "a" se evalua en false (con lo cual el AND daria false independientemente de lo que "b") no se evalua el resultado de "b".
a & b -> short circuit = false: Si "a" se evalua en false (con lo cual el AND daria false independientemente de lo que "b") igualmente se evalua el resultado de "b".

Es decir, si tengo una regla de tipo AND que esta compuesta por otras tres reglas, como se puede ver en la regla llamada "transferRule" (del ejemplo anterior), solo se evaluara en true si todas se evaluan en true individualmente.

<bean id="transferRule" class="net.sf.opentranquera.rules.logical.AndRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.DifferentAccountRule"/>
<bean class="net.sf.opentranquera.samples.rules.AccountsExistsRule">
<property name="rule" ref="accountExistsRule"/>
</bean>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>

El primer argumento del constructor es un List de Rules y el segundo argumento es un boolean que índica si la regla es short circuit (por defecto "short circuit = true").
Ahora bien, si "DifferentAccountRule = true", se evalua AccountsExistsRule, si esta es true, entonces la evaluación de la regla transferRule sera true. Pero sí "DifferentAccountRule = false", AccountsExistsRule no sera evaluada (ejecutada) y el resultado sera false.
De la misma forma que lo hacemos con la regla AND, lo podemos hacer con las reglas OR, XOR.
Entonces, podemos finalizar diciendo que en el caso de que sea necesario cambiar este tipo de comportamiento de una regla lógica simplemente se modifica el valor del atributo short circuit en la configuración (sea cual sea), es así de fácil.

La regla NOT.
Existe una regla lógica que permite negar el resultado de la evaluación de otro regla (net.sf.opentranquera.rules.logical.NotRule).
Esta regla se crea a partír de otra y la envuelve (se podría decír que la decora utilizando el pattern Decorator), luego al evaluarla (llamar a su método evaluate()) se evalua la regla contenida para finalmente negar su resultado (manteniendo todos sus mensajes).

Veamos algunos ejemplos:
Usando el XML de configuración de OR-Rules:

<rule name="test.not.rule" ruleClass="net.sf.opentranquera.rules.logical.NotRule">
<rule ruleClass="net.sf.opentranquera.rules.support.FalseRule"/>
</rule>

Creo una NotRule incluyendo una FalseRule. El resultado de esto es la negación de la evaluación de FalseRule (que siempre da false), es decir me devuelve el resultado true.

<rule name="test.negate.rule" ruleClass="net.sf.opentranquera.rules.support.FalseRule"
modifier="negate"/>

Aquí­, se utiliza el atributo "modifier", esto indica que la rule "test.negate.rule" que es del tipo FalseRule debe ser negada luego de ejecutar. Es decír, el resultado sera true.
Ahora veremos esta mismo configuración usando SpringFramework:

<bean id="transferRule" class="net.sf.opentranquera.rules.logical.NotRule">
<constructor-arg index="0">
<bean class="net.sf.opentranquera.rules.support.FalseRule"/>
</constructor-arg>
</bean>

Simple no?

Cambiar lógica de evaluación.
Llamo lógica de evaluación a aquella que no concierne a la regla en si, sino a como esta se evalua o a como se ejecutan las diferentes reglas que contiene, por ejemplo, si utilizo un regla AND para componer la ejecución de varias reglas, digo que la lógica del AND (ya sea con short circuit o no) es mi lógica de evaluación, mientras que las reglas ejecutan la lógica de negocio/validación que quiero evaluar.
OT-Rules provee varias clases (reglas) que me permiten modificar esta lógica de evaluación independientemente de lo que hacen las reglas en sí mismas, de forma tal que los programadores se concentren en resolver la problematica particular de negocio y luego las componen utilizando alguna clase de OT-Rules (o alguna creada por ellos dado que OT-Rules es flexible en este aspecto) para decidir como van a ser evaluadas y ejecutadas.
Ahora bien, si en lugar de tener las reglas escritar con OT-Rules las tendrias escritas directamente sobre el código del método del servicio y tendriamos la necesidad de modificar la forma en que se evaluan las reglas y no las reglas en sí­. Esto seria muy problematico, dado que tendriamos que modificar gran parte de nuestro código ya testeado.
Pero si tenemos las reglas separadas en clases (incluso con sus test unitarios) para luego decirles por configuración como se evaluan, podría no ser tan problematico. De hecho, utilizando OT-Rules sería muy simple. En el caso recien mencionado, simplemente tendriamos que cambiar la AND rule por la nueva forma de evalución requerida (OR, XOR, etc).

En el ejemplo anterior utilizabamos una AND rule para armar la regla "transferRule", pero si ahora necesitaramos que la evaluacion de esta rule esta basada en una lógica de OR, simplemente cambiamos la clase ANDRule, por la ORRule quedando de la siguiente manera:

<bean id="transferRule" class="net.sf.opentranquera.rules.logical.OrRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.DifferentAccountRule"/>
<bean class="net.sf.opentranquera.samples.rules.AccountsExistsRule">
<property name="rule" ref="accountExistsRule"/>
</bean>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>

La de misma forma que cambiamos un AND por un OR podemos, incluso, componer reglas lógicas, por ejemplo, dentro de una regla OR tener un regla NOT que contiene una regla AND que a su vez contiene otras reglas (que pueden ser reglas de negocio o reglas compuestas AND, OR, XOR, etc.).

Reuso de reglas (otra vez).
Veamos lo recien comentado con un ejemplo.
Recordemos del articulo anterior que teniamos la regla "transferRule" que evaluaba que al realizar una transferencia, las cuentas sean distintas, que existan y que la cuenta débito tenga el dinero disponible para realizarla.
Ahora agregaremos un nuevo método para el servicio TransferService que realice una transferencia pero entre un mismo banco a modo de ejemplo. Para este caso es válida la regla (compuesta) "transferRule" y ádemas agregaremos la siguiente lógica de validación:
# Como dijimos debe pasar la regla transferRule con lo cual estariamos haciendo reuso de la misma.
# Verificar que la transferencia tenga como cuenta débito y cuenta crédito el mismo banco o bancos del mismo grupo empresarial.
Veamos ahora como queda el nuevo método y la configuración de OT-Rules

public boolean bankTransfer(Transfer transfer) throws TransferException {
this.evaluator.setEvaluatedObject(transfer);
RuleResult result = this.evaluator.evaluateRule("bankTransfer");
if(!result.isSuccessful())
throw new TransferException(result.getMessages());

// TODO logic ...
return true;
}


<bean id="bankTransferRule" class="net.sf.opentranquera.rules.logical.AndRule">
<constructor-arg index="0">
<list>
<ref local="transferRule"/>
<bean class="net.sf.opentranquera.rules.logical.OrRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.SameBankRule"/>
<bean class="net.sf.opentranquera.samples.rules.SameBankGroupRule"/>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>
</list>
</constructor-arg>
<constructor-arg index="1" value="false"/>
</bean>

Como podemos ver la nueva regla (bankTransferRule) tiene una lógica de evaluación del tipo AND que contiene la ya creada y declarada "transferRule" junto con una nueva regla del tipo OR que a su vez se compone de otras dos reglas, una que verifica que las cuentas sean del mismo banco y la otra que las cuentas sean del mismo grupo empresarial.
Al evaluarse esta regla se dispararían las siguientes acciones:
# Se evalua "transferRule", es decir se evalua la regla AND junto con sus compuestos.
# Si la regla anterior da true, se evalua la regla OR. Esta regla compuesta ejecuta SameBankRule y SameBankGroupRule, si alguna de ellas da true, esta regla devuelve un resultado en true.
# Finalmente si ambas reglas se evaluaron en true, se retorna un resultado true.

Nota: Se podria hacer echo toda esta valiadcion en una sola regla (o de otras multiples formas utilizando diferentes tipos de composiciones), sin embargo lo hice así a modo de ejemplo.

Usar fluent interface como mecanismo de configuración.
OT-Rules tiene dos mecanismo de configuración por código:
1) Creando las clases directamente utilizando el operador new: Como lo hacen los test case

XorRule xorRule = new XorRule();
xorRule.addRule(new FalseRule());
xorRule.addRule(new TrueRule());

xorRule.evaluate();

2) Utilzando al API fluida: Evita la necesidad de conocer las clases, es mas declarativa e intuitiva

FluentRule fir = new FluentRule("test");
fir.rule(new FalseRule()).xor(new TrueRule()).or(new FalseRule()).not();

RuleEvaluator evaluator = FluentInterfaceRuleEvaluatorBuilder.createRuleEvaluator(fir);
RuleResult result = evaluator.evaluateRule("test");

Más allá de que podemos reemplazar toda la configuración del ejemplo anterior usando esta API, para este tutorial solamente reemplazaremos la regla "transferRule" y para ello haremos uso del componente de OTF llamado bridge (OT-Bridge sirve para integrar las frameworks de OTF con otras frameworks).
No modificaremos nada de código, todo es configuración (en realidad agregaremos una clase que tiene la codificación usando la API fluida).

La declaración de la regla en el rulesContext.xml queda asi:

<bean id="transferRule" class="net.sf.opentranquera.spring.rules.FluentRuleInterfaceFactoryBean">
<property name="config">
<bean class="net.sf.opentranquera.samples.rules.FluentConfigImpl"/>
</property>
</bean>

Usando el FactoryBean FluentRuleInterfaceFactoryBean podemos configurar una rule usando la API fluida. En la propiedad "config" se inyecta la clase que implemente de net.sf.opentranquera.spring.rules.FluentConfig que contiene la codificación/configuración permitente.

public class FluentConfigImpl implements FluentConfig, BeanFactoryAware {

private BeanFactory bf;

public FluentRule getFluent() {
// create the rules
DifferentAccountRule diffAccount = new DifferentAccountRule();
AccountsExistsRule accountExists = new AccountsExistsRule();
DebitAccountRule debitAccount = new DebitAccountRule();

// get object from Spring
AccountExistsRule accountExist = (AccountExistsRule)this.bf.getBean("accountExistsRule");
accountExists.setRule(accountExist);

FluentRule rule = new FluentRule("transferRule");
rule.rule(diffAccount).and(accountExists).and(debitAccount);
return rule;

}

public void setBeanFactory(BeanFactory bf) throws BeansException {
this.bf = bf;
}

}

Ahora, cuando se pide evaluar a la regla "transferRule" esta se obtendra ahora desde la configuración de la API fluida (y gracias los mecanismos internos de OT-Rules y OT-Bridge) permitiendo que sea transparente a la configuracion de la aplicacion.

Conclusión.
Hemos visto mas en detalle aspectos particulares de OT-Rules, como ser la categorización de reglas que propone y la regla NOT, como asi tambien el uso del atributo short circuit. Aprendimos que es la lógica de evaluación de una regla (según OT-Rules). Por ultimo conocimos como configurar el engine utilizando directamente código, mas presisamente con el uso de una API fluida.

jueves, 30 de noviembre de 2006

OT-Rules

Ejecutar validaciones de negocio utilizando OT Rules 1.0.1



Abstract
OT Rules es un simple rule engine orientado a la ejecución, validación y composición de reglas de negocio.
Una de las principales ventajas de utilizar OT-Rules es poder definir validaciones de negocio y mantenerlas separadas de la lógica de negocio en sí de forma tal que permita agregar, quitar, modificar y componer estas y nuevas reglas en una manera simple, flexible, mantenible y que no afecte la lógica de negocios de nuestra aplicación. En este articulo se verá como aplicar estas validaciones, habilitarlas, deshabilitarlas, reutilizarlas en diferentes métodos y agregar nuevas validaciones sin afectar al ódigo de los métodos de negocio.

Como crear una rule
La creación de una regla es un proceso simple, lo único que se debe hacer es crear una nueva clase que implemente o extienda de alguna de las siguientes interfaces o clases:
- net.sf.opentranquera.rules.Rule: Interface base para todas las reglas
- net.sf.opentranquera.rules.BusinessRule: Interface apropiada para reglas de negocio
- net.sf.opentranquera.rules.CompositeRule: Interface apropiada para reglar que se compongan de otras reglas
- net.sf.opentranquera.rules.AbstractRule: Clase conveniente para diferentes tipos de reglas
- net.sf.opentranquera.rules.AbstractBusinessRule: Clase conveniente para reglas de negocio
- Heredar de alguna rule existente dentro de OT Rules de forma de extender su comportamiento.

Una vez tomada la decisión de cual interface o clase extender se deben implementar los métodos requeridos. En nuestro ejemplo extenderemos de net.sf.opentranquera.rules.AbstractBusinessRule para crear las diferentes reglas que ejecutaran las diferentes validaciones de negocio.

Aplicación de ejemplo
Imaginemos que tenemos que desarrollar una aplicación que transfiera dinero entre diferentes cuentas. Podemos identificar varios servicios:
a) Transferir de una cuenta a otra.
b) Obtener el saldo de una cuenta en particular.

Existen validaciones de negocio que deben tenerse en cuenta a la hora de ejecutar el código de estos servicios, por ejemplo, cuando hacemos una transferencia o cuando obtenemos el saldo debemos validar que las cuentas existan. Para implementar estas validaciones utilizaremos OT-Rules por las siguientes razones:
1- Porque las validaciones pueden cambiar sin que cambie la lógica de negocios.
2- Porque se puede necesitar deshabilitar las validaciones en determinados ambientes o para un caso de prueba en particular.
3- Porque seguramente abra nuevas validaciones que ir incorporando a medida que el desarrollo crece.
4- Porque se requiere flexibilidad para componer validaciones.
5- Porque es necesario reutilizar validaciones de negocio sin repetir código.

Notas:
En nuestro caso para no complicar el desarrollo de la aplicación utilizaremos un java.util.Map en memoria.
La configuración de nuestra aplicación de ejemplo estara basada en Spring Framework.


Crear las rules
Identificamos las siguientes reglas de negocio:
DifferentAccountsRule: Verifica que las cuentas sean distintas.
AccountsExistsRule: Verifica que las ambas cuentas (débito y crédito) existan. Utiliza AccountExistsRule para verifica la existencia por separado de las cuentas.
Veremos el código de las Rules:

public class DifferentAccountRule extends AbstractBusinessRule {

/* (non-Javadoc)
* @see net.sf.opentranquera.rules.Rule#evaluate()
*/
public RuleResult evaluate() {
Transfer transfer = (Transfer) this.getEvaluatedObject();
if( transfer.getCreditAccount().equals(transfer.getDebitAccount()) )
return this.getError("The accounts are equals");
return this.getSuccess();
}

}


public class AccountsExistsRule extends AbstractBusinessRule {

private BusinessRule rule;

/*
* (non-Javadoc)
*
* @see net.sf.opentranquera.rules.Rule#evaluate()
*/
public RuleResult evaluate() {
Transfer transfer = (Transfer) this.getEvaluatedObject();
AbstractCompositeRuleResult result = new AbstractCompositeRuleResult(true) {
};

this.rule.setEvaluatedObject(transfer.getDebitAccount());
RuleResult r1 = this.rule.evaluate();

this.rule.setEvaluatedObject(transfer.getCreditAccount());
RuleResult r2 = this.rule.evaluate();

result.addResult( r1 );
result.addResult( r2 );
result.setSuccessful(r1.isSuccessful() && r2.isSuccessful());

return result;
}

public void setRule(BusinessRule rule) {
this.rule = rule;
}
}


public class AccountExistsRule extends AbstractBusinessRule {

private AccountDao dao;

/* (non-Javadoc)
* @see net.sf.opentranquera.rules.Rule#evaluate()
*/
public RuleResult evaluate() {
String account = (String)this.getEvaluatedObject();

// Verify that the account exists.
if(this.dao.getAccount(account) == null)
return super.getError("The account " + account + "does not exist.");
return this.getSuccess();
}

public void setDao(AccountDao dao) {
this.dao = dao;
}
}

Ahora configuramos las rules y el servicio utilizando, en este caso, SpringFramework (tambièn podrìmos utilizar el formato XML que provee OT-Rules).

<bean id="service" class="net.sf.opentranquera.samples.rules.TransferServiceImpl">
<property name="evaluator" ref="ruleEvaluator"/>
</bean>

<bean id="ruleEvaluator" class="net.sf.opentranquera.rules.RuleEvaluator">
<property name="rules">
<map>
<entry key="transfer"><ref local="transferRule"/></entry>
<entry key="balance"><ref local="accountExistsRule"/></entry>
</map>
</property>
</bean>

<bean id="transferRule" class="net.sf.opentranquera.rules.logical.AndRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.DifferentAccountRule"/>
<bean class="net.sf.opentranquera.samples.rules.AccountsExistsRule">
<property name="rule" ref="accountExistsRule"/>
</bean>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>

<bean id="accountExistsRule" class="net.sf.opentranquera.samples.rules.AccountExistsRule">
<property name="dao" ref="dao"/>
</bean>

<bean id="dao" class="net.sf.opentranquera.samples.rules.AccountDao"/>

Como vemos, al servicio se le inyecta un ''evaluator ''que es del tipo net.sf.opentranquera.rules.RuleEvaluator. El ruleEvaluator se configura como Spring-bean inyectándole las diferentes rules que puede evaluar, en este caso dos, transfer y balance.
Cada una de estas es una Rule que puede ser, como es el caso de transfer, una CompositeRule que contiene a su vez otras rules dentro.
Ahora solo queda desde el servicio (o utilizando algún tipo de interceptor) invocar al ''evaluator ''para evaluar las reglas configuradas.

public boolean transfer(Transfer transfer) throws TransferException {
this.evaluator.setEvaluatedObject(transfer);
RuleResult result = this.evaluator.evaluateRule("transfer");
if(!result.isSuccessful())
throw new TransferException(result.getMessages());

// TODO logic ..
return true;
}


Agregar una nueva validación utilizando composición.
Ahora veremos el potencial de OT-Rules para modificar/agregar nuevas reglas y ejecutar validaciones de negocio sin afectar el código fuente (en este caso del servicio). Agregaremos una nueva regla de negocio que verifique que haya dinero suficiente en la cuenta débito. Para ello primero creamos la nueva regla como una nueva clase Java:

public class DebitAccountRule extends AbstractBusinessRule {

/* (non-Javadoc)
* @see net.sf.opentranquera.rules.Rule#evaluate()
*/
public RuleResult evaluate() {
Transfer transfer = (Transfer) this.getEvaluatedObject();
// Obtener la cuenta debito y la cantidad de dinero disponible
// Verificar que haya dinero suficiente para cubrir la trasferencia.

return this.getSuccess();
}

}

En este caso tenemos una implementacion dummy con el solo echo de mostrar el funcionamiento y configuracion de OT-Rules.
Ahora agregamos esta nueva rule en la configuracion modificando el bean transferRule:

<bean id="transferRule" class="net.sf.opentranquera.rules.logical.AndRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.DifferentAccountRule"/>
<bean class="net.sf.opentranquera.samples.rules.AccountsExistsRule">
<property name="rule" ref="accountExistsRule"/>
</bean>
<bean class="net.sf.opentranquera.samples.rules.DebitAccountRule"/>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>

Así de simple es agregar nuevas reglas o modificar/reemplazar reglas existentes. En este caso no cambia el código de la clase TransferServiceImpl.

Reusar rules
OT-Rules también permite reusar reglas en diferentes objetos o RuleEvaluators, por ejemplo en el caso anterior reutilizamos la regla net.sf.opentranquera.samples.rules.AccountExistsRule, en el bean ruleEvaluator asignando la ejecución de la regla "balance" y en "transferRule" como una de sus reglas incluidas.

<bean id="ruleEvaluator" class="net.sf.opentranquera.rules.RuleEvaluator">
<property name="rules">
<map>
<entry key="transfer"><ref local="transferRule"/></entry>
<entry key="balance"><ref local="accountExistsRule"/></entry>
</map>
</property>
</bean>
<bean id="transferRule" class="net.sf.opentranquera.rules.logical.AndRule">
<constructor-arg index="0">
<list>
<bean class="net.sf.opentranquera.samples.rules.DifferentAccountRule"/>
<bean class="net.sf.opentranquera.samples.rules.AccountsExistsRule">
<property name="rule" ref="accountExistsRule"/>
</bean>
<bean class="net.sf.opentranquera.samples.rules.DebitAccountRule"/>
</list>
</constructor-arg>
<constructor-arg index="1" value="true"/>
</bean>


Mas Rules
OT-Rules tiene un conjunto de reglas preconstruidas para facilitar el desarrollo y configuración de reglas de negocios y validaciones:
* AndRule: Ejecuta la operación AND entre varias rules. Puede ser short circuit o no.
* OrRule: Ejecuta la operación OR entre varias rules. Puede ser short circuit o no.
* XorRule: Ejecuta la operación XORentre varias rules.
* NotRule: Niega la ejecución de una rule
* IfRule: Ejecuta una o otra rule en base al resultado devuelto por otra rule.

Además provee un conjunto de RuleResults como ser:
* SimpleResult: Provee funcionalidad básica para un RuleResult.
* TrueResult: Es un RuleResult que siempre devuelve true.
* FalseResult: Es un RuleResult que siempre devuelve false.

Por último, OT-Rules tiene diferentes formas de ser configurado:
* XML: Es un formato XML que propone la framework. Proximamente tendrá un plugin para Eclipse.

<rules>
<rule name="test.single.rule"
ruleClass="net.sf.opentranquera.rules.HelloWorldRule" />

<rule name="test.param.rule"
ruleClass="net.sf.opentranquera.rules.WordLengthRule">
<param name="length" value="11" />
</rule>

<rule name="test.and.rule"
ruleClass="net.sf.opentranquera.rules.logical.AndRule">
<rule ruleClass="net.sf.opentranquera.rules.HelloWorldRule" />
<rule ruleClass="net.sf.opentranquera.rules.WordLengthRule">
<param name="length" value="14" />
</rule>
</rule>

<rule name="test.not.rule"
ruleClass="net.sf.opentranquera.rules.logical.NotRule">
<rule ruleClass="net.sf.opentranquera.rules.support.FalseRule" />
</rule>

<rule name="test.negate.rule"
ruleClass="net.sf.opentranquera.rules.support.TrueRule"
modifier="negate" />

<rule name="test.and.ref"
ruleClass="net.sf.opentranquera.rules.logical.OrRule"
shortCircuit="false">
<rule ref="test.single.rule" />
<rule ref="test.param.rule" />
</rule>
</rules>

* Spring: Como ya se explico arriba
* API: Se pueden crear las rules a mano o utilizar la FluentAPI que facilita la creación programatica de reglas

FluentRule fir = new FluentRule("test");
fir.rule(new TrueRule()).and(new TrueRule()).or(new FalseRule()).not();

RuleEvaluator evaluator = FluentInterfaceRuleEvaluatorBuilder.createRuleEvaluator(fir);

jueves, 23 de noviembre de 2006

What is OT-Rules

What is OT-Rules?


OT Rules is a simple rule engine that focuses on execution, validation and business rules composition. One of the main advantages of using OT Rules is that you can define business validations and keep them isolated from business logic so you can add, remove, change or compose these rules and new rules in a simple, flexible way without affecting the business logic.

Download

Features (version 1.0.1)
* Flexible and configurable rules evaluation.
* Provide differents relational rules (AND, OR, XOR, NOT).
* Support simple and composite rules.
* Built-in rules.
* It is configured through the use of a XML file and fluent API.
* Integration with Spring Framework (rules are spring-beans).
* Multi-threading environment.
* Test cases that explains the behavior of the rules.
* More than 90% code coverage.

When do you use OT-Rules?
# To execute business validations.
# To evaluate (potential) business rules that changes in a time
# To develop rules incrementally and compose their in each iteration.
# To obtain a flexible environment to execute business logic.

martes, 28 de marzo de 2006

Read-Mostly Pattern

Este es un patrón propuesto en la documentación de bea weblogic para incrementar la performance de una aplicación que trabaja en su capa de persistence con EntityBeans más precisamente con CMP 2.0. La idea detras de este es hacer un uso intenso de la cache de entities y del mecanismo de invalidación implícita que WebLogic provee.
Las entidades candidatas a ser implementadas con este patrón son aquellas en las cuales se realizan operaciones de lectura frecuentes y operaciones de escritura ocasionalmente.
Para implementar este patrón se deben crear dos entity beans uno de read-only y otro de read-write apuntando a la misma tabla de la base de datos, el bean de read-only se utiliza para las operaciones de lectura mientras que el bean de read-write se utiliza para las operaciones de escritura y comportamiento transaccional. Luego se indica mediante configuración que cuando el bean de read-write sea modificado invalide el bean read-only de la cache.
Cuando se accede al bean de read-only en una transacción (JTA Transaction) el container activa una nueva instancia de este bean para la transacción con los datos tomados desde la cache, si no se encuentra en la cache llama a el método ejbLoad(), carga el bean y lo coloca en la cache de entities para su posterior uso. De esta forma las operaciones de lectura de la entidad se realizan todas sobre la cache mejorando los tiempos de acceso.

Ahora bien, cuando se utiliza el bean de read-write y este se ve modificado en alguno de sus campos, el container cuando comité la transacción (y llame a ejbStore() del bean) llama al mecanismo de invalidación y de esta forma se invalida el bean de read-only para que en su próxima lectura este se refrescado (se llame a ejbLoad()).

Otra forma de hacer que los beans de read-only se refresquen es utilizando un timeout de forma tal que cada un lapso determinado de tiempo estos bean se sincronizan con los datos en la base de datos.
Con el uso de este patrón se obtienen tiempo de respuesta mucho mejores dado el uso de la cache de bean read-only. Para casos similares podria tenerse en cuenta el uso de estrategias de concurrencia optimistas, las cuales mejoran el control de cambio de las entidades.