This is the 11th day of my participation in Gwen Challenge

Activiti Workflow Integration introduction to CDI

  • The Activiti-CDI module provides configurable and CDI extensions for Activiti
  • Activiti-cdi features:
    • Support @BusinessProcessScoped Beans, cDI beans bound to process instances
    • The process supports custom EL processors for CDI beans
    • Use annotations to provide declarative control for process instances
    • Activiti can be hooked up to the CDI event bus
    • Support for Java EE and Java SE, support for Spring
    • Unit testing support
  • To use Activiti-CDI in a Maven project, you need to add dependencies:
<dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-cdi</artifactId>
        <version>5.8</version>
</dependency>
Copy the code
  • Activiti-cdi 5.6 and above automatically adds Activiti-entin and Spring

Set the activiti – cdi

  • Activiti CDI can be installed in different environments

Find the process engine

  • cdiThe extension needs access toProcessEngine,To implement this feature:
    • Using org. Activiti. Cdi. Spi. ProcessEngineLookup interface to look up during operation
    • Cdi module USES the default name org. Activiti. Cdi. Impl. LocalProcessEngineLookup implementation, using ProcessEngines the tools to find the ProcessEngine
    • By default, use ProcessEngines#NAME_DEFAULT to find ProcessEngine.** this class may be a subclass with a custom name
    • == Note :== You need to put activiti.cfg. XML in your CLASspath
  • Activiti cdiusejava.util.ServiceLoader SPITo deal withorg.activiti.cdi.spi.ProcessEngineLookupAn instance of the
    • In order to provide the custom implementations of the interface, you need to create a text file, named meta-inf/services/org activiti. Cdi. Spi. ProcessEngineLookup, in the file you need to specify the full name of the class
    • If you don’t provide custom org. Activiti. Cdi. Spi. ProcessEngineLookup implementation, activiti will use the default LocalProcessEngineLookup implementation, need to do is put the activiti. CFG. XML into Under the classpath

Configuration Process Engine

  • The actual configuration depends on the ProcessEngineLookup policy chosen
  • The configuration available is discussed here primarily in conjunction with LocalProcessEngineLookup, which requires a Spring activiti.cfg.xml in the classpath
  • Activiti provides different ProcessEngineConfiguration implementation, mainly depend on the actual use of transaction management strategy
  • The activiti-CDI module is not strict about transactions, meaning that any transaction management strategy can be used, even the Spring transaction abstraction layer
  • cdiThe module provides two customizationsProcessEngineConfigurationImplementation:
    • Org. Activiti. Cdi. CdiJtaProcessEngineConfiguration: activiti JtaProcessEngineConfiguration subclass, for use in activiti JTA management transaction environment
    • org.activiti.cdi.CdiStandaloneProcessEngineConfiguration: Activiti StandaloneProcessEngineConfiguration subclass, for use in activiti simple JDBC transaction environment
  • Under the JBoss7 activiti. CFG. XML:

      
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

        <! -- lookup the JTA-Transaction manager -->
        <bean id="transactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
                <property name="jndiName" value="java:jboss/TransactionManager"></property>
                <property name="resourceRef" value="true" />
        </bean>

        <! -- process engine configuration -->
        <bean id="processEngineConfiguration"
                class="org.activiti.cdi.CdiJtaProcessEngineConfiguration">
                <! -- lookup the default Jboss datasource -->
                <property name="dataSourceJndiName" value="java:jboss/datasources/ExampleDS" />
                <property name="databaseType" value="h2" />
                <property name="transactionManager" ref="transactionManager" />
                <! -- using externally managed transactions -->
                <property name="transactionsExternallyManaged" value="true" />
                <property name="databaseSchemaUpdate" value="true" />
        </bean>
