lyyb2001

          只是為方便自己找記錄而已
          posts - 57, comments - 27, trackbacks - 0, articles - 5
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 ::  :: 管理

          OSWorkFlow入門指南

          Posted on 2007-03-20 16:43 skycity 閱讀(387) 評(píng)論(1)  編輯  收藏 所屬分類: workflow相關(guān)

          引用:http://www.duduwolf.com/cmd.asp?act=tb&id=212
          目的

          這篇指導(dǎo)資料的目的是介紹OSWorkflow的所有概念,指導(dǎo)你如何使用它,并且保證你逐步理解OSWorkflow的關(guān)鍵內(nèi)容。

          本指導(dǎo)資料假定你已經(jīng)部署OSWorkflow的范例應(yīng)用在你的container上。范例應(yīng)用部署是使用基于內(nèi)存的數(shù)據(jù)存儲(chǔ),這樣你不需要擔(dān)心如何配置其他持久化的例子。范例應(yīng)用的目的是為了說明如何應(yīng)用OSWorkflow,一旦你精通了OSWorkflow的流程定義描述符概念和要素,應(yīng)該能通過閱讀這些流程定義文件而了解實(shí)際的流程。

          本指導(dǎo)資料目前有3部分:
          1. 你的第一個(gè)工作流
          2. 測試你的工作流
          3. 更多的流程定義描述符概念

          1. Your first workflow

          創(chuàng)建描述符

          首先,讓我們來定義工作流。你可以使用任何名字來命名工作流。一個(gè)工作流對(duì)應(yīng)一個(gè)XML格式的定義文件。讓我們來開始新建一個(gè)“myworkflow.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>
          ??? ...
          ? </initial-actions><steps>
          ??? ...
          ? </steps></workflow>

          首先是標(biāo)準(zhǔn)的XML頭部,要注意的是OSWorkflow將會(huì)通過這些指定的DTD來驗(yàn)證XML內(nèi)容的合法性。你可以使用絕大多數(shù)的XML編輯工具來編輯它,并且可以highlight相應(yīng)的錯(cuò)誤。

          步驟和動(dòng)作

          接下來我們來定義初始化動(dòng)作和步驟。首先需要理解的OSWorkflow重要概念是steps (步驟) 和 actions (動(dòng)作)。一個(gè)步驟是工作流所處的位置,比如一個(gè)簡單的工作流過程,它可能從一個(gè)步驟流轉(zhuǎn)到另外一個(gè)步驟(或者有時(shí)候還是停留在一樣的步驟)。舉例來說,一個(gè)文檔管理系統(tǒng)的流程,它的步驟名稱可能有“First Draft - 草案初稿”,“Edit Stage -編輯階段”,“At publisher - 出版商”等。

          動(dòng)作指定了可能發(fā)生在步驟內(nèi)的轉(zhuǎn)變,通常會(huì)導(dǎo)致步驟的變更。在我們的文件管理系統(tǒng)中,在“草案初稿”這個(gè)步驟可能有“start first draft - 開始草案初稿”和“complete first draft - 完成草案初稿”這樣2個(gè)動(dòng)作。

          簡單的說,步驟是“在哪里”,動(dòng)作是“可以去哪里”。

          初始化步驟是一種特殊類型的步驟,它用來啟動(dòng)工作流。在一個(gè)工作流程開始前,它是沒有狀態(tài),不處在任何一個(gè)步驟,用戶必須采取某些動(dòng)作才能開始這個(gè)流程。這些特殊步驟被定義在 <initial-actions>。

          在我們的例子里面,假定只有一個(gè)簡單的初始化步驟:“Start Workflow”,它的定義在里面<initial-actions>:
          <action id="1" name="Start Workflow">
          <results>
          <unconditional-result old-status="Finished" status="Queued" step="1"/>
          </results>
          </action>

          這個(gè)動(dòng)作是最簡單的類型,只是簡單地指明了下一個(gè)我們要去的步驟和狀態(tài)。

          工作流狀態(tài)

          工作流狀態(tài)是一個(gè)用來描述工作流程中具體步驟狀態(tài)的字符串。在我們的文檔管理系統(tǒng)中,在“草案初稿”這個(gè)步驟可能有2個(gè)不同的狀態(tài):“Underway - 進(jìn)行中”和“Queued - 等候處理中”

          我們使用“Queued”指明這個(gè)條目已經(jīng)被排入“First Draft”步驟的隊(duì)列。比如說某人請(qǐng)求編寫某篇文檔,但是還沒有指定作者,那么這個(gè)文檔在“First Draft”步驟的狀態(tài)就是“Queued”。“Underway”狀態(tài)被用來指明一個(gè)作者已經(jīng)挑選了一篇文檔開始撰寫,而且可能正在鎖定這篇文檔。

          第一個(gè)步驟

          讓我們來看第一個(gè)步驟是怎樣被定義在<steps>元素中的。我們有2個(gè)動(dòng)作:第一個(gè)動(dòng)作是保持當(dāng)前步驟不變,只是改變了狀態(tài)到“Underway”,第二個(gè)動(dòng)作是移動(dòng)到工作流的下一步驟。我們來添加如下的內(nèi)容到<steps>元素:
          <step id="1" name="First Draft">
          <actions>
          <action id="1" name="Start First Draft">
          <results>
          <unconditional-result old-status="Finished"
          ??????? status="Underway" step="1"/>

          </results>
          </action>
          <action id="2" name="Finish First Draft">
          <results>
          <unconditional-result old-status="Finished"
          ??????? status="Queued" step="2"/>

          </results>
          </action>
          </actions>
          </step>
          <step id="2" name="finished" />

          這樣我們就定義了2個(gè)動(dòng)作,old-status屬性是用來指明當(dāng)前步驟完成以后的狀態(tài)是什么,在大多數(shù)的應(yīng)用中,通常用"Finished"表示。

          上面定義的這2個(gè)動(dòng)作是沒有任何限制的。比如,一個(gè)用戶可以調(diào)用action 2而不用先調(diào)用action 1。很明顯的,我們?nèi)绻麤]有開始撰寫草稿,是不可能去完成一個(gè)草稿的。同樣的,上面的定義也允許你開始撰寫草稿多次,這也是毫無意義的。我們也沒有做任何的處理去限制其他用戶完成別人的草稿。這些都應(yīng)該需要想辦法避免。

          讓我們來一次解決這些問題。首先,我們需要指定只有工作流的狀態(tài)為“Queued”的時(shí)候,一個(gè)caller (調(diào)用者)才能開始撰寫草稿的動(dòng)作。這樣就可以阻止其他用戶多次調(diào)用開始撰寫草稿的動(dòng)作。我們需要指定動(dòng)作的約束,約束是由Condition(條件)組成。

          條件

          OSWorkflow 有很多有用的內(nèi)置條件可以使用。在此相關(guān)的條件是“StatusCondition - 狀態(tài)條件”。 條件也可以接受參數(shù),參數(shù)的名稱通常被定義在javadocs里(如果是使用Java Class實(shí)現(xiàn)的條件的話)。在這個(gè)例子里面,狀態(tài)條件接受一個(gè)名為“status”的參數(shù),指明了需要檢查的狀態(tài)條件。我們可以從下面的xml定義里面清楚的理解:
          <action id="1" name="Start First Draft">
          <restrict-to>
          <conditions>
          <condition type="class">
          <arg name="class.name">
          ????????? com.opensymphony.workflow.util.StatusCondition</arg><arg name="status">Queued</arg></condition></conditions></restrict-to><results><unconditional-result old-status="Finished" status="Underway" step="1"/></results></action>

          希望對(duì)于條件的理解現(xiàn)在已經(jīng)清楚了。上面的條件定義保證了動(dòng)作1只能在當(dāng)前狀態(tài)為“Queued”的時(shí)候才能被調(diào)用,也就是說在初始化動(dòng)作被調(diào)用以后。

          函數(shù)

          接下來,我們想在一個(gè)用戶開始撰寫草稿以后,設(shè)置他為“owner”。為了達(dá)到這樣的目的,我們需要做2件事情:

          1) 通過一個(gè)函數(shù)設(shè)置“caller”變量在當(dāng)前的環(huán)境設(shè)置里。
          2) 根據(jù)“caller”變量來設(shè)置“owner”屬性。

          函數(shù)是OSWorkflow的一個(gè)功能強(qiáng)大的特性。函數(shù)基本上是一個(gè)在工作流程中的工作單位,他不會(huì)影響到流程本身。舉例來說,你可能有一個(gè)“SendEmail”的函數(shù),用來在某些特定的流程流轉(zhuǎn)發(fā)生時(shí)來發(fā)送email提醒。

          函數(shù)也可以用來添加變量到當(dāng)前的環(huán)境設(shè)置里。變量是一個(gè)指定名稱的對(duì)象,可以用來在工作流中被以后的函數(shù)或者腳本使用。

          OSWorkflow提供了一些內(nèi)置的常用函數(shù)。其中一個(gè)稱為“Caller”,這個(gè)函數(shù)會(huì)獲得當(dāng)前調(diào)用工作流的用戶,并把它放入一個(gè)名為“caller”的字符型變量中。

          因?yàn)槲覀冃枰粉櫴悄膫€(gè)用戶開始了編寫草稿,所以可以使用這個(gè)函數(shù)來修改我們的動(dòng)作定義:
          <action id="1" name="Start First Draft">
          <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="Underway"
          ??? step="1" owner="${caller}"/>
          ? </results></action>

          h3 組合起來
          把這些概念都組合起來,這樣我們就有了動(dòng)作1:
          <action id="1" name="Start First Draft">
          <restrict-to>
          <conditions>
          <condition type="class">
          <arg name="class.name">
          ????????? com.opensymphony.workflow.util.StatusCondition
          ??????? </arg><arg name="status">Queued</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="Underway"
          ??? step="1"? owner="${caller}"/>
          ? </results></action>

          我們使用類似想法來設(shè)置動(dòng)作2:
          <action id="2" name="Finish First Draft">
          <restrict-to>
          <conditions type="AND">
          <condition type="class">
          ??????? <arg name="class.name">
          ????????? com.opensymphony.workflow.util.StatusCondition
          ??????? </arg><arg name="status">Underway</arg></condition><condition type="class"><arg name="class.name">
          ????????? com.opensymphony.workflow.util.AllowOwnerOnlyCondition
          ?????? </arg></condition></conditions></restrict-to><results><unconditional-result old-status="Finished" status="Queued" step="2"/></results></action>

          在這里我們指定了一個(gè)新的條件:“allow owner only”。這樣能夠保證只有開始撰寫這份草稿的用戶才能完成它。而狀態(tài)條件確保了只有在“Underway”狀態(tài)下的流程才能調(diào)用“finish first draft”動(dòng)作。

          把他們組合在一起,我們就有了第一個(gè)流程定義:
          <?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="1" name="Start Workflow"><results><unconditional-result old-status="Finished"
          ??????? status="Queued" step="1"/>
          </results></action></initial-actions><steps><step id="1" name="First Draft"><actions><action id="1" name="Start First Draft"><restrict-to><conditions><condition type="class"><arg name="class.name">
          ?????????????????? com.opensymphony.workflow.util.StatusCondition
          ??????????????? </arg><arg name="status">Queued</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="Underway"
          ??????????? step="1"? owner="${caller}"/>
          ????????? </results></action><action id="2" name="Finish First Draft"><restrict-to><conditions type="AND"><condition type="class"><arg name="class.name"> com.opensymphony.workflow.util.StatusCondition </arg><arg name="status">Underway</arg></condition><condition type="class"><arg name="class.name">
          ????????????????? com.opensymphony.workflow.util.
          ????????????????? AllowOwnerOnlyCondition
          ??????????????? </arg></condition></conditions></restrict-to><results><unconditional-result old-status="Finished"
          ??????????? status="Queued" step="2"/>
          </results></action></actions></step><step id="2" name="finished" /></steps></workflow>

          現(xiàn)在這個(gè)工作流的定義已經(jīng)完整了,讓我們來測試和檢查它的運(yùn)行。

          2. Testing your workflow

          現(xiàn)在我們已經(jīng)完成了一個(gè)完整的工作流定義,下一步是檢驗(yàn)它是否按照我們預(yù)想的方式執(zhí)行。

          在一個(gè)快速開發(fā)環(huán)境中,最簡單的方法就是寫一個(gè)測試案例。通過測試案例調(diào)用工作流,根據(jù)校驗(yàn)結(jié)果和捕捉可能發(fā)生的錯(cuò)誤,來保證流程定義的正確性。

          我們假設(shè)你已經(jīng)熟悉Junit和了解怎樣編寫測試案例。如果你對(duì)這些知識(shí)還不了解的話,可以去JUnit的網(wǎng)站查找、閱讀相關(guān)文檔。編寫測試案例會(huì)成為你的一個(gè)非常有用的工具。

          在開始載入流程定義、調(diào)用動(dòng)作以前,我們需要配置OSWorkflow的數(shù)據(jù)存儲(chǔ)方式和定義文件的位置等。

          配置 osworkflow.xml

          我們需要?jiǎng)?chuàng)建的第一個(gè)文件是 osworkflow.xml。子:
          <osworkflow>
          <persistence class="com.opensymphony.workflow.
          ? spi.memory.MemoryWorkflowStore"
          />

          <factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory">
          <property key="resource" value="workflows.xml" />
          </factory>
          </osworkflow>

          這個(gè)例子指明了我們準(zhǔn)備使用內(nèi)存 (MemoryWorkflowStore) 來保存流程數(shù)據(jù)。這樣可以減少設(shè)置數(shù)據(jù)庫的相關(guān)信息,減少出問題的可能性。用內(nèi)存持久化對(duì)于測試來說是非常方便的。

          Workflow factories

          上面的配置文件還指明了我們工作流工廠(XMLWorkflowFactory),工作流工廠的主要功能是管理流程定義文件,包括讀取定義文件和修改定義文件的功能。通過'resource'這個(gè)屬性指明了采用通過從classpath中讀取流程定義文件的方式,按照這個(gè)定義,接下來我們需要在classpath中創(chuàng)建一個(gè)名為workflows.xml的文件。

          workflows.xml 的內(nèi)容:
          <workflows>
          <workflow name="mytest" type="resource" location="myworkflow.xml"/>
          </workflows>

          我們把 myworkflow.xml 和workflows.xml放在同一目錄,這樣它就能夠被工作流工廠讀取了。

          這樣就完成了配置,接下來是初始化一個(gè)流程并調(diào)用它。

          Initialising OSWorkflow

          OSWorkflow 的調(diào)用模式相當(dāng)簡單:通過一個(gè)主要的接口來執(zhí)行大部分操作。這個(gè)接口就是 Workflow interface,及其擴(kuò)展 AbstractWorkflow 的實(shí)現(xiàn),例如EJBWorkflow 和 SOAPWorkflow. 為了簡單起見,我們使用最基本的一種: BasicWorkflow。

          首先,我們來創(chuàng)建Workflow。在實(shí)際項(xiàng)目中,這個(gè)對(duì)象應(yīng)該被放在一個(gè)全局的位置上以供重用,因?yàn)槊看味紕?chuàng)建一個(gè)新的Workflow對(duì)象是需要耗費(fèi)比較昂貴的系統(tǒng)資源。在這里的例子,我們采用BasicWorkflow,它的構(gòu)建器由一個(gè)當(dāng)前調(diào)用者的用戶名構(gòu)成,當(dāng)然我們很少看到單用戶的工作流應(yīng)用,可以參考其他的Workflow實(shí)現(xiàn)有不同的方式去獲得當(dāng)前調(diào)用者。

          為了簡單起見,我們采用BasicWorkflow來創(chuàng)建一個(gè)單一的用戶模式,避免編寫其他獲取用戶方法的麻煩。

          這樣我們來創(chuàng)建一個(gè)'testuser'調(diào)用的workflow:

          Workflow workflow = new BasicWorkflow("testuser");

          下一步是提供配置文件,在大多數(shù)情況下,只是簡單的傳遞一個(gè)DefaultConfiguration實(shí)例:

          DefaultConfiguration config = new DefaultConfiguration();
          workflow.setConfiguration(config);

          現(xiàn)在我們已經(jīng)創(chuàng)建并且配置好了一個(gè)workflow,接下來就是開始調(diào)用它了。

          啟動(dòng)和進(jìn)行一個(gè)工作流程

          首先我們需要調(diào)用initialize 方法來啟動(dòng)一個(gè)工作流程,這個(gè)方法有3個(gè)參數(shù),workflow name (定義在workflows.xml里,通過workflow factory處理), action ID (我們要調(diào)用的初始化動(dòng)作的ID),和初始化變量。 因?yàn)樵诶永锩娌恍璩跏蓟兞浚晕覀冎皇莻鬟f一個(gè)null,

          								long workflowId = workflow.initialize("mytest", 1, null);

          我們現(xiàn)在已經(jīng)有了一個(gè)工作流實(shí)例,返回的workflowId可以在后續(xù)的操作中來代表這個(gè)實(shí)例。這個(gè)參數(shù)會(huì)在Workflow interface的絕大部分方法中用到。

          檢驗(yàn)工作流

          現(xiàn)在讓我們來檢驗(yàn)啟動(dòng)的工作流實(shí)例是否按照我們所預(yù)期的那樣運(yùn)行。根據(jù)流程定義,我們期望的當(dāng)前步驟是第一步,而且應(yīng)該可以執(zhí)行第一個(gè)動(dòng)作(開始編寫草稿)。

          Collection currentSteps = workflow.getCurrentSteps
          (workflowId);
          //校驗(yàn)只有一個(gè)當(dāng)前步驟
          assertEquals("Unexpected number of current steps", 
          1, currentSteps.size());
          //校驗(yàn)這個(gè)步驟是1
          Step currentStep = (Step)currentSteps.iterator().next();
          assertEquals("Unexpected current step", 1,
          currentStep.getStepId());
          
          int[] availableActions = 
          workflow.getAvailableActions(workflowId);
          //校驗(yàn)只有一個(gè)可執(zhí)行的動(dòng)作
          assertEquals("Unexpected number of available actions", 1, 
          availableActions.length);
          //校驗(yàn)這個(gè)步驟是1
          assertEquals("Unexpected available action", 1, availableActions[0]);

          執(zhí)行動(dòng)作

          現(xiàn)在已經(jīng)校驗(yàn)完了工作流實(shí)例正如我們所期望的到了第一個(gè)步驟,讓我們來開始執(zhí)行第一個(gè)動(dòng)作:

          workflow.doAction(workflowId, 1, null);

          這是簡單的調(diào)用第一個(gè)動(dòng)作,工作流引擎根據(jù)指定的條件,改變狀態(tài)到‘Underway’,并且保持在當(dāng)前步驟。

          現(xiàn)在我們可以類似地調(diào)用第2個(gè)動(dòng)作,它所需要的條件已經(jīng)都滿足了。

          在調(diào)用完第2個(gè)動(dòng)作以后,根據(jù)流程定義就沒有可用的動(dòng)作了,getAvailableActions將會(huì)返回一個(gè)空數(shù)組。

          Congratulations, 你已經(jīng)完成了一個(gè)工作流定義并且成功地調(diào)用了它。下一節(jié)我們將會(huì)講解osworkflow一些更深入的概念。

          3. Further descriptor concepts

          定義條件和函數(shù)

          你也許已經(jīng)注意到,到目前為止,我們定義的條件和函數(shù)類型都是“class”。這種類型的條件和函數(shù)接受一個(gè)參數(shù):“class.name”,以此來指明一個(gè)實(shí)現(xiàn)FunctionProvider或Condition接口的完整類名。

          在osworkflow里面也有一些其他內(nèi)置的類型,包括beanshell,無狀態(tài)的session bean,JNDI樹上的函數(shù)等。我們?cè)谙旅娴睦永锸褂胋eanshell類型。

          Property sets

          我們可能需要在工作流的任意步驟持久化一些少量數(shù)據(jù)。在osworkflow里,這是通過OpenSymphony的PropertySet library來實(shí)現(xiàn)。一個(gè)PropertySet基本上是一個(gè)可以持久化的類型安全map,你可以添加任意的數(shù)據(jù)到propertyset(一個(gè)工作流實(shí)例對(duì)應(yīng)一個(gè)propertyset),并在以后的流程中再讀取這些數(shù)據(jù)。除非你特別指定操作,否則propertyset中的數(shù)據(jù)不會(huì)被清空或者被刪除。任意的函數(shù)和條件都可以和propertyset交互,以beanshell script來說,可以在腳本上下文中用“propertyset”這個(gè)名字來獲取。下面來看具體寫法是怎么樣的,讓我們?cè)黾尤缦碌拇a在“Start First Draft”動(dòng)作的pre-functions里面:

          								<function type="beanshell">
          								<arg name="script">propertySet.setString("foo", "bar")</arg></function>

          這樣我們就添加了一個(gè)持久化的屬性“foo”,它的值是“bar”。這樣在以后的流程中,我們就可以獲得這個(gè)值了。

          Transient Map 臨時(shí)變量

          另外一個(gè)和propertyset變量相對(duì)的概念是臨時(shí)變量:“transientVars”。臨時(shí)變量是一個(gè)簡單的map,只是在當(dāng)前的工作流調(diào)用的上下文內(nèi)有效。它包括當(dāng)前的工作流實(shí)例,工作流定義等對(duì)應(yīng)值的引用。你可以通過FunctionProvider的javadoc來查看這個(gè)map有那些可用的key。

          還記得我們?cè)诮坛痰牡?部分傳入的那個(gè)null嗎?如果我們不傳入null的話,那么這些輸入數(shù)據(jù)將會(huì)被添加到臨時(shí)變量的map里。

          inputs 輸入

          每次調(diào)用workflow的動(dòng)作時(shí)可以輸入一個(gè)可選的map,可以在這個(gè)map里面包含供函數(shù)和條件使用的任何數(shù)據(jù),它不會(huì)被持久化,只是一個(gè)簡單的數(shù)據(jù)傳遞。

          Validators 校驗(yàn)器

          為了讓工作流能夠校驗(yàn)輸入的數(shù)據(jù),引入了校驗(yàn)器的概念。一個(gè)校驗(yàn)器和函數(shù),條件的實(shí)現(xiàn)方式非常類似(比如,它可以是一個(gè)class,腳本,或者EJB)。在這個(gè)教程里面,我們將會(huì)定義一個(gè)校驗(yàn)器,在“finish first draft”這個(gè)步驟,校驗(yàn)用戶輸入的數(shù)據(jù)“working.title”不能超過30個(gè)字符。這個(gè)校驗(yàn)器看起來是這樣的:
          package com.mycompany.validators;

          public class TitleValidator implements Validator
          {
          ? public void validate(Map transientVars, Map args,
          ? PropertySet ps)
          ??????? throws InvalidInputException, WorkflowException
          ? {
          ??? String title =
          ??? (String)transientVars.get("working.title");
          ??? if(title == null)
          ????? thrownew InvalidInputException("Missing working.title");
          ??? if(title.length() > 30)
          ????? thrownew InvalidInputException("Working title too long");
          ? }
          }

          然后通過在流程定義文件添加validators元素,就可以登記這個(gè)校驗(yàn)器了:
          <validators>
          <validator type="class">
          <arg name="class.name">
          ????? com.mycompany.validators.TitleValidator
          ??? </arg></validator></validators>

          這樣,當(dāng)我們執(zhí)行動(dòng)作2的時(shí)候,這個(gè)校驗(yàn)器將會(huì)被調(diào)用,并且檢驗(yàn)我們的輸入。這樣在測試代碼里面,如果加上:

          Map inputs = new HashMap();
          inputs.put("working.title", 
            "the quick brown fox jumped over the lazy dog," +
            " thus making this a very long title");
          workflow.doAction(workflowId, 2, inputs);

          我們將會(huì)得到一個(gè)InvalidInputException,這個(gè)動(dòng)作將不會(huì)被執(zhí)行。減少輸入的title字符,將會(huì)讓這個(gè)動(dòng)作成功執(zhí)行。

          我們已經(jīng)介紹了輸入和校驗(yàn),下面來看看寄存器。

          Registers 寄存器

          寄存器是一個(gè)工作流的全局變量。和propertyset類似,它可以在工作流實(shí)例的任意地方被獲取。和propertyset不同的是,它不是一個(gè)持久化的數(shù)據(jù),而是每次調(diào)用時(shí)都需要重新計(jì)算的數(shù)據(jù)。

          它可以被用在什么地方呢?在我們的文檔管理系統(tǒng)里面,如果定義了一個(gè)“document”的寄存器,那么對(duì)于函數(shù)、條件、腳本來說就是非常有用的:可以用它來獲得正在被編輯的文檔。

          寄存器地值會(huì)被放在臨時(shí)變量(transientVars map)里,這樣能夠在任意地方獲得它。

          定義一個(gè)寄存器和函數(shù)、條件的一個(gè)重要區(qū)別是,它并不是依靠特定的調(diào)用(不用關(guān)心當(dāng)前的步驟,或者是輸入數(shù)據(jù),它只是簡單地暴露一些數(shù)據(jù)而已),所以它不用臨時(shí)變量里的值。

          寄存器必須實(shí)現(xiàn)Register接口,并且被定義在流程定義文件的頭部,在初始化動(dòng)作之前。

          舉例來說,我們將會(huì)使用一個(gè)osworkflow內(nèi)置的寄存器:LogRegister。這個(gè)寄存器簡單的添加一個(gè)“l(fā)og”變量,能夠讓你使用Jakarta的commons-logging輸出日志信息。它的好處是會(huì)在每條信息前添加工作流實(shí)例的ID。
          <registers>
          <register type="class" variable-name="log">
          <arg name="class.name">
          ????? com.opensymphony.workflow.util.LogRegister
          ??? </arg><arg name="addInstanceId">true</arg><arg name="Category">workflow</arg></register></registers>

          這樣我們定義了一個(gè)可用的“l(fā)og”變量,可以通過其他的pre-function的腳本里面使用它:
          <function type="beanshell">
          <arg name="script">transientVars.get("log").info("executing action 2")
          ? </arg>
          </function>

          日志輸出將會(huì)在前面添加工作流實(shí)例的ID

          結(jié)論

          這個(gè)教程的目的是希望可以闡明一些主要的osworkflow概念。你還可以通過API和流程定義格式去獲取更多的信息。有一些更高級(jí)的特性沒有在此提到,比如splits 分支、joins 連接, nested conditions 復(fù)合條件、auto stpes 自動(dòng)步驟等等。你可以通過閱讀手冊(cè)來獲得更進(jìn)一步的理解。



          Lyyb2001

          評(píng)論

          # re: OSWorkFlow入門指南  回復(fù)  更多評(píng)論   

          2007-03-27 17:17 by stanley
          注意的是
          <initial-actions>
          <action id="10" name="啟動(dòng)">

          <steps>
          <step id="1" name="First Draft">
          <actions>
          <action id="1" name="Start First Draft">
          <results>
          中的ID值不要重復(fù)

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 沅江市| 古交市| 太湖县| 绥滨县| 玉山县| 龙南县| 洪泽县| 宾阳县| 宝丰县| 武清区| 汕尾市| 遂宁市| 藁城市| 义马市| 朔州市| 浮山县| 宝应县| 濉溪县| 新建县| 绥棱县| 新津县| 长汀县| 深圳市| 彰武县| 常山县| 东乌珠穆沁旗| 裕民县| 揭阳市| 龙岩市| 扶余县| 临武县| 奈曼旗| 清流县| 吐鲁番市| 桐城市| 黄龙县| 伽师县| 招远市| 北宁市| 和静县| 客服|