OpenWebFlow0.9用户手册与设计说明

1.    OpenWebFlow概述

OpenWebFlow是基于Activiti扩展的工作流引擎。Activiti (官方网站http://activiti.org/,代码托管在https://github.com/Activiti/Activiti)是一个新兴的基于 Apache 许可的支持 BPMN 2.0 标准的开源 BPM 产品,它是一个轻量级,可嵌入的 BPM 引擎,并且提供了功能丰富的开发和流程设计工具。OpenWebFlow与业务应用系统之间的关系如下图所示。

相对于Activiti,OpenWebFlow扩展的功能包括:

1) 完全接管了Activiti对活动(activity)权限的管理。
Activiti允许在设计model的时候指定每个活动的执行权限,但是,业务系统可能需要根据实际情况动态设置这些任务的执行权限(如:动态的Group)。OpenWebFlow完全实现了与流程定义时期的解耦,即用户对活动的访问控制信息单独管理(而不是在流程定义中预先写死),这样有利于动态调整权限,详见自定义活动权限管理;

2) 完全接管了Activiti对用户表(IDENTITY_XXX表)的管理。
在标准的工作流定义中,每个节点可以指定其候选人和候选用户组,但是比较惨的是,Activiti绑架了用户信息表的设计!这个是真正致命的,因为几乎每个业务系统都会属于自己的用户信息结构(包括User/Group/Membership),但不一定它存储在Activiti喜欢的那个库中,表的结构也不一定一样,有的时候,某些信息(如:动态的Group)压根儿就不采用表来存储。OpenWebFlow剥离了用户信息表的统一管理,客户程序可以忘掉Activiti的用户表、群组表、成员关系表,详见自定义用户成员关系管理;

3) 允许运行时定义activity!
彻底满足“中国特色”,并提供了安全的(同时也是优雅的)催办、代办、加签(包括前加签/后加签)、*跳转(包括前进/后)、分裂节点等功能;

2.    快速上手

2.1    引入OpenWebFlow框架

2.1.1    以jar的方式引入OpenWebFlow

OpenWebFlow的发布形式是一组正常的jar,其中openwebflow-core.XXX.jar包含了核心的工作流控制模块,以及基于内存的管理器实现模块。

此外,OpenWebFlow还提供了几个jar:openwebflow-mgr-hibernate.XXX.jar,openwebflow-mgr-mybatis.XXX.jar,它们提供了管理器的SQL实现模块,分别选取hibernate和mybatis作为ORM模型。还有一个是openwebflow-mgr-test.XXX.jar,它包含了几个测试类。

最新版本的下载地址:

https://github.com/bluejoe2008/openwebflow/blob/master/openwebflow-core/target/openwebflow-core-0.9-SNAPSHOT.jar

注意这些jar具有较多的依赖, https://github.com/bluejoe2008/openwebflow/tree/master/openwebflow-core/target/lib列举了所有的依赖包如下:

activation-1.1.jar

activiti-bpmn-converter-5.16.1.jar

activiti-bpmn-layout-5.16.1.jar

activiti-bpmn-model-5.16.1.jar

activiti-crystalball-5.16.1.jar

activiti-engine-5.16.1.jar

activiti-explorer-5.16.1.jar

activiti-image-generator-5.16.1.jar

activiti-json-converter-5.16.1.jar

activiti-process-validation-5.16.1.jar

activiti-simple-workflow-5.16.1.jar

activiti-spring-5.16.1.jar

aopalliance-1.0.jar

commons-collections-2.0.jar

commons-dbcp-1.4.jar

commons-email-1.2.jar

commons-io-2.4.jar

commons-lang-2.6.jar

commons-lang3-3.3.2.jar

commons-logging-1.1.1.jar

commons-pool-1.5.4.jar

dcharts-widget-0.10.0.jar

groovy-all-2.1.3.jar

h2-1.3.168.jar

hamcrest-core-1.3.jar

imgscalr-lib-4.2.jar

jackson-annotations-2.2.3.jar

jackson-core-2.2.3.jar

jackson-databind-2.2.3.jar

javaGeom-0.11.1.jar

jcl-over-slf4j-1.7.6.jar

jgraphx-1.10.4.1.jar

joda-time-2.1.jar

junit-4.12.jar

log4j-1.2.17.jar

mail-1.4.1.jar

mybatis-3.2.8.jar

mybatis-spring-1.2.2.jar

mysql-connector-java-5.1.32.jar

servlet-api-2.5.jar

slf4j-api-1.7.2.jar

slf4j-jdk14-1.7.2.jar

slf4j-log4j12-1.7.6.jar

spring-aop-3.2.4.RELEASE.jar

spring-beans-3.2.4.RELEASE.jar

spring-context-3.2.4.RELEASE.jar

spring-core-3.2.4.RELEASE.jar

spring-expression-3.2.4.RELEASE.jar

spring-jdbc-3.2.4.RELEASE.jar

spring-orm-3.2.4.RELEASE.jar

spring-tx-3.2.4.RELEASE.jar

spring-web-3.2.4.RELEASE.jar

spring-webmvc-3.2.4.RELEASE.jar

vaadin-6.8.8.jar

2.1.2    以maven的方式引入OpenWebFlow

以maven的方式引入OpenWebFlow比较简单,pom.xml中的依赖项写成:

<dependency>

<groupId>org.openwebflow</groupId>

<artifactId>openwebflow-core </artifactId>

<version>0.9-SNAPSHOT</version>

</dependency>

在引入依赖项之前可能需要先在本地仓库中安装OpenWebFlow项目。具体操作是在eclipse中选择OpenWebFlow项目,【右键菜单】【Maven】【install】。

2.2    配置文件

准备SpringIoC配置文件,分别是settings.properties 、activiti.cfg.core.xml和activiti.cfg.mem.xml(或者是activiti.cfg.sql.XXX.xml):

l  settings.properties:公共属性设置

l  activiti.cfg.core.xml:用以配置工作流引擎的基本配置信息;

l  activiti.cfg.mem.xml:用以定义一些用以支持OpenWebFlow工作的manager,注意名字中的mem,它暗示着仅提供了那些manager的基于内存实现的版本,类似的配置文件还可以是activiti.cfg.sql.XXX.xml;

2.2.1    settings.properties

settings.properties文件是一个正常的属性文件,用以spring IOC文件加载。如下是一个属性文件的内容:

1.     mail.host=smtp.bluejoe.cn

2.     mail.port=25

3.     mail.username=sdb-support@cnic.cn

4.     mail.password=sdbsupport

5.     mail.from=sdb-support@cnic.cn

6.     model.dir=../models

7.     alarm.mail.template=classpath:/alarm-template.txt

8.     hibernate.dialect=org.hibernate.dialect.MySQLDialect

9.     hibernate.hbm2ddl.auto=none

10.    activitidb.url=jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000

11.    activitidb.driver=org.h2.Driver

12.    activitidb.username=sa

13.    activitidb.password=

14.    owfdb.url=jdbc:mysql://localhost:3306/openwebflow?useUnicode=true&amp;characterEncoding=UTF-8

15.    owfdb.driver=com.mysql.jdbc.Driver

16.    owfdb.username=root

17.    owfdb.password=1

各属性的含义如下:

属性名

示例值

含义

mail.host

smtp.bluejoe.cn

催办邮件发件服务器主机地址

mail.port

25

催办邮件发件服务器端口号

mail.username

sdb-support@cnic.cn

催办邮件发件账号名

mail.password

sdbsupport

催办邮件发件账号密码

mail.from

sdb-support@cnic.cn

催办邮件发件人

model.dir

../models

自动加载的BPMN模型路径

alarm.mail.template

classpath:/alarm-template.txt

催办邮件正文模板

hibernate.dialect

org.hibernate.dialect.MySQLDialect

Hibernate方言

hibernate.hbm2ddl.auto

none

