﻿<?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-&lt;b&gt;成都心情&lt;/b&gt;-随笔分类-工作流</title><link>http://www.blogjava.net/rosen/category/2684.html</link><description>本 Blog 是从：http://blog.csdn.net/rosen 搬来。&lt;br/&gt;</description><language>zh-cn</language><lastBuildDate>Mon, 03 Dec 2007 09:16:28 GMT</lastBuildDate><pubDate>Mon, 03 Dec 2007 09:16:28 GMT</pubDate><ttl>60</ttl><item><title>工作流理论总结</title><link>http://www.blogjava.net/rosen/archive/2006/04/30/44209.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Sun, 30 Apr 2006 07:33:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2006/04/30/44209.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/44209.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2006/04/30/44209.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/44209.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/44209.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.            												工作流历史																																						工作流技术发端于				1970				年代中期办公自动化领域的研究工作，但工作流思想的出现还应该更早，				1968				年				Fritz Nordsieck				就已经清楚地表达了...&nbsp;&nbsp;<a href='http://www.blogjava.net/rosen/archive/2006/04/30/44209.html'>阅读全文</a><img src ="http://www.blogjava.net/rosen/aggbug/44209.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2006-04-30 15:33 <a href="http://www.blogjava.net/rosen/archive/2006/04/30/44209.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Drools 为你的业务逻辑提供框架（翻译）</title><link>http://www.blogjava.net/rosen/archive/2005/09/11/12668.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Sun, 11 Sep 2005 08:34:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/09/11/12668.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/12668.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/09/11/12668.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/12668.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/12668.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; 大部分 web 以及企业级 Java 应用可被分成三部分：与用户交互的前台，与数据库这样的后台系统交互的服务层，以及它们之间的业务逻辑。最近这段时间，通常我们会使用框架来实现前台和后台的需求（例如：Struts, Cocoon, Spring, Hibernate, JDO, 以及实体 Beans），但是却没有一种标准手段很好的组织业务逻辑。像 EJB 和 S...&nbsp;&nbsp;<a href='http://www.blogjava.net/rosen/archive/2005/09/11/12668.html'>阅读全文</a><img src ="http://www.blogjava.net/rosen/aggbug/12668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-09-11 16:34 <a href="http://www.blogjava.net/rosen/archive/2005/09/11/12668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>充分利用 OSWorkflow 的 function</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9888.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9888.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9888.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9888.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9888.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9888.html</trackback:ping><description><![CDATA[<P>&nbsp;&nbsp;&nbsp; 使用 OSWorkflow 已经有段时间了，现在看来实际需求不是请假条流程原型这么简单。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 有这样的需求：OA 系统中的公文审批共有六个 step，采用单点（不牵涉 split 和 join）逐级审核方式，不同角色登陆时，由同一页面处理，为了便于收发文统计，必须知道下一个接收人是哪个。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 由于在触发当前 action 的同时就要设置好下一接收者，遂需要引进新的协作表。当 action 时要调用另外的 save 方法，而这一过程当然不能在表现层进行。最开始的做法是用一个辅助 service 来取出每个 action 的下一接收者，如下：</P>
<P>
<TABLE style="WIDTH: 452px; HEIGHT: 166px" cellSpacing=1 cellPadding=1 width=452 border=1>
<TBODY>
<TR>
<TD><FONT size=2>&nbsp;&nbsp;public List getLeader(int type,int companyId) {<BR>&nbsp;&nbsp;switch (type) {<BR>&nbsp;&nbsp;&nbsp;case 1:<BR>&nbsp;&nbsp;&nbsp;&nbsp;return docSendDao.getThisFaculty(companyId);<BR>&nbsp;&nbsp;&nbsp;case 2:<BR>&nbsp;&nbsp;&nbsp;&nbsp;return docSendDao.getOffice();<BR>&nbsp;&nbsp;&nbsp;case 3:<BR>&nbsp;&nbsp;&nbsp;&nbsp;return docSendDao.getSecGroup();<BR>&nbsp;&nbsp;&nbsp;case 4:<BR>&nbsp;&nbsp;&nbsp;&nbsp;return docSendDao.getOfficeLead();<BR>&nbsp;&nbsp;&nbsp;case 5:<BR>&nbsp;&nbsp;&nbsp;&nbsp;return docSendDao.getSecFaculty();<BR>&nbsp;&nbsp;&nbsp;default :<BR>&nbsp;&nbsp;&nbsp;&nbsp;return new ArrayList();<BR>&nbsp;&nbsp;}<BR>&nbsp;}</FONT></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp;&nbsp; 这种做法在开发的前期还觉得不错，随着需求的进一步详细，发现当新增、修改流程时，也许我们要在这个 service 中满山遍野的找寻到底代码在哪里。更糟糕的是产品提交用户后，用户不会花费这么大的耐心让你这样维护。在经过短暂的思考后，决定利用 OSWorkflow 的 FunctionProvider 接口和 script 做文章。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 一个比较成熟的想法是（如各位有更好的方案不妨交流）：每个流程都可能面临修改，那就把流程的每个 action 要做的事抽取出来，这样修改起来相对独立，比如要把下一默认接收者改成其他人；另一个目的是快速响应用户对新流程的需求，在提出需求后，生成相应的流程文件及每个 action 要做的事，提交到服务器，重启就可以用了，而不是在已有代码基础上新增。这里的“每个 action 要做的事”就是 OSWorkflow 的 FunctionProvider 接口，实现这个接口，就可以为所欲为了。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 代码片断如下：<BR>
<TABLE style="WIDTH: 445px; HEIGHT: 23px" cellSpacing=1 cellPadding=1 width=445 border=1>
<TBODY>
<TR>
<TD>
<P>&nbsp;<STRONG>流程定义</STRONG><BR><FONT size=2>&nbsp;&nbsp;&nbsp; &lt;step id="1" name="科领导审批"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;actions&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;action id="2" name="批准" view="批准"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;results&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;unconditional-result id="2" old-status="Finished" status="Queued" step="2" owner="${stepOwner}"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;pre-functions&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //向 FacultyLea 类说明当前调用者<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;function type="beanshell"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;arg name="script"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String caller = context.getCaller();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transientVars.put("caller", caller);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/arg&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/function&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //FunctionProvider 实现类<BR>&nbsp;&nbsp;&nbsp;&nbsp;&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; &lt;function name="set.caller" type="class"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;arg name="class.name"&gt;***.*****.util.FacultyLea&lt;/arg&gt;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/function&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/pre-functions&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/unconditional-result&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/results&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/action&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;action id="3" name="拒绝" view="拒绝"&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;results&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;unconditional-result id="3" old-status="Finished" status="Finished" step="7"/&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/results&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/action&gt;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/actions&gt;<BR>&nbsp;&nbsp;&nbsp; &lt;/step&gt;</FONT></P>
<P><STRONG>FacultyLea</STRONG></P>
<P><FONT size=2>public class FacultyLea implements FunctionProvider{<BR>&nbsp;<BR>&nbsp;ReadProperty readProperty = ReadProperty.getInstance();<BR>&nbsp;ApplicationContext ctx=new<BR>&nbsp;FileSystemXmlApplicationContext(System.getProperty("user.dir")+"/web/WEB-INF/classes/applicationContext.xml");<BR>&nbsp;<BR>&nbsp;private SendDao sendDao = (SendDao) ctx.getBean("sendDao");<BR>&nbsp;private DocService docService = (DocService) ctx.getBean("docService");<BR>&nbsp;<BR>&nbsp;public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException {<BR>&nbsp;&nbsp;long l=((HibernateCurrentStep)((Collection)transientVars.get("currentSteps")).toArray()[0]).getEntryId();<BR>&nbsp;Doc md=docService.findDocByWrokFlowId(l+"");<BR>&nbsp;String caller=(String)transientVars.get("caller");<BR>&nbsp;&nbsp;<BR>&nbsp;//设置下一步的接收者<BR>&nbsp;Timestamp date = new Timestamp(System.currentTimeMillis());<BR>&nbsp;String query = "some hql here";<BR>&nbsp;List leaders = docSendDao.find(query);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0;i&lt;leaders.size();i++){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Send send = new Send();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send.setSendUser(new UserLogin(new Integer(caller)));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send.setDoc(md);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendDao.save(send);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;<BR>&nbsp;//设置该步骤处理者<BR>&nbsp;&nbsp;transientVars.put("stepOwner", caller);<BR>&nbsp;}<BR>}</FONT></P></TD></TR></TBODY></TABLE></P>
<P>&nbsp;&nbsp; function 只是 OSWorkflow 为我们提供众多功能中的一个，如果可能，我会把另外的使用心得写出来。</P>
<P>&nbsp;&nbsp;&nbsp; <BR><STRONG><FONT face=宋体 color=#ff0000 size=2>请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</FONT></STRONG><A href="http://www.blogjava.net/rosen"><FONT face=宋体 color=#ff0000 size=2><STRONG>http://www.blogjava.net/rosen</STRONG></FONT></A></P><img src ="http://www.blogjava.net/rosen/aggbug/9888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 10:24 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Shark 怎样...（翻译）</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9887.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 02:22:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9887.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9887.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9887.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9887.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 概																																																		述														 																						    																																										    									...&nbsp;&nbsp;<a href='http://www.blogjava.net/rosen/archive/2005/08/12/9887.html'>阅读全文</a><img src ="http://www.blogjava.net/rosen/aggbug/9887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 10:22 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Enhydra Shark 管理（翻译）</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9884.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 02:09:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9884.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9884.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9884.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9884.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9884.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 什么是 Enhydra Shark 管理程序？&nbsp;&nbsp;&nbsp; Shark 管理程序是一个 Java swing 应用程序，管理者可用于进行 Shark 引擎的管理。有两种管理程序，一种是把 shark 直接作为库来使用，另一种是利用 shark 的 CORBA 包装器接口，配置成CORBA 服务与Shark进行通信。该管理程序可用来处理含有XPDL文件（上传新的 XP...&nbsp;&nbsp;<a href='http://www.blogjava.net/rosen/archive/2005/08/12/9884.html'>阅读全文</a><img src ="http://www.blogjava.net/rosen/aggbug/9884.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 10:09 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9884.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Shark 从零开始(I)（翻译）</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9883.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 02:05:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9883.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9883.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9883.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9883.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9883.html</trackback:ping><description><![CDATA[
		<p>    本文一步步讲解如何从获得、编译、建立环境到运行 Shark 的方法。按照本文给出的步骤，Shark 可实际运行起来。应该注意的是，本文所用数据库为 MySQL，并在 windows 2000 上运行。本文是从很多笔记和 Shark 小组提供的线索中总结出来的，这种经历痛苦而又幸运。<br />    <br />    之所以我没有使用可执行安装程序的原因是，我想从零开始来构建 Shark。<br />    <br />    你最好拥有或能够安装下列程序，但这并不是 shark 所必需的，仅仅是本文档的要求：<br />    <br />    1、MySQL - 我使用 4.0.16-nt <br />    2、MySQL Connector - 我选择 mysql-connector-java-3.0.11-stable-bin.jar <br />    3、Java - 我使用 Sun j2sdk 版本为 1.4.2_04 <br />    4、CVS, Winzip, 等等</p>
		<p>    首先，自己独立安装它们，然后开始我们的 shark 学习！<br />    <br /><font size="3"><strong>获得 Shark</strong></font></p>
		<p>    我个人的安装方式是把所有的源文件拷贝到 C:\dev\Shark 目录下，最后的输出路径是 C:\Shark。你也可以自己放在任何地方，不过要调整以下命令。<br />    <br />    首先下载 Shark 1.0 <a href="http://forge.objectweb.org/project/showfiles.php?group_id=74&amp;release_id=512"><font color="#000080">http://forge.objectweb.org/project/showfiles.php?group_id=74&amp;release_id=512</font></a><br />    对于 Windows 系统，我下载 zip 文件并解包到 C:\dev\Shark 目录。<br />    <br />    如果你想获取 CVS （<a href="http://forge.objectweb.org/scm/?group_id=74"><font color="#000080">http://forge.objectweb.org/scm/?group_id=74</font></a>） <br />上的版本,则命令说明如下:<br />    <br />    通过使用下面的命令集，你可以用 anonymous 从 shark 的 cvs 库取到代码。下面的 modulename 指你想要 checkout 的模块名称，如果你不知道模块名称，请用 ”.” 代替。</p>
		<p>如果有提示要求输入口令，按 enter 就可以了。</p>
		<p>    cvs -d:pserver:anonymous@cvs.forge.objectweb.org:/cvsroot/shark login </p>
		<p>    cvs -z3 -d:pserver:anonymous@cvs.forge.objectweb.org:/cvsroot/shark co modulename </p>
		<p>
				<br />    在使用 CVS 的情况下，我把 /dev/Shark 作为 CVS 根目录。<br />    <br /><font size="3"><strong>编 译</strong></font><br />    <br />    切换到 C:\dev\Shark 目录。运行下列命令：<br />    <br />    configure -help</p>
		<p>    你会得到下面的输出:</p>
		<p> Parameters value for using with configure.bat :</p>
		<p> configure       - Make build.properties file with default values</p>
		<p> configure -help - Display this screen</p>
		<p> configure [-jdkhome jdk_home_dir] [-instdir installdir] -writes proper parameters to the build.properties file<br /> Examples :</p>
		<p> configure -jdkhome c:/j2sdk1.4.1 -instdir C:/Shark-1.0</p>
		<p>    有一个 *nix shell 脚本可以做同样的事情。对我来说用这个更简单，我不需要进行 jdkhome 设置，因为我的 JAVA_HOME 已经设置好了，我的安装目录是 c:/Shark，下面是我使用的命令：</p>
		<p>     configure -instdir c:/Shark</p>
		<p>    这个命令实际上是在 build.properties 文件中填充属性字段，我的文件是如下：</p>
		<p> version=1.0<br /> version_release=beta2<br /> version_build=13<br /> jdk_dir=C:/j2sdk1.4.2_04<br /> install_dir=C:/Shark<br /> build_debug=on<br />    <br />    现在准备开始编译了。编译使用 ant，但你应该用已经提供的 make file。使用帮助选项来查看到底有哪些选项可用：<br />    <br />        make –help<br />    <br />    大部分的选项要求我们必须先完全构建。当然，也可以用 shell 脚本来完成这个任务。我们用下面的命令来完全构建（可能要点时间）。<br />    <br />        make buildAll<br />        <br />    执行上述命令，ant 会构建所有的参数。凭借少许运气，就会顺利完成。如何处理构建上的问题超出了本文的范畴。最后，把这些前期准备好的原材料，文档，工具等等打包，再装载到之前指定的安装路径。<br />    <br />        make install<br />        <br />    该命令会组装（拷贝）文件到你的安装路径（我的是 C:\Shark）。<br />    <br /><font size="3"><strong>快速测试</strong></font></p>
		<p>    为了快速测试，我们将运行默认配置的 Shark 管理程序。<br />    <br />    在安装目录中，通常有个叫做 runsa.bat 的文件。运行该文件。Shark 管理程序（swing）将启动，开始向你询问用户名和密码了，分别是 "admin" 和 "enhydra"。如果验证通过，将会马上证明构建是成功的。<br />    <br />    TODO：详情请链接到 Enhydra Shark 管理文档<br />    <br /><font size="3"><strong>配置 Shark</strong></font></p>
		<p>    下面，我们开始配置 Shark<br />    <br />    <strong>修改 Shark.conf</strong><br />    <br />    首先，在 Shark 路径中找到名叫 Shark.conf 的文件。用你喜欢的编辑器打开它，第一个参数是：<br />    <br />    enginename=Shark<br />    <br />    我们将留下这一主题。正如前面笔记所提到的，虚拟机和数据库的不同将导致配置的差异。对于初次测试，我们不用改变参数值。请注意被注释了的 HypersonicSQL 驱动信息，HSQL 是运行 Shark 的默认数据库，由于 Shark 不能运行在多数据库平台下，我们配置为 MySQL。<br />    <br /> # HypersonicSQL<br /> #DatabaseManager.DB.sharkdb.JdbcDriver="org.hsqldb.jdbcDriver"<br /> #DatabaseManager.DB.sharkdb.Connection.Url="jdbc:hsqldb:C:/Shark/db/hsql/hsql"<br /> <br /> 未注释的 MySQL 部分：</p>
		<p> # MySQL<br /> DatabaseManager.DB.sharkdb.JdbcDriver="org.gjt.mm.mysql.Driver"<br /> DatabaseManager.DB.sharkdb.Connection.Url="jdbc:mysql://localhost/shark"<br /> <br /> 请注意，这里我还是完全用默认配置。该配置表明数据库是在本地机器上，用户名/密码使用 MySQL 默认的 "sa" 和 ""。如果这种配置不适合你，你完全可以修改它。<br /> <br /> #<br /> # Default cache configuration<br /> #<br /> DatabaseManager.defaults.cache.maxCacheSize=0<br /> DatabaseManager.defaults.cache.maxSimpleCacheSize=0<br /> DatabaseManager.defaults.cache.maxComplexCacheSize=0<br /> DatabaseManager.defaults.cache.reserveFactor=0.1<br /> <br /> 在这个部分，是了解我如何使用 Shark 的好途径，除非你用 CORBA 通讯，否则应用程序将直接与数据库交互。这些都不是 Shark 服务器代码。所以如果你有多个客户端，它们都需要与数据库直接交互。由于无法更新多个客户端的缓存，所以我关闭了缓存。<br /> <br /> LRU 缓存也应该被关闭：<br /> <br /> #=============================================================================<br /> # Default cache is LRU<br /> #<br /> #-----------------------------------------------------------------------------<br /> # Cache defaults<br /> #<br /> #CacheManagerClassName=org.enhydra.shark.caching.LRUCacheMgr<br /> <br /> 好了，目的达到，保存后关闭该文件。<br /> <br /> <strong>创建数据库</strong><br /> <br /> 现在安装 MySQL，创建一个名为 "shark" 的数据库。如果你想改变名字，需要在 Shark.conf 文件中修改数据库 URL。<br /> <br /> 其次，编辑 C:\Shark 目录下 recreateDB.bat 文件。注释掉 Hypersonic 部分，再反注释掉 MySQL 部分。<br /> <br /> rem HypersonicSQL database<br /> rem rmdir /q /s db\hsql<br /> rem mkdir db\hsql<br /> rem set LOADERJOBXML=sql\hsql\LoaderJob.olj<br /> <br /> rem MySQL database<br /> set LOADERJOBXML=sql\mysql\LoaderJob.olj<br /> <br /> 最后，我们将改变执行调用，因为脚本喜欢创建新窗口，而且在你看见错误信息前就关闭了。像这样修改它：<br /> <br /> start "Recreate Database" "C:\j2sdk1.4.2_04\bin\java" -Djava.ext.dirs=lib org.webdocwf.util.loader.Loader -cjs shark/conf  %LOADERJOBXML%<br /> <br /> 修改后：<br /> <br /> "C:\j2sdk1.4.2_04\bin\java" -Djava.ext.dirs=lib org.webdocwf.util.loader.Loader -cjs shark/conf  %LOADERJOBXML%<br /> <br /> 当然，如果你的 JDK 和上面的不一样，第一部分的引用会不同。<br /> <br /> 保存后关闭 recreateDB.bat 文件，再打开 LoaderJob.olj 文件。在我的系统中，位置在 C:\Shark\sql\mysql\LoaderJob.olj。其实你不需要做什么的，但应注意连接 URL 是否存在，如果你变更了数据库名，也要在这里修改。<br /> <br /> 最后的步骤是拷贝数据库驱动包到 C:\Shark\lib 目录。我使用 MySQL，所以拷贝相应的 jar 文件到 lib 目录。<br /> <br /> 现在运行 recreateDB 脚本。如果没有意外，就成功了。如果你发现了错误信息，就再次运行该脚本。再次阅读 “快速测试” 以确定所有步骤都已完成。你可以同时运行两个一样的管理程序来测试多客户端环境。</p>
		<p>
				<br />
				<strong>
						<font color="#ff0000" size="2">请注意！引用、转贴本文应注明原译者：Rosen Jiang 以及出处：</font>
				</strong>
				<a href="/rosen">
						<strong>
								<font color="#ff0000" size="2">http://www.blogjava.net/rosen</font>
						</strong>
				</a>
		</p>
<img src ="http://www.blogjava.net/rosen/aggbug/9883.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 10:05 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9883.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Enhydra Shark 简介（翻译）</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9882.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 02:01:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9882.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9882.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9882.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9882.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9882.html</trackback:ping><description><![CDATA[
		<p>
				<font size="3">
						<strong>介 绍</strong>
				</font>
		</p>
		<p>    Enhydra Shark 项目以一种不同的方式交付了一个工作流服务器。<br />    <br />    Enhydra Shark 是一个可扩展的工作流引擎框架，它包括一个完全基于 WFMC 规范的标准实现，它使用XPDL（没有任何自己新的扩展）作为自身的工作流流程定义格式，使用WFMC 的 "ToolAgents" API 作为系统活动的服务器端的执行形式。<br />    <br />    Enhydra JaWE 图形XPDL编辑器可用于为 Enhydra Shark 生成 XPDL 流程定义！<br />    <br />    ToolAgents 可用于 JavaScript，JDBC 访问，EJB 访问，纯 Java 类，CORBA 调用，EMail，Webservice 调用，等等...</p>
		<p>    流程与活动实例的存储通过一个可配置的持久化 API 来完成。持久层实现采用的标准是轻量级的Enhydra DODS O/R mapping 工具。更多重量级 J2EE EJB 持久层选择方案在下面展示。<br />    <br />    每个单一构件（持久层，事务管理，脚本引擎，流程库...）可用于它的标准实现或被项目特定模块所扩展/取代。<br />   <br />    通过这种方式，Enhydra Shark 可作为一个简单的位于servlet 或 swing 应用或运行在J2EE 容器（支持会话 bean API 以及用于 EJB 持久化）中的"Java library"，CORBA ORB 或 Web 服务来使用。<br />    <br />    工作流引擎内核为高负载环境下的活动工作流对象提供可配置的 LRU 缓存。缓存可在集群部署时关闭。 </p>
		<p>    当工作流运行时，WFMC WDF API 规范将用来把 JAWe 编辑器或 selfwritten 程序附加在运行期实例信息上，甚至修改实例。使用这一方法，Enhydra Shark支持动态工作流机制，能修改其自身来支持更复杂的工作流环境或组织的异常处理。<br />   <br />    通常，基于 Swing 的管理GUI可用于管理工作。JMX 扩展和基于 HTML 的管理客户端也可用于管理。<br />   <br />    其他 API 可用于知识库访问，日志，知识库持久化，事件通知，以及为转换评估(transition evaluations)设计的脚本引擎适配器。<br />    <br /><strong><font size="3">ObjectWeb 工作流工作组<br /></font></strong>    <br />    2003 年 12 月，新的 ObjectWeb 工作流工作组会议首次召开。<br />    <br />    本次会议的目标是在当前 ObjectWeb 工作流项目，也就是在 "Enhydra Shark"、"COW" 和 "Bonita" 之间确定可行的协作规则。<br />会议达成的共识是，这些组件的 API 应该遵循各自的标准（WFMC，OMG，BPEL）。这些组件将会是未来独立工作流引擎项目的组成部分。<br />    <br />    所有组件将不会依赖于特定的运行环境（Swing，Servlets，J2EE/EJB，CORBA...）。<br />    <br />    要选择一个通用组件模型（"glue"），当前非常可能的建议是采用 "Fractal"。<br />    新的邮件列表已经建立，以方便讨论日常工作流工作组事宜和支持项目间的合作。该列表可在 <a href="http://www.objectweb.org/wws/info/wow">http://www.objectweb.org/wws/info/wow</a> 上找到。<br />   其它达成的共识是使用 Enhydra JaWE 作为 基于XPDL进行流程定义的通用编辑器。</p>
		<p>    对WFMC WDF（工作流定义功能）的研究将表明，该 API 是否适合为流程和活动实例进行动态修改。如果 WDF 成为 API 的首选，JaWE 将支持该 API 以在运行期间可以进行图形化观看和实例修改。<br />    <br />    以下列出了初步确定的组件列表：<br />    <br />        模型库<br />        映射模块，包括到ToolAgents，脚本语言/引擎，以及参与者（用户和组）的映射<br />        流程和活动实例持久化（基于 Enyhdra DODS, Speedo, EJB's,...）<br />        脚本引擎适配器/包装器，适用于不同脚本语言（JavaScript, Python,...）的流程转换评估。<br />        活动流程和活动实例的运行期缓存（Perseus ?）<br />        事务管理（GOTM ?）<br />        ToolAgents <br />        分派API，用于动态参与者映射<br />        通知 API（Jabber, JMS, ...）<br />        日志（系统日志和管理活动日志）<br />        截止期（Deadline）管理（活动截止期（deadlines）, 活动持续时间（durations）, ...）<br />        记时器（Quartz, J2EE Timer Services,...）<br />        升级（Escalation） <br />    </p>
		<p>
				<font size="3">
						<strong>Enhydra Shark 架构</strong>
				</font>
		</p>
		<p>    根据上述已达成共识的Shark组件，当前 Enhydra Shark 架构目标如下图所示。<br />    <br /><img style="WIDTH: 657px; HEIGHT: 954px" height="1071" alt="" src="http://shark.objectweb.org/localmedia/SharkArch.jpg" width="657" /></p>
		<p>
				<br />
				<br />
				<strong>
						<font color="#ff0000" size="2">请注意！引用、转贴本文应注明原译者：Rosen Jiang 以及出处：</font>
				</strong>
				<a href="/rosen">
						<strong>
								<font color="#ff0000" size="2">http://www.blogjava.net/rosen</font>
						</strong>
				</a>
		</p>
<img src ="http://www.blogjava.net/rosen/aggbug/9882.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 10:01 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9882.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSWorkflow 探索</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9880.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 01:59:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9880.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9880.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9880.html#Feedback</comments><slash:comments>27</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9880.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9880.html</trackback:ping><description><![CDATA[
		<p>
				<font color="#ff0000">
						<strong>2007-04-16   版权声明</strong>
				</font>
		</p>
		<p>
				<font color="#ff0000">
						<strong>我知道这篇文章阅读量很大，但是请要继续转载本文的同志注意一下，本文是我于 2005 年中旬在成都麦柯系统集成有限公司写的，作为公司的技术探索并希望应用在公司 OA 产品中。请保留原文版权信息 OK？</strong>
				</font>
		</p>
		<p>----------------------------------------------------------------------------------------------</p>
		<p>
				<font size="3">
						<strong>前 言</strong>
				</font>
		</p>
		<p>    本文没有抛出可运行的范例，仅仅是程序片断而已，不过在 OSWorkflow 的 Wiki 上，Quake Wang 已把官方入门教程完整地翻译成中文了，有兴趣的读者可去阅读。关于 OSWorkflow 更加细节性的内容，可参考官方手册，相信你在了解了入门教程后，可轻松阅读官方手册。<br />    <br /><font size="3"><strong>OSWorkflow 概念</strong></font></p>
		<p>    在商用和开源世界里，OSWorkflow 都不同于这些已有的工作流系统。最大不同在于 OSWorkflow 有着非常优秀的灵活性。在开始接触 OSWorkflow 时可能较难掌握（有人说不适合工作流新手入门），比如，OSWorkflow 不要求图形化工具来开发工作流，而推荐手工编写 xml 格式的工作流程描述符。它能为应用程序开发者提供集成，也能与现有的代码和数据库进行集成。这一切似乎给正在寻找快速“即插即用”工作流解决方案的人制造了麻烦，但研究发现，那些“即插即用”方案也不能在一个成熟的应用程序中提供足够的灵活性来实现所有需求。<br />    <br /><font size="3"><strong>OSWorkflow 优势</strong></font></p>
		<p>    OSWorkflow 给你绝对的灵活性。OSWorkflow 被认为是一种“低级别”工作流实现。与其他工作流系统能用图标表现“loops(回路)”和“conditions(条件)”相比，OSWorkflow 只是手工“编码(coded)”来实现的。但这并不能说实际的代码是需要完全手工编码的，脚本语言能胜任这种情形。OSWorkflow 不希望一个非技术用户修改工作流程，虽然一些其他工作流系统提供了简单的 GUI 用于工作流编辑，但像这样改变工作流，通常会破坏这些应用。所以，进行工作流调整的最佳人选是开发人员，他们知道该怎么改变。不过，在最新的版本中，OSWorkflow 也提供了 GUI 设计器来协助工作流的编辑。</p>
		<p>    OSWorkflow 基于有限状态机概念。每个 state 由 step ID 和 status 联合表现（可简单理解为 step 及其 status 表示有限状态机的 state）。一个 state 到另一 state 的 transition 依赖于 action 的发生，在工作流生命期内有至少一个或多个活动的 state。这些简单概念展现了 OSWorkflow 引擎的核心思想，并允许一个简单 XML 文件解释工作流业务流程。</p>
		<p>
		</p>
		<p>
		</p>
		<p>
				<font size="3">
						<strong>OSWorkflow 核心概念</strong>
				</font>
				<br />    <br /><strong>step（步骤）<br /></strong>    一个 step 是工作流所处的位置。可能从一个 step 流转到另外一个 step（或者有时候还是停留在一样的 step）。举例来说，一个 OA 系统的请假流程，它的 step 名称可能有“本部门审批阶段”，“办公室审批阶段”，“总经理审批阶段”等。<br /> <br /><strong>status（状态）<br /></strong>    工作流 status 是一个用来描述工作流程中具体步骤状态的字符串。OSWorkflow 的有 Underway（进行中）、Queued（等候处理中）、Finished（完成）三种 status。<br /> <br /><strong>action（动作）<br /></strong>    action 指定了可能发生在 step 内的转变，会导致 step 的变更。在 OA 系统中，“本部门审批阶段”可能有“拒绝”或“批准”两个 action。action 和 step 之间的关系是，step 说明“在哪里”，action 说明“可以去哪里”。 一个 action 典型地由两部分组成：可以执行此动作的 condition（条件），以及执行此动作的 result（结果）。<br /> <br /><strong>condition（条件）</strong><br />    类似于逻辑判断，可包含“AND”和“OR”逻辑。比如一个请假流程中的“本部门审批阶段”，该阶段利用“AND”逻辑，判断流程状态是否为等候处理中，以及审批者是否为本部门主管。<br />    <br /><strong>result（结果）</strong><br />    Result 代表指向新的 step 及其 step status，也可能进入 split 或者 join。Result 分为两种， contidional-result （有条件结果），只有条件为真时才使用该结果，和 unconditional-result（无条件结果），当条件不满足或没有条件时使用该结果。</p>
		<p>
				<strong>split/join（分离/连接）</strong>
				<br />流程的切分和融合。很简单的概念，split 提供多个 result；join 则判断多个 current step 的状态，提供一个 result。</p>
		<p>
		</p>
		<p>
		</p>
		<p>
				<font size="3">
						<strong>OSWorkflow 包用途分析及代码片断</strong>
				</font>
				<br />    <br /><strong>com.opensymphony.workflow</strong><br />    该包为整个 OSWorkflow 引擎提供核心接口。例如 com.opensymphony.workflow.Workflow 接口，可以说，实际开发中的大部分工作都是围绕该接口展开的，该接口有 BasicWorkflow、EJBWorkflow、OfbizWorkflow 三个实现类。</p>
		<p>
				<strong>com.opensymphony.workflow.basic <br /></strong>    该包有两个类，BasicWorkflow 与 BasicWorkflowContext。BasicWorkflow 不支持事务，尽管依赖持久实现，事务也不能包裹它。BasicWorkflowContext 在实际开发中很少使用。</p>
		<p>
		</p>
		<table style="WIDTH: 417px; HEIGHT: 54px" cellspacing="1" cellpadding="1" width="417" border="1">
				<tbody>
						<tr>
								<td>
										<font size="2">  public void setWorkflow(int userId) {<br />  Workflow workflow = new BasicWorkflow(Integer.toString(userId));<br /> }</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<strong>com.opensymphony.workflow.config</strong>
				<br />    该包有一个接口和两个该接口的实现类。在 OSWorkflow 2.7 以前，状态由多个地方的静态字段维护，这种方式很方便，但是有很多缺陷和约束。最主要的缺点是无法通过不同配置运行多个 OSWorkflow 实例。实现类 DefaultConfiguration 用于一般的配置文件载入。而 SpringConfiguration 则是让 Spring 容器管理配置信息。</p>
		<p>
		</p>
		<table style="WIDTH: 418px; HEIGHT: 23px" cellspacing="1" cellpadding="1" width="418" border="1">
				<tbody>
						<tr>
								<td>
										<font size="2">  public void setConfiguration(SpringConfiguration configuration) {<br />  SpringConfiguration configuration = configuration;<br />workflow.setConfiguration(configuration);<br /> }</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<strong>com.opensymphony.workflow.ejb <br /></strong>    该包有两个接口 WorkflowHome 和 WorkflowRemote。该包的若干类中，最重要的是 EJBWorkflow，该类和 BasicWorkflow 的作用一样，是 OSWorkflow 的核心，并利用 EJB 容器管理事务，也作为工作流 session bean 的包装器。</p>
		<p>
				<strong>com.opensymphony.workflow.loader</strong>
				<br />    该包有若干类，用得最多的是 XxxxDescriptor，如果在工作流引擎运行时需要了解指定的动作、步骤的状态、名字，等信息时，这些描述符会起到很大作用。</p>
		<p>
		</p>
		<table style="WIDTH: 418px; HEIGHT: 23px" cellspacing="1" cellpadding="1" width="418" border="1">
				<tbody>
						<tr>
								<td>
										<font size="2">  public String findNameByStepId(int stepId,String wfName) {<br />  WorkflowDescriptor wd = workflow.getWorkflowDescriptor(wfName);<br />  StepDescriptor stepDes = wd.getStep(stepId);<br />  return stepDes.getName();<br /> }</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<strong>com.opensymphony.workflow.ofbiz <br /></strong>    OfbizWorkflow 和 BasicWorkflow 在很多方面非常相似，除了需要调用 ofbiz 的 TransactionUtil 来包装事务。</p>
		<p>
				<strong>com.opensymphony.workflow.query</strong>
				<br />    该包主要为查询而设计，但不是所有的工作流存储都支持查询。通常，Hibernate 和 JDBC 都支持，而内存工作流存储不支持。值得注意的是 Hibernate 存储不支持混合型查询（例如，一个查询同时包含了 history step 上下文和 current step 上下文）。执行一个查询，需要创建 WorkflowExpressionQuery 实例，接着调用 Workflow 对象的 query 方法来得到最终查询结果。</p>
		<p>
		</p>
		<table style="WIDTH: 419px; HEIGHT: 23px" cellspacing="1" cellpadding="1" width="419" border="1">
				<tbody>
						<tr>
								<td>
										<p>
												<font size="2">  public List queryDepAdmin(int userId,int type) {<br />  int[] arr = getSubPerson(userId,type);</font>
										</p>
										<p>
												<font size="2">  //构造表达式<br />  Expression[] expressions = new Expression[1 + arr.length];<br />  Expression expStatus = new FieldExpression(FieldExpression.STATUS,<br />    FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Queued");<br />  expressions[0] = expStatus;</font>
										</p>
										<p>
												<font size="2">  for (int i = 0; i &lt; arr.length; i++) {<br />   Expression expOwner = new FieldExpression(FieldExpression.OWNER,<br />     FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS,<br />     Integer.toString(arr[i]));<br />   expressions[i + 1] = expOwner;<br />  }</font>
										</p>
										<p>
												<font size="2">  //查询未完成流编号<br />  List wfIdList = null;<br />  try {<br />   WorkflowExpressionQuery query = new WorkflowExpressionQuery(<br />     new NestedExpression(expressions, NestedExpression.AND));<br />   wfIdList = workflow.query(query);<br />  } catch (Exception e) {<br />   e.printStackTrace();<br />  }</font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<br />
		<strong>com.opensymphony.workflow.soap</strong>
		<br />    OSWorkflow 通过 SOAP 来支持远端调用。这种调用借助 WebMethods 实现。 
<p><strong>com.opensymphony.workflow.spi <br /></strong>    该包可以说是 OSWorkflow 与持久层打交道的途径，如当前工作流的实体，其中包括：EJB、Hibernate、JDBC、Memory、Ofbiz、OJB、Prevayler。</p><p></p><table style="WIDTH: 422px; HEIGHT: 23px" cellspacing="1" cellpadding="1" width="422" border="1"><tbody><tr><td><font size="2">  HibernateWorkflowEntry hwfe = (HibernateWorkflowEntry) getHibernateTemplate()<br />     .find("from HibernateWorkflowEntry where Id="<br />         + wfIdList.get(i)).get(0);</font></td></tr></tbody></table><p><strong>com.opensymphony.workflow.util</strong><br />该包是 OSWorkflow 的工具包，包括了对 BeanShell、BSF、EJB Local、EJB Remote、JNDI 的支持。</p><p></p><p></p><p><font size="3"><strong>小 结</strong></font></p><p>    由于本人所在公司希望在 OA 系统中引入工作流引擎，经过分析决定采用 OSWorkflow 引擎。利用 OSWorkflow，已经在系统中实现了请假条流程原型，该流程结合 OA 系统中已有的 RBAC 模型进行逐级审核。我个人认为要用 OSWorkflow 让某个流程跑起来似乎很麻烦，主要是需要扩展和自己实现的太多。<br />    <br />    另外，引用一段 Quake Wang 的原话：电子政务/OA 如果要使用workflow engine的话，shark，jbpm 之类的workflow engine有点杀鸡用牛刀的味道。shark 和 jbpm 都强迫你使用它的用户模型，怎样把企业现有的用户模型（包括组织结构）映射过来是很繁琐的事情，比如常见的 OA 应用中，申请者对应的部门负责人为下一个流程的人工参与者，使用 shark 或者 jbpm 都得绕一圈，通过现有的人力资源系统，获得用户，再对应过来。这还仅仅是一个简单的需求，更不用说国内企业千奇百怪的组织结构，以及各种特殊流程，用 wfmc 或者其他所谓的 workflow 通用标准去做不怎么标准的事情。吃力不讨好。用 osworkflow 这种基于状态机的 workflow engine 反而会轻松很多，而且它也没有强迫你使用它的用户模型。另外纠正一点：osworkflow 不仅仅支持简单的 BeanShell，还支持 java class，bsf，ejb。如果做电子政务/OA 的话，觉得目前 osworkflow 是最适用的 opensource workflow engine。<br /><br /><br /><strong><font color="#ff0000" size="2">请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</font></strong><a href="/rosen"><strong><font color="#ff0000" size="2">http://www.blogjava.net/rosen</font></strong></a></p><img src ="http://www.blogjava.net/rosen/aggbug/9880.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 09:59 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9880.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>RBAC 模型初探</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9879.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 01:56:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9879.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9879.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9879.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9879.html</trackback:ping><description><![CDATA[
		<p>
				<strong>
						<font size="3">访问控制背景</font>
				</strong>
		</p>
		<p>    访问控制技术是由美国国防部（Department of Defense, DoD）资助的研究和开发成果演变而来的。这一研究导致两种基本类型访问控制的产生：自主访问控制（Discretionary Access Control, DAC）和强制访问控制（Mandatory Access Control, MAC）。最初的研究和应用主要是为了防止机密信息被未经授权者访问，近期的应用主要是把这些策略应用到为商业领域。</p>
		<p>    自主访问控制，允许把访问控制权的授予和取消留给个体用户来判断。为没有访问控制权的个体用户授予和废除许可。自主访问控制机制允许用户被授权和<br />取消访问其控制之下的任何客体（object），换句话说，用户就是他们控制下的客体的拥有者。然而，对于多数组织来说，最终用户对所访问的信息没有拥有权。对于这些组织，公司或代理机构是事实上的系统客体和处理他们的程序的拥有者。访问优先权受组织控制，而且也常常基于雇员功能而不是数据所有权。</p>
		<p>   强制访问控制，在美国国防部 Trusted Computer Security Evaluation Criteria (TCSEC) 中定义如下：“一种限制访问客体的手段，它以包含在这些客体中的信息敏感性和访问这些敏感性信息的主体的正式授权信息（如清除）为基础”。<br />   <br />   以上访问控制策略对于处理一些无需保密但又敏感的信息的政府和行业组织的需求并不是特别的适合。在这样的环境下，安全目标支持产生于现有法律、道德规范、规章、或一般惯例的高端组织策略。这些环境通常需要控制个体行为的能力，而不仅仅是如何根据信息的敏感性为其设置标签从而访问这一信息的个人能力。<br />     </p>
		<p>
				<br />
				<strong>
						<font size="3">什么是基于角色访问控制（Role-Based Access Control, RBAC）？NIST 有如下定义。<br /></font>
				</strong>   <br />   访问是一种利用计算机资源去做某件事情的的能力，访问控制是一种手段，通过它这种能力在某些情况下被允许或者受限制（通常是通过物理上和基于系统的控制）。基于计算机的访问控制不仅可规定是“谁”或某个操作有权使用特定系统资源，而且也能规定被允许的访问类型。这些控制方式可在计算机系统或者外部设备中实现。<br />   <br />    就基于角色访问控制而言，访问决策是基于角色的，个体用户是某个组织的一部分。用户具有指派的角色（比如医生、护士、出纳、经理）。定义角色的过程应该基于对组织运转的彻底分析，应该包括来自一个组织中更广范围用户的输入。<br />    <br />    访问权按角色名分组，资源的使用受限于授权给假定关联角色的个体。例如，在一个医院系统中，医生角色可能包括进行诊断、开据处方、指示实验室化验等；而研究员的角色则被限制在收集用于研究的匿名临床信息工作上。<br />    <br />    控制访问角色的运用可能是一种开发和加强企业特殊安全策略，进行安全管理过程流程化的有效手段。<br />      </p>
		<p>
				<br />
				<strong>
						<font size="3">用户（User）和角色（Role）</font>
				</strong>
		</p>
		<p>    用户指访问系统中的资源的主体，一般为人，也可为 Agent 等智能程序。角色指应用领域内一种权力和责任的语义综合体，可以是一个抽象概念，也可以是对应于实际系统中的特定语义体，比如组织内部的职务等。针对角色属性的不同，某些模型中将角色进一步细分为普通角色和管理员角色（可理解为全局角色）。</p>
		<p>
		</p>
		<p>
				<font size="3">
						<strong>许可（Permissions）和权限（Permission）</strong>
				</font>
		</p>
		<p>    许可描述了角色对计算机资源的访问和操作所具有的权限，其反映的是授权的结果。比如授予某个角色对计算机资源有读的权限，则代表了一个许可的存在，这个许可表示：角色获取了对计算机资源的读许可。针对操作来说，其描述的是许可和操作之间的一种关联关系，而这层关系则表示了某一角色对某一操作所具有的权限及权限状态。</p>
		<p>
				<br />      <br /><strong><font size="3">角色和指派（Assignment）</font></strong></p>
		<p>    指派包含两个方面，用户指派和许可指派。用户指派表示的是，将用户指派给特定的角色。许可指派表示的是为角色指派计算机资源的访问和操作许可。</p>
		<p>
		</p>
		<p>
				<strong>
						<font size="3">会话（session）</font>
				</strong>
		</p>
		<p>    会话表示的是用户和角色之间的关系。用户每次必须通过建立会话来激活角色，得到相应的访问权限。</p>
		<p>
		</p>
		<p>
				<strong>
						<font size="3">角色和角色等级（Role Hierarchies）</font>
				</strong>
		</p>
		<p>    角色本身仅仅只是一个名词，其本身并不能代表权限的大小。比如，我们可以定一个“Director”的角色，也可以定一个“Project Leader”的角色。对于现实中我们来说，看到这样两个角色，就清楚 DIR 的权限要比一个 PL 的权限级别高。但是对计算机来说，这两个角色仅仅是两个“词语”，是等同的。可以采用分等级角色，在角色上实现层次化来解决这些问题。也可以采用复合角色（其表示的就是一个角色组的概念），对角色实现一定的分组和复合，以便于权限指派。在一些 OA 产品中经常出现分等级角色。<br />    </p>
		<p>
				<br />
				<font size="3">
						<strong>限制（Constraints）</strong>
				</font>
				<br />    <br />    模型中的职责分离关系（Separation of Duty），用于控制冲突（Conflict）。静态职责分离（Static SD）指定角色的互斥关系，用于用户指派阶段。避免同一用户拥有互斥的角色。实现简单，角色互斥语义关系清楚，便于管理不够灵活，不能处理某些实际情况。动态职责分离（Dynamic SD）指定角色的互斥关系，用于角色激活阶段。允许同一用户拥有某些互斥的角色，但是不允许该用户同时激活互斥的角色。更灵活，直接与会话挂钩，适应实际管理需要，实现复杂，不易管理。</p>
		<p>              <img style="WIDTH: 637px; HEIGHT: 344px" height="520" alt="rbac.jpg" src="http://www.blogjava.net/images/blogjava_net/rosen/rbac.jpg" width="888" border="0" /></p>
		<p>
		</p>
		<p>
				<font size="3">
						<strong>  </strong>
				</font>
		</p>
		<p>
				<font size="3">
						<strong>参考文献</strong>
				</font>
		</p>《AN INTRODUCTION TO ROLE-BASED ACCESS CONTROL》 NIST 
<p>《工作流授权控制模型》        胡长城</p><p>《基于角色的权限管理综述》 俞诗鹏</p><p> </p><p></p><p>最后，感谢徐俊刚博士对本文翻译提供的指导。    <br /><br /><br /><strong><font color="#ff0000" size="2">请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</font></strong><a href="/rosen"><strong><font color="#ff0000" size="2">http://www.blogjava.net/rosen</font></strong></a></p><img src ="http://www.blogjava.net/rosen/aggbug/9879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 09:56 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9879.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>有限状态机（FSM）初探</title><link>http://www.blogjava.net/rosen/archive/2005/08/12/9878.html</link><dc:creator>Rosen</dc:creator><author>Rosen</author><pubDate>Fri, 12 Aug 2005 01:54:00 GMT</pubDate><guid>http://www.blogjava.net/rosen/archive/2005/08/12/9878.html</guid><wfw:comment>http://www.blogjava.net/rosen/comments/9878.html</wfw:comment><comments>http://www.blogjava.net/rosen/archive/2005/08/12/9878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rosen/comments/commentRss/9878.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rosen/services/trackbacks/9878.html</trackback:ping><description><![CDATA[
		<p>NIST 对有限状态机（Finite State Machine, FSM）的定义如下。<br />  <br />    包含一组状态集（states）、一个起始状态（start state）、一组输入符号集（alphabet）、一个映射输入符号和当前状态到下一状态的转换函数（transition function）的计算模型。当输入符号串，模型随即进入起始状态。它要改变到新的状态，依赖于转换函数。在有限状态机中，会有许多变量，例如，状态机有很多与动作（actions）转换(Mealy机)或状态（摩尔机）关联的动作，多重起始状态，基于没有输入符号的转换，或者指定符号和状态（非定有限状态机）的多个转换，指派给接收状态（识别者）的一个或多个状态，等等。</p>
		<p>    一个例子</p>
		<p>              <img height="233" alt="400px-Fsm_parsing_word_nice.jpg" src="http://www.blogjava.net/images/blogjava_net/rosen/400px-Fsm_parsing_word_nice.jpg" width="400" border="0" /></p>
		<p>    上图是一个接受者 FSM 模型，用来分析单词“nice”。该分析器只接受字符输入，包含6种状态，状态切换由输入的字符驱动。理解起来非常简单，在此不作解释了。</p>
		<p>    感谢宏云博士对本文翻译提供的指导。<br /><br /><br /><strong><font color="#ff0000" size="2">请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</font></strong><a href="/rosen"><strong><font color="#ff0000" size="2">http://www.blogjava.net/rosen</font></strong></a></p>
<img src ="http://www.blogjava.net/rosen/aggbug/9878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rosen/" target="_blank">Rosen</a> 2005-08-12 09:54 <a href="http://www.blogjava.net/rosen/archive/2005/08/12/9878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>