|
OSWorkflow 觀念探討(1) -- 流程設定基礎
( 史帝芬, 2005/6/6, hi.steven@gmail.com)
看完第一支程式,相信讀者會有許多疑問,這些先就流程的設定做初步的介紹。首先,讀者應該注意到了, 第一支程式的用到三個xml設定檔,沒錯,這三個是設定流程的設定檔。
- osworkflow.xml :這個檔案是設定流程是否存在資料庫或存在記憶體,前面的內容是存在MS SQL Server的寫法。
- leave.xml :請假流程寫在這個檔案,這也是osworkflow的重點之一。
- workflows.xml :指定系統啟動時要載入那些流程。
這裡針對leave.xml做些說明…
- initial-actions :每個流程都至少需定義一個initial-actions,這是流程的起點。
- action :導致流程變動的動作,每個action都有個編號,且不能重複。
- step :雖然它的名稱是步驟,似乎它會有動作? 其實將它視為流程位置可能比較恰當,osworkflow真正的動作在action發生。
- result :執行動作後的結果,result有兩種conditional-result和unconditional-result,每個result一定有unconditional-result, 當conditional-result的條件都不滿足時,就執行unconditional-result。
- status :流程在某個action時的狀態。
- old-status :流程執行某個action後的狀態。
- caller :這是OSWorkflow的保留字,可取得呼叫此工作流的user,即Workflow workflow = new BasicWorkflow(caller); 在資料庫中會記錄於Table OS_HISTORYSTEP如下:
記得在pre-functions加上如下設定…
<pre-functions>
<function type="class">
<arg name="class.name">com.opensymphony.workflow.util.Caller</arg>
</function>
</pre-functions>
- owner :這是傳工作流到此步驟的user。
OSWorkflow 的第二支程式 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
這裡將介紹如何在流程裡加上限制,首先修改leave.xml,限制送出假單的人一定要是啟動流程的人。 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN" "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd"> <workflow> <initial-actions> <action id="0" name=" 開始"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}" /> </results> </action> </initial-actions>
<steps> <step id="1" name=" 填假單"> <actions> <action id="1" name=" 送出"> <restrict-to> <conditions> <condition type="class"> <arg name="class.name"> com.opensymphony.workflow.util.AllowOwnerOnlyCondition </arg> </condition> </conditions> </restrict-to> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="2" owner="${caller}" /> </results> </action> </actions> </step>
<step id="2" name=" 批假單"> <actions> <action id="2" name=" 准許"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="3" owner="${caller}"/> </results> </action>
<action id="3" name=" 駁回"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}"/> </results> </action> </actions> </step>
<step id="3" name=" 停止" /> </steps> </workflow> 接著更改Leave.java及LeaveAction.java,讓啟動流程的人和送出假單的人可以不同。 package tw.idv.idealist;
import com.opensymphony.workflow.InvalidActionException; import com.opensymphony.workflow.InvalidEntryStateException; import com.opensymphony.workflow.InvalidInputException; import com.opensymphony.workflow.InvalidRoleException; import com.opensymphony.workflow.Workflow; import com.opensymphony.workflow.WorkflowException; import com.opensymphony.workflow.basic.BasicWorkflow; import com.opensymphony.workflow.config.DefaultConfiguration; import com.opensymphony.workflow.spi.Step;
/** * 請假流程 * @author steven */ public class Leave { /** * 啟動流程 * @param employee 員工編號 * @return 工作流編號 */ public long start(String employee) { Workflow workflow = new BasicWorkflow(employee); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); long workflowId = -1; try { //leave 是workflowx.xml中定的名稱 workflowId = workflow.initialize("leave", 0, null); } catch (InvalidActionException e) { e.printStackTrace(); } catch (InvalidRoleException e) { e.printStackTrace(); } catch (InvalidInputException e) { e.printStackTrace(); } catch (InvalidEntryStateException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); }
return workflowId; }
/** * 送出假單 * @param workflowId 工作流編號 * @param employee 員工編號 */ public void send(long workflowId, String employee) { Workflow workflow = new BasicWorkflow(employee); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); try { workflow.doAction(workflowId, 1, null); } catch (InvalidActionException e) { e.printStackTrace(); } catch (InvalidRoleException e) { e.printStackTrace(); } catch (InvalidInputException e) { e.printStackTrace(); } catch (InvalidEntryStateException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); } }
/** * 准假假單 * @param workflowId 工作流編號 * @param actionId 動作編號, 2 准許, 3 駁回 */ public void allow(long workflowId, int actionId) { Workflow workflow = new BasicWorkflow("manager1"); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); try { workflow.doAction(workflowId, actionId, null); } catch (InvalidInputException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); } catch (InvalidActionException e) { e.printStackTrace(); } } } LeaveAction.java package tw.idv.idealist.actions;
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import tw.idv.idealist.Leave;
/** * @author Steven */ public class LeaveAction extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); }
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Leave leave = new Leave(); String employee = req.getParameter("employee"); long workflowId = leave.start(employee); leave.send(workflowId, "someone"); // <<== 非啟動流程的人送出假單 resp.sendRedirect("allow.jsp?workflowId=" + workflowId); }
} package tw.idv.idealist.actions;
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import tw.idv.idealist.Leave;
/** * @author Steven */ public class LeaveAction extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); }
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Leave leave = new Leave(); String employee = req.getParameter("employee"); long workflowId = leave.start(employee); leave.send(workflowId, "someone"); // <<== 非啟動流程的人送出假單 resp.sendRedirect("allow.jsp?workflowId=" + workflowId); }
} 啟動Tomcat,並執行leave.jsp後,會出現如下exception,確實OSWorkflow偵測到啟動流程的人和送出假單的人不同。 com.opensymphony.workflow.InvalidActionException: Action 1 is invalid at com.opensymphony.workflow.AbstractWorkflow.doAction(AbstractWorkflow.java:546) at tw.idv.idealist.Leave.send(Leave.java:56) at tw.idv.idealist.actions.LeaveAction.doPost(LeaveAction.java:25) at tw.idv.idealist.actions.LeaveAction.doGet(LeaveAction.java:17) at javax.servlet.http.HttpServlet.service(HttpServlet.java:740) at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2422) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:163) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:199) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:700) at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:584) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683) at java.lang.Thread.run(Thread.java:534) | ||||||||||||||||||
OSWorkflow 觀念探討(2) -- 限制條件 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
第二支程式 只舉AllowOwnerOnlyCondition為例,事實上OSWorkflow 2.7版提供了以下 四種限制條件。
當同時要加上兩個限制條件時,可以如下寫。 <restrict-to> <conditions type="AND"> <condition type="class"> <arg name="class.name"> com.opensymphony.workflow.util.StatusCondition </arg> <arg name="status">Queued</arg> </condition> <condition type="class"> <arg name="class.name"> com.opensymphony.workflow.util.OSUserGroupCondition </arg> <arg name="group">A0001</arg> </condition> </conditions> </restrict-to> | ||||||||||||||||||
OSWorkflow 的第三支程式 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
如前面的請假流程,員工只是請假,但是假有分很多種,事假、病假、婚假、年假…,在workflow中如何區分呢? 我們可以傳值到流程中,並儲存在資料庫中供以後判斷!
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN" "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd"> <workflow> <initial-actions> <action id="0" name=" 開始"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> <function type="beanshell"> <arg name="script"> propertySet.setString("type", transientVars.get("type")); </arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}" /> </results> <post-functions> <function type="class"> <arg name="class.name"> tw.idv.idealist.OutputPropertySet </arg> <arg name="author">Steven Shi</arg> </function> </post-functions> </action> </initial-actions>
<steps> <step id="1" name=" 填假單"> <actions> <action id="1" name=" 送出"> <restrict-to> <conditions> <condition type="class"> <arg name="class.name"> com.opensymphony.workflow.util.AllowOwnerOnlyCondition </arg> </condition> </conditions> </restrict-to> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="2" owner="${caller}" /> </results> </action> </actions> </step>
<step id="2" name=" 批假單"> <actions> <action id="2" name=" 准許"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="3" owner="${caller}"/> </results> </action>
<action id="3" name=" 駁回"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}"/> </results> </action> </actions> </step>
<step id="3" name=" 停止" /> </steps> </workflow> leave.jsp <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML> <HEAD> <%@ page language="java" contentType="text/html; charset=BIG5" pageEncoding="BIG5" %> <%@ page import="tw.idv.idealist.*" %>
<META http-equiv="Content-Type" content="text/html; charset=BIG5"> <META http-equiv="Content-Style-Type" content="text/css"> <TITLE> 填寫假單</TITLE> <Script Language="JavaScript"> function DoAction(type) { document.myForm.type.value = type; document.myForm.submit(); } </Script> </HEAD> <BODY> <P> 員工請假</P>
<form name="myForm" action="LeaveAction"> <input type="hidden" name="type" value=""> 員工代號: <input type="text" name="employee"><br> <input type="button" value=" 事假" OnClick="DoAction(1)"> <input type="button" value=" 病假" OnClick="DoAction(2)"> </form>
</BODY> </HTML> Leave.java package tw.idv.idealist;
import java.util.HashMap; import com.opensymphony.workflow.*; import com.opensymphony.workflow.basic.BasicWorkflow; import com.opensymphony.workflow.config.DefaultConfiguration; import com.opensymphony.workflow.spi.Step;
/** * 請假流程 * @author steven */ public class Leave { /** * 啟動流程 * @param employee 員工編號 * @param type 假別 * @return 工作流編號 */ public long start(String employee, String type) { Workflow workflow = new BasicWorkflow(employee); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); long workflowId = -1; try { HashMap map = new HashMap(); map.put("type", type); //leave 是workflowx.xml中定的名稱 workflowId = workflow.initialize("leave", 0, map); } catch (InvalidActionException e) { e.printStackTrace(); } catch (InvalidRoleException e) { e.printStackTrace(); } catch (InvalidInputException e) { e.printStackTrace(); } catch (InvalidEntryStateException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); }
return workflowId; }
/** * 送出假單 * @param workflowId 工作流編號 * @param employee 員工編號 */ public void send(long workflowId, String employee) { Workflow workflow = new BasicWorkflow(employee); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); try { workflow.doAction(workflowId, 1, null); } catch (InvalidActionException e) { e.printStackTrace(); } catch (InvalidRoleException e) { e.printStackTrace(); } catch (InvalidInputException e) { e.printStackTrace(); } catch (InvalidEntryStateException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); } }
/** * 准假假單 * @param workflowId 工作流編號 * @param actionId 動作編號, 2 准許, 3 駁回 */ public void allow(long workflowId, int actionId) { Workflow workflow = new BasicWorkflow("manager1"); DefaultConfiguration config = new DefaultConfiguration(); workflow.setConfiguration(config); try { workflow.doAction(workflowId, actionId, null); } catch (InvalidInputException e) { e.printStackTrace(); } catch (WorkflowException e) { e.printStackTrace(); } catch (InvalidActionException e) { e.printStackTrace(); } } } LeavaAction.java package tw.idv.idealist.actions;
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import tw.idv.idealist.Leave;
/** * @author Steven */ public class LeaveAction extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); }
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Leave leave = new Leave(); String employee = req.getParameter("employee"); String type = req.getParameter("type"); long workflowId = leave.start(employee, type); leave.send(workflowId, employee); resp.sendRedirect("allow.jsp?workflowId=" + workflowId); }
} OutputPropertySet.java package tw.idv.idealist;
import java.util.Map;
import com.opensymphony.module.propertyset.PropertySet; import com.opensymphony.workflow.FunctionProvider; import com.opensymphony.workflow.WorkflowException;
/** * @author steven */ public class OutputPropertySet implements FunctionProvider { public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException { if (ps.getString("type").equals("1")) { System.out.println(" 事假"); } else if (ps.getString("type").equals("2")) { System.out.println(" 病假"); } System.out.println("author => " + args.get("author")); } }
病假 author => Steven Shi 資料庫Table OS_PROPERTYENTRY則出現如下的值,可以看到假別已存入資料庫。 | ||||||||||||||||||
OSWorkflow 觀念探討(3) -- 傳值儲值 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
<function type="class"> <arg name="class.name"> tw.idv.idealist.OutputPropertySet </arg> <arg name="author">Steven Shi</arg> </function> | ||||||||||||||||||
OSWorkflow 的第四支程式 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
在workflow執行的過程中,有時需要做一些條件的檢查,例如,公司員工編號都是四碼,如果有個工作流的 員工編號只有三碼,就要能檢查出來,下面我們就來做這樣的檢查,各位可以試著用四碼的員工編號請假, 確定可以通過檢查後,再用非四碼的員工編號測試,將會出現最後面顯示的exception。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN" "http://www.opensymphony.com/osworkflow/workflow_2_7.dtd"> <workflow> <initial-actions> <action id="0" name=" 開始"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> <function type="beanshell"> <arg name="script"> propertySet.setString("type", transientVars.get("type")); propertySet.setString("employee", transientVars.get("caller")); </arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}" /> </results> <post-functions> <function type="class"> <arg name="class.name"> tw.idv.idealist.OutputPropertySet </arg> <arg name="author">Steven Shi</arg> </function> </post-functions> </action> </initial-actions>
<steps> <step id="1" name=" 填假單"> <actions> <action id="1" name=" 送出"> <restrict-to> <conditions> <condition type="class"> <arg name="class.name"> com.opensymphony.workflow.util.AllowOwnerOnlyCondition </arg> </condition> </conditions> </restrict-to> <validators> <validator type="class"> <arg name="class.name"> tw.idv.idealist.MyValidator </arg> </validator> </validators> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="2" owner="${caller}" /> </results> </action> </actions> </step>
<step id="2" name=" 批假單"> <actions> <action id="2" name=" 准許"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="3" owner="${caller}"/> </results> </action>
<action id="3" name=" 駁回"> <pre-functions> <function type="class"> <arg name="class.name">com.opensymphony.workflow.util.Caller</arg> </function> </pre-functions> <results> <unconditional-result old-status="Finished" status="Queued" step="1" owner="${caller}"/> </results> </action> </actions> </step>
<step id="3" name=" 停止" /> </steps> </workflow> MyValidator.java package tw.idv.idealist;
import java.util.Map; import com.opensymphony.module.propertyset.PropertySet; import com.opensymphony.workflow.InvalidInputException; import com.opensymphony.workflow.Validator; import com.opensymphony.workflow.WorkflowException;
/** * @author steven */ public class MyValidator implements Validator {
public void validate(Map transientVars, Map args, PropertySet ps) throws InvalidInputException, WorkflowException { if (ps.getString("employee").length() != 4) { throw new InvalidInputException(" 員工編號錯誤"); } }
}
[InvalidInputException: [Error map: [{}]] [Error list: [[ 員工編號錯誤]]] at tw.idv.idealist.MyValidator.validate(MyValidator.java:17) at com.opensymphony.workflow.AbstractWorkflow.verifyInputs(AbstractWorkflow.java:1025) at com.opensymphony.workflow.AbstractWorkflow.transitionWorkflow(AbstractWorkflow.java:1248) at com.opensymphony.workflow.AbstractWorkflow.doAction(AbstractWorkflow.java:551) at tw.idv.idealist.Leave.send(Leave.java:55) at tw.idv.idealist.actions.LeaveAction.doPost(LeaveAction.java:26) at tw.idv.idealist.actions.LeaveAction.doGet(LeaveAction.java:17) at javax.servlet.http.HttpServlet.service(HttpServlet.java:740) at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2422) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:163) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174) at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:199) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:700) at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:584) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683) at java.lang.Thread.run(Thread.java:534) | ||||||||||||||||||
OSWorkflow 觀念探討(4) -- 校驗器 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
看完第四支程式應該多半的人已經知道怎麼做校驗器了! 這裡再大略講解一下。 首先寫一個類別,這個類別要實作Validator,如前面程式的MyValidator,如有錯誤拋出exception。接下來在流 程設定檔中加入 <validators> <validator type="class"> <arg name="class.name"> tw.idv.idealist.MyValidator </arg> </validator> </validators> 上面這一段設定應放在那裡? 這可以查一下DTD,就知道應放於那個位置了。 | ||||||||||||||||||
OSWorkflow 的第五支程式 | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
第五支程式要用OSWorkflow提供的API做查詢,查詢出已完成工作流的工作流編號。
package tw.idv.idealist;
import java.util.*; import com.opensymphony.workflow.*; import com.opensymphony.workflow.query.*; import com.opensymphony.workflow.spi.WorkflowEntry;
/** * @author steven */ public class Query extends AbstractWorkflow { public List getCompleted() { FieldExpression fe = new FieldExpression(FieldExpression.STATE, FieldExpression.ENTRY, FieldExpression.EQUALS, new Integer(WorkflowEntry.COMPLETED)); List list = null; try { list = getPersistence().query(new WorkflowExpressionQuery(fe)); } catch (StoreException e) { e.printStackTrace(); }
return list; } } completed.jsp <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML> <HEAD> <%@ page language="java" contentType="text/html; charset=BIG5" pageEncoding="BIG5" %> <%@ page import="tw.idv.idealist.*" %> <%@ page import="java.util.*" %>
<META http-equiv="Content-Type" content="text/html; charset=BIG5"> <META http-equiv="Content-Style-Type" content="text/css"> <LINK href="theme/Master.css" rel="stylesheet"type="text/css"> <TITLE>completed.jsp</TITLE> </HEAD> <BODY>
已完成的工作流編號:<br> <% Query query = new Query(); List completed = query.getCompleted(); for(int i=0; i<completed.size(); i++) { Long wfId = (Long) completed.get(i); out.println("workflow id => " + wfId + "<br>"); } %>
</BODY> </HTML>
| ||||||||||||||||||
OSWorkflow 觀念探討(5) -- 查詢API | ||||||||||||||||||
( 史帝芬, 2005/6/11, hi.steven@gmail.com) | ||||||||||||||||||
要使用OSWorkflow提供的Query API,先繼承AbstractWorkflow,透過AbstractWorkflow裡的getPersistence method 可連接資料做查詢,其餘的語法參考程式即可知道,這裡針對幾點做說明:
// Get all finished workflow entries //where the current owner is 'testuser' Expression queryLeft = new FieldExpression( FieldExpression.OWNER, FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, 'testuser'); Expression queryRight = new FieldExpression( FieldExpression.STATUS, FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Finished", true); WorkflowExpressionQuery query = new WorkflowExpressionQuery( new NestedExpression( new Expression[] {queryLeft, queryRight}, NestedExpression.AND)); |