jbpm4.4用户手册

更新时间:2024-05-12 16:38:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第 1 章 导言

上一页

下一页

第 1 章 导言

最好使用firefox浏览这份教程。 在使用internet explorer的时候会有一些问题。

1.1. 许可证与最终用户许可协议

jBPM是依据GNU Lesser General Public License(LGPL) 和JBoss End User License Agreement(EULA)中的协议发布的, 请参考 完整的LGPL协议和 完整的最终用户协议。

1.2. 下载

可以从sourceforge上下载发布包。

http://sourceforge.net/projects/jbpm/files/

1.3. 源码

可以从jBPM的SVN仓库里下载源代码。 https://anonsvn.jboss.org/repos/jbpm/jbpm4/

1.4. 什么是jBPM

jBPM是一个可扩展、灵活的流程引擎, 它可以运行在独立的服务器上或者嵌入任何Java应用中。

1.5. 文档内容

在这个用户指南里, 我们将介绍在持久执行模式下的jPDL流程语言。 持久执行模式是指流程定义、 流程执行以及流程历史都保存在关系数据库中, 这是jBPM实际通常使用的方式。

这个用户指南介绍了jBPM中支持的使用方式。 开发指南介绍了更多的、高级的、定制的、 没有被支持的选项。

1.6. 从jBPM 3升级到jBPM 4

没办法实现从jBPM 3到jBPM 4的升级。 可以参考开发指南来获得更多迁移的信息。

1.7. 报告问题

在用户论坛或者我们的支持门户报告问题的时候, 请遵循如下模板: === 环境 ============================== - jBPM Version : 你使用的是哪个版本的jBPM? - Database : 使用的什么数据库以及数据库的版本 - JDK : 使用的哪个版本的JDK?如果不知道可以使用'java -version'查看版本信息 - Container : 使用的什么容器?(JBoss, Tomcat, 其他) - Configuration : 你的jbpm.cfg.xml中是只导入了jbpm.jar中的默认配置, 还是使用了自定义的配置? - Libraries : 你使用了jbpm发布包中完全相同的依赖库的版本? 还是你修改了其中一些依赖库? === Process ================================== 这里填写jPDL流程定义 === API =================================== 这里填写你调用jBPM使用的代码片段 === Stacktrace ============================== 这里填写完整的错误堆栈 === Debug logs ============================== 这里填写调试日志 === Problem description ========================= 请保证这部分短小精悍并且切入重点。比如,API没有如期望中那样工作。 或者,比如,ExecutionService.SignalExecutionById抛出了异常。 聪明的读者可能已经注意到这些问题已经指向了可能导致问题的几点原因:) 特别是对依赖库和配置的调整都很容易导致问题。 这就是为什么我们在包括安装和使用导入实现建议配置机制时花费了大量的精力。 所以,在你开始在用户手册覆盖的知识范围之外修改配置之前,一定要三思而行。 同时在使用其他版本的依赖库替换默认的依赖库之前, 也一定要三思而行。

第 2 章 安装配置 2.1. 发布

只需要把jBPM (jbpm-4.X.zip) 下载下来,然后解压到你的硬盘上的什么地方。 你将看到下面的子目录:

? ? ? ? ? ? ?

doc: 用户手册,javadoc和开发指南 examples: 用户手册中用到的示例流程 install: 用于不同环境的安装脚本

lib: 第三方库和一些特定的jBPM依赖库 src: 源代码文件

jbpm.jar: jBPM主库归档 migration: 参考开发指南

2.2. 必须安装的软件

jBPM需要JDK (标准java)5或更高版本。 http://java.sun.com/javase/downloads/index.jsp

为了执行ant脚本,你需要1.7.0或更高版本的apache ant: http://ant.apache.org/bindownload.cgi

2.3. 快速上手

这个范例安装是最简单的方式开始使用jBPM。 这一章介绍了完成范例安装的步骤。

如果你之前下载过jboss-5.0.0.GA.zip,你可以把它放到

${jbpm.home}/install/downloads目录下。 否则脚本会为你下载它,但是它会消耗一些时间(与你的网络情况有关)。 eclipse-jee-galileo-win32.zip也一样(或者eclipse-jee-galileo-linux-gtk(-x86_64).tar.gz在linux平台下 和eclipse-jee-galileo-macosx-carbon.tar.gz在Mac OSX平台下)。 打开命令控制台,进入目录${jbpm.home}/install。 然后运行 ant demo.setup.jboss 或者

ant demo.setup.tomcat 这将

? ? ? ? ? ? ? ? ? ? ?

把JBoss安装到${jbpm.home}/jboss-5.0.0.GA目录 把jBPM安装到JBoss中。 安装hsqldb,并在后台启动。 创建数据库结构 在后台启动JBoss

根据示例创建一个examples.bar业务归档,把它发布到jBPM数据库中 从${jbpm.home}/install/src/demo/example.identities.sql,读取用户和组。

安装eclipse到${jbpm.home}/eclipse 启动eclipse

安装jBPM web控制台 安装Signavio web建模器 当这些都完成后,JBoss(或Tomcat,根据demo.setup脚本中的选择)会在后台启动。 一旦eclipse完成启动,你可以继续执行下面的教程 第 3 章 流程设计器(GPD)来开始编码你的jBPM业务流程。

