You are browsing the archive for Java开源.

jBPM开发:流程图的组成元素

二月 21, 2009 in Java开源

 

上一篇文章中我们实现了一个简单的审批流程,但是对于流程中涉及的元素没有做任何的解释,本文主要针对的流程的主要组成元素进行描述。

内容根据 jBPM的用户手册进行描述,主要描述一下后面将要实现的一个实际例子中所涉及的元素。

 

一,基本概念和名次解释

流程定义(Process Definition)是基于定向图表示的一个业务流程的声明,由节点和转换组成,图中的每个节点都有一个特定的类型,节点类型定义了运行时的行为,流程定义有且只有一个开始状态。

令牌(Token)是执行的一个路线,令牌是运行的时间概念,用来维护图中指向节点的指针。

流程实例(Process Instance)是一个流程定义执行的实例,当一个流程实例被建立后,一个令牌也为主要执行路线建立了,这个令牌称为这个流程实例的根令牌,它的位置处于流程定义的开始状态。

一个信号(Signal)指示令牌继续流程图的执行,当接受到无名的信号时,令牌将用缺省的离开转换离开节点,当转换名字在信号中明确指定,令牌将使用指定的转换离开节点。

在令牌进入节点后,节点被执行,节点负责继续图的执行。图执行的连续是通过让令牌离开节点来完成的,每个节点类型为了连续图执行实现了不同的行为,一个节点如果不能传播执行将被认为是一个状态。

动作(Action)是在流程执行中在事件上执行的一段Java代码。动作是一种在图形表示之外增加更多技术细节的机制,一旦图放在某个地方,它可以使用动作来修饰。

 

二,节点的职责

流程图由节点(Node)和转换(Transition)组成。每个接点有一个指定的类型,节点类型定义了当执行到达这个节点的时候将发生什么,jBPM 预定义了一套节点类型,开发人员可以编写自己的代码实现节点的行为。

节点有2个主要责任:

首先是执行Java代码,Java代码和节点的功能相关,如建立一个新的任务实例、发送一个通知、更新数据库等等;

其次,节点负责传播流程的执行,节点有下列可选的传播流程执行的选项:

  1. 不传播执行。节点的行为是作为一个等待的状态
  2. 执行节点的离开转换来传播执行。令牌到达节点后通过一个调用 executionContext.leaveNode(String)方法来达到离开转换,节点可执行一些客户化的程序逻辑,然后自动继续执行流程,不会等待。
  3. 建立新的执行路线。节点可以决定建立新的令牌。每个新令牌表示一个新的执行路线,并且每个新令牌可以通过节点的离开转换被调用。一个很好的例子就是fork(分支)节点模式的行为。
  4. 结束执行路线。节点可以决定结束执行路线,令牌一旦结束表明执行路线执行完成。

 

三,常用的节点类型

基于实用的原则,本节只介绍一些常用的节点类型,并没有覆盖全部的类型。

  1. 任务节点(Task Node)clip_image001任务型接点代表一个或多个可以被人执行的任务。当执行到达一个任务节点,任务实例将在工作流参与者任务清单中被建立,之后节点将被作为一个等待节点。因此当用户执行他们的任务,任务完成将触发执行继续。换句话说,令牌将调用一个新的信号。
  2. 状态(State)clip_image001[5]状态是一个单纯的等待状态。它没有任务实例在任务清单中创建,这在流程需要等待外部系统的时候非常有用。如:以上的节点入口中(node-enter事件中的动作),一个消息将被发送到外部系统,随后流程进入等待状态,当外部系统发回消息的时候,发送token.signal()方法触发流程继续往下执行
  3. 决策(Decision)clip_image001[7] 在jBPM中有两个方法来进行决策,它们之间的主要区别在于由“谁”来进行决策,其中一个是由流程来做出决定,另外一个是通过外部的实体来提供一个决策的结果。
  4. 当有一个流程需要来做一个决策的时候就要使用一个决策节点。有两个方式来指定决策的标准,最简单的方式是给转换增加一个条件,条件是一个返回结果为boolean的EL表达是或beanshell脚本表达。

    在运行时决策代码会被转换反复调用(按照XML指定的顺序)来评估每个条件,但条件值为“true”的时候就会发生转换,如果所有的条件都返回“false”的话,默认的转换将被执行(XML定义中的第一个)。

    另外一种方式是使用一个表达式来返回转换的名称,使用属性“expression”,可以为决策节点来指定一个表达式来决定如何转换。

    还有一种方式是指定一个“handler”属性,它需要是DecisionHandler接口的实现,在Java类中决策的转换由DecisionHandler实现中的决策方法(decide-method)来返回。

    当决策是由外部合作者来决定(含义:不是流程定义的一部分),可以用多个转换离开状态或等待状态节点,然后转换可以提供外部的触发在等待状态完成后继续执行。比如 Token.signal(String transitionName) and TaskInstance.end(String transitionName).

  5. 分支(fork)clip_image001[9] 一个分支把一个执行路线分割成多个并行的执行路线。默认分支的行为是为每个分支转换建立一个子令牌,在令牌要到达的分支之间建立一个父子关系
  6. 联合(join)clip_image001[11] 默认的联合假设所有来自同一个父亲的子令牌结合,上面介绍的分支发生的时候并且所有令牌分支创建之后,而且所有分支都到达同一个联合时,当全部令牌都进入联合的时候,联合就结束了。
  7. 节点(Node)clip_image001[13]节点类型是用来完成在节点中编写自己的程序代码,它需要一个动作的子元素,用来在执行路径到达节点的时候执行,编写在actionhandler中的代码可以实现任何的逻辑,同时它必须负责传播执行。他和任务节点的区别就在于它不需要等待用户做出响应就流程继续往后执行,而任务节点只有用户做出响应后流程才会继续

 

