E-State和工作流
我在前面的文章“狀態(tài)機(jī)與工作流(State Machines and Workflow)”(WLDJ,卷3,第1期)中討論過工作流和狀態(tài)機(jī),它們是面向流程的應(yīng)用程序的補(bǔ)充實(shí)現(xiàn)策略。 狀態(tài)技術(shù)是對許多業(yè)務(wù)流程中所采用的“里程碑”技術(shù)所做繼承的強(qiáng)大抽象。另一方面,工作流 - 這里特指BEA Weblogic Integration的Business Process Modeler(BPM)組件 - 提供了重要的企業(yè)級服務(wù),例如外部系統(tǒng)集成、人員工作列表(worklist)和任務(wù)管理,事件和計時器,以及XML消息處理。在前面的文章中指出過,混合的狀態(tài)-工作流解決方案有以下幾個部分:
1. 狀態(tài)機(jī)框架,由以下部分構(gòu)成:
- 狀態(tài)模型: 一套狀態(tài)和轉(zhuǎn)換,在XML文檔中表達(dá)。
- Actor數(shù)據(jù)庫: 主角(actor)是指具有狀態(tài)的實(shí)體。Actor的狀態(tài)由狀態(tài)機(jī)保存在數(shù)據(jù)庫里。
- 狀態(tài)機(jī)引擎: 把事件插入Actor的狀態(tài)模型中,并相應(yīng)地更新狀態(tài)。它還會在進(jìn)入、退出狀態(tài)或者發(fā)生轉(zhuǎn)換時,調(diào)用用戶自定義動作類。
- 動作類: 用戶自定義的Java類,負(fù)責(zé)響應(yīng)某種狀態(tài)的進(jìn)入或退出,或者某個Actor在特定狀態(tài)模型下執(zhí)行過濾形態(tài)。
2. BPM工作流:負(fù)責(zé)接收事件,然后把事件插入狀態(tài)機(jī)。
3. BPM工作流:設(shè)置計時器,在時間用盡的時候把超時事件插入狀態(tài)機(jī)。
4. BPM工作流:某一狀態(tài)動作調(diào)用該工作流,給它分配一個工作列表任務(wù)或與外部系統(tǒng)交互。
E-State 是第一部分即狀態(tài)機(jī)框架的參考實(shí)現(xiàn)。本文來討論狀態(tài)機(jī)的體系結(jié)構(gòu)。
E-State 體系結(jié)構(gòu)
方法學(xué)
E-State的狀態(tài)模型基于實(shí)時面向?qū)ο蠼#?/span>Real-time Object-Oriented Modeling -ROOM) 的方法。ROOM 的狀態(tài)圖是層次結(jié)構(gòu)的,也就是說每個狀態(tài)可以擁有子狀態(tài)。這個主意很簡單,效果卻異常強(qiáng)大。 從人類思維的角度來看,平面狀態(tài)模型無法進(jìn)行擴(kuò)展。當(dāng)狀態(tài)和轉(zhuǎn)換的數(shù)量增長時,平面模型就會變得難于理解。而層次狀態(tài)模型則可以分部分考察,每一部分理解起來相對就變得簡單了。例如,考慮圖 1。

在這個模型里,轉(zhuǎn)換 ab 會使?fàn)顟B(tài) a1 或 a2 變成狀態(tài) b; 而轉(zhuǎn)換ac 會使?fàn)顟B(tài)從 a1 或 a2 變成 c。所有狀態(tài)的轉(zhuǎn)換toC 會使?fàn)顟B(tài)變成c。 在狀態(tài) a1里的轉(zhuǎn)換 ba 會形成新的狀態(tài) a。初始狀態(tài)是 b。狀態(tài)從 a1變?yōu)?/span>a2時,要經(jīng)過轉(zhuǎn)換 a1a2,從 a2 變?yōu)?/span>a1時,要經(jīng)過a2a1。轉(zhuǎn)換ca把狀態(tài)引到一個選擇點(diǎn):如果最后的狀態(tài)是a1,就變成a1,否則就變成 a2。
同樣的場景,用層次結(jié)構(gòu)來表示,理解起來就容易多了,如圖2所示:

首先,超級狀態(tài) a被細(xì)分為狀態(tài)a1 和 a2(圖2中的右圖);這樣整個系統(tǒng)的狀態(tài)圖(圖2中的左圖)變得更簡潔。從狀態(tài)的高最層來看,轉(zhuǎn)換ab 和 ba只是在狀態(tài)a 和 b之間轉(zhuǎn)換;但是在狀態(tài) a里,可以看到 ba 指向子狀態(tài) a1,而 ab則來源于a1。 轉(zhuǎn)換ac 從 a1 或 a2 開始,指向 c;轉(zhuǎn)換 ca 從c開始,指向 狀態(tài)a的最后一個子狀態(tài)。另外,轉(zhuǎn)換toC不象圖1中那樣,要從每個狀態(tài)來開始;來自最高層狀態(tài)的非擴(kuò)展轉(zhuǎn)換點(diǎn)toC 的事件指向狀態(tài) c,就可以表示需要的行為。
作為層次結(jié)構(gòu)設(shè)計的成果之一,ROOM提供了二個強(qiáng)大的特性:組轉(zhuǎn)換和歷史恢復(fù)。所謂組轉(zhuǎn)換是指:針對指定狀態(tài)發(fā)生的轉(zhuǎn)換,不論指定狀態(tài)處在什么子狀態(tài)當(dāng)中;轉(zhuǎn)換 ac 把狀態(tài)從 a 變?yōu)?/span> c,不論狀態(tài)a的子狀態(tài)是a1還是 a2。歷史恢復(fù) 就是變回指定狀態(tài)最近的子狀態(tài);轉(zhuǎn)換 ca 把狀態(tài) c 變回 a最近的子狀態(tài).
可以選擇的方法還有UML和Petri-nets,它們都支持層次結(jié)構(gòu)。
引擎
E-State的核心是一個無狀態(tài)的會話Enterprise JavaBean (EJB),它被稱為狀態(tài)機(jī)(StateMachine),如圖3中的陰影部分所示。