或者你可以启动建模流程,通过 Signavio web设计器。 或者使用jBPM控制台。 你可以使用下面用户之一进行登陆: 表 2.1. 示例控制台用户: 用户名 密码 alex password mike password peter password mary password 目前存在的问题: 现在,对于一些比较慢的机器,在初始化报表时, 控制台的失效时间太短了,所以当你第一次请求报表时, 会出现超时,控制台会崩溃。 注销,然后再次登录,就可以避过这个问题。 这个问题已经提交到JIRA中了 JBPM-2508

2.4. 安装脚本

jBPM下载包中包含了一个install目录, 目录中有一个ant的build.xml文件,你可以使用它来 把jBPM安装到你的应用环境中。

最好严格按照这些安装脚本, 进行安装和发布jBPM配置文件。我们可以自定义jBPM配置文件, 但这是不被支持的。

要想调用安装脚本,打开命令行,进入${jbpm.home}/install目录。 使用ant -p你可以看到 这里可以使用的所有脚本。脚本的参数都设置了默认值, 可以快速执行,下面列表给出了可用脚本的概况:

?

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

demo.setup.jboss:安装jboss,把jbpm安装到jboss中, 启动jboss,创建jbpm数据库表结构,部署实例,加载实例身份认证信息, 安装并启动eclipse

demo.setup.tomcat:安装tomcat,把jboss安装到tomcat中, 启动tomcat,创建jbpm数据库表结构,部署实例,加载实例身份认证信息, 安装并启动eclipse

clean.cfg.dir:删除${jbpm.home}/install/generated/cfg 文件夹。 create.cfg:创建一个配置在 ${jbpm.home}/install/generated/cfg下,基于当前的参数。

create.jbpm.schema:在数据库中创建jbpm表 create.user.webapp创建一个基本的webapp在 ${jbpm.home}/install/generated/user-webapp中

delete.jboss:删除安装的jboss delete.tomcat:删除安装的Tomcat

demo.teardown.jboss:删除jbpm数据库的表并停止jboss

demo.teardown.tomcat:停止tomcat和hsqldb服务器(如果需要) drop.jbpm.schema:从数据库中删除jbpm的表 get.eclipse:下载eclipse如果它不存在

get.jboss:下载一个JBoss AS,已经测试过当前的jBPM版本,如果它不存在

get.tomcat:下载一个Tomcat,已经测试过当前的jBPM版本,如果它不存在

hsqldb.databasemanager:启动hsqldb数据库管理器

install.eclipse:解压eclipse,下载eclipse如果它不存在 install.jboss:下载JBoss如果它不存在,并解压 install.jbpm.into.jboss:把jBPM安装到JBoss中

install.tomcat:把tomcat下载到${tomcat.distro.dir}如果tomcat不存在,并解压tomcat

install.jbpm.into.tomcat:把jBPM安装到tomcat中 install.examples.into.tomcat:部署所有的实例流程

install.signavio.into.jboss:把signavio安装到jboss中 install.signavio.into.tomcat把signavio安装到tomcat中 load.example.identities:读取实例用户和用户组数据到数据库 reinstall.jboss:删除之前的jboss安装,并重新安装jboss

? ? ? ? ? ? ? ? ?

reinstall.jboss.and.jbpm:删除之前的jboss安装,并重新安装jboss并把jbpm安装到它里面

reinstall.tomcat:删除之前的tomcat安装,并重新安装tomcat reinstall.tomcat.and.jbpm:删除之前的tomcat安装,并重新安装tomcat并把jbpm安装到它里面

start.eclipse:启动eclipse

start.jboss:启动jboss,等待到jboss启动完,然后让jboss在后台运行

start.tomcat:启动Tomcat,等待到Tomcat启动完,然后让Tomcat在后台运行

stop.jboss:通知jboss停止,但是不等到它完成 stop.tomcat通知Tomcat停止,但是不等到它完成

upgrade.jbpm.schema:更新数据库中的jBPM表到当前版本 要想指定你的配置文件,使用上面的脚本(比如DB表结构生成), 最简单的方法是修改对应的配置文件,在目录${jbpm.home}/install/jdbc。 对应的配置文件会被脚本加载,根据对应的DB。 下面的参数也可以自定义。

? ?

database : 默认值是hsqldb。 可选值为mysql, oracle和postgresql jboss.version : 默认值是5.0.0.GA。 可选值是5.1.0.GA 如果想要自定义这些值,只需要像这样使用-D ant -Ddatabase=postgresql demo.setup.jboss 作为可选方案,你可以在${user.home}/.jbpm4/build.properties 中设置自定义的参数值

2.5. 依赖库和配置文件

我们提供了自动安装jBPM的ant脚本。 这些脚本会将正确的依赖库和正确的配置文件 为你安装到正确的位置。如果你想在你的应用中创建自己的jBPM, 可以参考开发指南获得更多信息。

2.6. JBoss

install.jbpm.into.jboss任务会把jBPM安装到你的JBoss 5中。 进入安装目录下,执行ant -p可以获得更多信息。 这个安装脚本会把jBPM安装为一个JBoss的服务, 因此所有应用都可以使用同一个jBPM的流程引擎。

可以指定-Djboss.home=PathToYourJBossInstallation 来修改你的JBoss的安装路径。

在JBoss中,ProcessEngine可以通过JNDI获得, new