</beans>
Copy the code
  • In Glassfish 3.1.1, assuming a datasource named JDBC/Activiti is configured:

      
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

        <! -- lookup the JTA-Transaction manager -->
        <bean id="transactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
                <property name="jndiName" value="java:appserver/TransactionManager"></property>
                <property name="resourceRef" value="true" />
        </bean>

        <! -- process engine configuration -->
        <bean id="processEngineConfiguration"
                class="org.activiti.cdi.CdiJtaProcessEngineConfiguration">
                <property name="dataSourceJndiName" value="jdbc/activiti" />
                <property name="transactionManager" ref="transactionManager" />
                <! -- using externally managed transactions -->
                <property name="transactionsExternallyManaged" value="true" />
                <property name="databaseSchemaUpdate" value="true" />
        </bean>
</beans>
Copy the code
  • Note: The above configuration introduces spring-Context module dependencies
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>3.0.3. RELEASE</version>
</dependency>
Copy the code

Release process

  • You can use the standard Activiti-API publishing process -RepositoryService
  • Activiti-cdi also provides a way to automatically publish processes listed in processs.xml under classpath
  • processes.xml:

      
<! -- list the processes to be deployed -->
<processes>
        <process resource="diagrams/myProcess.bpmn20.xml" />
        <process resource="diagrams/myOtherProcess.bpmn20.xml" />
</processes>
Copy the code

Process execution based on CDI environment

  • A BPMN business process is typically a long-running operation that involves the actions of users and system tasks
  • During execution, the process is divided into separate units of work, executed by users and application logic
  • inactiviti-cdiProcess instances can be assigned tocdiIn the context, an association is represented as a unit of work:
    • This is useful if the unit of work is too complex: for example, if the user tasks implemented are complex sequences of different forms, you can keep the non-process-scoped state in this operation
    • By default, the process instance is assigned to the Broadest activation environment and the interaction is initiated, and if the interaction environment is not activated, it is returned to the request

Associate interactions with process instances

  • Working with @BusinessProcessScoped Beans, or injecting process variables, enables the association of the active CDI environment with the process instance
  • Activiti-cdiprovidesorg.activiti.cdi.BusinessProcess beanTo control associations:
    • startProcessByXx(…) : corresponding to the related methods in Activiti’s RuntimeService that allow the startup and subsequent routing of associated business processes
    • ResumeProcessById (String processInstanceId): Allows process instances to be associated with the Id provided
    • ResumeTaskById (String taskId): Allows tasks to be associated with the Id provided, and also extends the associated process instance
  • After a unit of work is complete, the completeTask() method can be called to disassociate the process instance from the session or request. This notifies Activiti that the current task is complete and allows the process instance to continue
  • BusinessProcess beanis@Named bean,The exported method can be called using the expression language:
    • For example, in JSF pages. The following JSF 2 code starts a new interaction, assigns a user task instance, and passes the Id as a request parameter:
<f:metadata>
<f:viewParam name="taskId" />
<f:event type="preRenderView" listener="#{businessProcess.startTask(taskId, true)}" />
</f:metadata>
Copy the code

Declarative process control

  • Activiti-cdi allows you to start process instances and complete tasks through annotation declarations
  • @ org. Activiti. Cdi. The annotation. StartProcess annotation allows through key or name to start the process instance. The process instance is started after the annotated method returns:
@StartProcess("authorizeBusinessTripRequest")
public String submitRequest(BusinessTripRequest request) {
        // do some work
        return "success";
}
Copy the code
  • According to the configuration of activiti, annotation method code and start the process instances can be carried in the same transaction. @ org.activiti.cdi.annotation.Com pleteTask transactions using the same way:
@CompleteTask(endConversation=false)
public String authorizeBusinessTrip(a) {
        // do some work
        return "success";
}
Copy the code

The @completeTask annotation ends the current session. The default behavior terminates the session when Activiti returns. You can disable the end session function

Reference beans in the process

  • Activiti-cdi uses a custom parser to expose CDI beans to Activiti El, which can be referenced in the process:
<userTask id="authorizeBusinessTrip" name="Authorize Business Trip"
                        activiti:assignee="#{authorizingManager.account.username}" />
Copy the code
  • AuthorizingManager can bea bean provided by a producer method:
@Inject @ProcessVariable Object businessTripRequesterUsername;

