JBPM节点

1、Node节点
Node节点是一个自动完成节点,如果没有在Node节点上定义Action,流程达到Node节点后不会停留,而是继续往下执行到Node节点的下一个节点。利用之前的Helloworld例子,我们在Node节点上加上一个Action(Action的执行是在node-enter之后node-leave之前)
Xml代码
<node name="node1">
<action class="com.royzhou.action.NodeAction"></action>
<transition to="state1"></transition>
</node>

<node name="node1">
<action class="com.royzhou.action.NodeAction"></action>
<transition to="state1"></transition>
</node>

Action类如下:
Java代码
package com.royzhou.action;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

public class NodeAction implements ActionHandler {
public void execute(ExecutionContext executionContext) throws Exception {
System.out.println("node action……………………");
}
}

package com.royzhou.action;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;

public class NodeAction implements ActionHandler {
public void execute(ExecutionContext executionContext) throws Exception {
System.out.println("node action……………………");
}
}

测试类如下:
Java代码
package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class HelloWorldDB {
public static void deploy() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/helloworld/helloworld.zip ");
ZipInputStream zis = new ZipInputStream(fis);
ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
jbpmContext.deployProcessDefinition(processDefinition);
fis.close();
zis.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
HelloWorldDB.deploy();
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
jbpmContext.setActorId("royzhou");
//获取最新版本的流程定义对象
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("helloworld");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
//得到流程令牌
Token token = processInstance.getRootToken();

//打印流程当前所处节点
System.out.println("1:流程现在所处节点:" + token.getNode().getName());

//触发流程流转到下一个节点Node
token.signal();

/**
* 注意因为Node节点设置Action
* 所以流程会停留在Node节点
*/
System.out.println("2:流程现在所处节点:" + token.getNode().getName());

//触发流程流转到下一个节点State
token.signal();
System.out.println("3:流程现在所处节点:" + token.getNode().getName());
token.signal();
System.out.println("4:流程现在所处节点:" + token.getNode().getName());
System.out.println("流程状态是否结束:" + token.getProcessInstance().hasEnded());
jbpmContext.close();
}
}

package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class HelloWorldDB {
public static void deploy() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/helloworld/helloworld.zip ");
ZipInputStream zis = new ZipInputStream(fis);
ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
jbpmContext.deployProcessDefinition(processDefinition);
fis.close();
zis.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
HelloWorldDB.deploy();
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
jbpmContext.setActorId("royzhou");
//获取最新版本的流程定义对象
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("helloworld");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
//得到流程令牌
Token token = processInstance.getRootToken();

//打印流程当前所处节点
System.out.println("1:流程现在所处节点:" + token.getNode().getName());

//触发流程流转到下一个节点Node
token.signal();

/**
* 注意因为Node节点设置Action
* 所以流程会停留在Node节点
*/
System.out.println("2:流程现在所处节点:" + token.getNode().getName());

//触发流程流转到下一个节点State
token.signal();
System.out.println("3:流程现在所处节点:" + token.getNode().getName());
token.signal();
System.out.println("4:流程现在所处节点:" + token.getNode().getName());
System.out.println("流程状态是否结束:" + token.getProcessInstance().hasEnded());
jbpmContext.close();
}
}

测试结果如下:(验证了在Node上设置Action的时候,流程处于等待状态)
1:流程现在所处节点:start-state1
node action……………………
2:流程现在所处节点:node1
3:流程现在所处节点:state1
4:流程现在所处节点:end-state1
流程状态是否结束:true

2、State节点
State节点属性类似Node,不过当流程流转到State节点时就会停下来,直到外部向其发送流转的命令,如signal().

3、Task-Node
Task Node节点在Jbpm中是很重要的一个节点,可以用来添加任务,产生任务实例。一个Task Node 可以定义多个Task,为Task分配执行人等等。下面我们通过一个例子来解释Task Node。
Xml代码
<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="tasknode">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<task name="mytask">
<assignment actor-id="royzhou"></assignment>
</task>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>

<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="tasknode">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<task name="mytask">
<assignment actor-id="royzhou"></assignment>
</task>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

上面流程文件定义了一个Task Node ,在Task Node下面定义了一个Task节点,分配给了royzhou这个人(实际开发中的任务分配会更加复杂)
接下来我们开始写测试类:
Java代码
package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class TaskNode {

public static void deploy() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/tasknode/tasknode.zip");
ZipInputStream zis = new ZipInputStream(fis);
ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
jbpmContext.deployProcessDefinition(processDefinition);
fis.close();
zis.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
TaskNode.deploy();
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("tasknode");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
token.signal();
System.out.println("流程现在所处节点:" + token.getNode().getName());
jbpmContext.close();
}
}

package com.royzhou.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class TaskNode {

public static void deploy() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/tasknode/tasknode.zip");
ZipInputStream zis = new ZipInputStream(fis);
ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);
jbpmContext.deployProcessDefinition(processDefinition);
fis.close();
zis.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
TaskNode.deploy();
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("tasknode");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
token.signal();
System.out.println("流程现在所处节点:" + token.getNode().getName());
jbpmContext.close();
}
}