四, 转换

转换有一个来源节点和一个目标节点,来源节点通过一个from属性来指定,目标节点通过一个to属性来指定

一个转换有一个可选的名称,很多jBPM都依赖于唯一的转换名称,如果有多个转换都拥有同样的名称,那第一个转换将会被选中执行,重复的转换名称将会导致Map getLeavingTransitionsMap() 方法返回的元素数量少于 List getLeavingTransitions() ,列表中默认的转换是第一个转换。

 

五,动作(Actions)

动作其实就是一段 Java 代码,在有事件发生时执行流程,流程的图在软件需求社区是一个很重要的指令,但是图只是将要实现软件的一个视觉(投射),它隐藏了技术的实现细节。动作是在图形化表示之外加入技术细节的机制,当一个图被创建,它可以用加入动作来进行装饰,这样通过 Java 代码在不修改图结构的情况下可以和图关联起来了,主要的事件类型是:进入节点、离开节点执行转换

 

下一篇文章将描述变量的上下文。

 

jBPM开发:实现一个简单的审批流程

二月 18, 2009 in Java开源

 

本文使用jBPM自带的身份认证组件模型来实现一个简单的审批流程,其中使用到的技术点在本文中暂且

不解释,就先来一个先睹为快,对jBPM最常用的功能有一个感性的认识,在后面的文章中慢慢解释各个技术点,

进一步的加深jBPM的应用。

 

1,数据准备

 

jBPM的身份认证组件基于以下几张表:

  1. JBPM_ID_GROUP:组模型的层次关系
  2. JBPM_ID_MEMBERSHIP:模型组下的成员关系
  3. JBPM_ID_USER:成员信息

 

为了进行展示,我们先创建一些基础数据来测试后面创建的审批工作流

1
2
3
4
5
6
7
8
9
10
11
12
13
insert into JBPM_ID_GROUP (ID_, CLASS_, NAME_, TYPE_, PARENT_)
values (1, 'G', '资源管理室', 'UM', 2);
 
insert into JBPM_ID_MEMBERSHIP (ID_, CLASS_, NAME_, ROLE_, USER_, GROUP_)
values (6, 'M', null, 'role_superadmin', 1, 1);
insert into JBPM_ID_MEMBERSHIP (ID_, CLASS_, NAME_, ROLE_, USER_, GROUP_)
values (7, 'M', null, 'departmentManager', 2, 1);
 
insert into JBPM_ID_USER (ID_, CLASS_, NAME_, EMAIL_, PASSWORD_)
values (1, 'A', 'aronehome1', 'arone.lijun@gmail.com', '111111');
insert into JBPM_ID_USER (ID_, CLASS_, NAME_, EMAIL_, PASSWORD_)
values (2, 'A', 'aronehome1', 'arone.lijun@gmail.com', '111111');
commit;

 

2,定义流程

 

使用jBPM的流程定义向导来创建一个新的流程定义

  1. 首先在src/java目录下创建java包结构com.hand.processes
  2. 启动jBPM流程定义向导定义流程:表达式审批流程
    Source Folder:jBPMDemo/src/java/com/hand/processes
    Process Name:expression_approve
  3. 选择左边工具面板中的图标,后点击右边的画布创建流程中的各节点
  4. 添加节点后使用 clip_image001 将各节点连接起来

 

完成后的效果如下图:

clip_image002

 