Hibernate DDL设置

activitidb.url

jdbc:h2:mem:activiti;DB_CLOSE_DELAY

Activiti数据库JDBC URL

activitidb.driver

org.h2.Driver

Activiti数据库JDBC驱动

activitidb.username

sa

Activiti数据库账号名

activitidb.password

Activiti数据库账号密码

owfdb.url

jdbc:mysql://localhost:3306/openwebflow?useUnicode

OpenWebFlow数据库JDBC URL

owfdb.driver

com.mysql.jdbc.Driver

OpenWebFlow数据库JDBC驱动

owfdb.username

root

OpenWebFlow数据库账号名

owfdb.password

1

OpenWebFlow数据库账号密码

2.2.2    activiti.cfg.core.xml配置

activiti.cfg.core.xml的配置与Activiti要求的那个配置文件有点相似,但可以多一些内容,如下是个例子:

1.       <!--工作流核心数据库配置 -->

2.       <bean id="activitiDataSource"class="org.apache.commons.dbcp.BasicDataSource"

3.              destroy-method="close">

4.              <property name="driverClassName"value="${activitidb.driver}" />

5.              <property name="url" value="${activitidb.url}" />

6.              <property name="username"value="${activitidb.username}" />

7.              <property name="password"value="${activitidb.password}" />

8.              <property name="initialSize"value="20" />

9.              <property name="maxActive"value="50" />

10.             <property name="maxIdle"value="20" />

11.             <property name="minIdle"value="10" />

12.      </bean>

13.

14.      <!-- 任务催办配置 -->

15.      <bean id="myTaskAlarmService"class="org.openwebflow.alarm.impl.TaskAlarmServiceImpl">

16.             <!-- 截止日期提前量 -->

17.             <property name="periodInAdvance"value="P2D" />

18.             <!-- 设置消息通知机制 -->

19.             <property name="messageNotifier">

20.                    <!-- 采用邮件发送 -->

21.                    <bean class="org.openwebflow.alarm.impl.MailMessageNotifier">

22.                           <property name="subjectTemplate"value="请尽快处理#{'$'}{task.name}任务" />

23.                           <property name="messageTemplateResource"value="${alarm.mail.template}" />

24.                           <property name="mailSender">

25.                                  <bean class="org.openwebflow.alarm.impl.MailSender">

26.                                         <property name="serverHost"value="${mail.host}" />

27.                                         <property name="serverPort"value="${mail.port}" />

28.                                         <property name="authUserName"value="${mail.username}" />

29.                                         <property name="authPassword"value="${mail.password}" />

30.                                         <property name="mailFrom"value="${mail.from}" />

31.                                  </bean>

32.                           </property>

33.                    </bean>

34.             </property>

35.             <property name="membershipManager"ref="myMembershipManager" />

36.             <property name="userDetailsManager"ref="myUserDetailsManager" />

37.             <property name="taskNotificationManager"ref="myTaskNotificationManager" />

38.      </bean>

39.

40.      <bean id="transactionManager"

41.             class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

42.             <property name="dataSource"ref="activitiDataSource" />

43.      </bean>

44.

45.      <tx:annotation-driven transaction-manager="transactionManager"/>

46.

47.      <!-- 配置对象 -->

48.      <bean id="processEngineConfiguration"class="org.openwebflow.cfg.ProcessEngineConfigurationEx">

49.             <property name="dataSource"ref="activitiDataSource" />

50.             <property name="transactionManager"ref="transactionManager" />

51.             <property name="databaseSchemaUpdate"value="true" />

52.             <property name="jobExecutorActivate"value="false" />

53.             <property name="startEngineEventListeners">

54.                    <list>

55.                           <!-- 加载自定义表单元素类型 -->

56.                           <bean class="org.openwebflow.cfg.LoadDummyFormTypes">

57.                                  <property name="typeNames"value="user" />

58.                           </bean>

59.                           <!-- 自定义成员关系管理 -->

60.                           <bean class="org.openwebflow.cfg.ReplaceMembershipManager">

61.                                  <property name="customMembershipManager"ref="myMembershipManager" />

62.                           </bean>

63.                           <!-- 自定义活动权限管理 -->

64.                           <bean class="org.openwebflow.cfg.ReplaceTaskAssignmentHandler">

65.                                  <!-- 授权处理器列表,会组成一个链,越靠后优先级越高(越靠外) -->

66.                                  <property name="handlers">

67.                                         <list>

68.                                                <!-- 自定义授权项列表 -->

69.                                                <bean

70.                                                  class="org.openwebflow.assign.permission.ActivityPermissionAssignmentHandler">

71.                                                       <property name="activityPermissionManager"ref="myActivityPermissionManager" />

72.                                                </bean>

73.                                                <!-- 允许授权代理 -->

74.                                                <bean

75.                                                  class="org.openwebflow.assign.delegation.TaskDelagationAssignmentHandler">

76.                                                       <property name="delegationManager"ref="myDelegationManager" />

77.                                                       <property name="membershipManager"ref="myMembershipManager" />

78.                                                       <property name="hideDelegated"value="false" />

79.                                                </bean>

80.                                         </list>

81.                                  </property>

82.                           </bean>

83.                           <!-- 自动导入流程模型 -->

84.                           <bean class="org.openwebflow.cfg.ImportDefinedProcessModels">

85.                                  <property name="modelDir"value="${model.dir}" />

86.                           </bean>

87.                           <!-- 启动催办管理器 -->

88.                           <bean class="org.openwebflow.cfg.StartTaskAlarmService">

89.                                  <property name="taskAlarmService"ref="myTaskAlarmService" />

90.                                  <property name="runOnStartup"value="false" />

91.                           </bean>

92.                           <!-- 加载自定义activity -->

93.                           <bean class="org.openwebflow.cfg.LoadRuntimeActivityDefinitions">

94.                                  <property name="activityDefinitionManager"ref="myActivityDefinitionManager" />

95.                           </bean>

96.                    </list>

97.             </property>

98.      </bean>

99.

100.       <!--processEngine -->

101.       <bean id="processEngine"class="org.activiti.spring.ProcessEngineFactoryBean">

102.              <property name="processEngineConfiguration"ref="processEngineConfiguration" />

103.       </bean>

104.

105.       <!--工作流流转服务对象工厂 -->

106.       <bean class="org.openwebflow.ctrl.impl.DefaultTaskFlowControlServiceFactory"/>

107.

108.       <!--processEngineTool -->

109.       <bean id="processEngineTool"class="org.openwebflow.util.ProcessEngineTool"/>

110.

111.       <bean id="repositoryService"factory-bean="processEngine"

112.              factory-method="getRepositoryService" />

113.       <bean id="runtimeService"factory-bean="processEngine"

114.              factory-method="getRuntimeService" />

115.       <bean id="taskService"factory-bean="processEngine"

116.              factory-method="getTaskService" />

117.       <bean id="historyService"factory-bean="processEngine"

118.              factory-method="getHistoryService" />

119.       <bean id="managementService"factory-bean="processEngine"

120.              factory-method="getManagementService" />

其中processEngineConfiguration是增强型的工作流引擎配置对象,可以设置自定义用户群组成员关系管理策略自定义活动权限管理策略等。

完整的例子参见:https://github.com/bluejoe2008/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.core.xml

2.2.3     activiti.cfg.mem.xml配置

在activiti.core.xml中会用到一些manager,activiti.mem.xml定义基于内存的manager实现,默认的activiti.mem.xml内容如下:

1.       <!--自定义成员关系管理 -->

2.       <bean id="myMembershipManager"class="org.openwebflow.mgr.mem.InMemoryMembershipManager"/>

3.       <bean id="myUserDetailsManager"class="org.openwebflow.mgr.mem.InMemoryUserDetailsManager"/>

4.

5.       <!--自定义的活动权限表管理 -->

6.       <bean id="myActivityPermissionManager"

