﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-心情小站-随笔分类-工作流jbpm3</title><link>http://www.blogjava.net/RongHao/category/4728.html</link><description>勤学、勤思</description><language>zh-cn</language><lastBuildDate>Fri, 22 Jun 2007 10:42:35 GMT</lastBuildDate><pubDate>Fri, 22 Jun 2007 10:42:35 GMT</pubDate><ttl>60</ttl><item><title>JBPM时间服务的实现</title><link>http://www.blogjava.net/RongHao/archive/2007/06/22/125886.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Fri, 22 Jun 2007 09:13:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/06/22/125886.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/125886.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/06/22/125886.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/125886.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/125886.html</trackback:ping><description><![CDATA[&nbsp; 整体来说实现的非常清晰：<br>&nbsp; <span style="font-weight: bold;">1</span>、引擎解析流程定义xml时，给相应的事件挂接上create-timer 和 cancel-timer动作<br>&nbsp; <span style="font-weight: bold;">2</span>、流程实例实际运转时，create-timer动作在相应事件触发时执行<br>&nbsp; <span style="font-weight: bold;">3</span>、create-timer在job表里插入相应时间job记录，给该job记录附上计算完毕的执行时间<br>&nbsp; <span style="font-weight: bold;">4</span>、JobExecutorServlet在后台启动一到多个JobExecutorThread线程<br>&nbsp; <span style="font-weight: bold;">5</span>、JobExecutorThread线程不停的每隔一段时间对job表扫描一次，找出需要执行的job记录，执行之<br>&nbsp; <span style="font-weight: bold;">6</span>、只执行一次的job记录，执行完毕后删除之；重复执行的job记录，写入新的执行时间，更新之<br>&nbsp; <span style="font-weight: bold;">7</span>、相应事件触发cancel-timer动作，将对应job记录从job表里删除<br>&nbsp; 下面具体用代码来说话（挂接到node节点）：<br>&nbsp; <span style="font-weight: bold;">1</span>、引擎解析流程定义xml&nbsp; <br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;JpdlXmlReader.java&nbsp;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;readNodeTimer(Element&nbsp;timerElement,&nbsp;Node&nbsp;node)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;timerElement.attributeValue(</span><span style="color: #000000;">"</span><span style="color: #000000;">name</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;node.getName());<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;CreateTimerAction&nbsp;createTimerAction&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CreateTimerAction();<br>&nbsp;&nbsp;&nbsp;&nbsp;createTimerAction.read(timerElement,&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;createTimerAction.setTimerName(name);<br>&nbsp;&nbsp;&nbsp;&nbsp;createTimerAction.setTimerAction(readSingleAction(timerElement));<br>&nbsp;&nbsp;&nbsp;&nbsp;addAction(node,&nbsp;Event.EVENTTYPE_NODE_ENTER,&nbsp;createTimerAction);<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;CancelTimerAction&nbsp;cancelTimerAction&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CancelTimerAction();<br>&nbsp;&nbsp;&nbsp;&nbsp;cancelTimerAction.setTimerName(name);<br>&nbsp;&nbsp;&nbsp;&nbsp;addAction(node,&nbsp;Event.EVENTTYPE_NODE_LEAVE,&nbsp;cancelTimerAction);<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; 可以看到，引擎把xml中timer节点解析成了两个ACTION：CreateTimerAction和CancelTimerAction<br>&nbsp; CreateTimerAction会在进入该节点时触发，而CancelTimerAction会在令牌离开该节点时触发。<br>&nbsp; <span style="font-weight: bold;">2</span>、看看CreateTimerAction和CancelTimerAction究竟在做些什么<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;CreateTimerAction.java<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;execute(ExecutionContext&nbsp;executionContext)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Timer&nbsp;timer&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;createTimer(executionContext);<br>&nbsp;&nbsp;&nbsp;&nbsp;SchedulerService&nbsp;schedulerService&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(SchedulerService)&nbsp;Services.getCurrentService(Services.SERVICENAME_SCHEDULER);<br>&nbsp;&nbsp;&nbsp;&nbsp;schedulerService.createTimer(timer);<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; 很明显，是通过一个职责集中的schedulerService向job表中插入了一条job记录，注意到这个方法：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;Timer&nbsp;createTimer(ExecutionContext&nbsp;executionContext)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Timer&nbsp;timer&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Timer(executionContext.getToken());<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(dueDate</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Duration&nbsp;duration&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Duration(dueDate);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date&nbsp;dueDateDate&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;businessCalendar.add(&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Date(),&nbsp;duration&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timer.setDueDate(dueDateDate);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;timer;<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; 这里利用JBPM提供的工作时间计算组件计算了job的执行时间。<br>&nbsp; CancelTimerAction就很简单了，删除相应的job记录。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;CancelTimerAction.java<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;execute(ExecutionContext&nbsp;executionContext)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;SchedulerService&nbsp;schedulerService&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(SchedulerService)&nbsp;Services.getCurrentService(Services.SERVICENAME_SCHEDULER);<br>&nbsp;&nbsp;&nbsp;&nbsp;schedulerService.deleteTimersByName(timerName,&nbsp;executionContext.getToken());<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; <span style="font-weight: bold;">3</span>、JobExecutorServlet是干什么的<br>&nbsp; 启动线程<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;init()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;ServletException&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;&nbsp;jbpmConfiguration.startJobExecutor();<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; <span style="font-weight: bold;">4</span>、线程是如何工作<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentIdleInterval&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;idleInterval;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(isActive)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collection&nbsp;acquiredJobs&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;acquireJobs();&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">从job表里获得将要执行的job记录</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;acquiredJobs.isEmpty())&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">如果记录不为空，则开始执行</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterator&nbsp;iter&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;acquiredJobs.iterator();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(iter.hasNext()&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;isActive)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Job&nbsp;job&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(Job)&nbsp;iter.next();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executeJob(job);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">执行</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;no&nbsp;jobs&nbsp;acquired&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">如果没有可执行的job，则等待一段时间</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(isActive)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">long</span><span style="color: #000000;">&nbsp;waitPeriod&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;getWaitPeriod();&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">等待的时间是找出即将执行的job离现在最近的时间间隔</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(waitPeriod</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">(jobExecutor)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jobExecutor.wait(waitPeriod);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(getName()</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;leaves&nbsp;cyberspace</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; 看看实际执行的方法<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;executeJob(Job&nbsp;job)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;JbpmContext&nbsp;jbpmContext&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;jbpmConfiguration.createJbpmContext();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobSession&nbsp;jobSession&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;jbpmContext.getJobSession();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;job&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;jobSession.loadJob(job.getId());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">executing&nbsp;job&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">job);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(job.execute(jbpmContext))&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">交由Job对象本身去完成执行的逻辑，并决定是否删除job记录</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jobSession.deleteJob(job);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;}</span></div>
<br>&nbsp; <span style="font-weight: bold;">5</span>、着重关注Time对象<br>&nbsp; 在上面我们看到实际执行的代码是job.execute(jbpmContext);<br>&nbsp; Time 是Job的子类，看看它的实现：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;execute(JbpmContext&nbsp;jbpmContext)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;deleteThisJob&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">执行完毕后是否删除job记录</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;ExecutionContext&nbsp;executionContext&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ExecutionContext(token);<br>&nbsp;&nbsp;&nbsp;&nbsp;executionContext.setTimer(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(taskInstance</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executionContext.setTaskInstance(taskInstance);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;触发timer事件</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(graphElement</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;graphElement.fireAndPropagateEvent(Event.EVENTTYPE_TIMER,&nbsp;executionContext);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;如果timer节点上挂有action则执行之</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(action</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">executing&nbsp;timer&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #0000ff;">this</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">'</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action.execute(executionContext);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(Exception&nbsp;actionException)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;如果定义了transition属性，则流程顺着定义的路径流转</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(&nbsp;(transitionName</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;(exception</span><span style="color: #000000;">==</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;and&nbsp;if&nbsp;no&nbsp;unhandled&nbsp;exception&nbsp;occurred&nbsp;during&nbsp;the&nbsp;action&nbsp;</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(token.getNode().hasLeavingTransition(transitionName))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;token.signal(transitionName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;如果定义了repeat属性则job记录不容许删除，同时计算新的执行时间</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(repeat</span><span style="color: #000000;">!=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deleteThisJob&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(dueDate.getTime()</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">System.currentTimeMillis())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dueDate&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;businessCalendar<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.add(dueDate,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Duration(repeat));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">updated&nbsp;timer&nbsp;for&nbsp;repetition&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #0000ff;">this</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">'&nbsp;in&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">(dueDate.getTime()</span><span style="color: #000000;">-</span><span style="color: #000000;">System.currentTimeMillis())</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">'&nbsp;millis</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;deleteThisJob;<br>&nbsp;&nbsp;}</span></div>
<br><br><img src ="http://www.blogjava.net/RongHao/aggbug/125886.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-06-22 17:13 <a href="http://www.blogjava.net/RongHao/archive/2007/06/22/125886.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JBPM的时间服务</title><link>http://www.blogjava.net/RongHao/archive/2007/06/21/125512.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 21 Jun 2007 04:00:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/06/21/125512.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/125512.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/06/21/125512.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/125512.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/125512.html</trackback:ping><description><![CDATA[JBPM时间服务的使用主要体现在对timer节点的使用。timer节点有两种使用方式：一种是挂接到node节点下，在进入node节点时触发，在离开node节点时终止；另外一种是挂接到task节点下，在任务创建时触发，默认在任务完成后终止。下面举例说明：<br>&nbsp; <span style="font-weight: bold;">一、挂接到node节点&nbsp;</span>&nbsp; <br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">state&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">='catch&nbsp;</span><span style="color: #ff0000;">crooks'</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">timer&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">='reminder'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000;">duedate</span><span style="color: #0000ff;">='3&nbsp;</span><span style="color: #ff0000;">business&nbsp;hours'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;repeat</span><span style="color: #0000ff;">='10&nbsp;</span><span style="color: #ff0000;">business&nbsp;minutes'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transition</span><span style="color: #0000ff;">='time-out-transition'&nbsp;</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">action&nbsp;</span><span style="color: #ff0000;">class</span><span style="color: #0000ff;">='the-remainder-action-class-name'&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">transition&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">='time-out-transition'&nbsp;</span><span style="color: #ff0000;">to</span><span style="color: #0000ff;">='next'&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">timer</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">state</span><span style="color: #0000ff;">&gt;</span></div>
<br>&nbsp; 解释：timer将会在流程令牌进入节点catch crooks时触发，延迟3 business hours开始执行动作，每10 business minutes重复执行一次，直到令牌离开catch crooks节点。<br>&nbsp; 对time节点来说 name、repeat、transition都是可选属性。对一个流程定义来说，每一个time节点的name必须唯一，如果你不定义name属性，引擎会默认把node节点的name赋给timer。在上面这个例子里，如果你不定义timer节点的name，则它的name就会是catch crooks。说说repeat属性，如果你不定义它，则timer就会只执行一次动作不会重复执行。transition属性，如果定义了这个属性，流程令牌会在timer执行动作完毕后，顺着这个路径离开node节点。所以在上面这个例子里，尽管定义了repeat属性，action还是会只执行一次。<br>&nbsp; action节点，可选，即timer节点在时间到时执行的动作，可以是任意action类型，包括script。注意与时间有关的两种action类型：create-timer 和 cancel-timer。其实一个timer节点在被引擎解释时就是被分解为create-timer 和 cancel-timer两个action，create-timer挂接到node-enter事件中，cancel-timer挂接到node-leave事件中。action节点最多只可以挂一个。<br>&nbsp; 说说整个过程：<br>&nbsp; 1、令牌进入节点catch crooks<br>&nbsp; 2、timer被触发（实际这时是在执行create-timer动作）<br>&nbsp; 3、3 business hours后 timer 事件触发<br>&nbsp; 4、定义的action被执行<br>&nbsp; 5、令牌顺着time-out-transition路径离开catch crooks节点<br>&nbsp; 6、cancel-timer动作被执行即timer终止（没有给repeat的机会）<br>&nbsp; <span style="font-weight: bold;">二、挂接到task节点</span><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">task-node&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="Evaluate&nbsp;web&nbsp;order"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">task&nbsp;</span><span style="color: #ff0000;">swimlane</span><span style="color: #0000ff;">="salesman"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">timer&nbsp;</span><span style="color: #ff0000;">duedate</span><span style="color: #0000ff;">="20&nbsp;seconds"</span><span style="color: #ff0000;">&nbsp;repeat</span><span style="color: #0000ff;">="10&nbsp;seconds"</span><span style="color: #ff0000;">&nbsp;cancel-event</span><span style="color: #0000ff;">='task-start'&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #ff0000;">&lt;action&nbsp;class</span><span style="color: #0000ff;">="org.jbpm.websale.RemindActor"</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">swimlaneName</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">salesman</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">swimlaneName</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">action</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">timer</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">task</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">transition&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="OK"</span><span style="color: #ff0000;">&nbsp;to</span><span style="color: #0000ff;">="salefork"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">transition&nbsp;</span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="More&nbsp;info&nbsp;needed"</span><span style="color: #ff0000;">&nbsp;to</span><span style="color: #0000ff;">="Fix&nbsp;web&nbsp;order&nbsp;data"</span><span style="color: #ff0000;">&nbsp;</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">task-node</span><span style="color: #0000ff;">&gt;</span></div>
<br>&nbsp; 与挂接到node 的区别是：这里可以定义一个属性cancel-event，可以指定那些事件可以终止timer的执行，默认是task-end。可以指定多个事件，以','分割，任一事件触发timer即终止。<br>&nbsp; 可以看到jbpm对任务实例和节点执行时的时间服务还是支持的很好，可以做出很多的扩展，但是它没有对整个流程实例本身提供更多的服务，比如说定时的流程启动和整个流程的时间控制等等。以及对精确时间点的支持还不够。<br><img src ="http://www.blogjava.net/RongHao/aggbug/125512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-06-21 12:00 <a href="http://www.blogjava.net/RongHao/archive/2007/06/21/125512.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发现jbpm BusinessCalendar的一个疏忽</title><link>http://www.blogjava.net/RongHao/archive/2007/06/15/124549.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Fri, 15 Jun 2007 09:58:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/06/15/124549.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/124549.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/06/15/124549.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/124549.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/124549.html</trackback:ping><description><![CDATA[jbpm BusinessCalendar是一个很好用的计算工作日设定的时间服务组件，美中不足的是它的工作日设定是写死在配置文件中，不能灵活的由用户修改。另外hongsoft在他的博客中提到jbpm BusinessCalendar可能存在的一个bug：<br><a  href="http://blog.csdn.net/hongbo781202/archive/2006/02/28/612541.aspx">http://blog.csdn.net/hongbo781202/archive/2006/02/28/612541.aspx</a><br>这个bug在我的测试中没有重现，我的jbpm版本是3.2，可以认为jbpm已经修复这个bug。另外在<br>jbpm BusinessCalendar的配置文件中有这么一行<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">weekday.thuesday=&nbsp;&nbsp;9:00-12:00&nbsp;&amp;&nbsp;12:30-17:00</span></div>
<br>可以理解为是一个疏忽，应该是tuesday，礼拜二，呵呵。<br><img src ="http://www.blogjava.net/RongHao/aggbug/124549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-06-15 17:58 <a href="http://www.blogjava.net/RongHao/archive/2007/06/15/124549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>工作流时间管理需求</title><link>http://www.blogjava.net/RongHao/archive/2007/06/14/124259.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Thu, 14 Jun 2007 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/06/14/124259.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/124259.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/06/14/124259.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/124259.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/124259.html</trackback:ping><description><![CDATA[<span style="font-weight: bold; font-size: 18pt;">工作流时间管理按功能分类</span>：<br>&nbsp; <span style="font-weight: bold;">1.</span> 时间事件启动工作流流程实例（指定时间点、时间间隔、周期时间）<br>&nbsp; <span style="font-weight: bold;">2.</span> 任务挂起恢复（指定时间点、时间间隔）<br>&nbsp; <span style="font-weight: bold;">3.</span> 任务预警、报警、超时通知<br>&nbsp; <span style="font-weight: bold;">4.</span> 工作流流程实例超时通知<br>&nbsp; <span style="font-weight: bold;">5.</span> 非工作日、节假日设定<br><span style="font-weight: bold;">&nbsp; 6.</span> 流程、任务的处理时间统计<br style="font-weight: bold;"><span style="font-weight: bold; font-size: 18pt;">具体说明</span>：<br>&nbsp; <span style="font-weight: bold;">1、</span>工作流流程实例在设置的时间自动启动，设置时间包括下面两种方式：<br>&nbsp;&nbsp;&nbsp;&nbsp; a、指定一个固定的时间点，然后设置周期时间，例如每天、每周的周一、每月的第一天；<br>&nbsp;&nbsp;&nbsp;&nbsp; b、指定一个固定的时间点，然后设置时间间隔，例如20分钟后，2小时后，一天后，一个月后。<br>&nbsp; <span style="font-weight: bold;">2、</span>任务在上一个任务节点完成后多长时间启动。并发任务之间的时间启动关系。任务在指定时间点启动。<br>&nbsp;&nbsp;&nbsp;&nbsp; 举例：财务每周五下午2点开始集中处理报销事务，所有流程实例流转到财务报销节点处于等待状态，直到周五下午2点任务才启动，财务才在任务列表里看到待处理的报销事务并集中处理。<br>&nbsp; <span style="font-weight: bold;">3、</span>举例说明：经理审批这个任务节点设置完成时间1小时<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">预警</span>：时间过去预定完成时间一定百分比比如50%还未完成，则在任务发出半小时后系统发出预警信息，按一定时间间隔循环发出。直到任务报警或任务超时或任务完成。<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">报警</span>：时间过去预定完成时间一定百分比比如90%还未完成，则在任务发出54分钟后系统发出报警信息，预警自动终止。报警信息只发送一次。<br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">超时通知</span>：任务在规定时间内未完成，系统发出超时通知。同时任务超时存在业务或流程处理，任务<br>超时应当可以挂上javabean处理一定业务逻辑，同时流程可以选择继续等待或是跳转。<br>&nbsp; <span style="font-weight: bold;">4、</span>和任务超时类似，系统发送超时通知，同时应该存在业务和流程的处理。比如说流程自动终止。<br>&nbsp; <span style="font-weight: bold;">5、</span>主要提供时间计算时对非工作日、非工作时间和节假日的考虑。这里的时间计算仅仅针对于输入一个时间计算一定时间间隔后输出一个时间，比如说现在是周五2点，输入，两天时间间隔，输入，周日2点，输出。考虑非工作日，则输出应该为下周二2点。用途主要体现在对任务和流程的时间完成期限限定计算上。<br>&nbsp; <span style="font-weight: bold;">6、</span>统计，报表。<br>大家提提自己的意见。<br><br><img src ="http://www.blogjava.net/RongHao/aggbug/124259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-06-14 11:42 <a href="http://www.blogjava.net/RongHao/archive/2007/06/14/124259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我对BPM的认识</title><link>http://www.blogjava.net/RongHao/archive/2007/03/26/106395.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Mon, 26 Mar 2007 06:27:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2007/03/26/106395.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/106395.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2007/03/26/106395.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/106395.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/106395.html</trackback:ping><description><![CDATA[昨天参加了BEA UG的活动。其中第二场是BEA罗振东先生的BPM讲解。因为公司一直就是做工作流的，所以对BPM这个概念一直是非常的关注，但是一直也是搞不太清楚Workflow与BPM的关系，总是以为BPM是对WorkFlow的一层包装而已，是新瓶装老酒。在听罗振东先生演讲的过程中，我开始有了一些自己的认识。<br />一句话说：<b>BPM是建立在EAI基础上的工作流。</b><br />和工作流不同，BPM关注的是一个很完整概念上的业务流程，这个业务流程可能需要横跨多个IT系统，这些系统通过某种方式暴露出流程中所需要的服务（webservice是一种选择），BPM推动这个流程的流转。同时，相对于以往的工作流单纯的流程流转，BPM提供了更多，包括流程仿真，过程分析、过程优化等等。意思就是，在某个流程运行一段时间以后，BPM会基于数据提供对该流程的分析（数据挖掘？），从而能够基于这些分析提供对上层管理决策的支持。有点像运筹学。<br />那么，一个工作流厂商是否可以很容易的研发出BPM的产品？答案是不行。看看哪些BPM的厂商，无一不是在EAI方面有很多经验的大公司。所以，BPM实施的关键还是要建立在EAI实施的基础上。至于BPM和SOA，如果以前的系统是基于SOA架构的，那自然EAI起来是会更加容易，BPM理所当然是拥抱SOA的。（BEA的产品没用adapter）<br />那么当前工作流的发展方向呢？个人认为可以从BPM的功能里找到一些线索，那就是流程仿真，过程分析、过程优化。比如一个请假申请流程，统计一下，在哪个节点的办理效率最低，哪些节点在实际中不是必须等等，当然这些都是工作流本身基于流程的数据进行的独立的分析，有点决策的意思在里面。<br />呵呵，个人的一些浅见。希望多批评。<img src ="http://www.blogjava.net/RongHao/aggbug/106395.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2007-03-26 14:27 <a href="http://www.blogjava.net/RongHao/archive/2007/03/26/106395.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jbpm的用户角色管理 </title><link>http://www.blogjava.net/RongHao/archive/2005/11/16/20121.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Wed, 16 Nov 2005 10:00:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2005/11/16/20121.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/20121.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2005/11/16/20121.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/20121.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/20121.html</trackback:ping><description><![CDATA[jbpm在用户角色管理上共设计了四个类：Entity、 Membership、 Group、 User<BR>Entity类是其他三个类的父类，它包含了两个属性：name(String)、 permissions(Set)<BR>User类继承Entity类，包含三个属性：password(String)、 email(String)、 memberships(Set)<BR>Group类继承Entity类，包含四个属性: type(String) 、parent(Group)、 children(Set)、 memberships(Set)<BR>Membership类继承Entity类，包含三个属性:role(String)、 user(User)、 group(Group) <BR>很明显，一个user对应一个用户，一个group对应一个用户组，它们之间通过membership关联，并且一个user可以属于多个不同类型（type)的group，user和 group之间是多对多的关系。<BR>Membership类的role属性个人感觉用途不大，反倒是name属性代表了user在group里的role（角色）！<img src ="http://www.blogjava.net/RongHao/aggbug/20121.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2005-11-16 18:00 <a href="http://www.blogjava.net/RongHao/archive/2005/11/16/20121.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jbpm里的Node</title><link>http://www.blogjava.net/RongHao/archive/2005/11/15/19935.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Tue, 15 Nov 2005 10:14:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2005/11/15/19935.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/19935.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2005/11/15/19935.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/19935.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/19935.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个流程图由许多node和transition组成。每个node都有一种类型，这个类型决定了当流程执行到这个node时的不同行为。jbpm有一组node type可以供你选择，当然你可以定制自己node 。<BR><STRONG>node的作用<BR></STRONG>node有两个主要的作用：<BR>1）<STRONG>执行java代码</STRONG>，比如说创建task instance（任务实例）、发出通知、更新数据库等等。很典型的就是在node 上挂上我们的action<BR>2) <STRONG>控制流程的执行</STRONG>：<BR>&nbsp; A、等待状态<BR>&nbsp;&nbsp;&nbsp;&nbsp; 流程进入到这个node时将处于等待状态，直到一个signal 的发出<BR>&nbsp; B、流程将沿着一个leaving transition越过这个node<BR>&nbsp;&nbsp;&nbsp;&nbsp; 这种情况特殊一点，需要有个action挂在这个node上（注意这个action不是event触发的！），action中将会调用到API里<BR>&nbsp;&nbsp;&nbsp;&nbsp; executionContext.leaveNode(String transitionName)，transitionName即这里的leaving transition名字。<BR>&nbsp; C、创建新的执行路径<BR>&nbsp;&nbsp;&nbsp;&nbsp; 很典型的就是fork node。流程在这里会分叉，产生新的执行路径。这样就创建了新的token，每个新的token代表一个新的执行路径。注意的是，这些新的token和产生前的token是父子关系！<BR>&nbsp; D、结束执行路径<BR>&nbsp;&nbsp;&nbsp;&nbsp; 一个node可以结束一条执行路径，这同样意味着相应的token的结束和流程的结束。<img src ="http://www.blogjava.net/RongHao/aggbug/19935.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2005-11-15 18:14 <a href="http://www.blogjava.net/RongHao/archive/2005/11/15/19935.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>流程图中的node type </title><link>http://www.blogjava.net/RongHao/archive/2005/11/14/19735.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Mon, 14 Nov 2005 08:59:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2005/11/14/19735.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/19735.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2005/11/14/19735.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/19735.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/19735.html</trackback:ping><description><![CDATA[<STRONG>1、task-node<BR></STRONG>&nbsp; 一个task-node可以包含一个或多个task，这些task分配给特定的user。当流程执行到task-node时，task instance将会被创建，一个task对应一个task instance。task instances 创建后，task-node就处于等待状态。当所有的task instances被特定的user执行完毕后，将会发出一个新的signal 到token，即流程继续执行。<BR><STRONG>2、state</STRONG><BR>&nbsp; state是一个纯粹的wait state(等待状态）。它和task-node的区别就是它不会创建task instances。很典型的用法是，当进入这个节点时（通过绑定一个action到node-enter event），发送一条消息到外部的系统，然后流程就处于等待状态。外部系统完成一些操作后返回一条消息，这个消息触发一个signal 到token，然后流程继续执行。（不常用）<BR><STRONG>3、decision<BR></STRONG>&nbsp; 当需要在流程中根据不同条件来判断执行不同路径时，就可以用decision节点。两种方法：最简单的是在transitions里增加condition elements（条件），condition是beanshell script写的，它返回一个boolean。当运行的时候，decision节点将会在它的 leaving transitions里循环，同时比较 leaving transitions里的condition，最先返回'true'的condition，那个leaving transitions将会被执行；作为选择，你可以实现DecisionHandler接口，它有一个decide()方法，该方法返回一个String(leaving transition的名字）。<BR><STRONG>4、fork</STRONG><BR>&nbsp; fork节点把一条执行路径分离成多条同时进行（并发）的执行路径，每条离开fork节点的路径产生一个子token。<BR><STRONG>5、join<BR></STRONG>&nbsp; 默认情况下，join节点会认为所有到达该节点的token都有着相同的父token。join 节点会结束每一个到达该节点的token,当所有的子token都到达该节点后，父token会激活。当仍然有子token处于活动状态时，join 节点是wait state(等待状态）。<BR><STRONG>6、node<BR></STRONG>&nbsp; node节点就是让你挂自己的action用的（注意：不是event触发！！），当流程到达该节点时，action会被执行。你的action要实现ActionHandler接口。同样，在你的action里要控制流程！<img src ="http://www.blogjava.net/RongHao/aggbug/19735.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2005-11-14 16:59 <a href="http://www.blogjava.net/RongHao/archive/2005/11/14/19735.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jbpm的流程模型</title><link>http://www.blogjava.net/RongHao/archive/2005/11/12/19445.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Sat, 12 Nov 2005 01:46:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2005/11/12/19445.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/19445.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2005/11/12/19445.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/19445.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/19445.html</trackback:ping><description><![CDATA[<STRONG>1、process definition<BR></STRONG>&nbsp;&nbsp; 一个process definition代表了一个正式的业务流程，它以一个流程图为基础。这个流程图由&nbsp; 许多node和transition组成。每个node在这个流程图里都有着各自特殊的类型，这些不同的类型决定了node在运行时的不同行为。一个process definition只有一个start state 。<BR><STRONG>2、token</STRONG><BR>&nbsp;&nbsp; 一个token代表了一条执行路径，它包含了这条执行路径的当前的执行状态（current state）。 <BR><STRONG>3、process instance<BR></STRONG>&nbsp;&nbsp; 一个process instance（流程实例）即一个process definition（流程定义）的流程执行实例。一个process definition可以对应多个process instance。当一个process instance被创建的时候，一个主执行路径token同时被创建，这个token叫做root token，它指向流程定义的start state（processDefinition.getStartState()==token.getNode()）。<BR><STRONG>4、signal <BR></STRONG>&nbsp;&nbsp; 一个signal 发送给token通知token 继续流程的执行。如果signal 没有指定transition，token将沿缺省的transition离开当前状态,如果signal 指定transition，token将沿指定的transition离开当前的状态。看源代码可以看到发给process instance的signal 其实都是发送给了root token。 <BR><STRONG>5、Actions</STRONG> <BR>&nbsp;&nbsp; jbpm提供了灵活的action ，当流程执行，token 进入node和transition时，会触发相应的一些event（事件）。在这些event上附上我们自己写的action，就会带动action 的执行。action里是我们自己的相关java操作代码，非常方便。注意的是event（事件）是内置的，无法扩展。另外，action也可以直接挂在node上，而不依赖于event（事件）的触发，这个很重要！<img src ="http://www.blogjava.net/RongHao/aggbug/19445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2005-11-12 09:46 <a href="http://www.blogjava.net/RongHao/archive/2005/11/12/19445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jbpm任务分配管理</title><link>http://www.blogjava.net/RongHao/archive/2005/11/11/19333.html</link><dc:creator>ronghao</dc:creator><author>ronghao</author><pubDate>Fri, 11 Nov 2005 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/RongHao/archive/2005/11/11/19333.html</guid><wfw:comment>http://www.blogjava.net/RongHao/comments/19333.html</wfw:comment><comments>http://www.blogjava.net/RongHao/archive/2005/11/11/19333.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/RongHao/comments/commentRss/19333.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/RongHao/services/trackbacks/19333.html</trackback:ping><description><![CDATA[<P>一个Task instance（任务实例）可以被分配给一个actorId (java.lang.String)。所有的Task instance都被保存在数据库中的表jbpm_taskinstance里。当你想得到特定用户的任务清单时，你就可以通过一个与用户关联的actorId来查询这张表。</P>
<P>一个流程定义有一个TaskMgmtDefinition；一个TaskMgmtDefinition对应多个swimlane,同时对应多个task;一个swimlane有多个task,可以&nbsp; TaskMgmtDefinition中通过task的名称直接获取相应的task;</P>
<P>swimlane对象有四个属性，分别是name（名字）、assignmentDelegation（分配代理类）、taskMgmtDefinition、tasks（Set 对应多个task),可以增加task</P>
<P>task对象主要的属性：taskMgmtDefinition、swimlane、assignmentDelegation、taskNode，需要注意的是swimlane和assignmentDelegation中间只是可以一个属性有值，因为它们都和任务的分配有关系。</P>
<P>一个流程实例有一个TaskMgmtInstance；一个TaskMgmtInstance对应多个swimlaneInstance,同时对应多个taskInstance;一个swimlaneInstance有多个taskInstance,可以从TaskMgmtInstance中直接获取相应的taskInstance;</P>
<P>swimlaneInstance对象主要有五个属性，分别是name、actorId、pooledActors（Set）、swimlane、taskMgmtInstance。<BR>taskInstance对象的主要属性：name、actorId、task、swimlaneInstance、taskMgmtInstance、pooledActors。</P>
<P>当对任务进行分配时，一般需要实现AssignmentHandler这个接口，这个接口的方法只有一个：<BR>&nbsp; void assign( Assignable assignable, ExecutionContext executionContext ) throws Exception;<BR>一个典型的实现（把名字是'change nappy'的任务交给NappyAssignmentHandler这个类来分配）<BR>&nbsp;&nbsp; &lt;task name='change nappy'&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' /&gt;<BR>&nbsp;&nbsp; &lt;/task&gt;<BR>NappyAssignmentHandler类：<BR>&nbsp; public void assign(Assignable assignable, ExecutionContext executionContext) {<BR>&nbsp;&nbsp;&nbsp; assignable.setActorId("papa");<BR>&nbsp; }<BR>同样，Assignable只是一个接口，它有两个方法：setActorId()和setPooledActors()，Assignable的具体实现类也是两个<BR>&nbsp; swimlaneInstancehe和taskInstance。这样就不不难理解整个任务分配流程了：<BR>&nbsp; 1、流程进入TaskNode节点，执行TaskNode类的execute()方法，该方法首先获得TaskMgmtInstance实例，然后通过它来创建TaskInstance。taskMgmtInstance.createTaskInstance(task, executionContext);<BR>&nbsp; 2、在上面的createTaskInstance(task, executionContext)里，该方法调用了taskInstance.assign(executionContext)对taskInstance进行分配。<BR>&nbsp; 3、在assign(executionContext)方法里，首先会判断task属性里是否存在swimlane，如果有的话，这个taskInstance就会分配给swimlane指定的ActorId或 PooledActors；如果不存在，再去找task属性里 assignmentDelegation（分配代理类）通过代理类（即我们自己写的实现AssignmentHandler这个接口的类）指定ActorId或 PooledActors。 </P><img src ="http://www.blogjava.net/RongHao/aggbug/19333.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/RongHao/" target="_blank">ronghao</a> 2005-11-11 16:39 <a href="http://www.blogjava.net/RongHao/archive/2005/11/11/19333.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>