<<Task Node>>审批任务节点中,右键选择审批任务节点,添加一个任务,如下图:

clip_image002[6]

 

clip_image002[8]

 

Task Name:审批

Assignment Type:Expression

Assignment Expression:group(资源管理室)–>member(role_superadmin)

这个表达式利用了jBPM自带的身份组件模型,只要指定组的名称和角色的名称,jBPM会自动找出符合条件的用户,并为她们创建任务实例。

 

上面的审批流程说明流程启动之后就等待一个任务的执行,这个任务由组为:资源管理室,并且角色为:role_superadmin 的用户,

因此我们上面的数据中找到的用户就是aronehome,流程会等待aronehome这个用户的一个动作之后才会继续往下执行,否则一直处于等待状态。

 

 

3,发布流程到数据库

 

由于jBPM流程运行的时候,它是从数据库中读取相关的流程定义信息,因此开发完成流程之后需要先将流程定义信息发布到数据中。

在Myeclipse设计器中选择Deployment,选择本地保存方式,先将流程定义文件和图片打包为zip文件,选择如下图点击“Save Without Deploying…”按钮

clip_image002[10]

 

然后运行之前创建的“流程发布页面”:

http://localhost:7001/jbpmWeb/deploy.html

选择保存的zip文件,发布后可以到数据库中去验证流程是否成功。

1
SELECT * FROM jbpm_processdefinition WHERE name_ = '表达式审批流程';

 

 

4,启动jBPM流程

 

启动流程可以采用如下的两种方法

  1. 使用jBPM控制台管理页面来启动流程(操作步骤省略)
  2. 编写测试脚本来启动流程,主要的启动代码:
1
2
ProcessInstance processInstance = JbpmConfiguration.parseResource("jbpm.cfg.xml").createJbpmContext().newProcessInstance("表达式审批流程");
processInstance.signal();

 

 

5,查看流程执行图

 

先查询出流程中的任务实例ID(此SQL仅能用于开发中不严格的数据查询):

1
2
3
4
5
6
7
8
SELECT id_, name_, actorid_
  FROM jbpm_taskinstance
 WHERE token_ = (SELECT MAX(roottoken_)
                   FROM jbpm_processinstance
                  WHERE processdefinition_ =
                        (SELECT MAX(id_)
                           FROM jbpm_processdefinition
                          WHERE name_ = '表达式审批流程'));

 

运行之前创建的“流程执行情况查看页面”:

http://localhost:7001/jbpmWeb/showDiagram.jsp

输入上面SQL查询处理的taskinstance id,效果图如下:

clip_image002[12]

 

上图说明流程执行到审批这个任务节点,等待用户做出响应。

 

 

下一篇文章开始描述jBPM的主要组成。

 

 

jBPM开发:配置Eclipse IDE开发环境

二月 17, 2009 in Java开源

 

上文已经介绍了如何将jBPM Console应用发布到 Weblogic服务器,下面描述如何配置 Eclipse 开发环境,以提高后面jBPM开发的工作效率。

 

Jboss为jBPM提供了基于Eclipse的插件工具,因此开发人员可以使用原生的Eclipse IDE,也可以使用Myeclipse这样的集成工具。

本人使用Myeclispe作为开发工具,因此本文基于Myeclipse作为配置的环境

 

一、配置开发工具

 

1,安装Eclipse Designer到Myeclipse6

将jbpm-jpdl-suite-3.2.3/designer/eclipse/plugins目录下的文件及文件夹拷贝到myeclipse安装目录下的eclipse/plugins目录下之后,重起myeclipse即可

 

2,安装Eclipse Designer到Myeclipse7

首先是将jBPM设计器的插件,即jbpm-jpdl-suite-3.2.3/designer/eclipse/plugins目录下的文件及文件夹 拷贝到一个特定的目录,

如:D:\Genuitec\MyPlugins\jbpm-jpdl-designer-3.1.5;

后修改CreatePluginsConfig.java中的代码:new CreatePluginsConfig(“D:\\Genuitec\\MyPlugins\\jbpm-jpdl-designer-3.0.11″).print();

将路径修改为jBPM设计器插件的目录,并使用双斜杠(\\)代替单斜杠(\),运行它之后控制台会有结果输出。

之后将输出的结果拷贝添加到Myeclipse7安装目录下的configuration\org.eclipse.equinox.simpleconfigurator\bundles.info文件中

以clean的方式启动Myeclipse,命令:myeclipse.exe –clean

CreatePluginsConfig请参考前面的博文MyEclipse7下安装插件

 

3,添加jBPM设计和运行环境