7.              class="org.openwebflow.mgr.mem.InMemoryActivityPermissionManager"/>

8.

9.       <!--代理关系管理 -->

10.      <bean id="myDelegationManager"class="org.openwebflow.mgr.mem.InMemoryDelegationManager"/>

11.

12.      <!-- 自定义的动态自定义活动管理 -->

13.      <bean id="myActivityDefinitionManager"

14.             class="org.openwebflow.mgr.mem.InMemoryRuntimeActivityDefinitionManager"/>

15.

16.      <bean id="myTaskNotificationManager"class="org.openwebflow.mgr.mem.InMemoryTaskNotificationManager"/>

这里面定义了6个manager:

Manager类别

含义

myMembershipManager

自定义成员关系管理

myUserDetailsManager

自定义用户详细信息管理

myActivityPermissionManager

自定义的活动权限表管理

myDelegationManager

代理关系管理

myActivityDefinitionManager

自定义的动态自定义活动管理

myTaskNotificationManager

任务通知信息管理

完整的例子参见:https://github.com/bluejoe2008/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.mem.xml

与activiti.cfg.core.xml类似的可替代文件为activiti.cfg.sql.hibernate.xml和activiti.cfg.sql.mybatis.xml。

2.2.4    activiti.cfg.sql.hibernate.xml配置

activiti.sql.hibernate.xml提供基于SQL的manager实现,采用的ORM框架为Hibernate 4。

各manager的定义如下:

1.       <!--代理记录管理 -->

2.       <bean id="myDelegationManager"

3.              class="org.openwebflow.mgr.hibernate.service.SqlDelegationManager"/>

4.       <!--自定义成员关系管理 -->

5.       <bean id="myMembershipManager"

6.              class="org.openwebflow.mgr.hibernate.service.SqlMembershipManager"/>

7.       <!--自定义用户表 -->

8.       <bean id="myUserDetailsManager"

9.              class="org.openwebflow.mgr.hibernate.service.SqlUserDetailsManager"/>

10.      <!-- 自定义的活动权限表管理 -->

11.      <bean id="myActivityPermissionManager"

12.             class="org.openwebflow.mgr.hibernate.service.SqlActivityPermissionManager"/>

13.      <!-- 自定义的动态自定义活动管理 -->

14.      <bean id="myActivityDefinitionManager"

15.        class="org.openwebflow.mgr.hibernate.service.SqlRuntimeActivityDefinitionManager"/>

16.      <bean id="myTaskNotificationManager"

17.             class="org.openwebflow.mgr.hibernate.service.SqlTaskNotificationManager"/>

此外,还需要定义数据源、Hibernate Session工厂,以及事务。

1.       <context:component-scan base-package="org.openwebflow.mgr.hibernate.dao"/>

2.

3.       <!--数据库脚本见openwebflow.sql -->

4.       <bean id="owfDataSource"class="org.apache.commons.dbcp.BasicDataSource"

5.              destroy-method="close">

6.              <property name="driverClassName"value="${owfdb.driver}" />

7.              <property name="url" value="${owfdb.url}" />

8.              <property name="username"value="${owfdb.username}" />

9.              <property name="password"value="${owfdb.password}" />

10.             <property name="initialSize"value="20" />

11.             <property name="maxActive"value="50" />

12.             <property name="maxIdle"value="20" />

13.             <property name="minIdle"value="10" />

14.      </bean>

15.

16.      <!-- 配置SessionFactory -->

17.      <bean id="sessionFactory"

18.             class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

19.             <property name="dataSource"ref="owfDataSource" />

20.             <property name="hibernateProperties">

21.                    <props>

22.                           <prop key="hibernate.dialect">${hibernate.dialect}</prop>

23.                           <!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop>-->

24.                           <!-- 服务启动通过实体创建数据库表信息 -->

25.                           <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>

26.                           <prop key="hibernate.show_sql">true</prop>

27.                           <prop key="hibernate.format_sql">true</prop>

28.                           <prop key="hibernate.jdbc.batch_size">20</prop>

29.                           <prop key="hibernate.connection.release_mode">auto</prop>

30.                           <prop key="hibernate.autoReconnect">false</prop>

31.                           <prop key="hibernate.connection.autocommit">true</prop>

32.                           <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>

33.                           <prop key="hibernate.jdbc.use_streams_for_binary">true</prop>

34.                           <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext

35.                           </prop>

36.                           <!--解决weblogic无法使用hql的问题 -->

37.                           <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>

38.                    </props>

39.             </property>

40.

41.             <!-- 自动扫描备注解的实体 -->

42.             <property name="packagesToScan">

43.                    <list>

44.                           <value>org.openwebflow.mgr.hibernate.entity</value>

45.                    </list>

46.             </property>

47.      </bean>

48.

49.      <!-- 配置一个事务管理器 -->

50.      <bean id="transactionManager"

51.             class="org.springframework.orm.hibernate4.HibernateTransactionManager">

52.             <property name="sessionFactory"ref="sessionFactory" />

53.      </bean>

54.

55.      <tx:annotation-driven transaction-manager="transactionManager"/>

采用HibernateORM,openwebflow-mgr-hibernate的代码结构如下:

其中,DAO类、实体类、服务类分别存放在dao、entity、service包下面。service类的事务声明以及entity的映射皆采取注解方式。

完整的例子参见:https://github.com/bluejoe2008/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.sql.hibernate.xml

2.2.5     activiti.cfg.sql.mybatis.xml配置

activiti.sql.mybatis.xml提供基于SQL的manager实现,采用的ORM框架为mybatis 3。

各manager的定义如下:

1.       <!--代理记录管理 -->

2.       <bean id="myDelegationManager"

3.              class="org.openwebflow.mgr.mybatis.service.SqlDelegationManager"/>

4.       <!--自定义成员关系管理 -->

5.       <bean id="myMembershipManager"

6.              class="org.openwebflow.mgr.mybatis.service.SqlMembershipManager"/>

7.       <!--自定义用户表 -->

8.       <bean id="myUserDetailsManager"

9.              class="org.openwebflow.mgr.mybatis.service.SqlUserDetailsManager"/>

10.      <!-- 自定义的活动权限表管理 -->

11.      <bean id="myActivityPermissionManager"

12.             class="org.openwebflow.mgr.mybatis.service.SqlActivityPermissionManager"/>

13.      <!-- 自定义的动态自定义活动管理 -->

14.      <bean id="myActivityDefinitionManager"

15.             class="org.openwebflow.mgr.mybatis.service.SqlRuntimeActivityDefinitionManager"/>

16.      <bean id="myTaskNotificationManager"

17.              class="org.openwebflow.mgr.mybatis.service.SqlTaskNotificationManager"/>

此外,还需要定义数据源、SqlSessionFactory,以及事务。

1.       <!--数据库脚本见openwebflow.sql -->

2.       <bean id="owfDataSource"class="org.apache.commons.dbcp.BasicDataSource"

3.              destroy-method="close">

4.              <property name="driverClassName"value="${owfdb.driver}" />

5.              <property name="url" value="${owfdb.url}" />

6.              <property name="username"value="${owfdb.username}" />

7.              <property name="password"value="${owfdb.password}" />

8.              <property name="initialSize"value="20" />

9.              <property name="maxActive"value="50" />

10.             <property name="maxIdle"value="20" />

11.             <property name="minIdle"value="10" />

12.      </bean>

13.

14.      <!-- 创建SqlSessionFactory,同时指定数据源-->

15.      <bean id="owlSqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">

16.             <property name="dataSource"ref="owfDataSource" />

17.      </bean>

18.

19.      <!-- 配置一个事务管理器 -->

20.      <bean id="transactionManager"

21.             class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

22.             <property name="dataSource"ref="owfDataSource" />

23.      </bean>

24.

25.      <tx:annotation-driven transaction-manager="transactionManager" />

