Chapter 14. Integration with Spring
14.1. Configuring Red Hat JBoss BPM Suite with Spring
The jboss-bpms-engine.zip
file contains the Spring module, which is called kie-spring-VERSION-redhat-MINOR_VERSION.jar
.
You can configure the Spring modules:
- As a Self Managed Process Engine
-
If you require a single runtime manager instance, use the
RuntimeManager
API. TheRuntimeManager
API synchronizes the process engine and task service internally. - As a Shared Task Service
- If you require multiple runtime manager instances, use the jBPM services.
Do not use the shared task service if you use Spring and your process is instantiated using the per process or per request runtime strategy.
14.1.1. Integrating Spring with Runtime Manager API
To integrate Spring with the Runtime Manager API, include the following factory beans:
-
org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean
-
org.kie.spring.factorybeans.RuntimeManagerFactoryBean
-
org.kie.spring.factorybeans.TaskServiceFactoryBean
TaskServiceFactoryBean
is required only for shared task service.
RuntimeEnvironmentFactoryBean
RuntimeEnvironmentFactoryBean
produces RuntimeEnvironment
instances consumed by RuntimeManager
.
You can create the following types of RuntimeEnvironment
instances:
-
DEFAULT
: The default type. -
EMPTY
: An empty environment. -
DEFAULT_IN_MEMORY
: Same asDEFAULT
with no persistence of the runtime engine. -
DEFAULT_KJAR
: Same asDEFAULT
with knowledge assets taken from kJAR and identified byreleaseID
or GAV (Group, Artifact, Version). -
DEFAULT_KJAR_CL
: Built from class path that consists of akmodule.xml
descriptor.
Knowledge information is required for all the RuntimeEnvironment
types. Provide one or more of the following:
-
knowledgeBase
-
assets
-
releaseId
-
groupId
,artifactId
,version
For the DEFAULT
, DEFAULT_KJAR
, DEFAULT_KJAR_CL
types, configure persistence using entity manager factory
or transaction manager
.
RuntimeManagerFactoryBean
RuntimeManagerFactoryBean
creates RuntimeManager
instances based on runtimeEnvironment
. You can create the following runtimeEnvironment
instances:
-
SINGLETON
(default) -
PER_REQUEST
-
PER_PROCESS_INSTANCE
Every RuntimeManager
instance must have a unique ID. You can dispose of any RuntimeManager
instance created by RuntimeManagerFactoryBean
by calling the close()
method.
TaskServiceFactoryBean
TaskServiceFactoryBean
creates TaskService
instance based on the given properties. Creates a single instance only.
Properties required:
-
entity manager factory
-
transaction manager
When using the TaskServiceFactoryBean
, provide the Spring transaction manager. When using a shared entity manager from Spring, you can also provide EntityManager
instance instead of entity manager factory.
Optional properties:
-
userGroupCallback
:MVELUserGroupCallbackImpl
by default. -
userInfo
:DefaultUserInfo
by default. -
listener
: List ofTaskLifeCycleEventListener
instances.
Sample RuntimeManager Configuration with Spring
To create a single runtime manager Spring configuration:
Configure the entity manager factory and the transaction manager, for example:
<bean id="jbpmEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="org.jbpm.persistence.spring.jta"/> </bean> <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices"></bean> <bean id="BitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown" /> <bean id="jbpmTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="BitronixTransactionManager" /> <property name="userTransaction" ref="BitronixTransactionManager" /> </bean>
This configuration provides:
- JTA transaction manager, backed by Bitronix for unit tests or servlet containers.
-
The
org.jbpm.persistence.spring.jta
entity manager factory for persistence unit.
Configure resources you use, for example a business process:
<bean id="process" factory-method="newclass pathResource" class="org.kie.internal.io.ResourceFactory"> <constructor-arg> <value>jbpm/processes/sample.bpmn</value> </constructor-arg> </bean>
The
sample.bpmn
process is included from the class path.Configure
RuntimeEnvironment
using your entity manager, transaction manager, and resources:<bean id="runtimeEnvironment" class="org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean"> <property name="type" value="DEFAULT"/> <property name="entityManagerFactory" ref="jbpmEMF"/> <property name="transactionManager" ref="jbpmTxManager"/> <property name="assets"> <map> <entry key-ref="process"><util:constant static-field="org.kie.api.io.ResourceType.BPMN2"/></entry> </map> </property> </bean>
Create
RuntimeManager
:<bean id="runtimeManager" class="org.kie.spring.factorybeans.RuntimeManagerFactoryBean" destroy-method="close"> <property name="identifier" value="spring-rm"/> <property name="runtimeEnvironment" ref="runtimeEnvironment"/> </bean>
An example of complete configuration:
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <import resource="classpath:jbpm/configuration-template/assets.xml" /> <bean id="jbpmEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="org.jbpm.persistence.spring.jta"/> <property name="persistenceXmlLocation" value="classpath:jbpm/persistence-jta.xml"/> </bean> <bean id="btmConfig" factory-method="getConfiguration" class="bitronix.tm.TransactionManagerServices"/> <bean id="BitronixTransactionManager" factory-method="getTransactionManager" class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig" destroy-method="shutdown" /> <bean id="jbpmTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="BitronixTransactionManager" /> <property name="userTransaction" ref="BitronixTransactionManager" /> </bean> <bean id="runtimeEnvironment" class="org.kie.spring.factorybeans.RuntimeEnvironmentFactoryBean"> <property name="type" value="DEFAULT"/> <property name="entityManagerFactory" ref="jbpmEMF"/> <property name="transactionManager" ref="jbpmTxManager"/> <property name="assets" ref="assets"/> </bean> <bean id="logService" class="org.jbpm.process.audit.JPAAuditLogService" depends-on="runtimeEnvironment"> <constructor-arg value="#{runtimeEnvironment.environment}" /> <constructor-arg value="STANDALONE_JTA" /> </bean> </beans>
14.1.2. Spring and jBPM Services
If you require multiple runtime managers, you can use jBPM services directly in your application. Due to the dynamic nature of jBPM services, processes and other assets can be added and removed without restarting your application.
To configure jBPM services:
Add the
kie-spring
Maven dependency into yourpom.xml
:<dependencies> ... <dependency> <groupId>org.kie</groupId> <artifactId>kie-spring</artifactId> <version>6.5.0.Final-redhat-2</version> </dependency> ... </dependencies>
For the current Maven artifact version, see chapter Supported Component Versions of the Red Hat JBoss BPM Suite Installation Guide.
Depending on your implementation, other dependencies may be necessary, for example spring-security
.
Implement the
IdentityProvider
interface:import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.kie.internal.identity.IdentityProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; public class SpringSecurityIdentityProvider implements IdentityProvider { public String getName() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { return auth.getName(); } return "system"; } public List<String> getRoles() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { List<String> roles = new ArrayList<String>(); for (GrantedAuthority ga : auth.getAuthorities()) { roles.add(ga.getAuthority()); } return roles; } return Collections.emptyList(); } public boolean hasRole(String role) { return false; } }
To configure jBPM services in a Spring application:
Configure the transaction manager:
<context:annotation-config /> <tx:annotation-driven /> <tx:jta-transaction-manager /> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
Configure JPA and persistence:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="transactionManager"> <property name="persistenceXmlLocation" value="classpath:/META-INF/jbpm-persistence.xml" /> </bean>
Configure security providers:
<util:properties id="roleProperties" location="classpath:/roles.properties" /> <bean id="userGroupCallback" class="org.jbpm.services.task.identity.JBossUserGroupCallbackImpl"> <constructor-arg name="userGroups" ref="roleProperties"></constructor-arg> </bean> <bean id="identityProvider" class="org.jbpm.spring.SpringSecurityIdentityProvider"/>
Configure the runtime manager factory:
<bean id="runtimeManagerFactory" class="org.kie.spring.manager.SpringRuntimeManagerFactoryImpl"> <property name="transactionManager" ref="transactionManager"/> <property name="userGroupCallback" ref="userGroupCallback"/> </bean> <bean id="transactionCmdService" class="org.jbpm.shared.services.impl.TransactionalCommandService"> <constructor-arg name="emf" ref="entityManagerFactory"></constructor-arg> </bean> <bean id="taskService" class="org.kie.spring.factorybeans.TaskServiceFactoryBean" destroy-method="close"> <property name="entityManagerFactory" ref="entityManagerFactory"/> <property name="transactionManager" ref="transactionManager"/> <property name="userGroupCallback" ref="userGroupCallback"/> <property name="listeners"> <list> <bean class="org.jbpm.services.task.audit.JPATaskLifeCycleEventListener"> <constructor-arg value="true"/> </bean> </list> </property> </bean>
The runtime manager factory is Spring context aware and can interact with Spring containers.
Configure jBPM services as Spring beans:
<!-- definition service --> <bean id="definitionService" class="org.jbpm.kie.services.impl.bpmn2.BPMN2DataServiceImpl"/> <!-- runtime data service --> <bean id="runtimeDataService" class="org.jbpm.kie.services.impl.RuntimeDataServiceImpl"> <property name="commandService" ref="transactionCmdService"/> <property name="identityProvider" ref="identityProvider"/> <property name="taskService" ref="taskService"/> </bean> <!-- -- deployment service --> <bean id="deploymentService" class="org.jbpm.kie.services.impl.KModuleDeploymentService" depends-on="entityManagerFactory" init-method="onInit"> <property name="bpmn2Service" ref="definitionService"/> <property name="emf" ref="entityManagerFactory"/> <property name="managerFactory" ref="runtimeManagerFactory"/> <property name="identityProvider" ref="identityProvider"/> <property name="runtimeDataService" ref="runtimeDataService"/> </bean> <!-- process service --> <bean id="processService" class="org.jbpm.kie.services.impl.ProcessServiceImpl" depends-on="deploymentService"> <property name="dataService" ref="runtimeDataService"/> <property name="deploymentService" ref="deploymentService"/> </bean> <!-- user task service --> <bean id="userTaskService" class="org.jbpm.kie.services.impl.UserTaskServiceImpl" depends-on="deploymentService"> <property name="dataService" ref="runtimeDataService"/> <property name="deploymentService" ref="deploymentService"/> </bean> <!-- register runtime data service as listener on deployment service so it can receive notification about deployed and undeployed units --> <bean id="data" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" depends-on="deploymentService"> <property name="targetObject" ref="deploymentService"></property> <property name="targetMethod"><value>addListener</value></property> <property name="arguments"> <list> <ref bean="runtimeDataService"/> </list> </property> </bean>