启动myeclipse之后,通过windows –> Preferences –> JBoss jBPM添加jBPM运行环境,路径指向jbpm-jpdl-suite-3.2.3的位置。

clip_image002

 

 

二、配置开发环境

 

1,创建jBPM流程项目

安装jBPM设计器之后,可以在myeclipse新建向导中找到JBoss jBPM –> Process Project ,根据向导创建一个jBPM流程项目。

创建之后的jBPM项目结构如下:

clip_image002[6]

 

2,修改数据库连接信息

修改hibernate.cfg.xml文件中关于数据库连接的信息,可以根据实际情况选择其中的一种连接方式:JDBC Driver和JNDI DataSource。

JDBC Driver的方式:

1
2
3
4
5
org.hibernate.dialect.Oracle9Dialect
oracle.jdbc.driver.OracleDriver
jdbc:oracle:thin:@localhost:1521:xe
gdcms
gdcms1

JNDI DataSource方式:

1
java:comp/env/jdbc/jbpmDB

采用JNDI的方式需要在Weblogic服务器上面定义DataSource。

 

3,添加jar库文件

路径:<项目> –> 属性 –> Java Build Path –> Libraries –> Add External JARs

添加如下的库文件:
ojdbc14.jar
c3p0-0.9.0.jar:如果hibernate.cfg.xml配置中启用c3p0连接池需要提供
hibernate3.jar
jbpm-webapp-3.1.2.jar

 

 

三、配置本地发布环境

 

在进行jBPM工作流开发的过程中,开发人员可以在jBPM管理控制台中发布流程定义到数据库中;

也可以通过在Myeclipse工具中配置web应用来发布流程定义。本节描述如何利用Myeclipse在开发环境

中配置web应用来发布流程定义以及查看执行的流程图。

 

1,创建Web项目

利用Myeclipse的Web Project新建向导创建一个Web项目。

clip_image002[8]

 

2,拷贝配置和tag库文件

将上面创建jBPM项目后并配置好的相关配置文件拷贝到新建的web应用项目下,需要将jBPM项目下src/config.files文件目录拷贝到web项目下

从下载的jBPM套件中将jbpm.tld文件拷贝到WEB-INF目录下

添加jar库文件,参考2.3

 

3,修改web.xml配置

jBPM上传流程文件的时候会将流程图(jpg)文件上传到数据库表jbpm_bytearray中,因此需要添加servlet来处理图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	UploadServlet
	org.jbpm.webapp.servlet.UploadServlet
 
 
	ProcessImageServlet
	org.jbpm.webapp.servlet.ProcessImageServlet
 
 
	UploadServlet
	/upload
 
 
	ProcessImageServlet
	/processimage

 

4,添加weblogic.xml配置文件

添加weblogic.xml文件到WEB-INF目录下,主要内容包括:

1
2
3
4
 
		true
 
     /jbpmWeb

 

5,增加发布流程页面

在WebRoot路径下添加jBPM流程发布流程页面deploy.html,页面的代码如下:

?View Code HTML4STRICT
1
2
3
4
5
6
7
8
9
10
 
    <title>Deploy a Process Archive File</title>
 
 
    <h2>Let's Deploy a Process</h2>
    <form action="upload" enctype="multipart/form-data" method="post" />
      Select the file you want to upload : 
      <br>
 
    </form>

运行效果:

clip_image002[10]

 

6,增加流程执行情况查看页面

在WebRoot路径下添加jBPM流程运行页面showDiagram.jsp,只要流程运行之后,提供任务的实例ID就可以查询出流程执行情况,

并标记出停留在哪个任务节点上面,页面的代码如下:

?View Code HTML4STRICT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
 
 
 
 
 
<title>提供任务实例ID查询流程执行图</title>
 
 
 <form method="post" action="showDiagram.jsp">
	<p>
		Task Instance ID: <br>
 
	</p>
</form>

效果图:

clip_image002[12]

 

 

下一篇文章就正式进入jBPM工作流的开发。

 

Myeclipse工程项目文件:Download Oracle EBS二次开发系列视频教程之在Oracle EBS中注册Form和Function(5) Version 1

 

c3p0连接池连接Oracle报ORA-12519

一月 15, 2009 in Java开源

 

在使用Spring集成Hibernate开发Web应用时,数据库持久层采用Hibernate,我在开发过程中为了测试的方便,

就在本机安装了Oracle Express 10g数据库,然后在hibernate.cfg.xml配置文件中添加c3p0作为连接池,

