Jbpm 流程节点

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

Action类如下:
Java代码 复制代码 收藏代码
  1. package com.royzhou.action;   
  2.   
  3. import org.jbpm.graph.def.ActionHandler;   
  4. import org.jbpm.graph.exe.ExecutionContext;   
  5.   
  6. public class NodeAction implements ActionHandler {   
  7.     public void execute(ExecutionContext executionContext) throws Exception {   
  8.         System.out.println("node action……………………");   
  9.     }   
  10. }  
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代码 复制代码 收藏代码
  1. package com.royzhou.test;   
  2.   
  3. import java.io.FileInputStream;   
  4. import java.io.FileNotFoundException;   
  5. import java.util.zip.ZipInputStream;   
  6.   
  7. import org.jbpm.JbpmConfiguration;   
  8. import org.jbpm.JbpmContext;   
  9. import org.jbpm.graph.def.ProcessDefinition;   
  10. import org.jbpm.graph.exe.ProcessInstance;   
  11. import org.jbpm.graph.exe.Token;   
  12.   
  13. public class HelloWorldDB {   
  14.     public static void deploy() throws FileNotFoundException {   
  15.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  16.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  17.         try {   
  18.             FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/helloworld/helloworld.zip ");   
  19.             ZipInputStream zis = new ZipInputStream(fis);   
  20.             ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);   
  21.             jbpmContext.deployProcessDefinition(processDefinition);   
  22.             fis.close();   
  23.             zis.close();   
  24.         } catch(Exception e) {   
  25.             e.printStackTrace();   
  26.         } finally {   
  27.             jbpmContext.close();   
  28.         }   
  29.     }   
  30.        
  31.     public static void main(String[] args) throws FileNotFoundException {   
  32.         HelloWorldDB.deploy();   
  33.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  34.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  35.         jbpmContext.setActorId("royzhou");   
  36.         //获取最新版本的流程定义对象   
  37.         ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("helloworld");   
  38.         ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  39.         //得到流程令牌   
  40.         Token token = processInstance.getRootToken();   
  41.            
  42.         //打印流程当前所处节点   
  43.         System.out.println("1:流程现在所处节点:" + token.getNode().getName());   
  44.            
  45.         //触发流程流转到下一个节点Node   
  46.         token.signal();   
  47.            
  48.         /**  
  49.          * 注意因为Node节点设置Action  
  50.          * 所以流程会停留在Node节点  
  51.          */  
  52.         System.out.println("2:流程现在所处节点:" + token.getNode().getName());   
  53.            
  54.         //触发流程流转到下一个节点State   
  55.         token.signal();   
  56.         System.out.println("3:流程现在所处节点:" + token.getNode().getName());   
  57. token.signal();   
  58.         System.out.println("4:流程现在所处节点:" + token.getNode().getName());   
  59.         System.out.println("流程状态是否结束:" + token.getProcessInstance().hasEnded());   
  60.         jbpmContext.close();   
  61.     }   
  62. }  
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代码 复制代码 收藏代码
  1.     <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="tasknode">  
  4.     <start-state name="start-state1">  
  5.         <transition to="task-node1"></transition>  
  6.     </start-state>  
  7.     <task-node name="task-node1">  
  8.         <task name="mytask">  
  9.             <assignment actor-id="royzhou"></assignment>  
  10.         </task>  
  11.         <transition to="end-state1"></transition>  
  12.     </task-node>  
  13.     <end-state name="end-state1"></end-state>  
  14. </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代码 复制代码 收藏代码
  1.     package com.royzhou.test;   
  2.   
  3. import java.io.FileInputStream;   
  4. import java.io.FileNotFoundException;   
  5. import java.util.zip.ZipInputStream;   
  6.   
  7. import org.jbpm.JbpmConfiguration;   
  8. import org.jbpm.JbpmContext;   
  9. import org.jbpm.graph.def.ProcessDefinition;   
  10. import org.jbpm.graph.exe.ProcessInstance;   
  11. import org.jbpm.graph.exe.Token;   
  12.   
  13. public class TaskNode {   
  14.        
  15.     public static void deploy() throws FileNotFoundException {   
  16.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  17.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  18.         try {   
  19.             FileInputStream fis = new FileInputStream("F:/workspace/jbpm-test/src/main/jpdl/tasknode/tasknode.zip");   
  20.             ZipInputStream zis = new ZipInputStream(fis);   
  21.             ProcessDefinition processDefinition = ProcessDefinition.parseParZipInputStream(zis);   
  22.             jbpmContext.deployProcessDefinition(processDefinition);   
  23.             fis.close();   
  24.             zis.close();   
  25.         } catch(Exception e) {   
  26.             e.printStackTrace();   
  27.         } finally {   
  28.             jbpmContext.close();   
  29.         }   
  30.     }   
  31.        
  32.     public static void main(String[] args) throws FileNotFoundException {   
  33.         TaskNode.deploy();   
  34.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  35.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  36.         ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("tasknode");   
  37.         ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  38.         Token token = processInstance.getRootToken();   
  39.         token.signal();   
  40.         System.out.println("流程现在所处节点:" + token.getNode().getName());   
  41.         jbpmContext.close();   
  42.     }   
  43. }  
	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代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="forkjoin">  
  3.     <start-state name="start-state1">  
  4.         <transition to="fork1"></transition>  
  5.     </start-state>  
  6.     <fork name="fork1">  
  7.         <script>  
  8.             <variable name="forkTransition" access="write"></variable>  
  9.             <expression>  
  10.                 forkTransition = new ArrayList();   
  11.                 if(param &gt; 1000) {   
  12.                     forkTransition.add("to node1");   
  13.                     forkTransition.add("to node2");   
  14.                 } else {   
  15.                     forkTransition.add("to node3");   
  16.                     forkTransition.add("to node4");   
  17.                 }   
  18.             </expression>  
  19.         </script>  
  20.         <transition to="node1" name="to node1"></transition>  
  21.         <transition to="node2" name="to node2"></transition>  
  22.         <transition to="node3" name="to node3"></transition>  
  23.         <transition to="node4" name="to node4"></transition>  
  24.     </fork>  
  25.     <join name="join1">  
  26.         <transition to="end-state1"></transition>  
  27.     </join>  
  28.     <node name="node1">  
  29.         <event type="node-enter">  
  30.             <script>  
  31.                 print(&quot;node1 enter&quot;);   
  32.             </script>  
  33.         </event>  
  34.         <transition to="join1"></transition>  
  35.     </node>  
  36.     <node name="node2">  
  37.         <event type="node-enter">  
  38.             <script>  
  39.                 print(&quot;node2 enter&quot;);   
  40.             </script>  
  41.         </event>  
  42.         <transition to="join1"></transition>  
  43.     </node>  
  44.     <node name="node3">  
  45.         <event type="node-enter">  
  46.             <script>  
  47.                 print(&quot;node3 enter&quot;);   
  48.             </script>  
  49.         </event>  
  50.         <transition to="join1"></transition>  
  51.     </node>  
  52.     <node name="node4">  
  53.         <event type="node-enter">  
  54.             <script>  
  55.                 print(&quot;node4 enter&quot;);   
  56.             </script>  
  57.         </event>  
  58.         <transition to="join1"></transition>  
  59.     </node>  
  60.     <end-state name="end-state1"></end-state>  
  61. </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 &gt; 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(&quot;node1 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node2">
		<event type="node-enter">
			<script>
				print(&quot;node2 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node3">
		<event type="node-enter">
			<script>
				print(&quot;node3 enter&quot;);
			</script>
		</event>
		<transition to="join1"></transition>
	</node>
	<node name="node4">
		<event type="node-enter">
			<script>
				print(&quot;node4 enter&quot;);
			</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代码 复制代码 收藏代码
  1. <script>  
  2.             <variable name="forkTransition" access="write"></variable>  
  3.             <expression>  
  4.                 forkTransition = new ArrayList();   
  5.                 if(param &gt; 1000) {   
  6.                     forkTransition.add("to node1");   
  7.                     forkTransition.add("to node2");   
  8.                 } else {   
  9.                     forkTransition.add("to node3");   
  10.                     forkTransition.add("to node4");   
  11.                 }   
  12.             </expression>  
  13.         </script>  
<script>
			<variable name="forkTransition" access="write"></variable>
			<expression>
				forkTransition = new ArrayList();
				if(param &gt; 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代码 复制代码 收藏代码
  1. package com.royzhou.test;   
  2.   
  3. import org.jbpm.graph.def.ProcessDefinition;   
  4. import org.jbpm.graph.exe.ProcessInstance;   
  5. import org.jbpm.graph.exe.Token;   
  6.   
  7. public class ForkJoin {   
  8.        
  9.     public static void main(String[] args) {   
  10.         ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("forkjoin/processDefinition.xml");   
  11.         ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  12.         processInstance.getContextInstance().setVariable("param"10);   
  13.         Token token = processInstance.getRootToken();   
  14.         token.signal();   
  15.     }   
  16. }  
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代码 复制代码 收藏代码
  1.     <?xml version="1.0" encoding="UTF-8"?>  
  2. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="decision">  
  3.     <start-state name="start-state1">  
  4.         <transition to="decision1"></transition>  
  5.     </start-state>  
  6.     <decision name="decision1">  
  7.         <handler class="com.royzhou.action.SelectNode"></handler>  
  8.         <transition to="node1" name="to node1"></transition>  
  9.         <transition to="node2" name="to node2"></transition>  
  10.         <transition to="node3" name="to node3"></transition>  
  11.     </decision>  
  12.     <node name="node1">  
  13.         <script>  
  14.             print(&quot;node1 enter&quot;)   
  15.         </script>  
  16.     </node>  
  17.     <node name="node2">  
  18.         <script>  
  19.             print(&quot;node2 enter&quot;)   
  20.         </script>  
  21.         <transition to="end-state1"></transition>  
  22.     </node>  
  23.     <node name="node3">  
  24.         <script>  
  25.             print(&quot;node3 enter&quot;)   
  26.         </script>  
  27.     </node>  
  28.     <end-state name="end-state1"></end-state>  
  29. </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(&quot;node1 enter&quot;)
		</script>
	</node>
	<node name="node2">
		<script>
			print(&quot;node2 enter&quot;)
		</script>
		<transition to="end-state1"></transition>
	</node>
	<node name="node3">
		<script>
			print(&quot;node3 enter&quot;)
		</script>
	</node>
	<end-state name="end-state1"></end-state>
</process-definition>

SelectNode类:(必须实现DecisionHandler接口并重写decide方法,返回值是要走的transition的名称)
Java代码 复制代码 收藏代码
  1. package com.royzhou.action;   
  2.   
  3. import org.jbpm.graph.exe.ExecutionContext;   
  4. import org.jbpm.graph.node.DecisionHandler;   
  5. //实现DecisionHandler接口   
  6. public class SelectNode implements DecisionHandler {   
  7.     public String decide(ExecutionContext executionContext) throws Exception {   
  8.         //通过流程变量来判断要走哪个transition   
  9.         String whichWay = executionContext.getVariable("whichWay").toString();   
  10.         return whichWay;   
  11.     }   
  12. }  
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代码 复制代码 收藏代码
  1. package com.royzhou.test;   
  2.   
  3. import org.jbpm.graph.def.ProcessDefinition;   
  4. import org.jbpm.graph.exe.ProcessInstance;   
  5. import org.jbpm.graph.exe.Token;   
  6.   
  7. public class Decision {   
  8.        
  9.     public static void main(String[] args) {   
  10.         ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("decision/processDefinition.xml");   
  11.         ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  12.         processInstance.getContextInstance().setVariable("whichWay""to node2");   
  13.         Token token = processInstance.getRootToken();   
  14.         token.signal();   
  15.     }   
  16. }  
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代码 复制代码 收藏代码
  1. <decision name="decision1" expression="#{whichWay}">  
  2.     <!--   
  3.     <handler class="com.royzhou.action.SelectNode"></handler> 
  4.      -->  
  5.     <transition to="node1" name="to node1"></transition>  
  6.     <transition to="node2" name="to node2"></transition>  
  7.     <transition to="node3" name="to node3"></transition>  
  8. </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代码 复制代码 收藏代码
  1. <decision name="decision1">  
  2.         <transition to="node1" name="to node1">  
  3.             <condition expression="#{whichWay == 'to node1'}"></condition>  
  4.         </transition>  
  5.         <transition to="node2" name="to node2">  
  6.             <condition expression="#{whichWay == 'to node2'}"></condition>  
  7.         </transition>  
  8.         <transition to="node3" name="to node3">  
  9.             <condition expression="#{whichWay == 'to node3'}"></condition>  
  10.         </transition>  
  11.     </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代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="mainprocess">  
  3.     <start-state name="start-state1">  
  4.         <transition to="task-node1"></transition>  
  5.     </start-state>  
  6.     <task-node name="task-node1">  
  7.         <event type="node-enter">  
  8.             <script>  
  9.                 print(&quot;main task node1 enter&quot;)   
  10.             </script>  
  11.         </event>  
  12.         <task name="maintask1">  
  13.             <assignment actor-id="maintask1"></assignment>  
  14.         </task>  
  15.         <transition to="process-state1"></transition>  
  16.     </task-node>  
  17.     <process-state name="process-state1">  
  18.         <sub-process name="subprocess"/>  
  19.         <variable name="mainParam" access="read"></variable>  
  20.         <variable name="subParam" access="write"></variable>  
  21.         <transition to="task-node2"></transition>  
  22.     </process-state>  
  23.     <task-node name="task-node2">  
  24.         <event type="node-enter">  
  25.             <script>  
  26.                 print(&quot;main task node2 enter&quot;)   
  27.             </script>  
  28.         </event>  
  29.         <task name="maintask2">  
  30.             <assignment actor-id="maintask2"></assignment>  
  31.         </task>  
  32.         <transition to="end-state1"></transition>  
  33.     </task-node>  
  34.     <end-state name="end-state1"></end-state>  
  35. </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(&quot;main task node1 enter&quot;)
			</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(&quot;main task node2 enter&quot;)
			</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代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="subprocess">  
  3.     <start-state name="start-state1">  
  4.         <transition to="task-node1"></transition>  
  5.     </start-state>  
  6.     <task-node name="task-node1">  
  7.         <event type="node-enter">  
  8.             <script>  
  9.                 print(&quot;sub task node1 enter&quot;)   
  10.             </script>  
  11.         </event>  
  12.         <task name="subtask1">  
  13.             <assignment actor-id="subtask1"></assignment>  
  14.         </task>  
  15.         <event type="node-enter">  
  16.             <script>  
  17.                 print(&quot;sub task node1 enter&quot;)   
  18.             </script>  
  19.         </event>  
  20.         <transition to="end-state1"></transition>  
  21.     </task-node>  
  22.     <end-state name="end-state1"></end-state>  
  23. </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(&quot;sub task node1 enter&quot;)
			</script>
		</event>
		<task name="subtask1">
			<assignment actor-id="subtask1"></assignment>
		</task>
		<event type="node-enter">
			<script>
				print(&quot;sub task node1 enter&quot;)
			</script>
		</event>
		<transition to="end-state1"></transition>
	</task-node>
	<end-state name="end-state1"></end-state>
</process-definition>

测试类:
Java代码 复制代码 收藏代码
  1. package com.royzhou.test;   
  2.   
  3. import java.io.FileNotFoundException;   
  4.   
  5. import org.jbpm.JbpmConfiguration;   
  6. import org.jbpm.JbpmContext;   
  7. import org.jbpm.graph.def.ProcessDefinition;   
  8. import org.jbpm.graph.exe.ProcessInstance;   
  9. import org.jbpm.graph.exe.Token;   
  10. import org.jbpm.taskmgmt.exe.TaskInstance;   
  11.   
  12. public class SubProcess {   
  13.        
  14.     public static void init() {   
  15.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  16.         jbpmConfiguration.createSchema();   
  17.     }   
  18.        
  19.     public static void deploySub() throws FileNotFoundException {   
  20.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  21.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  22.         try {   
  23.             ProcessDefinition subProcessDefinition = ProcessDefinition.parseXmlResource("subprocess/processDefinition.xml");   
  24.             jbpmContext.deployProcessDefinition(subProcessDefinition);   
  25.         } catch(Exception e) {   
  26.             e.printStackTrace();   
  27.         } finally {   
  28.             jbpmContext.close();   
  29.         }   
  30.     }   
  31.        
  32.     public static void deployMain() throws FileNotFoundException {   
  33.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  34.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  35.         try {   
  36.             ProcessDefinition mainProcessDefinition = ProcessDefinition.parseXmlResource("mainprocess/processDefinition.xml");   
  37.             jbpmContext.deployProcessDefinition(mainProcessDefinition);   
  38.         } catch(Exception e) {   
  39.             e.printStackTrace();   
  40.         } finally {   
  41.             jbpmContext.close();   
  42.         }   
  43.     }   
  44.        
  45.     public static void startProcess() {   
  46.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  47.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  48.         try {   
  49.             ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition("mainprocess");   
  50.             ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  51.             Token token = processInstance.getRootToken();   
  52.             token.signal();   
  53.         } catch (Exception e) {   
  54.             e.printStackTrace();   
  55.         } finally {   
  56.             jbpmContext.close();   
  57.         }   
  58.     }   
  59.        
  60.     public static void startMainTask1() {   
  61.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  62.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  63.         try {   
  64.             //主流程maintask1   
  65.             TaskInstance mainTaskInstance1 = jbpmContext.loadTaskInstance(1L);   
  66.             //设置主流程变量   
  67.             mainTaskInstance1.getContextInstance().setVariable("mainParam""主流程设置的变量");   
  68.             mainTaskInstance1.end();   
  69.         } catch (Exception e) {   
  70.             e.printStackTrace();   
  71.         } finally {   
  72.             jbpmContext.close();   
  73.         }   
  74.     }   
  75.        
  76.     public static void startSubTask1() {   
  77.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  78.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  79.         try {   
  80.             //子流程subtask1   
  81.             TaskInstance subTaskInstance1 = jbpmContext.loadTaskInstance(2L);   
  82.             //获取主流程变量   
  83.             System.out.println(subTaskInstance1.getName() + "子流程读取主流程变量,mainParam的值是:" + subTaskInstance1.getContextInstance().getVariable("mainParam").toString());   
  84.             //设置子流程变量   
  85.             subTaskInstance1.getContextInstance().setVariable("subParam""子流程设置的变量");   
  86.             subTaskInstance1.end();   
  87.         } catch (Exception e) {   
  88.             e.printStackTrace();   
  89.         } finally {   
  90.             jbpmContext.close();   
  91.         }   
  92.     }   
  93.        
  94.     public static void startMainTask2() {   
  95.         JbpmConfiguration jbpmConfiguration = JbpmConfiguration.getInstance();   
  96.         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();   
  97.         try {   
  98.             TaskInstance mainTaskInstance2 = jbpmContext.loadTaskInstance(3L);   
  99.             //读取子流程变量   
  100.             System.out.println(mainTaskInstance2.getName()+"主流程读取子流程变量,subParam的值是:" + mainTaskInstance2.getContextInstance().getVariable("subParam").toString());   
  101.             mainTaskInstance2.end();   
  102.         } catch (Exception e) {   
  103.             e.printStackTrace();   
  104.         } finally {   
  105.             jbpmContext.close();   
  106.         }   
  107.     }    
  108.        
  109.     public static void main(String[] args) throws FileNotFoundException {   
  110.         //数据库清理   
  111.         SubProcess.init();   
  112.         //发布流程,必须先发布子流程再发布主流程   
  113.         SubProcess.deploySub();   
  114.         SubProcess.deployMain();   
  115.         SubProcess.startProcess();   
  116.         SubProcess.startMainTask1();   
  117.         SubProcess.startSubTask1();   
  118.         SubProcess.startMainTask2();   
  119.     }   
  120. }  
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代码 复制代码 收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="mail">  
  3.     <start-state name="start-state1">  
  4.         <transition to="mail-node1"></transition>  
  5.     </start-state>  
  6.     <mail-node name="mail-node1" template="test">  
  7.         <event type="node-enter">  
  8.             <script>  
  9.                 print(&quot;enter mail node&quot;)   
  10.             </script>  
  11.         </event>  
  12.         <event type="node-leave">  
  13.             <script>  
  14.                 print(&quot;leave mail node&quot;)   
  15.             </script>  
  16.         </event>  
  17.         <transition to="end-state1"></transition>  
  18.     </mail-node>  
  19.     <end-state name="end-state1"></end-state>  
  20. </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(&quot;enter mail node&quot;)
			</script>
		</event>
		<event type="node-leave">
			<script>
				print(&quot;leave mail node&quot;)
			</script>
		</event>
		<transition to="end-state1"></transition>
	</mail-node>
	<end-state name="end-state1"></end-state>
</process-definition>

我们使用的模版是test,但是jbpm.mail.template.xml没有,所以需要我们自己加:
Xml代码 复制代码 收藏代码
  1. <mail-template name="test">  
  2.         <actors>#{actorId}</actors>  
  3.         <subject>mail node 节点测试</subject>  
  4.         <text><![CDATA[Hi #{actorId}, 
  5.         这是mail node节点的测试内容。  
  6.         ]]></text>  
  7.     </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代码 复制代码 收藏代码
  1. package com.royzhou.util;   
  2.   
  3. import org.jbpm.mail.AddressResolver;   
  4.   
  5. public class MailAddressResolver implements AddressResolver {   
  6.   
  7.     public Object resolveAddress(String actorId) {   
  8.         return "royzhou1985@foxmail.com";   
  9.     }   
  10. }  
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代码 复制代码 收藏代码
  1. <jbpm-configuration>  
  2.     <!-- 邮件解析类 -->  
  3.     <bean name="jbpm.mail.address.resolver"  
  4.         class="com.royzhou.util.MailAddressResolver" singleton="true" />  
  5.     <!-- 邮箱配置信息 -->  
  6.     <string name="resource.mail.properties" value="jbpm.mail.properties" />  
  7.     <!-- 处理邮件发送的类 -->  
  8.     <string name="mail.class.name" value="com.royzhou.util.Mail" />  
  9.     <!-- 发送人地址 -->  
  10.     <string name="jbpm.mail.from.address" value="test@163.com"></string>  
  11. </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代码 复制代码 收藏代码
  1. package com.royzhou.util;   
  2.   
  3. import java.io.InputStream;   
  4. import java.io.Serializable;   
  5. import java.util.ArrayList;   
  6. import java.util.Arrays;   
  7. import java.util.Collection;   
  8. import java.util.Date;   
  9. import java.util.HashMap;   
  10. import java.util.Iterator;   
  11. import java.util.List;   
  12. import java.util.Map;   
  13. import java.util.Properties;   
  14. import java.util.StringTokenizer;   
  15.   
  16. import javax.mail.Message;   
  17. import javax.mail.PasswordAuthentication;   
  18. import javax.mail.Session;   
  19. import javax.mail.Transport;   
  20. import javax.mail.internet.InternetAddress;   
  21. import javax.mail.internet.MimeMessage;   
  22. import javax.mail.Authenticator;   
  23.   
  24. import org.apache.commons.logging.Log;   
  25. import org.apache.commons.logging.LogFactory;   
  26. import org.jbpm.JbpmConfiguration;   
  27. import org.jbpm.JbpmException;   
  28. import org.jbpm.graph.def.ActionHandler;   
  29. import org.jbpm.graph.exe.ExecutionContext;   
  30. import org.jbpm.jpdl.el.ELException;   
  31. import org.jbpm.jpdl.el.VariableResolver;   
  32. import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;   
  33. import org.jbpm.mail.AddressResolver;   
  34. import org.jbpm.util.ClassLoaderUtil;   
  35. import org.jbpm.util.XmlUtil;   
  36.   
  37. public class Mail implements ActionHandler {   
  38.   
  39.   private static final long serialVersionUID = 1L;   
  40.      
  41.   String template = null;   
  42.   String actors = null;   
  43.   String to = null;   
  44.   String bcc = null;   
  45.   String bccActors = null;   
  46.   String subject = null;   
  47.   String text = null;   
  48.      
  49.   ExecutionContext executionContext = null;   
  50.      
  51.   public Mail() {   
  52.   }   
  53.   
  54.   public Mail(String template,   
  55.               String actors,   
  56.               String to,   
  57.               String subject,   
  58.               String text) {   
  59.     this.template = template;   
  60.     this.actors = actors;   
  61.     this.to = to;   
  62.     this.subject = subject;   
  63.     this.text = text;   
  64.   }   
  65.      
  66.   public Mail(String template,   
  67.       String actors,   
  68.       String to,   
  69.       String bccActors,   
  70.       String bcc,   
  71.       String subject,   
  72.       String text) {   
  73.     this.template = template;   
  74.     this.actors = actors;   
  75.     this.to = to;   
  76.     this.bccActors = bccActors;   
  77.     this.bcc = bcc;   
  78.     this.subject = subject;   
  79.     this.text = text;   
  80.   }     
  81.      
  82.   public void execute(ExecutionContext executionContext) {   
  83.     this.executionContext = executionContext;   
  84.     send();   
  85.   }   
  86.   
  87.   public List getRecipients() {   
  88.     List recipients = new ArrayList();   
  89.     if (actors!=null) {   
  90.       String evaluatedActors = evaluate(actors);   
  91.       List tokenizedActors = tokenize(evaluatedActors);   
  92.       if (tokenizedActors!=null) {   
  93.         recipients.addAll(resolveAddresses(tokenizedActors));   
  94.       }   
  95.     }   
  96.     if (to!=null) {   
  97.       String resolvedTo = evaluate(to);   
  98.       recipients.addAll(tokenize(resolvedTo));   
  99.     }   
  100.     return recipients;   
  101.   }   
  102.   
  103.   public List getBccRecipients() {   
  104.     List recipients = new ArrayList();   
  105.     if (bccActors!=null) {   
  106.       String evaluatedActors = evaluate(bccActors);   
  107.       List tokenizedActors = tokenize(evaluatedActors);   
  108.       if (tokenizedActors!=null) {   
  109.         recipients.addAll(resolveAddresses(tokenizedActors));   
  110.       }   
  111.     }   
  112.     if (bcc!=null) {   
  113.       String resolvedTo = evaluate(to);   
  114.       recipients.addAll(tokenize(resolvedTo));   
  115.     }   
  116.     if (JbpmConfiguration.Configs.hasObject("jbpm.mail.bcc.address")) {   
  117.       recipients.addAll(tokenize(   
  118.           JbpmConfiguration.Configs.getString("jbpm.mail.bcc.address")));   
  119.     }   
  120.     return recipients;   
  121.   }   
  122.      
  123.   public String getSubject() {   
  124.     if (subject==nullreturn null;   
  125.     return evaluate(subject);   
  126.   }   
  127.   
  128.   public String getText() {   
  129.     if (text==nullreturn null;   
  130.     return evaluate(text);   
  131.   }   
  132.   
  133.   public String getFromAddress() {   
  134.     if (JbpmConfiguration.Configs.hasObject("jbpm.mail.from.address")) {   
  135.       return JbpmConfiguration.Configs.getString("jbpm.mail.from.address");   
  136.     }    
  137.     return "jbpm@noreply";   
  138.   }   
  139.   
  140.   public void send() {   
  141.     if (template!=null) {   
  142.       Properties properties = getMailTemplateProperties(template);   
  143.       if (actors==null) {   
  144.         actors = properties.getProperty("actors");   
  145.       }   
  146.       if (to==null) {   
  147.         to = properties.getProperty("to");   
  148.       }   
  149.       if (subject==null) {   
  150.         subject = properties.getProperty("subject");   
  151.       }   
  152.       if (text==null) {   
  153.         text = properties.getProperty("text");   
  154.       }   
  155.       if (bcc==null) {   
  156.         bcc = properties.getProperty("bcc");   
  157.       }   
  158.       if (bccActors==null) {   
  159.         bccActors = properties.getProperty("bccActors");   
  160.       }   
  161.     }   
  162.        
  163.     send(getMailServerProperties(),    
  164.             getFromAddress(),    
  165.             getRecipients(),    
  166.             getBccRecipients(),   
  167.             getSubject(),    
  168.             getText());   
  169.   }   
  170.      
  171.   public static void send(Properties mailServerProperties, String fromAddress, List recipients, String subject, String text) {   
  172.     send(mailServerProperties, fromAddress, recipients, null, subject, text);   
  173.   }   
  174.      
  175.   public static void send(Properties mailServerProperties, String fromAddress, List recipients, List bccRecipients, String subject, String text) {   
  176.     if ( (recipients==null)   
  177.          || (recipients.isEmpty())   
  178.        ) {   
  179.       log.debug("skipping mail because there are no recipients");   
  180.       return;   
  181.     }   
  182.     mailServerProperties.put("mail.smtp.auth""true");   
  183.     log.debug("sending email to '"+recipients+"' about '"+subject+"'");   
  184.        
  185.     /**  
  186.      * 添加认证类  
  187.      * royzhou 2009.07.21  
  188.      */  
  189.     String userName = mailServerProperties.getProperty("mail.smtp.user").toString();   
  190.     String password = mailServerProperties.getProperty("mail.smtp.password").toString();   
  191.     MyAuthentication myAuthentication = new MyAuthentication(userName,password);   
  192.     Session session = Session.getDefaultInstance(mailServerProperties, myAuthentication);   
  193.     MimeMessage message = new MimeMessage(session);   
  194.     try {   
  195.       if (fromAddress!=null) {   
  196.         message.setFrom(new InternetAddress(fromAddress));   
  197.       }   
  198.       Iterator iter = recipients.iterator();   
  199.       while (iter.hasNext()) {   
  200.         InternetAddress recipient = new InternetAddress((String) iter.next());   
  201.         message.addRecipient(Message.RecipientType.TO, recipient);   
  202.       }   
  203.       if (bccRecipients!=null) {   
  204.         iter = bccRecipients.iterator();   
  205.         while (iter.hasNext()) {   
  206.           InternetAddress recipient = new InternetAddress((String) iter.next());   
  207.           message.addRecipient(Message.RecipientType.BCC, recipient);   
  208.         }           
  209.       }   
  210.       if (subject!=null) {   
  211.         message.setSubject(subject);   
  212.       }   
  213.       if (text!=null) {   
  214.         message.setText(text);   
  215.       }   
  216.       message.setSentDate(new Date());   
  217.          
  218.       Transport.send(message);   
  219.     } catch (Exception e) {   
  220.       throw new JbpmException("couldn't send email", e);   
  221.     }   
  222.   }   
  223.   
  224.   protected List tokenize(String text) {   
  225.     if (text==null) {   
  226.       return null;   
  227.     }   
  228.     List list = new ArrayList();   
  229.     StringTokenizer tokenizer = new StringTokenizer(text, ";:");   
  230.     while (tokenizer.hasMoreTokens()) {   
  231.       list.add(tokenizer.nextToken());   
  232.     }   
  233.     return list;   
  234.   }   
  235.   
  236.   protected Collection resolveAddresses(List actorIds) {   
  237.     List emailAddresses = new ArrayList();   
  238.     Iterator iter = actorIds.iterator();   
  239.     while (iter.hasNext()) {   
  240.       String actorId = (String) iter.next();   
  241.       AddressResolver addressResolver = (AddressResolver) JbpmConfiguration.Configs.getObject("jbpm.mail.address.resolver");   
  242.       Object resolvedAddresses = addressResolver.resolveAddress(actorId);   
  243.       if (resolvedAddresses!=null) {   
  244.         if (resolvedAddresses instanceof String) {   
  245.           emailAddresses.add((String)resolvedAddresses);   
  246.         } else if (resolvedAddresses instanceof Collection) {   
  247.           emailAddresses.addAll((Collection)resolvedAddresses);   
  248.         } else if (resolvedAddresses instanceof String[]) {   
  249.           emailAddresses.addAll(Arrays.asList((String[])resolvedAddresses));   
  250.         } else {   
  251.           throw new JbpmException("Address resolver '"+addressResolver+"' returned '"+resolvedAddresses.getClass().getName()+"' instead of a String, Collection or String-array: "+resolvedAddresses);   
  252.         }   
  253.       }   
  254.     }   
  255.     return emailAddresses;   
  256.   }   
  257.   
  258.   Properties getMailServerProperties() {   
  259.     Properties mailServerProperties = new Properties();   
  260.   
  261.     if (JbpmConfiguration.Configs.hasObject("resource.mail.properties")) {   
  262.       String mailServerPropertiesResource = JbpmConfiguration.Configs.getString("resource.mail.properties");   
  263.       try {   
  264.         InputStream mailServerStream = ClassLoaderUtil.getStream(mailServerPropertiesResource);   
  265.         mailServerProperties.load(mailServerStream);   
  266.       } catch (Exception e) {   
  267.         throw new JbpmException("couldn't get configuration properties for jbpm mail server from resource '"+mailServerPropertiesResource+"'", e);   
  268.       }   
  269.        
  270.     } else if (JbpmConfiguration.Configs.hasObject("jbpm.mail.smtp.host")) {   
  271.       String smtpServer = JbpmConfiguration.Configs.getString("jbpm.mail.smtp.host");   
  272.       mailServerProperties.put("mail.smtp.host", smtpServer);   
  273.          
  274.     } else {   
  275.          
  276.       log.error("couldn't get mail properties");   
  277.     }   
  278.   
  279.     return mailServerProperties;   
  280.   }   
  281.   
  282.   static Map templates = null;   
  283.   static Map templateVariables = null;   
  284.   synchronized Properties getMailTemplateProperties(String templateName) {   
  285.     if (templates==null) {   
  286.       templates = new HashMap();   
  287.       String mailTemplatesResource = JbpmConfiguration.Configs.getString("resource.mail.templates");   
  288.       org.w3c.dom.Element mailTemplatesElement = XmlUtil.parseXmlResource(mailTemplatesResource).getDocumentElement();   
  289.       List mailTemplateElements = XmlUtil.elements(mailTemplatesElement, "mail-template");   
  290.       Iterator iter = mailTemplateElements.iterator();   
  291.       while (iter.hasNext()) {   
  292.         org.w3c.dom.Element mailTemplateElement = (org.w3c.dom.Element) iter.next();   
  293.   
  294.         Properties templateProperties = new Properties();   
  295.         addTemplateProperty(mailTemplateElement, "actors", templateProperties);   
  296.         addTemplateProperty(mailTemplateElement, "to", templateProperties);   
  297.         addTemplateProperty(mailTemplateElement, "subject", templateProperties);   
  298.         addTemplateProperty(mailTemplateElement, "text", templateProperties);   
  299.         addTemplateProperty(mailTemplateElement, "bcc", templateProperties);   
  300.         addTemplateProperty(mailTemplateElement, "bccActors", templateProperties);   
  301.   
  302.         templates.put(mailTemplateElement.getAttribute("name"), templateProperties);   
  303.       }   
  304.   
  305.       templateVariables = new HashMap();   
  306.       List variableElements = XmlUtil.elements(mailTemplatesElement, "variable");   
  307.       iter = variableElements.iterator();   
  308.       while (iter.hasNext()) {   
  309.         org.w3c.dom.Element variableElement = (org.w3c.dom.Element) iter.next();   
  310.         templateVariables.put(variableElement.getAttribute("name"), variableElement.getAttribute("value"));   
  311.       }   
  312.     }   
  313.     return (Properties) templates.get(templateName);   
  314.   }   
  315.   
  316.   void addTemplateProperty(org.w3c.dom.Element mailTemplateElement, String property, Properties templateProperties) {   
  317.     org.w3c.dom.Element element = XmlUtil.element(mailTemplateElement, property);   
  318.     if (element!=null) {   
  319.       templateProperties.put(property, XmlUtil.getContentText(element));   
  320.     }   
  321.   }   
  322.      
  323.   String evaluate(String expression) {   
  324.     if (expression==null) {   
  325.       return null;   
  326.     }   
  327.     VariableResolver variableResolver = JbpmExpressionEvaluator.getUsedVariableResolver();   
  328.     if (variableResolver!=null) {   
  329.       variableResolver = new MailVariableResolver(templateVariables, variableResolver);   
  330.     }   
  331.     return (String) JbpmExpressionEvaluator.evaluate(expression, executionContext, variableResolver, null);   
  332.   }   
  333.   
  334.   class MailVariableResolver implements VariableResolver, Serializable {   
  335.     private static final long serialVersionUID = 1L;   
  336.     Map templateVariables = null;   
  337.     VariableResolver variableResolver = null;   
  338.   
  339.     public MailVariableResolver(Map templateVariables, VariableResolver variableResolver) {   
  340.       this.templateVariables = templateVariables;   
  341.       this.variableResolver = variableResolver;   
  342.     }   
  343.   
  344.     public Object resolveVariable(String pName) throws ELException {   
  345.       if ( (templateVariables!=null)   
  346.            && (templateVariables.containsKey(pName))   
  347.          ){   
  348.         return templateVariables.get(pName);   
  349.       }   
  350.       return variableResolver.resolveVariable(pName);   
  351.     }   
  352.   }   
  353.   
  354.   private static Log log = LogFactory.getLog(Mail.class);   
  355. }   
  356.   
  357. /**  
  358.  * 邮箱认证类  
  359.  * @author royzhou  
  360.  * 2009.07.21  
  361.  */  
  362. class MyAuthentication extends Authenticator {   
  363.     private String userName;   
  364.     private String password;   
  365.     public MyAuthentication(String userName, String password) {   
  366.         this.userName = userName;   
  367.         this.password = password;   
  368.     }   
  369.     protected PasswordAuthentication getPasswordAuthentication() {   
  370.         return new PasswordAuthentication(userName,password);   
  371.     }   
  372. }  
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);
	}
}


下面我们开始写我们的测试类:MailNode
Java代码 复制代码 收藏代码
  1. package com.royzhou.test;   
  2.   
  3. import org.jbpm.graph.def.ProcessDefinition;   
  4. import org.jbpm.graph.exe.ProcessInstance;   
  5. import org.jbpm.graph.exe.Token;   
  6.   
  7. public class MailNode {   
  8.        
  9.     public static void main(String[] args) {   
  10.         ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("mail/processDefinition.xml");   
  11.         ProcessInstance processInstance = new ProcessInstance(processDefinition);   
  12.         processInstance.getContextInstance().setVariable("actorId""royzhou");   
  13.         Token token = processInstance.getRootToken();   
  14.         token.signal();   
  15.         System.out.println("end^^^^^^^^^^^^");   
  16.     }   
  17. }  
package com.royzhou.test;

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

public class MailNode {
	
	public static void main(String[] args) {
		ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("mail/processDefinition.xml");
		ProcessInstance processInstance = new ProcessInstance(processDefinition);
		processInstance.getContextInstance().setVariable("actorId", "royzhou");
		Token token = processInstance.getRootToken();
		token.signal();
		System.out.println("end^^^^^^^^^^^^");
	}
}

运行测试程序,后台打印:
enter mail node
test====test
leave mail node
end^^^^^^^^^^^^

打开你的收件箱发现邮件发送成功并且信息都是根据模版生成的。。


至此,我们将流程的节点基本上都过了一遍。。。。 笔记终于写完。。。累就一个字

明天出差。。。。
回来继续。。。。。 

展开阅读全文

没有更多推荐了,返回首页