采用Mybatis ORM,openwebflow-mgr-mybatis的代码结构如下:

其中,Mapper接口、实体类、服务类分别存放在mapper、entity、service包下面。service类的事务声明以及Mapper的映射皆采取注解方式。

完整的例子参见:https://github.com/bluejoe2008/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.sql.mybatis.xml

2.3    数据库设计

首先,Activiti引擎本身需要用到一系列的数据表,设置好数据源后,Activiti会自动生成这些表。

Activiti的表都以ACT_开头,第二部分是表示表的用途的两个字母标识。用途也和服务的API对应。

l  ACT_RE_*: 'RE'表示repository。这个前缀的表包含了流程定义和流程静态资源(图片,规则,等等)。

l  ACT_RU_*: 'RU'表示runtime。这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。这样运行时表可以一直很小速度很快。

l  ACT_ID_*: 'ID'表示identity。这些表包含身份信息,比如用户,组等等。

l  ACT_HI_*: 'HI'表示history。这些表包含历史数据,比如历史流程实例,变量,任务等等。

l  ACT_GE_*: 通用数据, 用于不同场景下。

OpenWebFlow为一系列manager提供了基于数据库的实现,需要用到一些数据表,对应的建库脚本参见https://github.com/bluejoe2008/openwebflow/tree/master/doc目录下的:

l  openwebflow-mysql4.sql:MySQL4脚本

l  openwebflow-mysql5.sql:MySQL5脚本

l  openwebflow-sqlserver2008.sql:SQLServer2008脚本

l  openwebflow-oracle10g.sql:Oracle脚本

其*定义了6张表格:

l  OWF_ACTIVITY_CREATION:用以存储自定义的活动定义信息

l  OWF_ACTIVITY_PERMISSION:用以存储自定义的活动权限信息

l  OWF_DELEGATION:用以存储用户代理信息

l  OWF_NOTIFICATION:用以存储催办通知记录

OWF_MEMBERSHIP:用以存储用户组成员关系

OWF_USER:用以存储用户信息

注意:OWF_MEMBERSHIP和OWF_USER仅为测试使用,建议用户使用自己的数据表(OpenWebFlow本身努力的一个方向就是将用户及成员关系管理与工作流引擎剥离开),并包装自己的Manager。

2.4    使用ApplicationContext定义的bean

采用Spring IoC框架加载完XML配置文件之后,ApplicationContext中会包含如下变量,可供客户程序使用:

l  processEngine:工作流引擎对象,标准的Activiti对象

l  processEngineTool:针对processEngine提供了一些工具方法

l  defaultTaskFlowControlServiceFactory:任务流控制器的工厂对象

l  repositoryService:提供了管理和控制发布包和流程定义的操作

l  RuntimeService:负责启动一个流程定义的新实例

l  TaskService:与任务相关相关的操作

l  IdentityService:管理(创建,更新,删除,查询...)群组和用户

l  FormService:提供了启动表单和任务表单两个概念

l  HistoryService:提供了Activiti引擎手机的所有历史数据

l  ManagementService:可以查询数据库的表和表的元数据

如下是使用OpenWebFlow的示例代码,可以看出来与Activiti的用法完全一致:

1.     ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:activiti.cfg.mem.xml");

2.     ProcessEngineTool tool = ctx.getBean(ProcessEngineTool.class);

3.     ProcessEngine processEngine = tool.getProcessEngine();

4.     // 启动流程实例

5.     ProcessInstance instance = processEngine.getRuntimeService().startProcessInstanceByKey("test1");

6.     TaskService taskService = processEngine.getTaskService();

7.     //会自动跳转到第一个task

8.     //management可以访问该task

9.     Assert.assertEquals(1, taskService.createTaskQuery().taskCandidateGroup("management").count());

2.5    运行测试用例

在openwebflow-test项目源代码中,用户可以找到一组测试用例来对工作流引擎的功能进行测试,它们分别是:

l  MemProcessEngineTest:基于内存的manager测试

l  SqlHibernateProcessEngineTest:基于hibernateORM的manager测试

l  SqlMybatisProcessEngineTest:基于mybatisORM的manager测试

以上3个测试类都继承于AbstractProcessEngineTest:

AbstractProcessEngineTest提供了测试方法:

方法摘要

void

testActivityPermission() 
          
测试流程动态授权

 void

testAlarm() 
          
测试催办功能

 void

testCachedDefinitions() 
          
测试TaskDefinition

 void

testDelegation() 
          
测试代理功能

 void

testInsertTasksAfter() 
          
测试后加签

 void

testInsertTasksBefore() 
          
测试前加签

 void

testInsertTasksWithPersistence() 
          
测试加签功能的持久化

 void

testModelDeployment() 
          
测试流程模型部署

 void

testMove() 
          
测试*跳转

 void

testMultiInstancesLoop() 
          
测试多实例节点

 void

testSplit() 
          
测试测试节点分裂

其中为了配合测试设计了一个复杂的流程(models/test2.bpmn)如图所示:

选择指定的测试单元(如:MemProcessEngineTest),以“JUnit测试”的方式运行(Run As…),即可观察到测试结果:

也可以选择运行测试套件AllTests:

3.    熟悉OpenWebFlow代码

3.1    下载源码

用户可以下载OpenWebFlow的zip包,下载地址为:https://github.com/bluejoe2008/openwebflow/archive/master.zip

也可以通过git方式获取到最新源码,git资源库地址为:https://github.com/bluejoe2008/openwebflow.git

3.2    代码结构

OpenWebFlow源码包含5个maven工程,其中openwebflow工程是父工程,它声明了包含openwebflow-core、openwebflow-mgr-hibernate、openwebflow-mgr-mybatis、openwebflow-test等4个model。

openwebflow-core:核心工程,包含OpenWebFlow扩展引擎的所有核心内容、以及基于内存的manager实现。

openwebflow-mgr-hibernate:依赖于openwebflow-core,提供了基于数据库的manager实现,ORM框架采用Hibernate。

openwebflow-mgr-mybatis:依赖于openwebflow-core,提供了基于数据库的manager实现,ORM框架采用MyBatis。

openwebflow-test:依赖于以上项目,提供了测试用例,包括配置文件、测试类等。

3.3    build项目

获取到的项目源码可以采用Maven完成build和install,如下为build截图:

3.4    核心对象

3.4.1    ProcessEngineConfigurationEx

ProcessEngineConfigurationEx是针对Activiti提供的ProcessEngineConfiguration类的派生类:

二者大部分参数完全一致,唯一不同的是,ProcessEngineConfigurationEx提供了一个属性:startEngineEventListeners。

startEngineEventListeners用以定义工作流引擎启动的时候需要同时启动的其它任务,startEngineEventListeners是个List,因此可以随意增加新的任务,默认的core.xml中会加载如下任务:LoadDummyFormTypes、ReplaceMembershipManager、ReplaceTaskAssignmentHandler、ImportDefinedProcessModels、StartTaskAlarmService、LoadRuntimeActivityDefinitions。各任务及类属性列表如下:

任务类

用途

属性名

属性含义

LoadDummyFormTypes

加载一些无用的Form类型,用以屏蔽一些自定义Form带来的错误

typeNames

需要屏蔽的Form类型名,以;分隔,如:user

ReplaceMembershipManager

直接接管用户组成员关系

customMembershipManager

指定客户程序自定义的管理器

ReplaceTaskAssignmentHandler

接管Activiti的用户权限管理,如果你想实现动态的节点权限分配,那必须要打开它。

handlers

定义一个授权处理器列表,值类型为List,运行时刻各授权处理器列表会组成一个链,越靠后优先级越高(越靠外)

ImportDefinedProcessModels

自动从指定目录导入BPMN模型

modelDir

用以指定模型的路径,可以是classpath:等路径

StartTaskAlarmService

启动任务催办服务

taskAlarmService

设置催办服务对象