但是在开发过程中,频繁的进行测试,会发现经常爆出如下的错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java.sql.SQLException: Listener refused the connection with the following error:
ORA-12519, TNS:no appropriate service handler found
The Connection descriptor used by the client was:
localhost:1521:xe
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:261)
  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:387)
  at oracle.jdbc.driver.PhysicalConnection.(PhysicalConnection.java:420)
  at oracle.jdbc.driver.T4CConnection.(T4CConnection.java:165)
  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:35)
  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:801)
  at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:81)
  at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:96)
  at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1.acquireResource(C3P0PooledConnectionPool.java:89)
  at com.mchange.v2.resourcepool.BasicResourcePool.acquireUntil(BasicResourcePool.java:665)
  at com.mchange.v2.resourcepool.BasicResourcePool.access$500(BasicResourcePool.java:32)
  at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1204)
  at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:368)

 

上面的错误是由于Oracle Express 10g的默认配置连接数只有20,而在hibernate.cfg.xml配置使用c3p0连接池的最大连接数远远超过了这个数据库允许

的数量,因此但频繁的去连接数据库的时候,无法获得连接,数据库Listner就直接拒绝连接的请求,因此只要修改c3p0连接池最大最小连接数为

合适的值即可,如下的配置:

1
2
5
10

 

 

MyEclipse7下安装插件

一月 10, 2009 in Java开源

?

?

MyEclipse7下安装插件和原来的版本有很大的差异,很多插件无法进行自动安装,下面记录一下从网上找到的解决方案。

?

下面以安装jbpm-jpdl-designer-3.0.11插件为实例进行说明:

1,下载插件,解压后将plugin中的文件拷贝到目录D:\Genuitec\MyPlugins\jbpm-jpdl-designer-3.0.11

2,修改com.oracleseeker.tools.CreatePluginsConfig.main中文件路径的值,需要将斜杠修改为双斜杠,并运行它

3,进入MyEclipse7的安装路径,找到Genuitec\MyEclipse 7.0\configuration\org.eclipse.equinox.simpleconfigurator\bundles.info

4,将2运行时控制台输出的内容添加到bundles.info文件的最后

5,通过命令行以clean模式启动MyEclipse:myeclipse.exe –clean

?

CreatePluginsConfig类的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.oracleseeker.tools;
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;
 
public class CreatePluginsConfig {
 
	private String path;
 
	public CreatePluginsConfig(String path) {
		this.path = path;
	}
 
	public void print() {
		List list = getFileList(path);
		if (list == null) {
			return;
		}
 
		int length = list.size();
		for (int i = 0; i &lt; length; i++) {
			String result = "";
			String thePath = getFormatPath(getString(list.get(i)));
			File file = new File(thePath);
			if (file.isDirectory()) {
				String fileName = file.getName();
				if (fileName.indexOf("_") &lt; 0) {
					continue;
				}
				String[] filenames = fileName.split("_");
				String filename1 = filenames[0];
				String filename2 = filenames[1];
				result = filename1 + "," + filename2 + ",file:/" + path + "\\"
						+ fileName + "\\,4,false";
				System.out.println(result);
			} else if (file.isFile()) {
				String fileName = file.getName();
				if (fileName.indexOf("_") &lt; 0) {
					continue;
				}
				int last = fileName.lastIndexOf("_");
				String filename1 = fileName.substring(0, last);
				String filename2 = fileName.substring(last + 1, fileName
						.length() - 4);
				result = filename1 + "," + filename2 + ",file:/" + path + "\\"
						+ fileName + ",4,false";
				System.out.println(result);
			}
		}
	}
 
	public List getFileList(String path) {
		path = getFormatPath(path);
		path = path + "/";
		File filePath = new File(path);
		if (!filePath.isDirectory()) {
			return null;
		}
		String[] filelist = filePath.list();
		List filelistFilter = new ArrayList();
 
		for (int i = 0; i &lt; filelist.length; i++) {
			String tempfilename = getFormatPath(path + filelist[i]);
			filelistFilter.add(tempfilename);
		}
		return filelistFilter;
	}
 
	public String getString(Object object) {
		if (object == null) {
			return "";
		}
		return String.valueOf(object);
	}
 
	public String getFormatPath(String path) {
		path = path.replaceAll("\\\\", "/");
		path = path.replaceAll("//", "/");
		return path;
	}
 
	public static void main(String[] args) {
		//new CreatePluginsConfig("C:\\eclipse-plugins\\plugins\\JBossTools-2.1.2.GA-ALL-win32").print();
		new CreatePluginsConfig("D:\\Genuitec\\MyPlugins\\jbpm-jpdl-designer-3.0.11").print();
 
	}
}