0. Índice de contenidos.
- 1. Introducción.
- 2. Entorno.
- 3. Instalación.
- 4. Primeros pasos.
- 5. Cómo hacer uso de recursos de guvnor.
- 6. Referencias.
- 7. Conclusiones.
1. Introducción
JBosss Guvnor es el nombre del proyecto open source sobre el cual se libera la versión empresarial del BRMS de Jboss. Como ya vimos en el tutorial de introducción a drools, Guvnor es básicamente un repositorio centralizado de reglas de negocio que permite gestionarlas con una interface web; si bien, dentro de la suite de productos de jBPM, Guvnor se convierte en un repositorio central de conocimiento en el que, además de almacenar reglas de negocio, podemos:
- crear reglas guiadas con un wizard,
- crear tablas de decisión de una forma visual,
- crear, editar y almacenar modelos de negocio, bien creados en lenguaje DSL o realizando un upload de POJOS, para que puedan usarse como modelo de las reglas de negocio,
- crear, editar y almacenar procesos, pudiendo editarlos mediante una interfaz web,
- crear nuestra propia definición tipos de tareas dentro de un proceso de negocio,
- crear los formularios asociados a tareas del proceso de negocio,
- simular escenarios de prueba sobre los procesos de negocio,
- definir contextos de spring para la inicialización de drools conforme a una serie establecida de reglas y procesos, que luego estarán disponibles vía http,
- categorizar los contenidos,
- llevar un histórico de cambio de versiones de todos los recuros que almacena, y
- permite el acceso a los contenidos del repositorio a través de webdav y servicios REST. También podemos conectar con los recursos del repositorio desde Eclipse, para llevar a cabo su descarga y, del mismo modo, actualización o subida
En este tutorial vamos a hacer uso de Guvnor fuera de la demo de instalación de jBPM y a realizar una vista rápida de las posibilidades de la herramienta.
El objetivo es disponer de los proyectos necesarios, para ejecutar guvnor en cualquier servidor de aplicaciones o contenedor de servlets, mavenizándolos.
2. Entorno.
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 15′ (2.4 GHz Intel Core i7, 8GB DDR3 SDRAM).
- Sistema Operativo: Mac OS X Lion 10.7.4
- Drools Guvnor 5.5.0.Final
- Apache Tomcat 7.0.35
3. Instalación.
En la instalación que viene por defecto con jBPM 5.4, podemos tener problemas de comunicaciones…
Aunque en realidad es un error de pérdida de conectividad entre el cliente y el servidor que se da frecuentemente.
De ahí que optemos por realizar una instalación personalizada, con el soporte de maven, teniendo más control sobre la generación del war, su despliegue y nos permita:
- llevar a cabo una personalización de la interfaz de usuario,
- modificar la estrategia por defecto de autenticación y autorización, o
- modificar la estrategia por defecto de persistencia de contenidos.
Guvnor hace uso de las siguientes tecnologías:
- Apache Jackrabbit como repositorio de contenidos, pero se puede cambiar la configuración para que se persistan en una base de datos relacional,
- Jboss Seam 3 en la capa de control, negocio y para la gestión de seguridad. La autenticación por defecto está configurada para un único usuario administrador pero se puede modificar para que haga uso de una autenticación tipo JAAS o enganche con el SSO de CAS, y
- GWT en la capa de presentación.
Además, para hacer uso del modelador BPMN2 debemos hacer uso de una segunda aplicación, el designer.
Lo primero que vamos a hacer es crear un proyecto parent, que nos permitirá establecer las propiedades comunes al resto y el repositorio desde el cuál realizar las descargas.
A continuación el pom.xml del proyecto parent:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.autentia.bpm.repository</groupId> <artifactId>tnt-jbpm</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>tnt-jbpm</name> <inceptionYear>2013</inceptionYear> <properties> <java.version>1.6</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <drools.version>5.5.0.Final</drools.version> <jbpm.version>5.4.2.Final</jbpm.version> </properties> <repositories> <repository> <id>jboss-public-repository-group</id> <name>JBoss Public Maven Repository Group</name> <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> </repository> </repositories> <modules> <module>tnt-guvnor</module> <module>tnt-designer</module> </modules> </project>
Los módulos serán dos:
- tnt-guvnor: el módulo que contiene la aplicación guvnor, que proporciona una interfaz web del repositorio de contenidos, y
- tnt-designer: la aplicación web que permitirá crear procesos BPMN2 desde guvnor.
3.1. tnt-guvnor.
El pom.xml del proyecto tnt-guvnor es el siguiente:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.autentia.bpm.repository</groupId> <artifactId>tnt-jbpm</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.autentia.bpm.repository</groupId> <artifactId>tnt-guvnor</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <inceptionYear>2013</inceptionYear> <build> <finalName>drools-guvnor</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.26</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <stopKey>foo</stopKey> <stopPort>9999</stopPort> <stopPort>9966</stopPort> <connectors> <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> <port>9080</port> <maxIdleTime>60000</maxIdleTime> </connector> </connectors> <webAppConfig> <contextPath>/drools-guvnor</contextPath> </webAppConfig> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>guvnor-webapp-drools</artifactId> <version>${drools.version}</version> <type>war</type> </dependency> </dependencies> </project>
Configuramos el plugin de jetty para poder levantar la aplicación en un jetty de forma embebida:
mvn package jetty:run-exploded
Con el soporte de war overlay de maven, generaremos un proyecto war con el mismo contenido que el proyecto guvnor-webapp-drools, sobreescribiendo aquellos ficheros que nos interese modificar el proyecto original.
Como ejemplo, vamos a incluir nuestras imágenes corporativas para personalizar la interfaz de usuario de guvnor.
Y podemos modificar el layout para adaptar los estilos que necesitemos; tomaremos el fichero Guvnor.jsp del directorio de despliegue y lo incluimos en el path src/main/webapp/org.drools.guvnor.Guvnor/; en nuestro caso hemos modificado los iconos:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> <meta name="gwt:property" content="locale=<%=request.getLocale().toString()%>"> <title>JBoss Guvnor</title> <link rel="shortcut icon" href="images/delfin.png" type="image/png" /> <link rel="icon" href="images/delfin.png" type="image/png" />
Por último, si queremos desplegar en Apache Tomcat 7, debemos «traernos» también el descriptor de despliegue web.xmlpara solucionar un bug de Jboss Seam 3, una NPE, NullPointerException. Debemos incluir el siguiente parámetro de contexto.
<context-param> <param-name>org.jboss.seam.transaction.disableListener</param-name> <param-value>true</param-value> </context-param>
Con todo ello, bien en jetty o Tomcat, podríamos desplegar y tendríamos la siguiente interfaz de usuario accediendo a la siguiente url: http://localhost:9080|8080/drools-guvnor.
También podríamos modificar la política de autenticación sobreescribiendo el fichero beans.xml, pero esto queda fuera del objetivo de este primer tutorial.
3.2. tnt-designer.
El pom.xml del proyecto tnt-designer es el siguiente:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.autentia.bpm.repository</groupId> <artifactId>tnt-jbpm</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.autentia.bpm.repository</groupId> <artifactId>tnt-designer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <inceptionYear>2013</inceptionYear> <build> <finalName>designer</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.4.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.26</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <stopKey>foo</stopKey> <stopPort>9999</stopPort> <stopPort>9966</stopPort> <connectors> <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> <port>9080</port> <maxIdleTime>60000</maxIdleTime> </connector> </connectors> <webAppConfig> <contextPath>/designer</contextPath> </webAppConfig> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.jboss.drools</groupId> <artifactId>jbpm-designer</artifactId> <version>2.4.0-SNAPSHOT</version> <type>war</type> </dependency> </dependencies> </project>
El proyecto no requiere de más configuración y, tras desplegar tendremos accesible la aplicación a través de la siguiente url: http://localhost:8080/designer
Ahora ya podremos desplegar ambas aplicaciones en el mismo servidor y crear un proceso BPMN2 desde Guvnor.
La recomendación sería redimensionar la configuración de memoria de arranque de la JVM, para evitar problemas de falta de memoria, puesto que el despliegue de ambas aplicaciones puede comenzar a ser pesado.
4. Primeros pasos.
Vamos a hacer una visita rápida; crearemos un proceso y una regla de negocio, para poder hacer uso después de los mismos desde una clase de prueba.
4.1. Definición de procesos.
Ya hemos visto que tenemos accesible el editor visual de procesos BPMN directamente desde la interfaz de Guvnor, para que funcione correctamente debemos respetar el nombre original de los contextos de aplicación puesto que son dos proyectos distintos y en ellos se comunican a través de los servicios rest.
Cuando entremos más en frofundidad tendremos que configurar ambos proyectos para que sepan hablar entre ellos fuera del dominio local y haciendo uso de la política de autenticación definida; ahora, por defecto, se buscan en localhost y con usuario admin.
Para crear un proceso nuevo no hay más que posicionarse en un paquete y pulsar sobre Crear nuevo > Nuevo Proceso BPMN2; se mostrará la interfaz que hemos visto con anterioridad y en ella disponemos de una paleta de formas, un area de edición y una paleta de propiedades de cada uno de los objetos del diagrama.
Se hace importante la opción de validar «Validate Process» del menú para comprobar que efectivamente nuestro diagrama cumple con la especificación y las validaciones mínimas.
Cuando terminemos con el proceso debemos empaquetarlo y lo ideal es asignar un número de versión, para poder añadir a posteriori modificaciones en el proceso sin perder el histórico.
Una vez hecho esto, sobre la vista de paquete, en la pestaña de «Modificar», podemos «Construir el paquete» para poder hacer uso del proceso empaquetado.
Debemos comprobar que disponemos de la imagen del proceso que se usará para indicar el paso en el que se encuentra un proceso desde la consola. Deberíamos tener en el listado de recursos del paquete algo similar a esto:
4.2. Definición de reglas.
Para crear una nueva regla de negocio no tenemos más que seleccionar la opción correspondiente del menú «Crear Nuevo»; pero más que crear una nueva regla de negocio vamos a reutilizar las reglas que ya creamos de la mano de mi compi Miguel en el primer tutorial de drools.
Para ello vamos a generar un jar con los objetos de negocio y los vamos a subir como un modelo de POJOs; tras seleccionar la opción correspondiente del menú se mostrará una interfaz como la que sigue en la que podremos asignar un nombre:
Tras pulsar OK se mostrará una interfaz como la que sigue desde la que podremos importar el jar.
Tras la importación tendremos en el listado de modelos una entrada como esta:
Lo siguiente será, en vez de crear una regla desde cero, importar el contenido de la regla que ya teníamos, para ello crearemos un archivo simple con extensión drl, «Crear nuevo» > «Crear un archivo».
Al incluir la extensión drl, Guvnor entiende que es una regla de negocio y nos propone una pantilla para comenzar a trabajar, en la que podemos pegar el contenido textual de la regla que ya teníamos del tutorial de Miguel.
Tras guardar tendremos en el listado de reglas técnicas una entrada como la que sigue:
Con ello, ya tenemos contenido en nuestro repositorio que consumir.
5. Cómo hacer uso de recursos de guvnor.
Los recursos de Guvnor los podemos importar en el espacio de trabajo con el plugin de conexión a Guvnor que incorpora jBPM para Eclipse y hacer uso de una copia local de los mismos. Del mismo modo podemos incorporar a Guvnor recursos desde el espacio de trabajo de Eclipse al repositorio de contenidos.
Lo ideal, sobre todo para el proceso de promoción entre entornos, sería disponer de esos recursos versionados en un control de versiones y generar un empaquetado automatizado de los mismos para importarlos en Guvnor (sería la filosofía de los recursos amp de Alfresco).
En este punto, omitiendo dicha configuración, vamos a proponer consumir los recursos de Guvnor mediante la exposición de los mismos en un contexto de Spring. Guvnor permite crear contextos de Spring, accesibles vía url, publicando en el mismo el contenido de la última versión de un paquete de recursos. Con ello, el negocio de las reglas en Guvnor podría variar en el tiempo y para nuestras aplicaciones sería transparente.
Para crear un nuevo contexto de Spring no tenemos más que pulsar en «Crear Nuevo» > «Nuevo contexto de Spring» y se mostrará una ventana como esta:
Tras pulsar OK, nos redirije al area de edición del contenido del fichero desde la cuál podremos añadir configuraciones de paquetes desde el árbol inferior izquierdo:
Lo que hará es añadir configuración al xml, en función de la selección y, cuando hayamos finalizado lo ideal es validar el contenido del xml con la opción «Origen/Fuente» > validar. En este punto podemos tener un error como el que sigue:
Resulta que la xsd ha dejado de estar disponible en la URL que propone Guvnor. Buscando una solución podemos sustituir la ruta de la xsd de drools-spring por esta:
http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.2.0.xsd
Y, con ello, tener el siguiente contenido:
Llegados a este punto, deberíamos disponer de un acceso público a la configuración de spring vía url; a nivel de paquete en la pestaña de «Modificar», deberíamos tener un contenido similar a este:
Con ello, ya podríamos jugar a levantar el contexto de Spring con esta configuración para poder acceder a los recursos del paquete en Guvnor; si bien como nuestra intención es realizar un test de jUnit, la URL de acceso al contexto de Spring está securizada y no queremos aún configurar la autenticación y autorización en Guvnor, para realizar la prueba, en vez hacer uso de la url, vamos a tomcat el contenido del fichero y crear una copia local en la carpeta de recursos de test dentro de nuestro workspace.
El contenido del applicationContext-order.xml sería el siguiente:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.2.0.xsd" default-autowire="byName"> <drools:kbase id="kbase1"> <drools:resources> <drools:resource type="PKG" source="http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/com.autentia.bpm.tutoriales/LATEST" basic-authentication="enabled" username='admin' password='admin'/> </drools:resources> </drools:kbase> <drools:ksession id="ksession" type="stateful" kbase="kbase1" /> </beans>
Y vamos a escribir un test como el que sigue, con el soporte de Spring, para arrancar un proceso de negocio:
package com.autentia.tutorial.guvnor; import static org.junit.Assert.assertEquals; import javax.annotation.Resource; import org.drools.runtime.StatefulKnowledgeSession; import org.drools.runtime.process.ProcessInstance; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:applicationContext-order.xml"}) public class OrderGuvnorTest { @Resource private StatefulKnowledgeSession ksession; @Test public void shouldStartGuvnorProcess(){ final ProcessInstance processInstance = ksession.startProcess("sayHi"); assertEquals(ProcessInstance.STATE_COMPLETED,processInstance.getState()); } }
La referencia a la factoría de sesiones la obtenemos por inyección con el soporte de Spring y podemos arrancar un proceso por id.
Siguiendo el código del test de reglas que ya teníamos del primer tutorial podríamos escribir un segundo test con el siguiente código:
package com.autentia.tutorial.guvnor; import java.util.Arrays; import java.util.List; import javax.annotation.Resource; import org.drools.runtime.StatefulKnowledgeSession; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.autentia.tutorial.drools.data.Customer; import com.autentia.tutorial.drools.data.Order; import com.autentia.tutorial.drools.data.Product; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:applicationContext-order.xml"}) public class OrderGuvnorTest { @Resource private StatefulKnowledgeSession ksession; @Test public void shouldUseGuvnorRules(){ final List<Order> orders = Arrays.asList(getOrderWithDefaultCustomer(), getOrderWithSilverCustomer(), getOrderWithGoldCustomer(), getOrderWithGoldCustomerAndTenProducts()); for (Order order : orders) { ksession.insert(order); } ksession.fireAllRules(); showResults(orders); } private static Order getOrderWithDefaultCustomer() { final Order order = new Order(getDefaultCustomer()); order.addProduct(getProduct1()); return order; } private static Order getOrderWithSilverCustomer() { final Order order = new Order(getSilverCustomer()); order.addProduct(getProduct1()); return order; } private static Order getOrderWithGoldCustomer() { final Order order = new Order(getGoldCustomer()); order.addProduct(getProduct1()); return order; } private static Order getOrderWithGoldCustomerAndTenProducts() { final Order order = new Order(getSilverCustomer()); for (int i = 0; i < 10; i++) { order.addProduct(getProduct1()); } return order; } private static Customer getDefaultCustomer() { return new Customer(Customer.DEFAULT_CUSTOMER, "Cliente estandar"); } private static Customer getSilverCustomer() { return new Customer(Customer.SILVER_CUSTOMER, "Cliente SILVER"); } private static Customer getGoldCustomer() { return new Customer(Customer.GOLD_CUSTOMER, "Cliente GOLD"); } private static Product getProduct1() { return new Product(1, "Producto 1", 100d); } private static void showResults(List<Order> orders) { for (Order order : orders) { System.out.println("Cliente " + order.getCustomer() + " productos: " + order.getProducts().size() + " Precio total: " + order.getTotalPrice()); } } }
Lo único que varia es la obtención de la factoría mediante el soporte de inyección de Spring, que además es in singleton.
Podéis descargar aquí los fuentes usados en el tutorial. Se trata de un fichero comprimido con dos proyectos maven:
- tnt-jbpm: el proyecto parent que permite desplegar guvnor y el designer, y
- tutorial-guvnor: el proyecto que contiene los tests.
6. Referencias.
- http://docs.jboss.org/drools/release/5.4.0.Final/drools-guvnor-docs/pdf/guvnor-docs.pdf
- http://kverlaen.blogspot.com.es/2011/10/introducing-service-repository.html
- http://vimeo.com/28473009
- http://vimeo.com/21445110
7. Conclusiones.
Aún nos quedan cuestiones por resolver en relación a Guvnor, sobre todo:
- el tema de la autenticación y autorización de usuarios,
- la parametrización de la comunicación entre el designer y guvnor, para que no esté acoplado con el dominio local, y
- el versionado y la promoción entre entornos de los recursos.
Pero ya podemos pensar en él como una buena solución para la gestión centralizada de reglas y de procesos dentro de nuestro ecosistema BPM, con jBPM.
Un saludo.
Jose
]
Buen día,he seguido el tutorial paso a paso,pero al momento de desplegar el jbpm designer,no me quiere dejar iniciar el contexto,me toco que cambiar los puertos para que no se chocara con el guvnor,cuando intento desplegar me sale el siguiente error
java.lang.ClassNotFoundException: org.apache.catalina.servlets.DefaultServlet
at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
[ERROR] Failed startup of context org.mortbay.jetty.plugin.Jetty6PluginWebAppContext@136df72{/designer,E:***DroolsGuvnortnt-designertargetdesigner}
java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:256)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
Muchas gracias de antemano