runOnStartup

是否一开始就启动(默认为true)

LoadRuntimeActivityDefinitions

加载运行时的节点定义,主要用来支持在运行时刻定义新的节点

activityDefinitionManager

指定节点定义管理器

3.4.2    ProcessEngineTool

ProcessEngineTool提供了一些工具方法,这些方法的功能一般很难通过ProcessEngine直接拿到:

方法摘要

 org.activiti.engine.repository.Model

createNewModel(java.lang.String name, java.lang.String description) 
          
创建一个空白的Model对象

 org.activiti.engine.repository.Deployment

deployModel(java.lang.String modelId) 
          
部署一个已注册的model

 org.activiti.engine.impl.pvm.process.ActivityImpl

getActivity(java.lang.String processDefId, java.lang.String activityId) 
          
获取指定名字的活动

 java.util.Map<java.lang.String,java.lang.Object>

getHistoricProcessVariables(java.lang.String processId) 
          
获取指定历史流程的变量列表

 org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity

getProcessDefinition(java.lang.String processDefId) 
          
获取指定ID的流程定义

 org.activiti.engine.ProcessEngine

getProcessEngine() 
           

 void

grantPermission(org.activiti.engine.impl.pvm.process.ActivityImpl activity, java.lang.String assigneeExpression, java.lang.String candidateGroupIdExpressions, java.lang.String candidateUserIdExpressions) 
          
设置指定活动的用户权限,包括钦定用户、候选用户、候选组

 void

grantPermission(java.lang.String processDefId, java.lang.String activityId, java.lang.String assigneeExpression, java.lang.String candidateGroupIdExpressions, java.lang.String candidateUserIdExpressions) 
          
设置指定活动的用户权限,包括钦定用户、候选用户、候选组

 void

setProcessEngine(org.activiti.engine.ProcessEngine processEngine) 

3.4.3    各种Utils

OpenWebFlow提供了一些常见的工具类,如下所示:

类摘要

CloneUtils

实现对象的克隆功能

ExpressionUtils

实现常见类型的expression的包装和转换

IdentityUtils

实现用户、成员关系等相关操作

ModelUtils

包装了对BPMN模型的部署、注册等功能

ProcessDefinitionUtils

流程定义相关操作的封装

3.4.4    TaskFlowControlService

TaskFlowControlService用以实现流程的*控制,它提供的方法如下:

方法摘要

 org.activiti.engine.impl.pvm.process.ActivityImpl[]

insertTasksAfter(java.lang.String targetTaskDefinitionKey, java.lang.String... assignees) 
          
后加签

 org.activiti.engine.impl.pvm.process.ActivityImpl[]

insertTasksBefore(java.lang.String targetTaskDefinitionKey, java.lang.String... assignees) 
          
前加签

 void

moveBack() 
          
后退一步

 void

moveBack(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity) 
          
后退至指定活动

 void

moveForward() 
          
前进一步

 void

moveForward(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity) 
          
前进至指定活动

 void

moveTo(java.lang.String targetTaskDefinitionKey) 
          
跳转(包括回退和向前)至指定活动节点

 void

moveTo(java.lang.String currentTaskId, java.lang.String targetTaskDefinitionKey) 
          
跳转(包括回退和向前)至指定活动节点

 void

moveTo(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity, java.lang.String targetTaskDefinitionKey) 
          
跳转(包括回退和向前)至指定活动节点

 org.activiti.engine.impl.pvm.process.ActivityImpl

split(java.lang.String targetTaskDefinitionKey, boolean isSequential, java.lang.String... assignees) 
          
分裂某节点为多实例节点

 org.activiti.engine.impl.pvm.process.ActivityImpl

split(java.lang.String targetTaskDefinitionKey, java.lang.String... assignee) 
          
分裂某节点为多实例节点

TaskFlowControlService需要一个TaskFlowControlServiceFactory来创建,可以从applicationcontext中获取到该工厂对象。

4.    核心功能的设计与使用

4.1    用户管理托管

4.1.1    设计方案

OpenWebFlow通过ReplaceMembershipManager的beforeStartEngine()事件,设置ProcessEngineConfigurationImpl的sessionFactories,将自定义的用户管理器、群组管理器、用户成员关系管理器注射进去:

1.              sessionFactories.add(newSessionedEntityManagerFactory(UserIdentityManager.class, new DummyUserIdentityManager(

2.                            _customMembershipManager)));

3.              sessionFactories.add(newSessionedEntityManagerFactory(GroupIdentityManager.class,

4.                            new DummyGroupIdentityManager(_customMembershipManager)));

5.              sessionFactories.add(newSessionedEntityManagerFactory(MembershipIdentityManager.class,

6.                            newDummyMembershipIdentityManager()));

DummyUserIdentityManager、DummyGroupIdentityManager和DummyMembershipIdentityManager是三个适配器,实现用户自定义Manager到Activiti所需的UserIdentityManager、GroupIdentityManager和MembershipIdentityManager的适配。

4.1.2    使用方法

如果需要挂接应用的用户成员关系管理框架,用户需要提供一个IdentityMembershipManager实现类,替换掉配置文件中的membershipManager即可。

如果需要挂接应用的用户详细信息管理框架,用户提供一个UserDetailsManager实现类,替换掉配置文件中的userDetailsManager即可。

参见“5.5用户详细信息管理”“5.6用户组成员关系管理”。

4.2    任务权限框架托管

4.2.1    设计方案

OpenWebFlow的任务权限框架托管的核心思想在于org.openwebflow.assign.TaskAssignmentHandler:

1.     public interface TaskAssignmentHandler

2.     {

3.       void handleAssignment(TaskAssignmentHandlerChainchain, TaskEntity task, ActivityExecution execution);

4.     }

TaskAssignmentHandler配合自定义的UserTaskActivityBehavior,用以篡改Activiti的任务权限分配方法:

1.     public class MyUserTaskActivityBehaviorextends UserTaskActivityBehavior

2.     {

3.       List<TaskAssignmentHandler> _handlers;

4.

5.       publicMyUserTaskActivityBehavior(List<TaskAssignmentHandler> handlers,TaskDefinition taskDefinition)

6.       {

7.              super(taskDefinition);

8.              _handlers = handlers;

9.       }

10.

11.      protectedTaskAssignmentHandlerChainImpl createHandlerChain()

12.      {

13.             TaskAssignmentHandlerChainImplhandlerChain = new TaskAssignmentHandlerChainImpl();

14.             final MyUserTaskActivityBehaviormyUserTaskActivityBehavior = this;

15.             handlerChain.addHandler(new TaskAssignmentHandler()

16.             {

17.                    @Override

18.                    public voidhandleAssignment(TaskAssignmentHandlerChain chain, TaskEntity task,ActivityExecution execution)

19.                    {

20.                           myUserTaskActivityBehavior.superHandleAssignments(task,execution);

21.                    }

22.             });

23.

24.             handlerChain.addHandlers(_handlers);

25.             return handlerChain;

26.      }

27.

28.      @Override

29.      protected void handleAssignments(TaskEntitytask, ActivityExecution execution)

30.      {

31.             createHandlerChain().resume(task,execution);

32.      }

33.

34.      protected voidsuperHandleAssignments(TaskEntity task, ActivityExecution execution)

35.      {

36.             super.handleAssignments(task,execution);

37.      }

38.    }

TaskAssignmentHandlerChainImpl将一系列的TaskAssignmentHandler从内到外组成一个处理链,然后再委托给MyUserTaskActivityBehavior来执行。查看配置文件可以观察到这个链的结构:

1.<!-- 授权处理器列表,会组成一个链,越靠后优先级越高(越靠外) -->

2.<property name="handlers">

3.  <list>

4.         <!-- 自定义授权项列表 -->

5.         <bean

6.           class="org.openwebflow.assign.permission.ActivityPermissionAssignmentHandler">