@Produces
@Named
public Employee authorizingManager(a) {
        TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.account.username='"
                + businessTripRequesterUsername + "'", Employee.class);
        Employee employee = query.getSingleResult();
        return employee.getManager();
Copy the code

Using the @ BusinessProcessScoped beans

  • useactiviti-cdi,beanThe lifecycle of can be bound to a process instance:
    • You can provide a custom implementation of the environment called BusinessProcessContext.
    • The instance of the BusinessProcessScoped Bean is saved as a process variable in the current process instance
    • The BusinessProcessScoped bean needs to be **PassivationCapable,** such as serialization
  • The following is an example of using a process-scoped bean:
@Named
@BusinessProcessScoped
public class BusinessTripRequest implements Serializable {
        private static final long serialVersionUID = 1L;
        private String startDate;
        private String endDate;
        // ...
}
Copy the code
  • Sometimes, you need to use a process scoped bean that is not associated with a process instance:
    • Such as before starting the process. If the current process instance is not active,BusinessProcessScoped beanInstances are temporarily stored in local scopes:
      • The session
      • request
      • Depend on the environment
  • If the scope is later associated with the business process instance, the bean instance is flushed to the process instance

Injecting process variables

  • Process variables can be implemented for injection
  • Activiti-CDIThe following methods for injecting process variables are supported:
    • @businessProcessScoped uses @Inject type attribute names to implement type-safe process variable injection
    • Use the ** @processVariable (name)** modifier to implement injection of process variables that are not type safe
@Inject @ProcessVariable Object accountNumber;
@Inject @ProcessVariable("accountNumber") Object account
Copy the code
  • To reference process variables through EL,You can use the following methods:
    • @named @businessProcessScoped Beans can be referenced directly
    • Other ProcessVariables can be used using the ProcessVariables bean
#{processVariables['accountNumber']}
Copy the code

Receive process events

  • Activiti can hang onto the CDI event bus and listen for process events using the standard CDI event mechanism
  • To enable Activiti’s CDI event support, you need to enable the corresponding resolution listener in the configuration:
<property name="postBpmnParseHandlers">
        <list>
                <bean class="org.activiti.cdi.impl.event.CdiEventSupportBpmnParseHandler" />
        </list>
</property>
Copy the code
  • Activiti is then configured to publish events using the CDI event bus
  • inCDI beanHow to handle events in:
    • Declare a specific event listener using the **@ pax ** annotation
    • Event listening is type safe
    • Process is the event type org. Activiti. Cdi. BusinessProcessEvent
  • An example of a simple event listening method:
public void onProcessEvent(@Observes BusinessProcessEvent businessProcessEvent) {
        // handle event
}
Copy the code
  • Listeners can listen for all events. If you want to limit the types of events that listeners receive, you can add a modifier:
    • @BusinessProcess:Limits the events specified for the process definition
      • @Observes @BusinessProcess(“billingProcess”)
    • @StartActivity:Restricts the events specified to enter the link
      • @Observes @StartActivity(“shipGoods”)
    • @EndActivity:Restricts the events that specify the end of the link
      • @Observes @EndActivity(“shipGoods”)
    • @takeTransition: Limits the events of a specified connection
  • Modifier names can be freely combined:
    • To receive all events leaving the shipGoods part of the shipmentProcess:
public void beforeShippingGoods(@Observes @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) {
        // handle event
}
Copy the code
  • By default, event listeners are called synchronously and in the same transactional environment
  • CDI transactional listeners can control when listeners process events:
    • Listeners are guaranteed to process only after the transaction in the event succeeds
public void onShipmentSuceeded(@Observes(during=TransactionPhase.AFTER_SUCCESS) @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) {
        // send email to customer.
}
Copy the code

More features in Activiti CDI

  • Process engine and service can be injected into: Inject ProcessEngine, RepositoryService TaskService,…
  • Current process instances and tasks can be injected: @Inject ProcessInstance, Task
  • The current service ID can be injected as follows: @Inject @BusinessKey String BusinessKey
  • The current ProcessInstanceId can be injected as @inject @processinstanceid String pid