JBoss Video’s Channel en YouTube
Julio 14, 2009
Gente, para los que no sepan todavia, hay un canal de JBoss donde publican distintos eventos donde la empresa va participando. Ultimamente han agregado al canal los videos de la JavaOne 09, donde tenian un stand chiquito, pero vistoso y daban mini charlas sobre los distintos proyectos.
Les dejo la URL y luego trateremos de embeber el canal en la pagina del JBug.
http://www.youtube.com/user/JBossVideo
Saludos
Lanzamiento de JBug Argentina
Mayo 5, 2009
Los invito a visitar y ser parte de esta iniciativa que intenta conformar una comunidad activa de profesionales con conocimientos en JBoss. Donde la meta es compartir intereses, gustos y conocimientos sobre las herramientas y middleware que JBoss propone.
Si ya tenes un blog o has escrito artículos sobre tecnologías propuestas por JBoss, contactate con el grupo de usuarios de JBoss y hagamos juntos crecer esta comunidad de habla hispana.
Jugando con jBPM #16 – Task Controllers
Diciembre 18, 2008
El propósito de este post es mostrar el uso de task controllers, los beneficios que nos presentan y el comportamiento por defecto que podemos obtener al utilizarlos.
Para mostrar esta funcionalidad utilizo el siguiente ejemplo muy simple de proceso:

Proceso Simple - 1 Task Node - 1 Task
Donde podemos observar que es un proceso que tiene un solo nodo (aparte del nodo start y end) el cual contiene una tarea definida dentro de el.
La funcionalidad principal de los task controllers es facilitarnos la tarea de la administración de las variables que vamos a utilizar dentro de las tareas que van a realizar personas en nuestro proceso.
Esto quiere decir que tenemos la posibilidad de acotar el espacio de variables que vamos llevando en el proceso a un set mucho mas reducido y especifico de la funcionalidad de una cierta tarea. Y al mismo tiempo copiar el valor, para no modificar la variable del proceso, sino una copia de la misma que puede ser plasmada nuevamente en el proceso cuando la tarea ya este finalizada.
Para hablar un poco mas de la implementación en jBPM, esto que estamos hablando seria realizar una copia de algunas de las variables que se encuentran en ProcessInstance.contextInstance (scope del proceso) a TaskInstance.variables (scope de la tarea).
Mediante esta copia, las tareas pueden realizarse y modificar las variables que estan en su scope, sin molestar a las variables del proceso. También mediante este esquema, se nos permite guardar el estado de estas variables de las tareas mientras se va realizando el trabajo y luego plasmarla cuando la tarea se de por finalizada (que es donde los valores se consideran correctos).
Otra de las utilidades de los task controllers, es la de especificar que variables vera el usuario en el formulario que representara la tarea. Esto quiere decir, que el task controller sirve como puente entre las variables de proceso y el formulario que el usuario vera en la presentación con las variables especificadas en el task controller.

Task Controllers
Como ultimo detalle para cerrar el comportamiento básico de los task controllers, hace falta aclarar que a cada una de las variables que pasemos del proceso a la tarea se le pueden especificar distintas políticas a tener en cuenta.
Estas políticas son 3:
- read: realiza una copia de la variable, que puede ser modificada dentro de la tarea, pero cuando se finalice la tarea, no se copiara el nuevo valor a la variable del proceso.
- write: cuando termine la tarea, el valor modificado dentro de la tarea sera plasmado en la variable del proceso
- required: obliga al que realiza la tarea a cargar este dato, sino genera una exception
Para demostrar este funcionamiento cree un ejemplo muy básico que consiste en un test de JUnit dentro de un proyecto jBPM creado con GPD en eclipse.
Este ejemplo consiste en el proceso mostrado al comienzo del post y un test que tiene la siguiente funcionalidad:
- Crea una instancia del proceso
- Agrega 3 variables al contexto del proceso
- En el task controller definido dentro de la tarea del task-node se especifica la copia de dos de esas 3 variables con distintas políticas (variable1: con política read,write y variable2: con política solo de read)
- Se recupera la tarea y se modifican ambas variables
- Se termina la tarea
- Se comprueba que una de las dos variables fue plasmada en el proceso y la otra no
Aca les dejo el link al proyecto para que puedan jugar con el:
http://rapidshare.com/files/295154070/TaskControllers.rar.html
(Por favor comenten si el link esta roto asi lo vuelvo a subir y lo actualizo)
Notas sobre el ejemplo:
- Revisar la definición de la tarea y como se define el task controller
- Leer los comentarios en el test: com.sample.SimpleProcessTest
- Debuggear y analizar los objetos dentro del ProcessInstance.contextInstance y taskInstance
- Genere un formulario dinámicamente para que la tarea se vea en la jbpm-console, pueden analizar los archivos forms.xml y tarea 1.xhtml, pero les recomiendo no utilizar estos formularios
- Comentar aqui si no quedo algo claro
Saludos! Espero sus comentarios y sus dudas!
Jugando con jBPM #15 – Identity Component
Noviembre 5, 2008
Primero que nada bienvenidos al post numero #15 de la serie Jugando con jBPM. En este post veremos algunos detalles del componente de identidades.
Como estamos acostumbrados a ver en la típica imagen de arquitectura (o división lógica del proyecto) de jBPM se diferencia el componente de Identity (Identidades) como un bloque separado del core del framework:

Componentes de jBPM
Esta separacion le da a jBPM la flexibilidad de poder adaptarse a cualquier modulo de identidades que ya se encuentre en la empresa donde se vaya a realizar una implementación.
Pero entonces, en que consiste este modulo Identity que muestra la figura?
La respuesta es bastante simple, consiste en un modulo muy simple, que funciona out-of-the-box, que cuenta con tres conceptos para administrar nuestras identidades: Usuarios, Grupos y Membresias (User, Group y Membership). La idea es que apenas empezamos a usar jBPM ya tengamos una forma fácil y sencilla de user datos de usuarios, grupos y las relaciones N a N entre ellos con las membresias.
Esto no quiere decir que jBPM esta fuertemente acoplado a este esquema de usuarios, ya que en la mayoría de los casos, tenemos que adaptarnos a implementaciones y estructuras ya existentes de identidades.
Llegado al caso en el que tenemos que remover el componente de identidades que viene con jBPM y adaptar nuestro propio componente, debemos tener en cuenta cuales son los pasos a seguir y que bloques o clases debemos reescribir para adaptarnos.
El primer dato que encontramos si buscamos un poco sobre el tema es que debemos comentar en el archivo hibernate.cfg.xml las siguientes lineas:
<!-- identity mappings (begin) === <mapping resource="org/jbpm/identity/User.hbm.xml"/> <mapping resource="org/jbpm/identity/Group.hbm.xml"/> <mapping resource="org/jbpm/identity/Membership.hbm.xml"/> ==== identity mappings (end) -->
Estos mapeos de hibernate se encargan de administrar las entidades que se manejan en este modulo que viene por defecto, cuyo diagrama de clases es el siguiente:

Modelo de Clases de Identity
Por lo tanto desactivando estos mapeos desacoplamos totalmente a jBPM de este modulo de identidades que viene por defecto, y estamos listos para insertar nuestro propio (puede ser ya existente) modelo al framework.
jBPM para realizar este desacoplamiento de la forma mas transparente posible, maneja el concepto de actor, que es simplemente un String que representa a nuestros usuarios o grupos de usuarios.
Ahora bien, si en este punto nosotros tenemos un proceso que tiene una tarea y la asignación de esta tarea se realiza mediante una expresion, como por ejemplo:
<task name="Elegir tarea del dia"> <assignment expression="group(admin)"/> ..
Esta expresión lo que hace es resolver el grupo admin y asignarle la tarea a todos los usuarios de este grupo (en este caso admin).
Les recomiendo que vean en la documentación oficial como pueden ser estas expresiones ya que es un tema bastante interesante. (link: http://docs.jboss.com/jbpm/v3.2/userguide/html_single/#theidentitycomponent)
Por lo tanto si tratamos de ejecutar nuestro proceso y hemos desactivado los mapeos a las entidades de hibernate, vamos a ver en la consola el siguiente WARN:
11:10:24,812 [main] WARN QuerySplitter : no persistent classes found for query class: select g from org.jbpm.identity.Group as g where g.name = :groupName
Que nos dice exactamente eso, no tiene ninguna clase para consultar los grupos de usuarios y resolver la expresion que habiamos puesto en el tag assigment dentro de nuestra tarea.
Entonces, la pregunta que se hace obvia es: quien se encarga de hacer estas resoluciones de expresiones?
La respuesta tambien es obvia y es una clase llamada: org.jbpm.identity.assignment.ExpressionAssignmentHandler
La cual mediante una propiedad ExpressionSession expressionSession, se encarga de comunicarse con el esquema de identidades que se encontraba mapeado con hibernate. En este caso del mapeo con hibernate donde nuestro esquema de identidades se encuentra almacenado en la base de datos (es muy comun que el esquema de identidades este en un Arbol LDAP tambien) la clase que implementa la interfaz ExpressionSession para esta implementacion del componente de identidades es: org.jbpm.identity.hibernate.IdentitySession.
SI analizamos los metodos de esta clase veremos que ellos cumplen con todas las funcionalidades necesarias para resolver usuarios y grupos de la manera mas simple (en este caso realizando consultas con la session de hibernate a las entidades mapeadas).
Algunos metodos de org.jbpm.identity.hibernate.IdentitySession:
</pre>
public User getUserByName(String userName) {
User user = null;
Query query = session.createQuery(
"select u " +
"from org.jbpm.identity.User as u " +
"where u.name = :userName"
);
query.setString("userName", userName);
List users = query.list();
if ( (users!=null)
&& (users.size()>0) ) {
user = (User) users.get(0);
}
return user;
}
public Group getGroupByName(String groupName) {
Group group = null;
Query query = session.createQuery(
"select g " +
"from org.jbpm.identity.Group as g " +
"where g.name = :groupName"
);
query.setString("groupName", groupName);
List groups = query.list();
if ( (groups!=null)
&& (groups.size()>0) ) {
group = (Group) groups.get(0);
}
return group;
}
Como ultimo dato agrego que la sugerencia, muy correcta en la documentación, dice que si queremos reutilizar el esquema de acceso a los componentes de identidades que nos propone jBPM debemos extender la clase ExpressionAssignmentHandler y sobre escribir el método getExpressionSession que en este caso nos devolvería en vez de un org.jbpm.identity.hibernate.IdentitySession nuestra propia implementación de acceso a nuestras propias identidades.
Entonces las ideas que me gustaría que quedaran claras en este post son las cosas a tener en cuenta para implementar o acoplar un nuevo esquema de identidades a jBPM.
También espero que les sirva como punta pie inicial para investigar en profundidad estas expresiones de asignación que son muy importantes cuando tenemos tareas y grupos de usuarios complejos.
Cualquier consulta, ya saben que estoy a su disposición.
jBPM vs 7 visiones de BPM
Noviembre 3, 2008
Pocas veces hago un review sobre algún articulo que publica alguien mas, ya por lo general me gusta expresar mi visión sobre los distintos frameworks con los que suelo jugar todos los dias.
En este caso me dedico a comentar un articulo escrito nada mas y nada menos que por el senior Tom Baeyens (Leader y Core Developer del desarrollo de jBPM), tambien agregándole mi vision y no tanto traduciendo el articulo.
En este articulo, lleno de experiencia, Tom comenta 7 formas distintas de ver a BPM, ya que actualmente BPM es un termino muy sobrecargado y por esto es muy importante distinguir entre los distintos significados a la hora de abordar el tema no solo tecnológica mente sino en todos los aspectos que el termino califica.
A continuación vemos estas 7 visiones de BPM resumidas del articulo original:
1) BPM como una disciplina:
Siempre debemos recordar que Business Process Management surge como una disciplina que se enfoca en el análisis, la documentación y la mejora de procesos que dictan como las personas y los sistemas trabajan dentro de una organización.
En esta disciplina se hace un esfuerzo para, primero que nada detectar y visualizar como trabajan las personas, como se comunican entre ellas, como se mueve la información que administra la organización, etc. Una vez que tenemos un estudio inicial se formalizan estos procesos en algún lenguaje como BPMN (Business Process Management Notation) y al mismo tiempo se trata de mejorar estos procesos para ahorrar tiempos y recursos dentro de la organización.
Como podran ver (y si leen un poco de BPMN) nos damos cuenta que en esta disciplina hay una distancia bastante considerable con el aspecto tecnológico. Ya que por lo general el resultado de esta disciplina, son los procesos optimizados presentados como una extensa documentación.
Por lo tanto, como menciona Tom en su articulo, jPDL (jBPM Process Definition Language) trata de ser el vinculo entre este análisis y formalización que se realiza en la disciplina con el aspecto tecnológico de un proyecto de software.
2) Combinando administración de tareas basadas en templates y tareas ad-hoc
Las cosas importantes que me parece que hay que destacar en este punto del articulo es que por lo general en los procesos de la vida real se termina haciendo una orquestación de las tareas humanas que se definen formalmente. Y por lo general, no es un tema al que se le preste mucha atención ya que por lo general estas orquestaciones, para que funcionen bien hay que ser muy rigurosos en cuanto al modelado y cubrir todas las posibles excepciones que puedan llegar a presentarse en la ejecución de las mismas.
Esto presenta situaciones donde la complejidad del análisis es alta y el costo de estabilizar estos procesos es alto.
Para esto en jBPM 4 van a aparecer las tareas ad-hoc que nos permiten definir tareas dentro de tareas, es decir que dentro de una tarea podamos crear sub tareas y asignarlas para modelar situaciones complejas donde las tareas humanas juegan un rol mas que importante en nuestros procesos.
3) Arquitecturas asíncronas transaccionales:
Como ya nos imaginamos con el nombre de este caso de uso, esta perspectiva esta fuertemente asociada a conceptos técnicos y de implementación de BPM, y por lo tanto esta en gran contraste con el caso de uso numero uno (BPM como disciplina).
En este caso, el proceso que vamos a implementar, por lo general no tiene relación con ningún proceso de nivel de negocio real. Sino que nuestro proceso nos va a permitir reflejar una implementación limpia y transparente para una solución compleja de comunicación entre varios puntos de manera transaccional (esto quiere decir, que en todo momento podremos saber en que estado estamos y tenemos la posibilidad de deshacer todo lo que hemos hecho, por conocer el estado en el que estamos y los estados por donde fuimos pasando)
4) Orquestacion de servicios
Esta es otra de las frases mas escuchadas cuandos se habla de jBPM, y este caso de uso es un caso particular del mensionado en el punto 3, ya que tambien esta fuertemente basado en la comunicaciones asincronicas entre varios interesados, pero en este caso la implementación de la comunicación suele darse por medio de un ESB (Enterprise Service Bus). “En estos casos es donde BPEL cobra un sentido fuerte, ya que se caracteriza por darnos un lenguaje de comunicación común y standard para nuestras comunicaciones”.
5) Programación Visual
La programación visual, como menciona Tom en el articulo, es importante ya que brinda a los analistas y a desarrolladores que no estan tan acostumbrados a entornos Java, a empezar fácilmente dibujando los procesos de manera bastante simple.
Si bien esto es mucho menos flexible que la programación en Java, esto presenta varias ventajas entre las cuales se incluyen: una curva mucho mas baja de aprendizaje, un alto impacto visual y fácil comprendimiento.
6) Lenguaje de Control de ejecuciones multi hilo
Es importante notar un caso particular de esta programación visual que mencionábamos en el punto anterior, ya que el lenguaje que utilizamos cuando programamos visualmente (con designer / plug in para eclipse de jBPM) nos permite, usando nodos Fork/Join, modelar situaciones donde concurrentemente deben ejecutarse varias ramas del mismo proceso.
7) Fácil creación de DSLs (Data Definition Languages)
Uno de los pilares de jBPM es reconocer que cada entorno de los procesos en la vida real es distinto. Por lo tanto una sola nomenclatura para definir los nodos de nuestros procesos no basta. Por esto mismo jBPM presenta jPDL, BPEL y PageFlow (de Seam) como tres lenguajes propuestos para tres entornos distintos.
Pero la idea real detras de todo esto es que sobre la Process Virtual Machine (PVM, el nucleo de jBPM) pueda escribirse/definirse cualquier lenguaje que se adapte correctamente al entorno del proceso que vamos a modelar.
Como menciona Tom en su conclusión, la mayoría de las personas que han leido poco de BPM y jBPM piensan que BPM es un software donde podemos dibujar un flujo de acciones y ya estamos listos para ejecutarlo y ponerlo en producción. Esta es una idea que escapa mucho a la realidad del framework jBPM y a la teoría de BPM en general, por esto mismo deben tenerse en cuenta estos puntos planteados.
Les dejo el link del articulo original para que lean la experiencia de Tom y los links que deja ya que son muy interesantes, porque amplían en detalle el tema.
Jugando con jBPM #14 – TaskMGMT API
Noviembre 3, 2008
En este post vamos a ver un poco de la API para la administración de tareas en jBPM, la cual es muy útil a la hora consultar las tareas que se van creando a medida que nuestra ejecución del proceso va pasando por los diferentes Task Nodes que tengamos definidos.
En este caso, y para este ejemplo, cree el siguiente proceso básicamente compuesto por Task Nodes:
Como vemos en la imagen, una vez que el proceso comience se creara una tarea contenida dentro del task node “Elegir Tarea del Dia”. Como por defecto las tareas que van a ser realizadas por personas se comportan como Wait States (Estados de espera), nos bloquean la ejecución del proceso. Por lo tanto el comportamiento del proceso sera el siguiente:
1) Se comienza la ejecución del mismo desde el nodo Start (mediante la llamada al método signal)
2) La ejecución del proceso llega hasta el task node llamado “Elegir Tarea del Dia”, crea las instancias de las tareas que estan especificadas dentro del task node (crea objetos TaskInstance).
3) Se persisten los cambios y las instancias de las tareas que se crearon en el schema de jBPM, para esperar la interacción del usuario.
Cuando el usuario quiere interactuar con la tarea que fue creada para el debe ir a buscar en su lista de tareas, donde encontrara todas las TaskInstances que fueron creadas por procesos para el.
Una vez que encontramos la tarea que queremos comenzar en la lista de tareas, deberíamos seleccionarla, completar los datos y luego finalizarla para que el proceso continúe su ejecución.
En esta caso, para el ejemplo decidi que la tarea dentro del task node “Elegir Tarea del Dia”, tuviera como requerida una variable que se llama “tarea” que le va a indicar al proceso porque rama continuar su ejecucion usando el valor de esta variable para decidir en el nodo decisión.
Vamos a ver un poco el código asi se van aclarando las cosas, para esto les cuento un poco el contexto donde estoy ejecutando el siguiente bloque de código:
context=conf.createJbpmContext();
// Obtenemos a partir del contexto una sesion del administrador de tareas, esta nos dara acceso a todas las tareas
// creadas en todos los procesos y asignadas al usuario salaboy.
// Tambien podriamos haber utilizado la instancia del proceso para acceder a una API mas enfocada a la instancia
// del proceso.
List<TaskInstance> tasksForSalaboy=context.getTaskMgmtSession().findTaskInstances("salaboy");
// Itereamos sobre la lista de tareas para el usuario Salaboy
// de esta manera deberiamos armar la UI
for(TaskInstance ti : tasksForSalaboy){
System.out.println("TaskInstance ID: "+ti.getId()+" - Name: "+ti.getName()+ " - Creada: " +ti.getCreate());
}
if(tasksForSalaboy.size() > 0){
TaskInstance elegirTarea=tasksForSalaboy.get(0);
System.out.println("Encontre una tarea = "+elegirTarea.getName());
// Deberiamos comprobar que es la tarea de elegir tarea
// Lo podemos hacer revisando el nombre de la tarea con elegirTarea.getName()
elegirTarea.start();
//Comprobamos que no tenga seteada nada la variable
assertNull(elegirTarea.getVariable("tarea"));
System.out.println("la variable TAREA tiene el valor = "+elegirTarea.getVariable("tarea"));
// Le asignamos el valor lavar a la variable tarea, cocinar nunca antes morir!
elegirTarea.setVariable("tarea", "lavar");
System.out.println("la variable TAREA tiene el valor = "+elegirTarea.getVariable("tarea"));
assertEquals("lavar",elegirTarea.getVariable("tarea"));
//Terminamos la tarea
elegirTarea.end();
}
context.close();
Hay que tener en cuenta que para ejecutar este bloque de código tenemos que tener una instancia de JbpmConfiguration (la variable conf) que debe estar correctamente configurada para comunicarse con nuestra fuente de datos que contiene el schema de jBPM (esta configuración se realiza en el archivo hibernate.cfg.xml).
Creo que el codigo se explica por si solo y los comentarios ayudan en caso de que no se entienda alguna linea en particular. Como se que si no ven el proyecto entero se complica terminar de entender el ejemplo, subi el proyecto entero (pesa 45k) a rapidshare para que pueda verlo. Aca les dejo el link:
(Actualizado)
http://rapidshare.com/files/289991585/jBPMTaskMGMTExample.zip.html
Algunas Notas sobre el Ejemplo:
1) Uso postgreSQL como base de datos, por lo tanto necesitaran el driver JDBC de postgreSQL (el cual pueden descargar de aca: http://jdbc.postgresql.org/download.html, revisar bien la version que necesiten)
2) En este ejemplo la configuración realizada en hibernate.cfg.xml es para un cliente standalone y no para el framework deployado en un Servidor de Aplicaciones como JBoss. En el caso de estar dentro de una aplicación que esta corriendo sobre JBoss habría que configurar un DataSource y no la conexión directa por JDBC.
3) El ejemplo esta creado con eclipse y el plug in de jBPM, no es como acostumbro a trabajar pero para las personas que estan comenzando me parece un buen punto de partida. (Ver post anteriores para ver como configurar el plug in de jBPM en eclipse/ También llamado designer )
4) Toda la funcionalidad del proyecto se encuentra en una clase que utiliza JUnit para realizar las pruebas de funcionalidad. Buscar en la sección de Tests (scr/test/java/com/sample/SimpleProcessTest.java). Estas pruebas no estan muy prolijas por cuestiones de tiempo.
5) Si el link de rapidshare se cae, por favor avisar asi lo vuelvo a subir.
Les dejo el link de la documentacion oficial donde se habla bastante sobre las tareas:
http://docs.jboss.org/jbpm/v3/userguide/taskmanagement.html
Es importantísima!!!!!!! la sección que se llama: “11.2.2. Task instances and graph execution”
Saludos, espero que sirva de ayuda para entender el uso muy basico de la API, en un post futuro prometo escribir un post sobre la API mas en profundidad.
Cualquier duda sobre la documentacion oficial o sobre este post, no duden en comentar!!!
Que feo es hacerse auto propaganda.
Septiembre 17, 2008
Es bastante feo el hecho de hacerse propaganda a uno mismo, la verdad nunca lo habia pensado.
Para ser mas claro, siempre pensé que la mejor propaganda para uno mismo es la que le hacen los demas o sus acciones pasadas.
Pero hoy, revisando mis mails, en la lista del foro oficial de jBPM mencionaron mi nombre y eso me lleno de orgullo, me hizo sentir realmente parte de esta especial comunidad. Mas aun si los comentarios vienen de un grande de la lista como kukeltje quien se declara a si mismo:
“A kind jBPM user and forum ‘addict’”
Aca les dejo el link, no para hacerme propaganda a mi mismo, sino para que si algun otro entisiaste de jBPM crea post al respecto, se anuncie en este thread del foro oficial de jBPM!
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4176927#4176927
Saludos!
Actualización: Mas auto propaganda en un nuevo blog creado para reunir todos los blogs de jBPM en todos los idiomas: http://planetjbpm.wordpress.com/
Actualización 2: Otro grande de los foros de JBoss hizo una resenia de este blog: http://www.jorambarrez.be/blog/2008/09/19/blogs-about-jbpm/
Actualización 3: Otro blog de un Ingeniero de Valencia, España me menciono:
http://www.workflowsworld.com/2008/10/salaboy-jbpm-en-castellano/
Jugando con jBPM #13 – Swimlanes a nivel conceptual
Septiembre 1, 2008
Es algo sobre lo que se pregunta bastante, ya que es un concepto que esta asociado con el modelado de procesos en general. Para no confundir, podemos definir a una swimlane como un rol del proceso, para ser mas especificos, podriamos decir que vamos a usar una swimlane cuando en un proceso que estemos modelando necesitemos especificar que un set de tareas deben ser realizadas por la misma persona, ya que esta es la que conoce el contexto de esas tareas para una instancia del proceso en particular.
Por lo tanto el comportamiento que vamos a obtener en jBPM es el siguiente:
- Definimos (modelamos) varias tareas asignadas a una swimlane
- Cuando la primer tarea de la swimlane se instancia, se llama al AssignmentHandler correspondiente y se asigna un actor a la swimlane
- Cuando la segunda tarea de la swimlane se instancie, se recupera el actor ya asignado por el AssignmentHandler y se asigna este a la tarea.
- Así para el resto de las tareas que estén asignadas a la swimlane.
Por lo tanto debemos tener cuidad de no aplicar un assignment handler a las tareas que se encuentran con una swimlane especificada.
Notas o aclaraciones nuevas:
Voy a tratar de en un par de puntos aclarar algunos conceptos que puede ayudar:
- En la definicion del proceso definimos task-node y task.
- Las task-nodes contienen 0 o mas task, las cuales se instancian dinámicamente (por defecto) cuando el flujo del proceso llega al task-node que las contiene
- En el momento de instanciación de cada una de las tareas (tasks dentro del task-node) se llama al correspondiente AssignmentHandler que esta definido en cada tarea.
- En un caso normal este AssignmentHandler resuelve a que actor del proceso le corresponde realizar la tarea y asigna al campo ActorId el nombre del actor obtenido. (También esta el caso de pooled actors pero no viene al tema)
- En el caso de que haya varias tareas a lo largo de varios task-nodes asociadas a un swimlane, genera otro comportamiento, que describo a continuación:
- Cuando el flujo de ejecución del proceso llega al primer task-node que contiene una tarea la cual esta asociada a una swimlane, esta tarea se instancia y se llama al assignment que tenga asociado la swimlane. Este AssignmentHandler tiene la particularidad que solo va a ser invocado por la primer tarea que se instancie y que este asociada con la swimlane. Lo que significa que cuando se instancie la segunda tarea asociada a la swimlane, el actor ya estará resuelto y deberá llamarse al AssignmentHandler correspondiente. Todo esto se logra manteniendo una ” instancia” de la clase SwimlaneInstance con el actor ya resuelto y recordándola (o sea persistiendo la) para que las nuevas tareas no tengan que realizar la logica de asignación nuevamente.
Espero que haya quedado un poco mas claro, prometo subir un ejemplo para discutir mas adelante.
Saludos!
Jugando con jBPM #12 – jBPM + Drools
Septiembre 1, 2008
Bueno como siempre, la idea del post es tratar de mostrar alguna funcionalidad de jBPM. Pero en este caso nos vamos a fusionar con otro framework muy importante dentro de la suite de productos de JBoss. Estamos hablando de JBoss Drools, este framework pretende cumplir todas las funcionalidades de un BRMS (Business Rule Management System – Sistema de administración de Reglas de Negocio).
En este caso vamos a ver un ejemplo sencillo de como podemos usar a Drools dentro de un ActionHandler de jBPM.
Para empezar con el ejemplo vamos a ver el gráfico del proceso del negocio que vamos a utilizar:
Este proceso básicamente se encargara de obtener los datos de una persona (de algún modo, podría ser una tarea humana cargar los datos de la persona) y con estos datos automáticamente se categorizara la persona teniendo en cuenta su edad, su sueldo, su categoría de trabajo, si posee vehículos, etc. Este es un proceso muy común en los análisis de riesgo crediticio, o también podría ser parte de la decisión para dar un seguro. La idea es que esta categorización se haga de manera automática con el motor de inferencias que nos provee Drools y de paso aprovechar de separar esta lógica de categorización dejándola afuera del código Java compilado, haciendo que esta sea mucho mas flexible a cambios. Sin dejar de lado la ventaja de que con los DSL (Domain Specific Language – Lenguajes Específicos de Dominio) podemos enmascarar las reglas definidas en lenguaje de Drools a algo muy parecido al lenguaje natural. (Mas de esto en un futuro post)
Entonces pasamos directamente a ver código y los pre-requisitos que necesitamos para que todo esto ande.
Como ya explique en post anteriores para que jBPM ande necesitamos sus dependencias, de la misma manera Drools tiene las suyas. Para obtener estas dependencias nos dirigimos a la pagina oficial de Drools y descargamos los binarios (Aprox. 50 megas)
Bajamos los binarios de Drools (Drools 4.0.7 Binaries):
http://www.jboss.org/drools/downloads.html
También recomiendo bajar el plug-in para eclipse, el cual nos hará las cosas mucho mas fáciles a la hora de escribir las reglas y sus correspondientes DSLs.
Drools 4.0.7 Eclipse Europa 3.3 Workbench (funciona para Ganymede también)
Una vez que tengamos esto descargado, necesitaremos descomprimirlos por ahí y luego crear una User Library en eclipse con los jars de Drools y sus correspondientes dependencias (que se encuentran en el directorio /lib).
(Para los que les interese Drools, recomiendo los ejemplos que hay en la pagina de downloads y la documentación oficial)
Una vez que tenemos los plug-ins instalados (jBPM y Drools) y las dependencias de ambos en nuestro proyecto, ya estamos listos para ver el codigo del proceso mostrado anteriormente.
Primero vamos al nodo (de tipo node) Obtener Persona, el cual tiene un ActionHandler asociado que posee el siguiente código:
public void execute(ExecutionContext context) throws Exception {
Persona persona=new Persona();
persona.setEdad(45);
Trabajo trabajo = new Trabajo();
trabajo.setPuesto(Puesto.GERENTE);
trabajo.setSueldo(50000);
persona.setTrabajo(trabajo);
ArrayList<Vehiculo> vehiculos = new ArrayList<Vehiculo>();
Vehiculo vehiculo=new Vehiculo();
vehiculo.setValor(130000);
vehiculo.setModelo("Audi A3");
vehiculos.add(vehiculo);
persona.setVehiculos(vehiculos);
context.setVariable("persona", persona);
context.leaveNode();
}
Como se puede observar en este ActionHandler solo armamos un objeto persona, la idea en la realidad seria que sacáramos de algún lado (como por ejemplo de una base de datos, o un servicio) este objeto. Una vez que tenemos este objeto Persona, lo asignamos a una variable de contexto y continuamos la ejecución del proceso.
Al continuar la ejecución, el proceso llega al nodo llamado Categorizar, el cual también tiene un ActionHandler asociado, el cual se encarga de levantar una Sesion de Drools para ejecutar las reglas que vamos a ver mas adelante. Vemos el codigo de este ActionHandler:
public void execute(ExecutionContext context) throws Exception {
//Creamos un paquete de reglas a partir del archivo categorizar.drl
PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl(new InputStreamReader(this.getClass().getResourceAsStream("/categorizar.drl"));
//Con este paquete de reglas creamos un RuleBase
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage(builder.getPackage());
//Con este rule base instanciamos una nueva Session Stateful de reglas.
StatefulSession session = ruleBase.newStatefulSession();
//Buscamos en el contexto el objeto persona anteriormente obtenido
Persona persona=(Persona)context.getContextInstance().getVariable("persona");
//insertamos este objeto a la Working Memory como un fact
session.insert(persona);
//Creamos un objeto de tipo Salida que va a contener los resultados de las ejecuciones de la reglas
//Y lo agregamos como una variable global
Categoria categoria=Categoria.BAJA;
Salida salida=new Salida();
salida.setCategoria(categoria);
session.setGlobal("salida", salida);
//Una vez que tenemos las reglas (en el paquete) y los hechos insertados en la WM
//Disparamos las reglas
session.fireAllRules();
session.dispose();
//Buscamos los resultados y los guardamos en una variable del contexto del proceso
context.getContextInstance().setVariable("categoria", salida.getCategoria());
//Continuamos la ejecucion
context.leaveNode();
}
Para los que recién comienzan con Drools este código suele ser bastante traumático, ya que se hacen varias cosas bastantes inexplicables a simple vista. Para tratar de explicar un poco lo que estamos haciendo veamos el siguiente gráfico que explica como generamos un paquete de reglas, que nos va a servir para inferir sobre nuestros objetos.
Como observamos en el gráfico y en el código vamos a armar un paquete de reglas partiendo de una definición de reglas que en nuestro caso esta en un archivo drl llamado categorizar.drl (también podría estar en una definición en xml de las reglas). Como podemos ver esta tarea la tiene encargada la clase PackageBuilder, la cual compila y genera el código que termina resultando en un paquete de reglas. Una vez que tenemos este paquete de reglas (que no es mas que un resultado binario y optimizado para la ejecución de nuestras reglas) creamos una nueva instancia de la clase RuleBase a la cual le agregamos el paquete que acabamos de generar. Esta clase RuleBase va a ser la encargada de tener todos los paquetes de reglas (por ende todas las reglas que se encuentren en esos paquetes) para que el motor de inferencias pueda ejecutarlas contra los hechos (o facts en ingles, que son nuestros objetos) que se van a encontrar en la Working Memory (es una memoria especial donde nosotros almacenamos nuestros hechos/objetos)
Con los siguiente gráficos de la documentación oficial espero que se aclara un poco el panorama:
Cuando el flujo de ejecución llega a este nodo, vamos a notar que Drools se pone a trabajar, lo que significa que hasta este momento, no se había hecho uso de Drools, por esto vamos a notar una demora en este nodo. Como resultado de este nodo guardamos una variable llamada categoría que decidirá en el siguiente nodo que acción hay que ejecutar.
Lo único importante que nos esta faltando ver es el archivo de reglas llamado categorizar.drl:
package com.sample.rules
import com.sample.action.dominio.Persona; import com.sample.action.dominio.Persona.Categoria; import com.sample.action.dominio.Vehiculo; import com.sample.action.dominio.Trabajo; import com.sample.action.dominio.Trabajo.Puesto; global com.sample.action.output.Salida salida;
rule "Evaluar Categoria Alta"
when
$persona : Persona ( edad > 35)
$trabajo : Trabajo(puesto == Puesto.GERENTE, sueldo > 10000) from $persona.trabajo
exists ($vehiculo : Vehiculo(valor > 40000) from $persona.vehiculos)
then
System.out.println("Categoria Alta");
salida.setCategoria(Categoria.ALTA);
end
rule "Evaluar Categoria Media"
when
$persona : Persona ( edad > 21 )
$trabajo : Trabajo(puesto == Puesto.ESCLAVO, sueldo < 6000) from $persona.trabajo
exists ($vehiculo : Vehiculo() from $persona.vehiculos)
then
System.out.println("Categoria Media");
salida.setCategoria(Categoria.MEDIA);
end
rule "Evaluar Categoria Baja"
when
$persona : Persona ( edad > 21 , edad < 35)
$trabajo : Trabajo(puesto == Puesto.ESCLAVO, sueldo < 6000) from $persona.trabajo
not (exists ($vehiculo : Vehiculo() from $persona.vehiculos))
then
System.out.println("Categoria Baja");
salida.setCategoria(Categoria.BAJA);
end
Como podemos ver son reglas muy sencillas y fáciles de leer. Y lo mejor de todo es que estas reglas las tenemos centralizadas en este archivo drl, lo cual nos hará la vida mucho mas fácil cuando estas cambien y tengamos que adaptarnos a los cambios.
Espero que haya servido de algo el post, me imagino que le falta mucho detalle de como funciona Drools y como es la sintaxis de las reglas y que podemos hacer dentro de ellas. Pero ahondare en siguientes post, la finalidad de este era mostrar rápidamente como podíamos integrar muy desacoplada mente Drools con jBPM.
Espero comentarios, ya que me imagino que hay muchas cosas sobre el post que pueden no quedar claras.
Jugando con jBPM #11 – Crear Task Dinámicas!
Agosto 29, 2008
La idea de este post es mostrar que detalles hay que tener en cuenta a la hora de crear tareas dinámicas, algo muy útil cuando se presenta un caso donde no podemos saber de antemano cuantas tareas se deberán instanciar, o cuando esta cantidad de tareas nos la dicta algún variable del proceso. (También tenemos que optar por esta opción cuando necesitamos tener mas de una tarea de la cual tenemos una sola definición)
En este simple proceso, que carece de significado real (debido a que el modelado, raramente debería ser de la manera planteada), pero útil para demostrar la practica, vamos a ver como podemos crear en el nodo Tomar Curso una cantidad X de tareas “Tomar Curso” dependiendo de cuantos alumnos atiendan al dictado.
Para realizar esto tendríamos que a la hora de iniciar el proceso, en cualquier paso antes de llegar al nodo Tomar Curso asignar una nueva variable en el contexto que indique la cantidad de alumnos que van a asistir al curso. Esto lo hacemos de la siguiente manera.
executionContext.getContextInstance().setVariable(“cantStudent”, 4);
Donde la cantidad 4, podría ser calculada mediante la llamada a un servicio de reservas, o algo similar.
Luego a nivel jPDL vemos como seria la definición del Task-Node para que no nos cree la tarea definida dentro de el automáticamente cuando la ejecución del proceso llegue a este nodo:
<task-node name="Tomar Curso" create-tasks="false"> <task name="Tomar Curso" swimlane="student"></task> <event type="node-enter"> <action name="Create Dinamic Tasks" class="com.sample.action.CreateDinamicTasksActionHandler"></action> </event> <transition to="end"></transition> </task-node>
Dos cosas importantes tenemos que notar en jPDL:
- create-tasks=”false”: se encarga de que la tarea (task name=”Tomar Curso”) no sea instanciada cuando el flujo de ejecución llegue al task-node
- La acción en el evento node-enter: esta acción sera la encargada de crear automáticamente las tareas especificadas dentro del nodo task-node.
Sin duda el comportamiento del proceso que definimos sera el siguiente:
- El proceso comienza su ejecución mediante un signal sobre el nodo de arranque
- La ejecución continua hasta el nodo Tomar Curso. Ya que la ejecución no se detiene en el nodo Dictar Curso, porque he decidido que el nodo Dictar Curso solo debe crear la tarea para el instructor y debe dar la posibilidad de que los alumnos puedan ver sus tareas creadas antes de que se termine de dictar el curso. Para esto utilice la siguiente propiedad del nodo task-node:
<task-node name="Dictar Curso" signal="unsynchronized"> <task name="Dictar Curso" swimlane="instructor"></task> <transition to="Tomar Curso"></transition> </task-node>
- Cuando la ejecución llega al nodo Tomar Curso, este por definición no crea las tareas (TaskInstances) que tiene definidas dentro, sino que delega esta acción al evento que especifico en el evento node-enter. Esta clase delegada contiene lo siguiente:
public void execute(ExecutionContext context) throws Exception { TaskMgmtInstance tmi=context.getTaskMgmtInstance(); TaskNode tomarCurso=(TaskNode)context.getNode(); Task tomarCursoTask=tomarCurso.getTask("Tomar Curso"); int cantStudent = Integer.parseInt(context.getContextInstance().getVariable("cantStudent").toString()); for(int i=0; i < cantStudent;i++){ tmi.createTaskInstance(tomarCursoTask, context.getToken()); } }Lo que podemos ver a simple vista es que obtenemos el nodo donde estamos parados, a este le pedimos las tareas (por nombre) que tiene y a esta tareas la instanciamos haciendo uso del método createTaskInstance de la clase TaskMgmtInstance. Como el nodo task-node que contiene a estas tareas no le he cambiado la opción por defecto para hacer signal, va a esperar que se completen las tareas instanciadas dinámicamente (en este caso 4 iguales).
- Cuando las cuatro tareas se finalizan el proceso llega con su ejecución al nodo end.
Espero que haya servido de ayuda para introducir un poco la API de Task MGMT. Cualquier duda comenten!