InitialContext().lookup(\, 相同的流程引擎可以通过Configuration.getProcessEngine()获得。

2.7. Tomcat

install.jbpm.into.tomcat任务会把jBPM安装到 你的Tomcat中。

2.8. Signavio基于web的流程编辑器

使用install.signavio.into.jboss和 install.signavio.into.tomcat任务可以将Signavio基于web 的流程编辑器安装到JBoss或Tomcat中。

2.9. 用户web应用

如果你希望把jBPM部署为你的web应用的一部分,可以使用

create.user.webapp这个安装任务。 这会创建一个包含jBPM的web应用,在${jbpm.home}/install/generated/user-webapp目录下。

如果你在JBoss上或其他包含jta.jar的应用服务器上部署了你的应用, 你需要把${jbpm.home}/install/generated/user-webapp/WEB-INF/lib/jta.jar删除。

2.10. 数据库

安装脚本也包含了执行数据库的操作 比如创建表,如果你是第一次安装jBPM, 或者更新数据库使用之前版本的表结构。 删除表也是可选的。

使用任何数据库操作的前提条件是 在${jbpm.home}/install/jdbc中指定你的连接参数。

2.10.1. 创建或删除表结构

要想创建表结构,执行create.jbpm.schema任务 在${jbpm.home}/install目录下。 作为创建表、约束的一部分,涉及的任务会初始化 JBPM4_PROPERTY表, 使用当前的引擎版本(key db.version)和ID生成器版本 (key next.dbid)。

要想删除表结构,只要执行drop.jbpm.schema任务。 注意这个操作会删除jBPM表中的 所有数据。

2.10.2. 更新已存在的数据库

要想更新,执行upgrade.jbpm.schema任务 在${jbpm.home}/install目录下。 更新是一个两步操作。前一步是添加额外的表,列或者约束 这些是在新版本中的。 下一步,插入种子数据。

从4.0到4.1,表JBPM4_VARIABLE添加了一个新列 CLASSNAME_用来支持设置 流程变量的值的自定义类型,hibernate的类型映射。 这个列是可为null的,因为这个功能在4.0中没有支持, 所以没有初始值。 从4.1到4.2,更新过程更有趣一些。

一个新表 JBPM4_PROPERTY 被用来保存引擎范围的数据。

? jBPM版本保存在JBPM4_PROPERTY表中 使用key db.version用来在未来发布中 精确指定标示符。 ? ID生成策略是完全跨数据库的。 下一个有效的ID是通过搜索所有包含主键列的表计算出的, 保存在key next.dbid中 在JBPM4_PROPERTY表中。 ? 流程语言设置为jpdl-4.0 用于所有已经存在的流程定义,对应key langid 在表JBPM4_DEPLOYPROP中。jPDL解析器对应 langid属性来读取流程文档 以此支持向后的兼容。

?

2.11. 流程设计器(GPD)

图形化流程设计器(GPD)使用Eclipse作为其平台, 这一节的内容将介绍如何获得和安装Eclipse, 并把GPD插件安装到eclipse上。

2.11.1. 获得eclipse

你需要Eclipse3.5.0

使用实例安装 或手工下载eclipse: Eclipse IDE for Java EE Developers (163 MB)

eclipse的传统版本无法满足要求, 因为它没有XML编辑器。 Eclipse的Java开发者版也可以工作。

2.11.2. 在eclipse中安装GPD插件

使用Eclipse软件升级(Software Update)机制安装设计器是非常简单的。 在gpd目录下有一个install/src/gpd/jbpm-gpd-site.zip文件, 这就是更新站点(archived update site)的 压缩包。 在Eclipse里添加更新站点的方法:

? ? ? ? ? ? ? ? ?

帮助 --> 安装新软件... 点击 添加...

在 添加站点 对话框中,单击 压缩包...

找到 install/src/gpd/jbpm-gpd-site.zip 并点击 '打开' 点击 确定 在 添加站点 对话框中,会返回到 '安装'对话框 选择出现的 jPDL 4 GPD 更新站点 点击 下一步.. 然后点击 完成 接受协议

当它询问的时候重启eclipse

图 2.1. 添加设计器的更新站点

2.11.3. 配置jBPM运行时

? ? ?

点击 Window --> Preferences

选择 JBoss jBPM --> jBPM 4 --> Runtime Locations 点击 Add...

在 Add Location 对话框中,输入一个名字,比如 jbpm-4.0 然后点击 Search... ? 在 Browse For Folder 对话框中,选择你的jbpm根目录,然后点击 OK ? 点击 OK 在 Add Location 对话框中

?

图 2.2. 定义jBPM依赖库

2.11.4. 定义jBPM用户库

这一节演示如何在你的工作空间定义一个用户库, 用来放置jBPM的库文件。 如果你创建一个新工程, 只需要将用户库全部添加到build path下

? ? ? ? ? ? ? ?

点击窗口 --> 属性(Windows --> Preferences)

选择Java --> 创建路径 --> 用户类库(Java --> Build Path --> User Libraries)

点击新建(New)

类型名字jBPM Libraries

点击添加JARs(Add JARs...) 找到jBPM安装程序下的lib目录

选择lib下的所有jar文件并点击打开(Open) 选择jBPM Libraries作为入口

? ? ? ? ? ? ? ? ?

重新点击添加JARs(Add JARs)

在jBPM的安装程序的根目录下选择jbpm.jar文件 点击打开(Open)

在jbpm.jar下选择源码附件(Source attachment)作为入口 点击编辑(Edit)

在源码附件的配置(Source Attachment Configuration)对话框中,点击目录(External Folder...)

找到jBPM安装程序下的src目录 点击选择(Choose)

点击两次'确定'(Ok)会关闭所有对话框

图 2.3. 定义jBPM类库

2.11.5. 在目录中添加jPDL4模式

如果你想直接编辑XML源码, 最好是在你的XML目录中指定一下模式(schema), 这样当你在编辑流程源码的时候,可以更好的帮助你编写代码。

? ? ? ? ? ? ?

点击窗口 --> 属性(Windows --> Preferences) 选择XML --> 目录(XML --> CataLog) 点击添加(Add)

添加XML目录(Add XML Catalog Entry)的窗口打开

点击map-icon的图标下面的按钮并选择文件系统(File System)

在打开的对话框中, 选择jBPM安装目录下src文件夹中jpdl.xsd文件 点击打开(Open)并且关闭所有的对话框

图 2.4. 在目录中添加jPDL4模式

2.11.6. 导入示例

这一节我们会在Eclipse的安装程序下 导入示例工程

? ? ? ? ? ? ?

选择文件 --> 导入(File --> Import)

选择正常 --> 工作区中已有的工程(General --> Existing Projects into Workspace)

点击下一步(Next)

点击浏览去选择一个根目录(Browse) 通向jBPM安装程序的根目录 点击好(Ok)

示例工程会自动找到并且选中

?

点击完成(Finish)

在配置了jBPM用户依赖库也导入了实例后, 所以的例子可以作为JUnit测试运行了。在一个测试上右击, 选择'Run As' --> 'JUnit Test'。 设置完成,现在你可以开始享受这个最酷的Java流程技术。

2.11.7. 使用ant添加部分文件

你可以使用eclipse和ant整合来处理流程的发布。 我们会告诉你它是如何在例子里工作地。然后你可以把这些复制到你的项目中。 首先,打开ant视图。

? ?

选择Window --> Show View --> Other... --> Ant --> Ant 例子项目中的构建文件build.xml,从包视图拖拽到ant视图。

第 3 章 流程设计器(GPD)

这一章我们讲述了怎样使用流程设计器, 在安装流程设计器和配置好例子之后, 你会看到jPDL流程文件都有一个对应的特殊图标, 在包视图的下面双击某一个这种图标文件,就会在流程设计器中打开一个jPDL流程文件。

图 3.1. 流程设计器

3.1. 创建一个新的流程文件

Ctrl+N将打开向导选择器。

图 3.2. 选择向导对话框

选择 jBPM --> jPDL 4 文件(File). 点击下一步( Next >). 然后新的jPDL 4文件(New jPDL 4 File),就会打开向导。

图 3.3. 创建一个新的流程对话框

选择上一级目录,输入一个文件名字并点击'完成'(Finish), 你便创建了第一个jPDL流程文件。

3.2. 编辑流程文件的源码

GPD里有一个可以修改XML内容的'Source'标签。 可以在标签里直接进行编辑,当你切换到图形时,图形视图会反映出刚才进行的修改。

图 3.4. 使用source视图编辑jPDL

第 4 章 部署业务归档

业务归档是一系列文件的集合 分发在一个jar格式的文件里。。 业务归档中的文件可以使jPDL流程文件,表单,类, 流程图和其他流程资源。

4.1. 部署流程文件和流程资源

流程文件和流程资源必须 部署到流程资源库里 并保存到数据库中。 这儿有一个jBPM的ant任务来部署业务流程归档

(org.jbpm.pvm.internal.ant.JbpmDeployTask)。 JbpmDeployTask可以部署

单独的流程文件和流程归档。 它们通过JDBC连接直接部署到数据库中。 所以在你部署流程之前 需要保证数据库正在运行。

创建和部署流程归档的例子 可以在发布包的examples目录下找到ant脚本(build.xml)。 让我们看一下相关部分。 首先,path用来声明包含jbpm.jar和它的所有依赖库。

你使用的数据库的JDBC驱动jar应该也包含在path中。 MySQL, PostgreSQL和HSQLDB的驱动都包含在发布包中。 但是oracle的驱动你必须从oracle网站上单独下载, 因为我们没有被允许重新分发这个文件。

当一个业务归档被发布时,jBPM扫描 业务归档中所有以.jpdl.xml结尾的文件。 所以那些文件会被当做jPDL流程解析,然后可以用在运行引擎中。 业务归档中所有其他的资源也会作为资源 保存在部署过程中,然后可以通过 RepositoryService类中的 InputStream getResourceAsStream(long deploymentDbid, String resourceName);访问。 为了创建一个业务归档, 可以使用jar任务。

在jbpm-deploy被使用之前,它需要像这样进行声明:

从4.2版本开始,jBPM拥有了一个像jBPM3一样的流程类加载器机制。 从流程中引用的类必须至少在下面三种方式之一是 有效的:

业务存档中的.class文件。和jBPM3中不同,现在 存档文件的根被用来搜索类资源。 所以当类com.superdeluxsandwiches.Order 在流程文件中引用时,它会找到,当它在相同的业务归档中 的入门名称

com/superdeluxsandwiches/Order.class 类会被缓存(key是结合了发布和上下文类加载器), 所以它应该比jBPM 3中执行的更好。 ? 在调用jBPM的web应用中可用的类。 当jBPM部署到服务器端的jboss或tomcat中,jBPM会找到你的 web应用或企业应用,调用jBPM的类。 这是因为你使用了当前上下文类加载器, 在流程执行过程中查找类时。 ? 服务器端可用的类文件。比如像是在 tomcat和jboss的lib目录下的jar。

?

在实例中,一个包含了所有类的examples.jar被创建了, 并把它放在了JBoss服务器配置的lib目录下。 tomcat下操作相同。参考

install.examples.into.tomcat 和install.examples.into.jboss任务。在未来的一个发布版中 我们可能切换到业务存档自身包含的类。

第 5 章 服务

5.1. 流程定义,流程实例和执行

一个流程定义式对过程的步骤的描述。 比如,一个保险公司可以有一个贷款流程定义 描述公司如何处理贷款请求 的步骤的描述。

图 5.1. 贷款流程定义示例

流程实例代表着流程定义的特殊执行例子, 例如:上周五John Doe提出贷款买船, 代表着一个贷款流程定义的流程实例。

一个流程实例包括了所有运行阶段, 其中最典型的属性就是跟踪当前节点的指针。

图 5.2. 贷款流程实例的例子

假设汇款和存档可以同时执行, 那么主流程实例就包含了2个 用来跟踪状态的子节点:

图 5.3. 贷款执行例子

一般情况下,一个流程实例是一个执行树的根节点, 当一个新的流程实例启动时,实际上流程实例就处于根节点的位置, 这时只有它的\子节点\才可以被激活。

使用树状结构的原因在于, 这一概念只有一条执行路径, 使用起来更简单。 业务API不需要了解流程实例和执行之间功能的区别。 因此, API里只有一个执行类型来引用流程实例和执行。

5.2. ProcessEngine流程引擎

在jBPM内部通过各种服务相互作用。 服务接口可以从ProcessEngine中获得, 它是从Configuration构建的。

流程引擎是线程安全的,它可以保存在静态变量中, 甚至JNDI中或者其他重要位置。 在应用中,所有线程和请求都可以使用同一个流程引擎对象, 现在就告诉你怎么获得流程引擎。

这章中涉及到的代码和下一章中关于流程部署的代码, 都来自org.jbpm.examples.services.ServicesTest 例子。 ProcessEngine processEngine = new Configuration() .buildProcessEngine(); 上面的代码演示了如何通过classpath根目录下 默认的配置文件jbpm.cfg.xml创建一个ProcessService。 如果你要指定其他位置的配置文件, 请使用setResource()方法:

ProcessEngine processEngine = new Configuration() .setResource(\ .buildProcessEngine(); 还有其他setXxxx()方法可以获得配置内容, 例如:从InputStream中、 从xml字符串中、从InputSource中、 从URL中或者从文件(File)中。 我们可以根据流程引擎得到 下面的服务:

RepositoryService repositoryService = processEngine.getRepositoryService(); ExecutionService executionService = processEngine.getExecutionService(); TaskService taskService = processEngine.getTaskService(); HistoryService historyService = processEngine.getHistoryService(); ManagementService managementService = processEngine.getManagementService();

在配置中定义的这些流程引擎(ProcessEngine)对象, 也可以根据类型processEngine.get(Class) 或者根据名字processEngine.get(String)来获得。

5.3. Deploying a process部署流程

RepositoryService包含了用来管理发布资源的所有方法。 在第一个例子中,我们会使用RepositoryService 从classpath中部署一个流程资源。 String deploymentid = repositoryService.createDeployment() .addResourceFromClasspath(\xml\ .deploy(); 通过上面的addResourceFromClass方法, 流程定义XML的内容可以从文件, 网址,字符串,输入流或zip输入流中获得。

每次部署都包含了一系列资源。每个资源的内容都是一个字节数组。 jPDL流程文件都是以.jpdl.xml作为扩展名的。 其他资源是任务表单和java类。 部署时要用到一系列资源, 默认会获得多种流程定义和其他的归档类型。 jPDL发布器会自动识别后缀名是.jpdl.xml 的流程文件。

在部署过程中,会把一个id分配给流程定义。 这个id的格式为{key}-{version}, key和version之间使用连字符连接。

如果没有提供key, 会在名字的基础自动生成。 生成的key会把所有不是字母和数字的字符替换成下划线。

同一个名称只能关联到一个key, 反之亦然。

如果没有为流程文件提供版本号, jBPM会自动为它分配一个版本号。 请特别注意那些已经部署了的名字 相同的流程文件的版本号。 它会比已经部署的同一个key的流程定义 里最大的版本号还大。 没有部署相同key的流程定义的版本号会分配为1。

在下面第1个例子里,我们只提供了流程的名字,没有提供其他信息: 假设这个流程是第一次部署, 下面就是它的属性:

表 5.1. 没有key值的属性流程 Property name key Value Source process xml generated generated Insurance claim Insurance_claim version 1 id Insurance_claim-1 generated 第2个例子我们将演示如何通过设置流程的key 来获得更短的id。 这个流程定义的属性就会像下面这样: 表 5.2. 有key值属性的流程 Property name key Value Source Insurance claim process xml ICL process xml generated generated version 1 id ICL-1 5.4. 删除流程定义

删除一个流程定义会把它从数据库中删除。

repositoryService.deleteDeployment(deploymentId); 如果在发布中的流程定义还存在活动的流程实例, 这个方法就会抛出异常。 如果希望级联删除一个发布中流程定义的 所有流程实例, 可以使用deleteDeploymentCascade。

5.5. 启动一个新的流程实例

5.5.1. 最新的流程实例

下面是为流程定义启动一个新的流程实例的最简单也是 最常用的方法: ProcessInstance processInstance = executionService.startProcessInstanceByKey(\上面service的方法会去查找 key为ICL的最新版本的流程定义, 然后在最新的流程定义里启动流程实例。

当insurance claim流程部署了一个新版本, startProcessInstanceByKey方法会自动切换到 最新部署的版本。

5.5.2. 指定流程版本

换句话说,你如果想根据特定的版本启动流程实例, 便可以使用流程定义的id启动流程实例。如下所示:

ProcessInstance processInstance = executionService.startProcessInstanceById(\5.5.3. 使用key

我们可以为新启动的流程实例分配一个key, 这个key是用户执行的时候定义的,有时它会作为“业务key”引用。 一个业务key必须在流程定义的 所有版本范围内是唯一的。通常很容易 在业务流程领域找到这种key。 比如,一个订单id或者一个保险单号。

ProcessInstance processInstance = executionService.startProcessInstanceByKey(\key可以用来创建流程实例的id, 格式为{process-key}.{execution-id}。 所以上面的代码会创建一个id为 ICL.CL92837的流向 (execution)。 如果没有提供用户定义的key,数据库就会把主键作为key。 这样可以使用如下方式获得id:

ProcessInstance processInstance = executionService.startProcessInstanceByKey(\String pid = processInstance.getId(); 最好使用一个用户定义的key。 特别在你的应用代码中,找到这样的key并不困难。提供给一个用户定义的key, 你可以组合流向的id,而不是执行一个基于流程变量的搜索 - 那种方式太消耗资源了。

5.5.4. 使用变量

当一个新的流程实例启动时就会提供一组对象参数。 将这些参数放在variables变量里, 然后可以在流程实例创建和启动时使用。

Map variables = new HashMap(); variables.put(\variables.put(\variables.put(\ ProcessInstance processInstance = executionService.startProcessInstanceByKey(\5.6. 执行等待的流向

当使用一个state活动时,执行(或流程实例) 会在到达state的时候进行等待,直到一个signal(也叫外部触发器)出现。 signalExecution方法可以被用作这种情况。 执行通过一个执行id(字符串)来引用。

在一些情况下,到达state的执行会是流程实例本身。 但是这不是一直会出现的情况。在定时器和同步的情况, 流程是执行树形的根节点。所以我们必须确认你的signal 作用在正确的流程路径上。

获得正确的执行的比较好的方法是给state活动分配一个事件监听器, 像这样: ... 在事件监听器StartExternalWork中,你可以执行那些需要额外完成的部分。 在这个时间监听器里,你也可以通过execution.getId()获得确切的流程id。 那个流程id,在额外的工作完成后, 你会需要它来提供给signal操作的: executionService.signalExecutionById(executionId); 这里有一个可选的(不是太推荐的)方式,来获得流程id, 当流程到达state活动的时候。 只可能通过这种方式获得执行id,如果你知道哪个jBPM API调用了之后, 流程会进入state活动:

// assume that we know that after the next call // the process instance will arrive in state external work ProcessInstance processInstance = executionService.startProcessInstanceById(processDefinitionId); // or ProcessInstance processInstance = // executionService.signalProcessInstanceById(executionId); Execution execution = processInstance.findActiveExecutionIn(\work\String executionId = execution.getId(); 要注意上面的解决方式和应用逻辑联系(太)紧密 通过使用真实业务结构的知识。

5.7. TaskService任务服务

TaskService的主要目的是提供对任务列表的访问途径。 例子代码会展示出如何为id为johndoe 的用户获得任务列表

List taskList = taskService.findPersonalTasks(\一般来说,任务会对应一个表单,然后显示在一些用户接口中。 表单需要可以读写与任务相关的数据。

// read task variables Set variableNames = taskService.getVariableNames(taskId); variables = taskService.getVariables(taskId, variableNames); // write task variables variables = new HashMap(); variables.put(\variables.put(\taskService.setVariables(taskId, variables); taskSerice也用来完成任务。

taskService.completeTask(taskId); taskService.completeTask(taskId, variables);

taskService.completeTask(taskId, outcome); taskService.completeTask(taskId, outcome, variables); 这些API允许提供一个变量map,它在任务完成之前作为流程变量添加到流程里。 它也可能提供一个“外出outcome”,这会用来决定哪个外出转移会被选中。 逻辑如下所示:

如果一个任务拥有一个没用名称的外向转移:

? ? ? ?

taskService.getOutcomes() 返回包含一个null值集合,。 taskService.completeTask(taskId) 会使用这个外向转移。

taskService.completeTask(taskId, null) 会使用这个外向转移。 taskService.completeTask(taskId, \会抛出一个异常。 如果一个任务拥有一个有名字的外向转移:

? ? ? ? ?

gtaskService.getOutcomes() 返回包含这个转移名称的集合。

taskService.completeTask(taskId) 会使用这个单独的外向转移。 taskService.completeTask(taskId, null) 会抛出一个异常(因为这里没有无名称的转移)。

taskService.completeTask(taskId, \会抛出一个异常。 taskService.completeTask(taskId, \会根据给定的名称使用转移。

如果一个任务拥有多个外向转移,其中一个转移没有名称,其他转移都有名称:

?

taskService.getOutcomes() 返回包含一个null值和其他转移名称的集合。

taskService.completeTask(taskId) 会使用没有名字的转移。 ? taskService.completeTask(taskId, null) 会使用没有名字的转移。 ? taskService.completeTask(taskId, \会抛出异常。 ? taskService.completeTask(taskId, \会使用名字为'myName'的转移。

?

如果一个任务拥有多个外向转移,每个转移都拥有唯一的名字:

? ? ? ? ?

taskService.getOutcomes() 返回包含所有转移名称的集合。

taskService.completeTask(taskId) 会抛出异常,因为这里没有无名称的转移。

taskService.completeTask(taskId, null) 会抛出异常,因为这里没有无名称的转移。

taskService.completeTask(taskId, \会抛出异常。 taskService.completeTask(taskId, \会使用名字为'myName'的转移。

任务可以拥有一批候选人。候选人可以是用户也可以是用户组。 用户可以接收自己是候选人的任务。 接收任务的意思是用户会被设置为被分配给任务的人。 在那之后,其他用户就不能接收这个任务了。

人们不应该在任务做工作, 除非他们被分配到这个任务上。 用户界面应该显示表单,并允许用户完成任务, 如果他们被分配到这个任务上。对于有了候选人,但是还没有分配的任务, 唯一应该暴露的操作就是“接收任务”。 更多的任务见第 6.2.6 节 “task” 。

5.8. HistoryService历史服务

在流程实例执行的过程中,会不断触发事件。 从那些事件中,运行和完成流程的历史信息会被收集到历史表中。 HistoryService提供了 对那些信息的访问功能。

如果想查找某一特定流程定义的所有流程实例, 可以像这样操作:

List historyProcessInstances = historyService .createHistoryProcessInstanceQuery() .processDefinitionId(\ .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME) .list(); 单独的活动流程也可以作为HistoryActivityInstance 保存到历史信息中。 List histActInsts = historyService .createHistoryActivityInstanceQuery() .processDefinitionId(\ .activityName(\ .list(); 也可以使用简易方法avgDurationPerActivity和 choiceDistribution。 可以通过javadocs获得这些方法的更多信息。

有时,我们需要获得指定流程实例已经过的节点的完整列表。 下面的查询语句可以用来获得所有已经执行的节点列表:

List histActInsts = historyService .createHistoryActivityInstanceQuery() .processInstanceId(\ .list(); 上面的查询与通过execution id查询有一些不同。有时execution id和流程实例id是不同的, 当一个节点中使用了定时器,execution id中就会使用额外的后缀, 这就会导致当我们通过execution id查询时, 这个节点不会出现在结果列表中。

5.9. ManagementService管理服务

管理服务通常用来管理job。可以通过javadocs获得这些方法的更多信息。 这个功能也是通过控制台暴露出来。

5.10. 查询 API

从jBPM 4.0开始,一个新的API被介绍使用查询系统, 可以覆盖大多数你可以想到的查询。开发者需要编写企业特定查询时 当然也可以使用Hibenrate。但是对大多数用例来说, 查询API是不足够的。 查询可以写成同ideas方式,用于主要的jBPM概念: 流程实例,任务,发布,历史流程,等等。 比如:

List results = executionService.createProcessInstanceQuery() .processDefinitionId(\ss_definition\ .notSuspended() .page(0, 50) .list(); 这个例子返回指定流程定义的所有流程实例, 流程定义不是暂停的。结果支持分页,第一页的前50条数据 会被我们获得。 查询任务也可以使用相同的方式完成:

List myTasks = taskService.createTaskQuery() .processInstanceId(piId) .assignee(\ .page(100, 120) .orderDesc(TaskQuery.PROPERTY_DUEDATE) .list(); 这个查询会获得指定流程实例,分配给John的所有任务,也使用分页,对duedate进行逆序查询。

每个服务拥有操作这些统一查询的功能(比如,查询job通过

ManagementService,查询完成的 流程实例通过HistoryService。 可以参考服务的javadoc了解这些查询API的所有细节。)

第 6 章 jPDL

这章将会解释用来描述流程定义的 jPDL文件格式。jDPL是jBPM的突出的流程语言。jPDL的目标 是尽量精简和尽可能的开发者友好,在提供所有你期望 从BPM流程语言中获得功能的同时。

jPDL的schema文件包含了比这个文档中更多的属性和元素。 这个文档解释了jPDL中稳定的被支持的部分。 试验性的、不支持的jPDL特性可以在开发者指南中找到。

下面是一个jPDL流程文件的例子:

6.1. process流程处理

顶级元素(element)是流程处理定义。 表 6.1. process流程处理的属性 属性 name名称 类型 文本 默认值 是否必须 必须 描述 在与用户交互时, 作为流程名字显示的一个名字或是标签。 key键 用来辨别不同的流程定字母如果省略,key中义。 拥有同一个key的流或数的非字母和非数可选程会有多个版本。 对于所字,下字的字符会被替(optional) 有已发布的流程版本,划线 换为 下划线。 key-name这种组合都必须是 完全一样的。 比已部署的key相同的流程版本号高1, 如果还没有与之相同的可选 key的流程被部署,那么版本就从1开始。 version整型 版本 流程的版本号 表 6.2. process流程的元素

元素 description描述 个数 0个或1个 描述文本 流程中会有很多活动, 至少要有1个是启动的活动。 描述 activities活动 至少1个 6.2. 控制流程Activities活动

6.2.1. start启动

说明一个流程的实例从哪里开始。 在一个流程里必须有一个开始节点。 一个流程必须至少拥有一个开始节点。 开始节点必须有一个向外的流向,这个流向会在流程启动的时候执行。

已知的限制:直到现在, 一个流程处理只能有一个启动节点(start)。 表 6.3. start启动的属性 默认是否属性 类型 值 必须 name名文 称 本 表 6.4. start启动的元素

元素 个数 描述 可选 描述 活动的名字,在启动活动没有内部的转移(transition)时, name名称是可选的。 transition转移 1 向外的转移 6.2.2. State状态节点

一个等待状态节点。 流程处理的流向会在外部触发器调用提供的API之前一直等待。 状态节点和其他的活动不一样, 它没有其他任何属性或元素。

6.2.2.1. 序列状态节点

让我们看一个用序列连接状态 和转移的例子。

图 6.1. 序列状态节点

下列代码将启动一个流向:

ProcessInstance processInstance = executionService.startProcessInstanceByKey(\创建的流程处理实例会停留在状态节点a的位置, 使用signalExecution方法就会触发 一个外部触发器。

Execution executionInA = processInstance.findActiveExecutionIn(\assertNotNull(executionInA); processInstance = executionService.signalExecutionById(executionInA.getId()); Execution executionInB = processInstance.findActiveExecutionIn(\assertNotNull(executionInB); processInstance = executionService.signalExecutionById(executionInB.getId()); Execution executionInC = processInstance.findActiveExecutionIn(\assertNotNull(executionInC); 6.2.2.2. 可选择的状态节点

在第2个状态节点的例子里, 我们将演示如何使用状态节点实现 路径的选择。

图 6.2. 状态节点中的选择

让我们在这个流程处理定义里启动一个新的流程实例。 ProcessInstance processInstance = executionService .startProcessInstanceByKey(\现在,流向到达wait for response状态节点了。 流向会一直等待到外部触发器的出现。 这里的状态节点拥有多个向外的转移, 外部触发器将为向外的转移提供不同的信号名(signalName), 下面我们将提供accept信号名(signalName):

String executionId = processInstance .findActiveExecutionIn(\ .getId(); processInstance = executionService.signalExecutionById(executionId, \ assertTrue(processInstance.isActive(\流向会沿着名字是accept的向外的转移继续进行。 同样,当使用reject作为参数触发signalExecutionXxx方法时。流 向会沿着名字是reject的向外的转移 继续进行。

6.2.3. decision决定节点

在多个选择中选择一条路径。也可以当做是一个决定。 一个决定活动拥有很多个向外的转移。当一个流向到达一个决定活动时, 会自动执行并决定交给哪个向外的转移。

一个决定节点应该配置成下面三个方式之一。

6.2.3.1. decision决定条件

decision中会运行并判断每一个transition里的判断条件。 当遇到一个嵌套条件是true或者没有设置判断条件的转移, 那么转移就会被运行。 表 6.5. exclusive.transition.condition 属性 属性 类型 默认值 是否必须? 描述 将被运required行的 必须 指定脚本 指定expr中执行的 脚本语言的种类 expr expression lang expression 从脚本引擎配置里得到的默认代表性可选 language 语言(default-expression-language) 例子:

图 6.3. 流程处理的决定条件例子

在使用good content启动一个流程之后

Map variables = new HashMap(); variables.put(\ProcessInstance processInstance = executionService.startProcessInstanceByKey(\variables); submit document活动会变成活动的

assertTrue(processInstance.isActive(\参考实例中的单元测试,了解更多的场景。

6.2.3.2. decision expression唯一性表达式

decision表达式返回类型为字符串的 向外转移的名字。 表 6.6. 决定属性 属性 类型 默认值 是否必须? 描述 将被运required行的指必须 定 脚本 指定expr中执行的脚本语言的 种类。 expr expression 从脚本引擎配置里得到的默认指定的expression lang 脚本语言language (default-expression-language) 可选 例子:

图 6.4. 流程处理的决定表达式例子

当你使用good content启动一个新的流程实例,代码如下:

Map variables = new HashMap(); variables.put(\ProcessInstance processInstance = executionService.startProcessInstanceByKey(\variables); 然后新流程会到达submit document活动。 参考实例中的单元测试,获得其他场景。

6.2.3.3. Decision handler决定处理器

唯一性管理是继承了DecisionHandler接口的java类。 决定处理器负责选择 向外转移。

public interface DecisionHandler { String decide(OpenExecution execution); } 这个handler被列为decision的子元素。 配置属性和decision的handler的内容元素 可以在第 6.7 节 “用户代码”中找到。 下面是一个决定使用DecisionHandler的流程处理例子:

图 6.5. 流程处理的exclusive管理例子

下面是ContentEvalation类:

public class ContentEvaluation implements DecisionHandler { public String decide(OpenExecution execution) { String content = (String) execution.getVariable(\ if (content.equals(\ return \ } if (content.equals(\ return \ } return \ } } 当你启动流程处理实例, 并为变量content提供值you're great时, ContentEvalation就会返回字符串good, 流程处理实例便会到达Submit document活动。

6.2.4. concurrency并发

流程的并发路径可以使用 fork 和 join 活动来建模。下面的表格描述了 join 的属性;fork没有特别的属性。 表 6.7. join属性:

是否默认值 必须? 传入转移的数目 属性 类型 描述 multiplicity 整数或表达式 在这个join活动之前需要到达的执行的数目, 可然后一个执行 会沿着选 join的单独的外向转移向外执行。 lockmode {none, read, upgrade, upgrade_nowait, write} hibernate的锁定模式,应用在上级执行, 来防可upgrade 止两个还没到达join的选 同步事务看到对方, 这会导致死锁。 6.2.4.1. 使用 fork实现并行分支

fork 活动允许将一个单独的流程路径分成 两个或多个分支,这些流程分支可以同步执行。

图 6.6. 流程处理的并发例子

本文来源:https://www.bwwdw.com/article/d83g.html

Top