7.                <property name="activityPermissionManager" ref="myActivityPermissionManager" />

8.         </bean>

9.         <!-- 允许授权代理 -->

10.         <bean

11.                class="org.openwebflow.assign.delegation.TaskDelagationAssignmentHandler">

12.                <property name="delegationManager" ref="myDelegationManager" />

13.                <property name="membershipManager" ref="myMembershipManager" />

14.                <property name="hideDelegated" value="false"/>

15.         </bean>

16.  </list>

17.</property>

可以看出链列表里的内容依次为:

(BPMN静态模型权限定义) à ActivityPermissionAssignmentHandler à TaskDelagationAssignmentHandler

用户程序通过TaskAssignmentHandlerChainImpl访问活动的顺序如下图所示:

其中,BPMN模型权限控制由createHandlerChain()方法体内的一个匿名类包装完成,自定义权限表策略由ActivityPermissionAssignmentHandler类完成,代理策略由TaskDelagationAssignmentHandler类完成。ActivityPermissionAssignmentHandler和TaskDelagationAssignmentHandler是TaskAssignmentHandler的两个实现类,如下图所示。

ActivityPermissionAssignmentHandler会实现活动权限运行时自定义的功能,相关内容参见“5.1活动定义管理”。

TaskDelagationAssignmentHandler会实现任务代办的功能,相关内容参见“0欲使用任务权限框架托管功能,需要遵循如下步骤:

l  配置myActivityPermissionManager、myDelegationManager以及myMembershipManager;

l  在activiti.cfg.core.xml中的processEngineConfiguration里打开ReplaceTaskAssignmentHandler(默认情况下这是打开的);

接下来,不需要任何设置,在查询任务的时候,会自动根据以上授权策略进行筛选。

任务代办”。

4.2.2    使用方法

欲使用任务权限框架托管功能,需要遵循如下步骤:

l  配置myActivityPermissionManager、myDelegationManager以及myMembershipManager;

l  在activiti.cfg.core.xml中的processEngineConfiguration里打开ReplaceTaskAssignmentHandler(默认情况下这是打开的);

接下来,不需要任何设置,在查询任务的时候,会自动根据以上授权策略进行筛选。

4.3    任务代办

Activiti本身提供了任务代办功能,TaskService具有如下方法:

void delegateTask(String taskId,

String userId)

Delegates thetask to another user. This means that the assignee is set and the delegationstate is set to DelegationState.PENDING.If no owner is set on the task, the owner is set to the current assignee of thetask.

注意OpenWebFlow关注的“任务代办”功能与上面的概念不同,它的含义是:用户A暂时委派用户B代理处理“所有可能的任务”,而不是专指“某个任务”。

4.3.1    设计方案

通过任务权限框架的托管,OpenWebFlow任务代办的实现比较简便。TaskDelagationAssignmentHandler通过DelegationManager和IdentityMembershipManager两个字段,实现了任务代理的功能。核心的实现方法如下:

1.       @Override

2.  public void handleAssignment(TaskAssignmentHandlerChainchain, TaskEntity task, ActivityExecution execution)

3.  {

4.         //先执行其它规则

5.         chain.resume(task, execution);

6.

7.         overwriteAssignee(task);

8.

9.         Map<String, Object> userIdMap = new HashMap<String, Object>();

10.         Map<String, Object> groupIdMap = new HashMap<String, Object>();

11.         retrieveCandidateUserIdsAndGroupIds(task,userIdMap, groupIdMap);

12.         Map<String, Object> newUserIdMap= new HashMap<String, Object>();

13.         Map<String, Object>removeUserIdMap = new HashMap<String, Object>();

14.

15.         //遍历所有的被代理人

16.         List<DelegationEntity> entries = _delegationManager.listDelegationEntities();

17.         overwriteCandicateUserIds(userIdMap,newUserIdMap, removeUserIdMap, entries);

18.         overwriteCandicateGroupIds(groupIdMap,newUserIdMap, entries);

19.

20.         addCandidateUsers(task,newUserIdMap.keySet());

21.         removeCandidateUsers(task, removeUserIdMap.keySet());

22.  }

DelegationManager的设计参见“5.4.1DelegationManager”。

4.3.2    使用方法

欲使用任务代办功能,只需要遵循如下步骤:

l  配置myDelegationManager和myMembershipManager;

l  在业务代码中通过调用DelegationManagerEx的saveDelegation()来设置一条代理规则;

l  在activiti.cfg.core.xml中的processEngineConfiguration里打开TaskDelagationAssignmentHandler(默认情况下这是打开的);

接下来,不需要任何设置,在分配任务(或者选择候选人)的时候,会自动包含被代理人。

4.4    任务催办

任务催办的功能与引擎相对独立,它负责针对未能及时处理的任务(根据任务的dueDate),给出通知,包括邮件通知、短信通知等。

4.4.1    设计方案

OpenWebFlow针对催办功能设计了一个TaskAlarmService服务,一个典型的TaskAlarmServiceImpl服务定义如下:

如下示出myTaskAlarmService的配置:

1.       <!-- 任务催办配置 -->

2.  <bean id="myTaskAlarmService" class="org.openwebflow.alarm.impl.TaskAlarmServiceImpl">

3.         <!-- 截止日期提前量 -->

4.         <property name="periodInAdvance" value="P2D" />

5.         <!-- 设置消息通知机制 -->

6.         <property name="messageNotifier">

7.                <!-- 采用邮件发送 -->

8.                <bean class="org.openwebflow.alarm.impl.MailMessageNotifier">

9.                       <property name="subjectTemplate" value="请尽快处理#{'$'}{task.name}任务" />

10.                       <property name="messageTemplateResource" value="${alarm.mail.template}" />

11.                       <property name="mailSender">

12.                              <bean class="org.openwebflow.alarm.impl.MailSender">

13.                                     <property name="serverHost" value="${mail.host}"/>

14.                                     <property name="serverPort" value="${mail.port}"/>

15.                                     <property name="authUserName" value="${mail.username}"/>

16.                                     <property name="authPassword" value="${mail.password}"/>

17.                                     <property name="mailFrom" value="${mail.from}"/>

18.                              </bean>

19.                       </property>

20.                </bean>

21.         </property>

22.         <property name="membershipManager" ref="myMembershipManager" />

23.         <property name="userDetailsManager" ref="myUserDetailsManager" />

24.         <property name="taskNotificationManager" ref="myTaskNotificationManager" />

25.  </bean>

可以看到,TaskAlarmServiceImpl包含如下重要属性:

l  periodInAdvance:任务催办时间提前量(相对于dueDate而言),格式采用ISO 8601时间段表示法(和Activiti的due date格式一样,参考http://en.wikipedia.org/wiki/ISO_8601#Durations),如:P2D代表提前2天

l  messageNotifier:定义通知的方式,如上示例的是邮件发送的方式,用户可以改造成其它方式,如:短信方式,或者组合方式;

l  membershipManager:成员关系管理器,TaskAlarmService会通知到候选组里面的所有成员;

l  userDetailsManager:用户详细信息管理器,TaskAlarmService会在发送通知信息的时候用到用户相关属性,如:邮箱、手机号等;

l  taskNotificationManager:任务通知信息管理;

ProcessEngine在启动时会加载StartTaskAlarmService,从而启动催办服务。

4.4.2    使用方法

欲使用任务催办功能,需要遵循如下步骤:

l  配置myTaskNotificationManager 、myUserDetailsManager和myMembershipManager;

l  配置myTaskAlarmService;

l  在activiti.cfg.core.xml中的processEngineConfiguration里打开StartTaskAlarmService(默认情况下这是打开的);

接下来,不需要任何设置,在任务即将过期(dueDate)的时候,委托人(assignee)或候选人就会收到催办通知。

4.5    任务流程控制

OpenWebFlow提供了安全的加签(包括前加签/后加签)、*跳转(包括前进/后)、分裂节点等功能。

4.5.1    设计方案

任务流程控制功能由TaskFlowControlService提供,相关的实现在org.openwebflow.ctrl包里面,一般通过TaskFlowControlServiceFactory获取到TaskFlowControlService。

任务流程控制功能实现的关键思路是:将对既有流程的各种调整映射成“对Activity对象的更新及克隆”,并在必要的时候还要实现持久化和加载。

OpenWebFlow在实现“新流程”的持久化的时候玩了一个trick,即仅仅将“调整”的方式(活动工厂信息)做持久化,而非针对“调整之后的新版本”做持久化。譬如,我们根据step2活动创建一个step21活动,所有的信息都一样,这个时候只要持久化工厂类型(活动克隆)、模板活动ID(step2)、新活动ID(step21)就可以了。比较复杂的例子,是将某个活动分裂成N个串行的会签活动,这种情况也只需要记录模板活动ID、新活动ID数组,不需要记录更多的信息。如下示出一个创建N个用户任务活动的例子:

1.     public class ChainedActivitiesCreator extends RuntimeActivityCreatorSupport implements RuntimeActivityCreator

2.{

3.  public ActivityImpl[]createActivities(ProcessEngine processEngine, ProcessDefinitionEntityprocessDefinition,

4.                RuntimeActivityDefinitionEntity info)

5.  {

6.         info.setFactoryName(ChainedActivitiesCreator.class.getName());

7.         RuntimeActivityDefinitionEntityIntepreter radei = newRuntimeActivityDefinitionEntityIntepreter(info);

8.

9.         if(radei.getCloneActivityIds() == null)

10.         {

11.                radei.setCloneActivityIds(CollectionUtils.arrayToList(new String[radei.getAssignees().size()]));

12.         }

13.

14.         returncreateActivities(processEngine, processDefinition, info.getProcessInstanceId(),

15.                radei.getPrototypeActivityId(),radei.getNextActivityId(), radei.getAssignees(),

16.                radei.getCloneActivityIds());

17.  }

18.

19.  private ActivityImpl[]createActivities(ProcessEngine processEngine, ProcessDefinitionEntityprocessDefinition,

20.                String processInstanceId, String prototypeActivityId,String nextActivityId, List<String> assignees,

21.                List<String> activityIds)

22.  {

23.         ActivityImpl prototypeActivity = ProcessDefinitionUtils.getActivity(processEngine,processDefinition.getId(),

24.                prototypeActivityId);

25.

26.         List<ActivityImpl> activities = new ArrayList<ActivityImpl>();

27.         for (int i = 0; i < assignees.size(); i++)

28.         {

29.                if(activityIds.get(i) == null)

30.                {

31.                       String activityId = createUniqueActivityId(processInstanceId,prototypeActivityId);

32.                       activityIds.set(i, activityId);

33.                }

34.

35.                ActivityImpl clone = createActivity(processEngine,processDefinition, prototypeActivity,

36.                       activityIds.get(i), assignees.get(i));

37.                activities.add(clone);

38.         }

39.

40.         ActivityImpl nextActivity = ProcessDefinitionUtils.getActivity(processEngine,processDefinition.getId(),

41.                nextActivityId);

42.         createActivityChain(activities, nextActivity);

43.

44.         returnactivities.toArray(newActivityImpl[0]);

45.  }

46.}

活动工厂信息用RuntimeActivityDefinitionEntity类来表示,为了方便,不同活动工厂的个性化信息存成了一个JSON字符串,并会在加载的时候解析成一个Map。如下是一个节点分裂的活动工厂信息:

1.     {"sequential":true,"assignees":["bluejoe","alex"],"cloneActivityId":"2520001:step2:1419823449424-8","prototypeActivityId":"step2"}

通过RuntimeActivityDefinitionEntity来调整流程,通过一系列的creator来表示。如:org.openwebflow.ctrl.creator.MultiInstanceActivityCreator用来创建多实例节点。

4.5.2    使用方法

欲使用任务流程控制功能,需要遵循如下步骤:

l  配置myActivityPermissionManager、myActivityDefinitionManager;

l  在activiti.cfg.core.xml中的processEngineConfiguration里打开LoadRuntimeActivityDefinitions(默认情况下这是打开的),该设置会自动加载持久化的活动定义;

l  配置TaskFlowControlServiceFactory;

1.       <!-- 工作流流转服务对象工厂-->

2.  <bean class="org.openwebflow.ctrl.impl.DefaultTaskFlowControlServiceFactory"/>

l  获取到TaskFlowControlServiceFactory,创建TaskFlowControlService:

1.              _taskFlowControlServiceFactory = _ctx.getBean(DefaultTaskFlowControlServiceFactory.class);

2.              ProcessInstanceinstance = _processEngine.getRuntimeService().startProcessInstanceByKey("test2");

3.              TaskFlowControlServicetfcs = _taskFlowControlServiceFactory.create(instance.getId());

l  使用TaskFlowControlService:

1.              ActivityImpl[]as = tfcs.insertTasksBefore("step2", "bluejoe", "alex");

4.6    模型文件导入

默认情况下,在activiti.cfg.core.xml中的processEngineConfiguration里会打开ImportDefinedProcessModels:

1.       <!-- 启动催办管理器 -->

2.       <bean class="org.openwebflow.cfg.StartTaskAlarmService">

3.              <property name="taskAlarmService" ref="myTaskAlarmService" />

4.              <property name="runOnStartup" value="false"/>

5.       </bean>

该配置自动加载指定路径下(${model.dir})的BPMN模型文件(以.bpmn为后缀)至Activiti的repository库。

如果需要手动加载,可以使用ProcessEngineTool或者ModelUtils类。

5.    使用管理器接口实现自定义扩展

OpenWebFlow需要用户提供6类管理器的接口,它们分别是:

l  RuntimeActivityDefinitionManager:负责获取活动的定义信息,用以支持运行时期的新建活动

l  ActivityPermissionManager:负责获取活动的权限设置信息

l  TaskNotificationManager:负责存取任务催办通知信息

l  DelegationManager:负责获取用户的代理信息

l  UserDetailsManager:负责获取用户的信息(包括E-mail、昵称、手机号等),主要用以发送催办通知

l  IdentityMembershipManager:负责获取用户组成员关系,获取某用户的候选任务队列时,需要通过用户名获取到用户组

除了这些Manager之外,用户会发现OpenWebFlow还提供了一系列的ManagerEx接口:

l  ActivityPermissionManagerEx:负责保存活动的权限设置信息

l  TaskNotificationManagerEx:负责保存任务催办通知信息

l  DelegationManagerEx:负责保存用户的代理信息

l  UserDetailsManagerEx:负责保存用户的信息

l  IdentityMembershipManagerEx:负责保存用户组成员关系

可以简单的认为,Manager接口主要用以信息读取(read),ManagerEx接口主要用以信息写入(write),注意使用OpenWebFlow引擎时,ManagerEx不是必须要提供相应实现的!OpenWebFlow引擎的所有操作只会调用到Manager而非ManagerEx,提供ManagerEx的唯一用处是为了测试(如果没有写入,读取返回的永远是空白,测试就无法正常进行了)。

5.1   活动定义管理

客户程序往往需要在运行时候调整某个工作流的流程,如:让活动step5执行完之后跳转至step2,这样的操作需要创建一个新的路径,为了保证后续流程的正常执行(特别是应用重启之后),这样的路径需要保存和加载。

5.1.1    RuntimeActivityDefinitionManager

RuntimeActivityDefinitionManager包含如下方法:

方法摘要

 java.util.List <RuntimeActivityDefinitionEntity>

list() 
          获取所有的活动定义信息,引擎会在启动的时候加载这些活动定义并进行注册

 void

removeAll() 
          删除所有活动定义

 void

save(RuntimeActivityDefinitionEntity entity) 
          新增一条活动定义的信息

5.1.2    RuntimeActivityDefinitionEntity

RuntimeActivityDefinitionEntity对应于一条活动的定义信息:

方法摘要

 void

deserializeProperties() 
          
反序列化PropertiesText到Map

 java.lang.String

getFactoryName() 
          
获取工厂名

 java.lang.String

getProcessDefinitionId() 
          
获取流程定义的ID

 java.lang.String

getProcessInstanceId() 
          
获取流程实例的ID

 java.lang.String

getPropertiesText() 
          
获取PropertiesText,它是一个JSON字符串

<T> T

getProperty(java.lang.String name) 
          
获取指定的属性值

 void

serializeProperties() 
          
序列化Map至PropertiesText

 void

setFactoryName(java.lang.String factoryName) 
          
设置工厂名

 void

setProcessDefinitionId(java.lang.String processDefinitionId) 
          
设置流程定义ID

 void

setProcessInstanceId(java.lang.String processInstanceId) 
          
设置流程实例ID

 void

setPropertiesText(java.lang.String propertiesText) 
          
设置PropertiesText

<T> void

setProperty(java.lang.String name, T value) 

5.2    活动权限管理

5.2.1    ActivityPermissionManager

活动权限的管理接口为ActivityPermissionManager,它的定义如下:

方法摘要

 ActivityPermissionEntity

load(java.lang.String processDefinitionId, java.lang.String taskDefinitionKey, boolean addOrRemove) 
          
获取指定活动的权限定义信息

5.2.2    ActivityPermissionEntity

非常简单,它只需要一个方法,该方法返回一个ActivityPermissionEntity,该实体的定义如下:

方法摘要

 java.lang.String

getAssignee() 
          
获取直接授权人

 java.lang.String[]

getGrantedGroupIds() 
          
获取候选组列表

 java.lang.String[]

getGrantedUserIds() 
          
获取候选用户列表

5.2.3    ActivityPermissionManagerEx

ActivityPermissionManagerEx实现对活动权限表的“写”操作:

方法摘要

void

removeAll() 
          
删除所有权限定义信息

 void

save(java.lang.String processDefId, java.lang.String taskDefinitionKey, java.lang.String assignee, java.lang.String[] candidateGroupIds, java.lang.String[] candidateUserIds) 
          
保存一条权限定义信息

5.3    任务催办通知管理

5.3.1    TaskNotificationManager

TaskNotificationManager负责读取和设置任务催办的状态,该接口也很简单:

方法摘要

 boolean

isNotified(java.lang.String taskId) 
          
判断指定任务是否通知过

 void

setNotified(java.lang.String taskId) 
          
设置指定任务的通知状态

可以理解成TaskNotificationManager维护了一个队列,记录了每个任务的通知状态(已通知为true,未通知为false)。

5.3.2    TaskNotificationManagerEx

TaskNotificationManagerEx实现了对通知记录的“写”操作:

方法摘要

 void

removeAll() 
          
删除所有通知记录

5.4    用户代理关系管理

5.4.1    DelegationManager

DelegationManager用以维护用户之间的代理关系。接口包含2个方法:

方法摘要

 java.lang.String[]

getDelegates(java.lang.String delegated) 
          
获取指定用户的代理人列表

 java.util.List<DelegationEntity>

listDelegationEntities() 
          
获取所有的代理信息列表,引擎会在启动的时候加载

5.4.2    DelegationEntity

DelegationEntity描述一条代理关系:

方法摘要

 java.lang.String

getDelegate() 
          
获取当前代理记录的代理人

 java.lang.String

getDelegated() 
          
获取当前代理记录的被代理人

5.4.3    DelegationManagerEx

DelegationManagerEx用以实现对代理记录的“写”操作:

方法摘要

 void

removeAll() 
          
删除所有代理信息

 void

saveDelegation(java.lang.String delegated, java.lang.String delegate) 
          
保存一条代理信息

5.5   用户详细信息管理

5.5.1    UserDetailsManager

UserDetailsManager负责获取用户的信息(包括E-mail、昵称、手机号等),主要用以发送催办通知。UserDetailsManager接口包含的方法如下:

方法摘要

 UserDetailsEntity

findUserDetails(java.lang.String userId) 
          
根据用户名获取用户详细信息

5.5.2    UserDetailsEntity

UserDetailsEntity用以描述用户详细信息,注意它没有强制要求提供诸如getName()这样的方法,而是提供了一个getProperty(Stringname)方法:

方法摘要

<T> T

getProperty(java.lang.String name) 
          
获取指定属性的值

 java.lang.String[]

getPropertyNames() 
          
获取所有的属性名

 java.lang.String

getUserId() 
          
获取用户的ID

<T> void

setProperty(java.lang.String name, T value) 
          
设置指定属性的值

UserDetailsEntity同时提供了几个字符串常量:

字段摘要

static java.lang.String

STRING_PROPERTY_EMAIL 
          EMAIL
属性名

static java.lang.String

STRING_PROPERTY_MOBILE_PHONE_NUMBER 
          
手机号码属性名

static java.lang.String

STRING_PROPERTY_NICK_NAME 
          
昵称属性名

static java.lang.String

STRING_PROPERTY_USER_ID 
          
用户ID属性名

5.5.3    UserDetailsManagerEx

UserDetailsManagerEx用以实现用户信息的“写”操作:

方法摘要

 void

removeAll() 
          
删除所有用户信息

 void

saveUserDetails(UserDetailsEntity userDetails) 
          
保存某个用户的信息

5.6   用户组成员关系管理

5.6.1    IdentityMembershipManager

IdentityMembershipManager负责获取用户组成员关系,简单点,就是获取指定用户所在的组的ID列表,以及指定组内的成员ID列表。

方法摘要

java.util.List <java.lang.String>

findGroupIdsByUser(java.lang.String userId) 
          
获取指定的用户所在的组ID列表

 java.util.List <java.lang.String>

findUserIdsByGroup(java.lang.String groupId) 
          
获取指定组的成员用户ID列表

5.6.2    IdentityMembershipManagerEx

IdentityMembershipManagerEx提供了对成员关系信息的“写”操作:

方法摘要

 void

removeAll() 
          
删除所有成员关系

 void

saveMembership(java.lang.String userId, java.lang.String groupId) 
          
保存成员关系

6.    其他帮助

本文档的下载地址为:https://github.com/bluejoe2008/openwebflow/tree/master/doc,可通过该地址及时查阅最新版本。

如果用户需要查阅OpenWebFlow的Java API,可以参考javadoc(https://github.com/bluejoe2008/openwebflow/tree/master/openwebflow-core/doc/javadoc)。

另外可以关注Wiki(https://github.com/bluejoe2008/openwebflow/wiki),提交话题(https://github.com/bluejoe2008/openwebflow/issues),以及与作者bluejoe2008@gmail.com直接联系。

7.    Activiti的BUG及对策

目前作者发现Activiti框架存在2个bug,主要表现在:

第一个bug是在BaseBpmnJsonConverter将BPMN模型转存为JSON格式的时候,会忽略对true布尔值的输出,这个bug会造成JsonConverterUtil.getPropertyValueAsBoolean()获取到false值(因为此时的判断标准变成Yes或No)。该bug的报告地址:https://github.com/Activiti/Activiti/pull/464#event-204722250

另外一个bug是在BPMN文件加载的时候,当本地字符集为非UTF-8(如:GB2312)时,会出现模型加载的错误。该bug的报告地址:https://github.com/Activiti/Activiti/pull/486#event-220121880

目前作者已经针对以上两个bug提交了bugfix并被master版本合并。不过考虑到版本稳定性问题,OpenWebFlow最新版本还是采用了其他方法来避免了如上bug的发生。

上一篇:(转)SQLServer_十步优化SQL Server中的数据访问五


下一篇:crm踩坑记(二)