StateMachine EJB被配置成指向具體的狀態(tài)模型,使用XML文件來進(jìn)行配置,配置文件中包含以下內(nèi)容:
·一組狀態(tài)和一組轉(zhuǎn)換;
·唯一的命名空間,唯一命名空間有助于多重部署,稍后介紹。
·Java “動作”回調(diào)類的名稱,狀態(tài)機(jī)處理事件時,調(diào)用回調(diào)類。
EJB把模型用于“Actor”。在ROOM方法中,Actor指的是一個“活動”對象,狀態(tài)模型最好地描述了這個對象的行為。
(在 ROOM里,活動對象擁有自己的控制線程,以及一組自己的入站、出站消息接口。E-State里Actor的概念更嚴(yán)格) 在 E-State里,Actor是擁有狀態(tài)的實(shí)體,例如一個保險索賠。在一個模型里,從一個狀態(tài)到另一個狀態(tài)的轉(zhuǎn)換,反映了Actor的狀態(tài)變化;例如,索賠可能處在等待狀態(tài),激活狀態(tài),或者空閑狀態(tài)。 E-State 有三個表負(fù)責(zé)跟蹤Actor的狀態(tài),這三個表是 Actor(主角)、Actor_Property(主角屬性)和 Actor_State(主角狀態(tài)),還有對應(yīng)的實(shí)體 EJB (Actor,ActorProperty,和 ActorState) 來表示這三個表,如圖3所示。StateMachine EJB 某種程度上可以看作這些實(shí)體EJB的一個層面(facade)。StateMachine EJB的Actor管理方法有: createActor(),getCurrentState(),getChildState(), getActorProperty(),getActorProperties() 和 setActorProperty()。
狀態(tài)機(jī)余下的方法 (startMachine() 和 injectEvent()) 形成了狀態(tài)機(jī)引擎,驅(qū)動著Actor的狀態(tài)變化。實(shí)際上,startMachine()只是調(diào)用 injectEvent(),給它傳遞了一個特殊的“初始化”事件,由injectEvent()執(zhí)行轉(zhuǎn)換操作,轉(zhuǎn)換操作的起點(diǎn)是模型中每個狀態(tài)的初始轉(zhuǎn)換點(diǎn)。所以, injectEvent() 方法是狀態(tài)機(jī)的核心,由它來驅(qū)動業(yè)務(wù)流程的動作前進(jìn)。這個方法可以調(diào)用用戶自定義動作類,從而實(shí)現(xiàn)模型中所定義的狀態(tài)行動(StateAction)接口。動作類的功能是將重要的狀態(tài)機(jī)事件通知客戶,并向客戶請示邏輯決策。在表1里列出了動作類的方法。
表1 動作類的方法
方法 | 動作 |
OnStateEnter | 通知進(jìn)入了一個狀態(tài) |
OnStateExit | 通知退出了一個狀態(tài) |
OnTransitionExecute | 通知執(zhí)行了一個轉(zhuǎn)換。如果方法返回真,則允許該轉(zhuǎn)換發(fā)生,如果為假,則阻止轉(zhuǎn)換(在ROOM的概念里,稱為警衛(wèi)(guard)) |
Choice | 要執(zhí)行選擇點(diǎn)決策的請求。返回值為真或假,控制著狀態(tài)模型里控制分支的流轉(zhuǎn)方向。 |
在保險索賠的例子里,動作類啟動工作流,執(zhí)行與任務(wù)相關(guān)的工作或者清理工作,或者啟動計數(shù)器。在 WebLogic Integration 7.0里,由BPM 的API啟動工作流。在In WebLogic Integration 8.1里,則用Web服務(wù)調(diào)用工作流。
表2里歸納了StateMachine EJB的方法。
表2 StateMachine EJB的方法
方法 | 動作 |
CreateActor | 在Actor表中為StateMachine EJB代表的模型建立一個新記錄 |
GetCurrentState | 取得StateMachine EJB代表的模型的Actor的當(dāng)前葉子狀態(tài) |
GetChildState | 取得StateMachine EJB代表的模型的Actor的指定狀態(tài)的當(dāng)前子狀態(tài) |
GetActorProperty | 取得StateMachine EJB代表的模型的Actor的指定屬性值 |
SetActorProperty | 設(shè)置StateMachine EJB代表的模型的Actor的指定屬性值 |
GetActorProperties | 取得StateMachine EJB代表的模型的Actor的名稱、類型和每個屬性的值 |
StartMachine | 執(zhí)行模型里的每個狀態(tài)的初始化轉(zhuǎn)換,啟動StateMachine EJB代表的模型的Actor的狀態(tài)模型 |
InjectEvent | 把指定事件插入StateMachine EJB代表的模型的Actor的狀態(tài)模型里 |
在保險索賠的例子里,插入器(Injector)工作流調(diào)用狀態(tài)機(jī)的 injectEvent()方法。在WebLogic Integration 7.0里,工作流使用一個業(yè)務(wù)操作來調(diào)用這個方法,而在 WebLogic Integration 8.1,則用EJB控件來完成。
數(shù)據(jù)庫架構(gòu)
圖4顯示了保持Actor持久狀態(tài)信息的表結(jié)構(gòu)。.