后台打印结果:
流程现在所处节点:task-node1
查看jbpm_taskinstance表看到一个名叫mytask的任务,指定给了royzhou说明我们的任务创建成功了。
Task Node有几个比较重要的属性:
Signal:
last:最后一个完成之后继续往下流转,如果没有任务被创建直接流转到下一节点
last-wait:最后一个完成之后继续往下流转,如果没有任务被创建处于等待状态
first:只要有一个完成就继续往下流转,如果没有任务被创建直接流转下一个节点
first-wait:只要一个完成就继续往下流转,如果没有任务被创建则处于等待状态
never:必须显示调用processInstance.signal()才继续流转
unsynchronized:不停留,直接流转到下个节点

task-creates:流程流转到这个节点上时是不是自动创建任务,默认是true。通过设置为false,配合其他事件我们可以实现会签的功能。

4、Start节点
Start节点在每个流程中有且只能有一个。Start中可以配置Task,但是配置在Start节点中的task不会调用任务分配机制。这点是不同于Task Node的。。。。

5、fork和join节点
二者是成对出现的。Fork节点可以将流程拆分成多条并行也就是将Token拆分成多个子Token,到join节点的时候再汇聚成一个Token继续往下执行
一般来说,在经过fork节点之后,必须等待每个子token都走完才会通过join节点继续往下走,但是我们可以通过修改join节点的discriminator属性来,设置为true之后只要有一个子token到达join节点,就会往下流转。不过这样做产生的一个影响就是其他没有结束的子token上的任务实例依然存在且处于等待状态,任务参与者仍然可以处理这些任务。因此,在设置join节点的discriminator为true时,我们还需要手动结束掉其他分支上的任务实例。
在fork节点中,我们可以设定条件来选择只走满足条件的分支。主要是通过之前提到的beanshell脚本来实现。举例说明一下这个实现:
流程定义由一个start节点,一个end节点,一对fork/join节点以及分支中的四个node节点组成,流程定义的xml文件如下:
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="forkjoin">
<start-state name="start-state1">
<transition to="fork1"></transition>
</start-state>
<fork name="fork1">
<script>
<variable name="forkTransition" access="write"></variable>
<expression>
forkTransition = new ArrayList();
if(param > 1000) {
forkTransition.add("to node1");
forkTransition.add("to node2");
} else {
forkTransition.add("to node3");
forkTransition.add("to node4");
}
</expression>
</script>
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
<transition to="node4" name="to node4"></transition>
</fork>
<join name="join1">
<transition to="end-state1"></transition>
</join>
<node name="node1">
<event type="node-enter">
<script>
print("node1 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node2">
<event type="node-enter">
<script>
print("node2 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node3">
<event type="node-enter">
<script>
print("node3 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node4">
<event type="node-enter">
<script>
print("node4 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="forkjoin">
<start-state name="start-state1">
<transition to="fork1"></transition>
</start-state>
<fork name="fork1">
<script>
<variable name="forkTransition" access="write"></variable>
<expression>
forkTransition = new ArrayList();
if(param > 1000) {
forkTransition.add("to node1");
forkTransition.add("to node2");
} else {
forkTransition.add("to node3");
forkTransition.add("to node4");
}
</expression>
</script>
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
<transition to="node4" name="to node4"></transition>
</fork>
<join name="join1">
<transition to="end-state1"></transition>
</join>
<node name="node1">
<event type="node-enter">
<script>
print("node1 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node2">
<event type="node-enter">
<script>
print("node2 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node3">
<event type="node-enter">
<script>
print("node3 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<node name="node4">
<event type="node-enter">
<script>
print("node4 enter");
</script>
</event>
<transition to="join1"></transition>
</node>
<end-state name="end-state1"></end-state>
</process-definition>

默认情况下,当流程进入fork节点之后会分成四个分支,分别经过Node节点。在上面定义文件中我们在fork节点下做了判断,如果流程变量param>1000的时候走分支1和分支2,如果小于则走分支3和分支4。
Xml代码
<script>
<variable name="forkTransition" access="write"></variable>
<expression>
forkTransition = new ArrayList();
if(param > 1000) {
forkTransition.add("to node1");
forkTransition.add("to node2");
} else {
forkTransition.add("to node3");
forkTransition.add("to node4");
}
</expression>
</script>

<script>
<variable name="forkTransition" access="write"></variable>
<expression>
forkTransition = new ArrayList();
if(param > 1000) {
forkTransition.add("to node1");
forkTransition.add("to node2");
} else {
forkTransition.add("to node3");
forkTransition.add("to node4");
}
</expression>
</script>

注意这里的forkTransition必须是集合类型,它存放的是流程经过fork之后生成的分支名称。access属性设置为write表示是写入流程实例对应的Fork节点,才能生成我们指定的分支。在Expression标签下是我们做的逻辑处理,通过流程变量param来判断Fork节点具体要生成那些分支。
默认我们不为Fork节点添加script,流程到Fork节点时将生成所有transition。一旦设置了script,还必须设置一个变量,如上面的forkTransition写回流程变量中生成具体的分支。

测试类如下:(为方便测试没有将流程发布到数据库,下面测试例子也是采用相同做法)
Java代码
package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class ForkJoin {

public static void main(String[] args) {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("forkjoin/processDefinition.xml");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("param", 10);
Token token = processInstance.getRootToken();
token.signal();
}
}

package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class ForkJoin {

public static void main(String[] args) {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("forkjoin/processDefinition.xml");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("param", 10);
Token token = processInstance.getRootToken();
token.signal();
}
}

执行成功之后后台输出:
node3 enter
node4 enter

修改我们的param改为2000再次执行,后台变为:
node1 enter
node2 enter

6、Decision节点
Decision节点是判断节点,当流程到达decision节点之后会有多个路由选择,我们可以在这个节点上定义handler或者是使用脚本等等来决定流程走向。Decision节点不同于Fork节点,它只能选择多个Transition中的其中一个,而Fork节点是并行的。
举例说明一下:
流程定义由一个start节点,一个end节点,一个Decision节点以及分支中的3个node节点组成,在Decision我们设置了delegation,使用实现DecisionHandler接口的类SelectNode来判断流程走向,它返回的结果是其中分支的名称,流程定义的xml文件如下:
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="decision">
<start-state name="start-state1">
<transition to="decision1"></transition>
</start-state>
<decision name="decision1">
<handler class="com.royzhou.action.SelectNode"></handler>
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
</decision>
<node name="node1">
<script>
print("node1 enter")
</script>
</node>
<node name="node2">
<script>
print("node2 enter")
</script>
<transition to="end-state1"></transition>
</node>
<node name="node3">
<script>
print("node3 enter")
</script>
</node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="decision">
<start-state name="start-state1">
<transition to="decision1"></transition>
</start-state>
<decision name="decision1">
<handler class="com.royzhou.action.SelectNode"></handler>
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
</decision>
<node name="node1">
<script>
print("node1 enter")
</script>
</node>
<node name="node2">
<script>
print("node2 enter")
</script>
<transition to="end-state1"></transition>
</node>
<node name="node3">
<script>
print("node3 enter")
</script>
</node>
<end-state name="end-state1"></end-state>
</process-definition>

SelectNode类:(必须实现DecisionHandler接口并重写decide方法,返回值是要走的transition的名称)
Java代码
package com.royzhou.action;

import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.node.DecisionHandler;
//实现DecisionHandler接口
public class SelectNode implements DecisionHandler {
public String decide(ExecutionContext executionContext) throws Exception {
//通过流程变量来判断要走哪个transition
String whichWay = executionContext.getVariable("whichWay").toString();
return whichWay;
}
}

package com.royzhou.action;

import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.graph.node.DecisionHandler;
//实现DecisionHandler接口
public class SelectNode implements DecisionHandler {
public String decide(ExecutionContext executionContext) throws Exception {
//通过流程变量来判断要走哪个transition
String whichWay = executionContext.getVariable("whichWay").toString();
return whichWay;
}
}

测试类:
Java代码
package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class Decision {

public static void main(String[] args) {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("decision/processDefinition.xml");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("whichWay", "to node2");
Token token = processInstance.getRootToken();
token.signal();
}
}

package com.royzhou.test;

import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class Decision {

public static void main(String[] args) {
ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("decision/processDefinition.xml");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
processInstance.getContextInstance().setVariable("whichWay", "to node2");
Token token = processInstance.getRootToken();
token.signal();
}
}

运行测试类,后台打印出 :
node2 enter
修改流程变量whichWay为to node1 重新运行,后台打印出:
node1 enter
说明我们的decision节点正确处理了其走向。

除了使用delegation,我们也可以在流程文件中直接定义decision节点的expression属性,如下所示:
Xml代码
<decision name="decision1" expression="#{whichWay}">
<!--
<handler class="com.royzhou.action.SelectNode"></handler>
-->
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
</decision>

<decision name="decision1" expression="#{whichWay}">
<!--
<handler class="com.royzhou.action.SelectNode"></handler>
-->
<transition to="node1" name="to node1"></transition>
<transition to="node2" name="to node2"></transition>
<transition to="node3" name="to node3"></transition>
</decision>

这里采用的是JPDL表达式来指定流程走向,JPDL表达式是一种类似EL表达式的语言。
上面expression表示从流程变量中获取whichWay这个变量作为我们流程走向的选择。

重新运行我们的测试类。发现结果与上面一种做法相同。

此外我们还可以直接在transition节点下定义condition标签,配合JPDL表达式来作为我们的判断依据
Xml代码
<decision name="decision1">
<transition to="node1" name="to node1">
<condition expression="#{whichWay == 'to node1'}"></condition>
</transition>
<transition to="node2" name="to node2">
<condition expression="#{whichWay == 'to node2'}"></condition>
</transition>
<transition to="node3" name="to node3">
<condition expression="#{whichWay == 'to node3'}"></condition>
</transition>
</decision>

<decision name="decision1">
<transition to="node1" name="to node1">
<condition expression="#{whichWay == 'to node1'}"></condition>
</transition>
<transition to="node2" name="to node2">
<condition expression="#{whichWay == 'to node2'}"></condition>
</transition>
<transition to="node3" name="to node3">
<condition expression="#{whichWay == 'to node3'}"></condition>
</transition>
</decision>

再次运行测试程序发现结果仍然一致。

由此可见 Decision节点支持我们使用delegation、condition以及expression三种方式来指定流程走向。

7、Process State节点
子流程节点可以简化我们的复杂流程。主流程与子流程之间可以共享变量。如果使用子流程,在主流程发布之前必须先发布子流程。
举例说明一下主流程与子流程及其变量共享:
主流程定义文件mainprocess/processdefinition.xml
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="mainprocess">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<event type="node-enter">
<script>
print("main task node1 enter")
</script>
</event>
<task name="maintask1">
<assignment actor-id="maintask1"></assignment>
</task>
<transition to="process-state1"></transition>
</task-node>
<process-state name="process-state1">
<sub-process name="subprocess"/>
<variable name="mainParam" access="read"></variable>
<variable name="subParam" access="write"></variable>
<transition to="task-node2"></transition>
</process-state>
<task-node name="task-node2">
<event type="node-enter">
<script>
print("main task node2 enter")
</script>
</event>
<task name="maintask2">
<assignment actor-id="maintask2"></assignment>
</task>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="mainprocess">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<event type="node-enter">
<script>
print("main task node1 enter")
</script>
</event>
<task name="maintask1">
<assignment actor-id="maintask1"></assignment>
</task>
<transition to="process-state1"></transition>
</task-node>
<process-state name="process-state1">
<sub-process name="subprocess"/>
<variable name="mainParam" access="read"></variable>
<variable name="subParam" access="write"></variable>
<transition to="task-node2"></transition>
</process-state>
<task-node name="task-node2">
<event type="node-enter">
<script>
print("main task node2 enter")
</script>
</event>
<task name="maintask2">
<assignment actor-id="maintask2"></assignment>
</task>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

主流程中设置了process-state节点,其sub-process 的name属性表示子流程的名称,
<variable name="mainParam" access="read"></variable>表示从主流程读取mainParam变量
<variable name="subParam" access="write"></variable>表示子流程将变量subParam写回主流程中。

子流程定义文件:subprocess/processdefinition.xml
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="subprocess">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<event type="node-enter">
<script>
print("sub task node1 enter")
</script>
</event>
<task name="subtask1">
<assignment actor-id="subtask1"></assignment>
</task>
<event type="node-enter">
<script>
print("sub task node1 enter")
</script>
</event>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="subprocess">
<start-state name="start-state1">
<transition to="task-node1"></transition>
</start-state>
<task-node name="task-node1">
<event type="node-enter">
<script>
print("sub task node1 enter")
</script>
</event>
<task name="subtask1">
<assignment actor-id="subtask1"></assignment>
</task>
<event type="node-enter">
<script>
print("sub task node1 enter")
</script>
</event>
<transition to="end-state1"></transition>
</task-node>
<end-state name="end-state1"></end-state>
</process-definition>

测试类:
Java代码
package com.royzhou.test;

import java.io.FileNotFoundException;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;

public class SubProcess {

public static void init() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
jbpmConfiguration.createSchema();
}

public static void deploySub() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlResource("subprocess/processDefinition.xml");
jbpmContext.deployProcessDefinition(subProcessDefinition);
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void deployMain() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition mainProcessDefinition = ProcessDefinition.parseXmlResource("mainprocess/processDefinition.xml");
jbpmContext.deployProcessDefinition(mainProcessDefinition);
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startProcess() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("mainprocess");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
token.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startMainTask1() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
//主流程maintask1
TaskInstance mainTaskInstance1 = jbpmContext.loadTaskInstance(1L);
//设置主流程变量
mainTaskInstance1.getContextInstance().setVariable("mainParam", "主流程设置的变量");
mainTaskInstance1.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startSubTask1() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
//子流程subtask1
TaskInstance subTaskInstance1 = jbpmContext.loadTaskInstance(2L);
//获取主流程变量
System.out.println(subTaskInstance1.getName() + "子流程读取主流程变量,mainParam的值是:" + subTaskInstance1.getContextInstance().getVariable("mainParam").toString());
//设置子流程变量
subTaskInstance1.getContextInstance().setVariable("subParam", "子流程设置的变量");
subTaskInstance1.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startMainTask2() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
TaskInstance mainTaskInstance2 = jbpmContext.loadTaskInstance(3L);
//读取子流程变量
System.out.println(mainTaskInstance2.getName()+"主流程读取子流程变量,subParam的值是:" + mainTaskInstance2.getContextInstance().getVariable("subParam").toString());
mainTaskInstance2.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
//数据库清理
SubProcess.init();
//发布流程,必须先发布子流程再发布主流程
SubProcess.deploySub();
SubProcess.deployMain();
SubProcess.startProcess();
SubProcess.startMainTask1();
SubProcess.startSubTask1();
SubProcess.startMainTask2();
}
}

package com.royzhou.test;

import java.io.FileNotFoundException;

import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;

public class SubProcess {

public static void init() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
jbpmConfiguration.createSchema();
}

public static void deploySub() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlResource("subprocess/processDefinition.xml");
jbpmContext.deployProcessDefinition(subProcessDefinition);
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void deployMain() throws FileNotFoundException {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition mainProcessDefinition = ProcessDefinition.parseXmlResource("mainprocess/processDefinition.xml");
jbpmContext.deployProcessDefinition(mainProcessDefinition);
} catch(Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startProcess() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("mainprocess");
ProcessInstance processInstance = new ProcessInstance(processDefinition);
Token token = processInstance.getRootToken();
token.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startMainTask1() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
//主流程maintask1
TaskInstance mainTaskInstance1 = jbpmContext.loadTaskInstance(1L);
//设置主流程变量
mainTaskInstance1.getContextInstance().setVariable("mainParam", "主流程设置的变量");
mainTaskInstance1.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startSubTask1() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
//子流程subtask1
TaskInstance subTaskInstance1 = jbpmContext.loadTaskInstance(2L);
//获取主流程变量
System.out.println(subTaskInstance1.getName() + "子流程读取主流程变量,mainParam的值是:" + subTaskInstance1.getContextInstance().getVariable("mainParam").toString());
//设置子流程变量
subTaskInstance1.getContextInstance().setVariable("subParam", "子流程设置的变量");
subTaskInstance1.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void startMainTask2() {
JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();
JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
TaskInstance mainTaskInstance2 = jbpmContext.loadTaskInstance(3L);
//读取子流程变量
System.out.println(mainTaskInstance2.getName()+"主流程读取子流程变量,subParam的值是:" + mainTaskInstance2.getContextInstance().getVariable("subParam").toString());
mainTaskInstance2.end();
} catch (Exception e) {
e.printStackTrace();
} finally {
jbpmContext.close();
}
}

public static void main(String[] args) throws FileNotFoundException {
//数据库清理
SubProcess.init();
//发布流程,必须先发布子流程再发布主流程
SubProcess.deploySub();
SubProcess.deployMain();
SubProcess.startProcess();
SubProcess.startMainTask1();
SubProcess.startSubTask1();
SubProcess.startMainTask2();
}
}

运行上面程序,成功执行之后结果为:
main task node1 enter
sub task node1 enter
sub task node1 enter
subtask1子流程读取主流程变量,mainParam的值是:主流程设置的变量
main task node2 enter
maintask2主流程读取子流程变量,subParam的值是:子流程设置的变量

8、Mail Node 节点
该节点可以实现邮件的发送,具有通知提醒功能。
具体有两种配置方式:
通过mail node节点的template属性设置,采用此种方式需要修改jbpm.mail.template.xml文件里的模版,加上我们需要的模版,具体模版设置可参照里面已有模版。举例说明下:
流程模版文件:start -> mail node ->end
Xml代码
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="mail">
<start-state name="start-state1">
<transition to="mail-node1"></transition>
</start-state>
<mail-node name="mail-node1" template="test">
<event type="node-enter">
<script>
print("enter mail node")
</script>
</event>
<event type="node-leave">
<script>
print("leave mail node")
</script>
</event>
<transition to="end-state1"></transition>
</mail-node>
<end-state name="end-state1"></end-state>
</process-definition>

<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="mail">
<start-state name="start-state1">
<transition to="mail-node1"></transition>
</start-state>
<mail-node name="mail-node1" template="test">
<event type="node-enter">
<script>
print("enter mail node")
</script>
</event>
<event type="node-leave">
<script>
print("leave mail node")
</script>
</event>
<transition to="end-state1"></transition>
</mail-node>
<end-state name="end-state1"></end-state>
</process-definition>

我们使用的模版是test,但是jbpm.mail.template.xml没有,所以需要我们自己加:
Xml代码
<mail-template name="test">
<actors>#{actorId}</actors>
<subject>mail node 节点测试</subject>
<text><![CDATA[Hi #{actorId},
这是mail node节点的测试内容。
]]></text>
</mail-template>

<mail-template name="test">
<actors>#{actorId}</actors>
<subject>mail node 节点测试</subject>
<text><![CDATA[Hi #{actorId},
这是mail node节点的测试内容。
]]></text>
</mail-template>

这个是我们自己定义的模版,其中actors标签表示的是收件人的地址,需要使用邮件解析类解析,邮件解析类是一个实现AddressResolver接口的类。并且需要在jbpm.cfg.xml中配置,告诉jbpm要使用这个类去解析获取发送邮件的地址。
Java代码
package com.royzhou.util;

import org.jbpm.mail.AddressResolver;

public class MailAddressResolver implements AddressResolver {

public Object resolveAddress(String actorId) {
return "royzhou1985@foxmail.com";
}
}

package com.royzhou.util;

import org.jbpm.mail.AddressResolver;

public class MailAddressResolver implements AddressResolver {

public Object resolveAddress(String actorId) {
return "royzhou1985@foxmail.com";
}
}

下面是jbpm.cfg.xml的配置内容。
Xml代码
<jbpm-configuration>
<!-- 邮件解析类 -->
<bean name="jbpm.mail.address.resolver"
class="com.royzhou.util.MailAddressResolver" singleton="true" />
<!-- 邮箱配置信息 -->
<string name="resource.mail.properties" value="jbpm.mail.properties" />
<!-- 处理邮件发送的类 -->
<string name="mail.class.name" value="com.royzhou.util.Mail" />
<!-- 发送人地址 -->
<string name="jbpm.mail.from.address" value="test@163.com"></string>
</jbpm-configuration>

<jbpm-configuration>
<!-- 邮件解析类 -->
<bean name="jbpm.mail.address.resolver"
class="com.royzhou.util.MailAddressResolver" singleton="true" />
<!-- 邮箱配置信息 -->
<string name="resource.mail.properties" value="jbpm.mail.properties" />
<!-- 处理邮件发送的类 -->
<string name="mail.class.name" value="com.royzhou.util.Mail" />
<!-- 发送人地址 -->
<string name="jbpm.mail.from.address" value="test@163.com"></string>
</jbpm-configuration>


邮箱配置信息如下:
mail.smtp.host=smtp.163.com
mail.smtp.user=test
mail.smtp.password=test
mail.smtp.auth=true

配置中我们使用的是自己的邮件发送类,这是因为jbpm自己提供的邮件发送类没有提供身份认证,直接使用会报异常。
修改之后的邮件发送类如下:
Java代码
package com.royzhou.util;

import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.Authenticator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.jpdl.el.ELException;
import org.jbpm.jpdl.el.VariableResolver;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.mail.AddressResolver;
import org.jbpm.util.ClassLoaderUtil;
import org.jbpm.util.XmlUtil;

public class Mail implements ActionHandler {

private static final long serialVersionUID = 1L;

String template = null;
String actors = null;
String to = null;
String bcc = null;
String bccActors = null;
String subject = null;
String text = null;

ExecutionContext executionContext = null;

public Mail() {
}

public Mail(String template,
String actors,
String to,
String subject,
String text) {
this.template = template;
this.actors = actors;
this.to = to;
this.subject = subject;
this.text = text;
}

public Mail(String template,
String actors,
String to,
String bccActors,
String bcc,
String subject,
String text) {
this.template = template;
this.actors = actors;
this.to = to;
this.bccActors = bccActors;
this.bcc = bcc;
this.subject = subject;
this.text = text;
}

public void execute(ExecutionContext executionContext) {
this.executionContext = executionContext;
send();
}

public List getRecipients() {
List recipients = new ArrayList();
if (actors!=null) {
String evaluatedActors = evaluate(actors);
List tokenizedActors = tokenize(evaluatedActors);
if (tokenizedActors!=null) {
recipients.addAll(resolveAddresses(tokenizedActors));
}
}
if (to!=null) {
String resolvedTo = evaluate(to);
recipients.addAll(tokenize(resolvedTo));
}
return recipients;
}

public List getBccRecipients() {
List recipients = new ArrayList();
if (bccActors!=null) {
String evaluatedActors = evaluate(bccActors);
List tokenizedActors = tokenize(evaluatedActors);
if (tokenizedActors!=null) {
recipients.addAll(resolveAddresses(tokenizedActors));
}
}
if (bcc!=null) {
String resolvedTo = evaluate(to);
recipients.addAll(tokenize(resolvedTo));
}
if (JbpmConfiguration.Configs.hasObject("jbpm.mail.bcc.address")) {
recipients.addAll(tokenize(
JbpmConfiguration.Configs.getString("jbpm.mail.bcc.address")));
}
return recipients;
}

public String getSubject() {
if (subject==null) return null;
return evaluate(subject);
}

public String getText() {
if (text==null) return null;
return evaluate(text);
}

public String getFromAddress() {
if (JbpmConfiguration.Configs.hasObject("jbpm.mail.from.address")) {
return JbpmConfiguration.Configs.getString("jbpm.mail.from.address");
}
return "jbpm@noreply";
}

public void send() {
if (template!=null) {
Properties properties = getMailTemplateProperties(template);
if (actors==null) {
actors = properties.getProperty("actors");
}
if (to==null) {
to = properties.getProperty("to");
}
if (subject==null) {
subject = properties.getProperty("subject");
}
if (text==null) {
text = properties.getProperty("text");
}
if (bcc==null) {
bcc = properties.getProperty("bcc");
}
if (bccActors==null) {
bccActors = properties.getProperty("bccActors");
}
}

send(getMailServerProperties(),
getFromAddress(),
getRecipients(),
getBccRecipients(),
getSubject(),
getText());
}

public static void send(Properties mailServerProperties, String fromAddress, List recipients, String subject, String text) {
send(mailServerProperties, fromAddress, recipients, null, subject, text);
}

public static void send(Properties mailServerProperties, String fromAddress, List recipients, List bccRecipients, String subject, String text) {
if ( (recipients==null)
|| (recipients.isEmpty())
) {
log.debug("skipping mail because there are no recipients");
return;
}
mailServerProperties.put("mail.smtp.auth", "true");
log.debug("sending email to '"+recipients+"' about '"+subject+"'");

/**
* 添加认证类
* royzhou 2009.07.21
*/
String userName = mailServerProperties.getProperty("mail.smtp.user").toString();
String password = mailServerProperties.getProperty("mail.smtp.password").toString();
MyAuthentication myAuthentication = new MyAuthentication(userName,password);
Session session = Session.getDefaultInstance(mailServerProperties, myAuthentication);
MimeMessage message = new MimeMessage(session);
try {
if (fromAddress!=null) {
message.setFrom(new InternetAddress(fromAddress));
}
Iterator iter = recipients.iterator();
while (iter.hasNext()) {
InternetAddress recipient = new InternetAddress((String) iter.next());
message.addRecipient(Message.RecipientType.TO, recipient);
}
if (bccRecipients!=null) {
iter = bccRecipients.iterator();
while (iter.hasNext()) {
InternetAddress recipient = new InternetAddress((String) iter.next());
message.addRecipient(Message.RecipientType.BCC, recipient);
}
}
if (subject!=null) {
message.setSubject(subject);
}
if (text!=null) {
message.setText(text);
}
message.setSentDate(new Date());

Transport.send(message);
} catch (Exception e) {
throw new JbpmException("couldn't send email", e);
}
}

protected List tokenize(String text) {
if (text==null) {
return null;
}
List list = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(text, ";:");
while (tokenizer.hasMoreTokens()) {
list.add(tokenizer.nextToken());
}
return list;
}

protected Collection resolveAddresses(List actorIds) {
List emailAddresses = new ArrayList();
Iterator iter = actorIds.iterator();
while (iter.hasNext()) {
String actorId = (String) iter.next();
AddressResolver addressResolver = (AddressResolver) JbpmConfiguration.Configs.getObject("jbpm.mail.address.resolver");
Object resolvedAddresses = addressResolver.resolveAddress(actorId);
if (resolvedAddresses!=null) {
if (resolvedAddresses instanceof String) {
emailAddresses.add((String)resolvedAddresses);
} else if (resolvedAddresses instanceof Collection) {
emailAddresses.addAll((Collection)resolvedAddresses);
} else if (resolvedAddresses instanceof String[]) {
emailAddresses.addAll(Arrays.asList((String[])resolvedAddresses));
} else {
throw new JbpmException("Address resolver '"+addressResolver+"' returned '"+resolvedAddresses.getClass().getName()+"' instead of a String, Collection or String-array: "+resolvedAddresses);
}
}
}
return emailAddresses;
}

Properties getMailServerProperties() {
Properties mailServerProperties = new Properties();

if (JbpmConfiguration.Configs.hasObject("resource.mail.properties")) {
String mailServerPropertiesResource = JbpmConfiguration.Configs.getString("resource.mail.properties");
try {
InputStream mailServerStream = ClassLoaderUtil.getStream(mailServerPropertiesResource);
mailServerProperties.load(mailServerStream);
} catch (Exception e) {
throw new JbpmException("couldn't get configuration properties for jbpm mail server from resource '"+mailServerPropertiesResource+"'", e);
}

} else if (JbpmConfiguration.Configs.hasObject("jbpm.mail.smtp.host")) {
String smtpServer = JbpmConfiguration.Configs.getString("jbpm.mail.smtp.host");
mailServerProperties.put("mail.smtp.host", smtpServer);

} else {

log.error("couldn't get mail properties");
}

return mailServerProperties;
}

static Map templates = null;
static Map templateVariables = null;
synchronized Properties getMailTemplateProperties(String templateName) {
if (templates==null) {
templates = new HashMap();
String mailTemplatesResource = JbpmConfiguration.Configs.getString("resource.mail.templates");
org.w3c.dom.Element mailTemplatesElement = XmlUtil.parseXmlResource(mailTemplatesResource).getDocumentElement();
List mailTemplateElements = XmlUtil.elements(mailTemplatesElement, "mail-template");
Iterator iter = mailTemplateElements.iterator();
while (iter.hasNext()) {
org.w3c.dom.Element mailTemplateElement = (org.w3c.dom.Element) iter.next();

Properties templateProperties = new Properties();
addTemplateProperty(mailTemplateElement, "actors", templateProperties);
addTemplateProperty(mailTemplateElement, "to", templateProperties);
addTemplateProperty(mailTemplateElement, "subject", templateProperties);
addTemplateProperty(mailTemplateElement, "text", templateProperties);
addTemplateProperty(mailTemplateElement, "bcc", templateProperties);
addTemplateProperty(mailTemplateElement, "bccActors", templateProperties);

templates.put(mailTemplateElement.getAttribute("name"), templateProperties);
}

templateVariables = new HashMap();
List variableElements = XmlUtil.elements(mailTemplatesElement, "variable");
iter = variableElements.iterator();
while (iter.hasNext()) {
org.w3c.dom.Element variableElement = (org.w3c.dom.Element) iter.next();
templateVariables.put(variableElement.getAttribute("name"), variableElement.getAttribute("value"));
}
}
return (Properties) templates.get(templateName);
}

void addTemplateProperty(org.w3c.dom.Element mailTemplateElement, String property, Properties templateProperties) {
org.w3c.dom.Element element = XmlUtil.element(mailTemplateElement, property);
if (element!=null) {
templateProperties.put(property, XmlUtil.getContentText(element));
}
}

String evaluate(String expression) {
if (expression==null) {
return null;
}
VariableResolver variableResolver = JbpmExpressionEvaluator.getUsedVariableResolver();
if (variableResolver!=null) {
variableResolver = new MailVariableResolver(templateVariables, variableResolver);
}
return (String) JbpmExpressionEvaluator.evaluate(expression, executionContext, variableResolver, null);
}

class MailVariableResolver implements VariableResolver, Serializable {
private static final long serialVersionUID = 1L;
Map templateVariables = null;
VariableResolver variableResolver = null;

public MailVariableResolver(Map templateVariables, VariableResolver variableResolver) {
this.templateVariables = templateVariables;
this.variableResolver = variableResolver;
}

public Object resolveVariable(String pName) throws ELException {
if ( (templateVariables!=null)
&& (templateVariables.containsKey(pName))
){
return templateVariables.get(pName);
}
return variableResolver.resolveVariable(pName);
}
}

private static Log log = LogFactory.getLog(Mail.class);
}

/**
* 邮箱认证类
* @author royzhou
* 2009.07.21
*/
class MyAuthentication extends Authenticator {
private String userName;
private String password;
public MyAuthentication(String userName, String password) {
this.userName = userName;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName,password);
}
}

package com.royzhou.util;

import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.Authenticator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.jpdl.el.ELException;
import org.jbpm.jpdl.el.VariableResolver;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.mail.AddressResolver;
import org.jbpm.util.ClassLoaderUtil;
import org.jbpm.util.XmlUtil;

public class Mail implements ActionHandler {

private static final long serialVersionUID = 1L;

String template = null;
String actors = null;
String to = null;
String bcc = null;
String bccActors = null;
String subject = null;
String text = null;

ExecutionContext executionContext = null;

public Mail() {
}

public Mail(String template,
String actors,
String to,
String subject,
String text) {
this.template = template;
this.actors = actors;
this.to = to;
this.subject = subject;
this.text = text;
}

public Mail(String template,
String actors,
String to,
String bccActors,
String bcc,
String subject,
String text) {
this.template = template;
this.actors = actors;
this.to = to;
this.bccActors = bccActors;
this.bcc = bcc;
this.subject = subject;
this.text = text;
}

public void execute(ExecutionContext executionContext) {
this.executionContext = executionContext;
send();
}

public List getRecipients() {
List recipients = new ArrayList();
if (actors!=null) {
String evaluatedActors = evaluate(actors);
List tokenizedActors = tokenize(evaluatedActors);
if (tokenizedActors!=null) {
recipients.addAll(resolveAddresses(tokenizedActors));
}
}
if (to!=null) {
String resolvedTo = evaluate(to);
recipients.addAll(tokenize(resolvedTo));
}
return recipients;
}

public List getBccRecipients() {
List recipients = new ArrayList();
if (bccActors!=null) {
String evaluatedActors = evaluate(bccActors);
List tokenizedActors = tokenize(evaluatedActors);
if (tokenizedActors!=null) {
recipients.addAll(resolveAddresses(tokenizedActors));
}
}
if (bcc!=null) {
String resolvedTo = evaluate(to);
re
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JBPM(Java Business Process Management)是一个基于Java的开源业务流程管理框架,结合Idea(智慧,创意)可以提供一种更强大的业务流程管理解决方案。 集成JBPM能够帮助企业更好地管理和优化业务流程,提高工作效率,实现业务自动化。利用JBPM的流程引擎,可以将复杂的业务流程分解为一系列简单的任务和决策节点,通过流程图的形式直观地展示整个流程的执行路径。这种可视化的方式使得流程的定义、执行和监控更加方便和直观。 通过集成JBPM和Idea,可以实现以下功能和优势: 1. 流程设计和优化:通过Idea的创意和智慧,可以更好地设计和优化业务流程。基于JBPM的流程引擎,可以快速创建和调整流程,根据实际需求进行灵活的修改和优化。 2. 流程自动化:借助JBPM的工作流引擎,可以将人工操作和决策节点与系统集成,实现业务流程的自动化。这样可以节省大量人工操作的时间和精力,提高工作效率。 3. 流程监控和跟踪:通过JBPM的流程监控功能,可以实时跟踪流程的执行状态和进度。结合Idea的创意,可以提供更多的监控指标和报表,帮助管理者更好地掌握和分析流程的运行情况,及时发现问题并进行调整。 4. 异常处理和决策支持:JBPM可以支持在流程中进行异常处理和决策,通过Idea的智慧,可以实现更加灵活和智能的异常处理和决策支持。这可以帮助企业快速响应和处理异常情况,提高业务的灵活性和应变能力。 综上所述,通过集成JBPM和Idea,可以提供一个更强大和智能的业务流程管理解决方案。这不仅可以提高企业的工作效率和运营质量,还可以帮助企业更好地适应和应对市场变化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值