在主表 Actor里,保存了特定 模型類型的Actor的當(dāng)前狀態(tài)。當(dāng)前狀態(tài)是指Actor目前所處的葉子狀態(tài)。這個表的主鍵由Actor的唯一標(biāo)識符和它的模型命名空間組合而成的。一個Actor可能在多個 模型命名空間里具有狀態(tài)。特別的是,如果在不同的命名空間里存在著同一模型的二個版本,那么在每個命名空間里的Actor狀態(tài)都能在Actor表里表示。
Actor_State表捕捉特定命名空間里的特定Actor的復(fù)合狀態(tài)的活動子狀態(tài)。這個表僅供內(nèi)部使用,狀態(tài)引擎用來來實(shí)現(xiàn)歷史恢復(fù)。在actor和actor_state表之間存在著一對多的關(guān)系。
Actor_Property 表保存特定命名空間里的特定Actor的用戶自定義屬性。每個屬性都有一個名字(對于每個命名空間的每個Actor,名字必須是唯一的),一個類型,和一個值。這個表為客戶應(yīng)用程序提供了方便,可以把一組數(shù)據(jù)與角色關(guān)聯(lián);更常見的情況是,應(yīng)用程序的數(shù)據(jù)保存在應(yīng)用程序的數(shù)據(jù)存儲機(jī)制里。
部署
StateMachine EJB會為每個狀態(tài)模型部署一個不同的實(shí)例。每個實(shí)例的源代碼是相同的(相同的home和 remote接口,相同的實(shí)現(xiàn)),但是具體的配置不同。StateMachine EJB的部署描述符指定了唯一的JNDI(Java命名和目錄接口)名(客戶用這個名字來定位EJB),還有一個對模型XML文件的引用。例如,保險狀態(tài)模型的StateMachine EJB可能有一個 JNDI 名"state_insurance" ,并指向文件 "Insurance.xml"。要與這個模型交互,客戶應(yīng)用程序可以用"state-insurance"這個JNDI名來訪問模型的EJB并調(diào)用EJB的方法。這個特殊的方法有著顯著的優(yōu)勢:
·生命周期:要想準(zhǔn)備好一個可供處理的新狀態(tài)模型,需要部署一個指定該模型的StateMachine EJB。要想取消這個模型,需要取消EJB的部署。要把變化交給模型,需要用修改過的模型文件重新部署EJB。
·版本管理:如果現(xiàn)有的狀態(tài)模型有一個新的主版本,那么新版本可以部署成獨(dú)立的EJB,與以前的版本并存。
例如,“state-insurance-1.1”可以與“state-insurance”并存。
數(shù)據(jù)模型同樣支持版本管理。給定的Actor有多個模型的持久狀態(tài),包括相同模型的不同版本,只有模型有不同的名稱。.
大多數(shù)業(yè)務(wù)流程要運(yùn)行相當(dāng)長的時候,所以應(yīng)用程序升級的管理變得極富挑戰(zhàn)。有二個場景很難解決:
1.做了一個小補(bǔ)丁,但是有Actor正在用沒有打補(bǔ)丁的版本運(yùn)行著。
2. 做了一個主要補(bǔ)丁,只有新Actor可用,舊的Actor仍然使用以前的版。.
E-State 是解決這些問題聰明的解決方案:
1.應(yīng)用小補(bǔ)丁,意味著為模型重新部署現(xiàn)有EJB。Actor會在停止的地方重新開始,補(bǔ)丁同時發(fā)揮作用。.
2.應(yīng)用主要補(bǔ)丁,意味著用一個獨(dú)立的命名空間部署新的EJB,而現(xiàn)在已經(jīng)部署的EJB保持不變。模型彼此獨(dú)立,這樣老Actor用舊版本運(yùn)行,新Actor用新版本運(yùn)行。
結(jié)束語
E-State是由ROOM方法所啟發(fā)的一個企業(yè)級狀態(tài)機(jī)框架。它與BMP工作流集成在一起,提供了關(guān)鍵的集成服務(wù),例如系統(tǒng)集成、事件、計時器、工作列表以及XML。這為開發(fā)面向流程的業(yè)務(wù)應(yīng)用程序提供了強(qiáng)大的解決方案。E-State中包括:運(yùn)行時引擎,狀態(tài)模型架構(gòu),持久性服務(wù),用戶自定義“動作”類(在發(fā)生轉(zhuǎn)換時,在進(jìn)入或退出狀態(tài)時,引擎會調(diào)用用戶自定義“動作”類。)動作類調(diào)用工作流來利用BPM服務(wù);而工作流被事件觸發(fā)時,則調(diào)用引擎來觸發(fā)轉(zhuǎn)換。
參考資料
· Selic, Gullickson, and Ward. (1994). Real-Time Object-Oriented Modeling. Wiley.