• 沒有找到結果。

4. Implementation and experimental result

N/A
N/A
Protected

Academic year: 2021

Share "4. Implementation and experimental result "

Copied!
28
0
0

加載中.... (立即查看全文)

全文

(1)

55

4. Implementation and experimental result

在這章節中,我們將介紹一些元件實作面技術以及測試平台架構的設計,並 且附帶上實驗結果

4.1 詳述 AOP 概念,並加以描述我們如何利用 AOP 來定義我們的通用機制。

4.2 解釋 Agent 的實作

4.3 解釋 TS-WfMS 解析元件實作

4.4 講解如何將一些資料透過 DAO Pattern 存入資料庫 4.5 解釋 IOC 概念以及本實驗如何利用 IOC 設計與實作 4.6 則詳述移植 Reachability Testing 到 WfMS 上的問題

4.1 AOP

AOP[17]此一名詞於 1997 年提出,但其概念也應用於 90 年代的許多技術中。

AOP 架構於 OOP 或 Procedure programming 之上,目標是解決 OOP 中難以處理的 Cross cutting concern 上,提供建構於原有 OOP 中 class、method、field 之上 的一個方法,利用 aspect、pointcut、advice 的組合來管理系統中的 Cross cutting concern。為了更生動的解釋 AOP 的概念,以下我們利用實際的程式架 構範例來講解 AOP 的專有名詞。

Figure 4.1 代表有三個不同程式,若此三程式需要在特定的地點加入登入 (Login)和登出(Logout)的功能,在原本 OOP 的做法中,他們必須在原本的程式 中加上一段程式碼,內容則是呼叫登入以及登出的 API。Figure 4.2 表示將登入 以及登出的功能加入原本程式中。若要將這些功能原件加入原本的程式中,必須 個別修改這些程式,最後重新編譯;若要移除時,也必須在每支程式中逐一將呼 叫登入和登出的程式碼移除。

然而,隨著應用程式所需用到的相同功能越來越多,往後維護這些功能原件 的增加或移除必定會有很大的困擾,因此,AOP 的產生對於原本這些原件的管理 有相當大的裨益,以下利用上述的程式範例來介紹 AOP 的專有名詞。

(2)

56

Program flow 1 Program flow 2 Program flow 3

Figure 4.1 original program flow [19]

Cross cutting concern

Program flow 1 Program flow 2 Program flow 3 Log in

Log out

Figure 4.2 program flow with cross cutting concern [19]

1. Cross cutting concern:登入和登出這兩原件就是一種 Cross cutting concern,因為登入和登出的行為被橫切(Cross cutting)入各個不同的程式 流程中,因此稱之。

(3)

57

2. Aspect:將散落在不同程式中的 Cross cutting concern 重新設計成為一個 可以獨立使用的原件,這些原件稱之為 Aspect。 AOP 中最重要的就是 Aspect 的辨認,且必須將它獨立出來,在適當的地點將 Aspect 縫合(Weave)到原本 的程式上,若不需要該項服務時,也可以立即透過重新設定將其從原本的程 式移除,因此原本的程式本身將不會受到是否有 Aspect 的加入而必須改變程 式碼,簡而言之,被縫合的程式並不知道有此項服務存在他的程式流程之中。

若以上述的範例解釋之,將原本的登入和登出系統獨立出來重新設計,這便 是 Aspect。

3. Advice:Aspect 的具體實作稱為 Advice,以上述登入登出的例子來解說,實 作登入與登出的程式碼讓他得以在必要時 Weave 進各個程式便稱為 Advice。

4. Joinpoint:適時的將定義的 Aspect 插入原本程式的時機點,稱為 JoinPoint。

以上述之範例來解釋,在哪些時機點分別將登入和登出插入原本的程式流程 中,這些時機點就是 Joinpoint。

5. Weave:Advice 被應用至物件之上的過程稱之為縫合(Weave),在 AOP 中縫 合的方式有幾個時間點:編譯時期(Compile time)、類別載入時期(Classload time)、執行時期(Runtime)

6. Pointcut:Pointcut 是一個定義,藉由這個定義您可以指定某個 Aspect 在 哪些 Joinpoint 時被應用至應用程式之上。具體的說,您可以在某個定義檔 中撰寫 Pointcut,當中說明了哪些 Aspect 要應用至應用程式中的哪些 Joinpoint。

總合上述定義後,我們將 Figure 4.1 以及 Figure 4.2 用 AOP 的方法來表示 結果如 Figure 4.3 所示。

(4)

58 Cross cutting concern

Program flow 1 Program flow 2 Program flow 3 Log in

Log out Aspect

Recognize as Log in

Log out

Implement as Advice

JoinPoint JoinPoint JoinPoint

JoinPoint JoinPoint JoinPoint

Pointcut

According to

Weave

Figure 4.3 Program flow using AOP [19]

在本篇文章所述的架構裡,我們廣泛的利用 AOP 來設計架構本身以及測試的 原件實作,其中最為重要的是我們在 Execution-Collector 裡有提到我們定義一 個架構於 AOP 上的通用機制,藉由此機制讓我們的 Test Framework 得以迅速移 植到不同的平台上。以下我們講述此機制為何適宜使用在我們的測試平台。

原本的測試平台實作方法是必須透過 Code injection 的方式插入原本的受 測 WfMS,而經由仔細分析原本需要利用 Code injection 來達成的測試方法,我 們歸納出兩個特徵:

1. 所有的測試原件的使用可能都是因為 WfMS 內某些函式的呼叫前/後而必 須進行。

2. 這些測試原件除了在我們實驗的 WfMS 使用以外,也必須能在其他 WfMS 實作品上使用。

有了這些特徵後,我們從 AOP 的 Cross cutting concern 的定義上獲得一些 靈感,我們發現測試原件混合進系統的時間點應該可以透過將他們辨識為 Aspect

(5)

59

而得到一些裨益,因此我們便逐步開始將原本使用 Code injection 的地點一個 一個獨立出來,最後集中成為我們的通用機制。

通用機制的核心精神在於我們把測試平台的元件以及驗證程序都辨識為 Aspect, 因為這些原件其實都具有 cross cutting concern 的特性,他們隨時 可能發生在不同的程式執行點上,或是不同的 WfMS 上,因此我們將這些辨認出 的 Aspect 加以實作成 Advice,並把我們的驗證程式 Weave 到整個 WfMS。

Table 4.1 是利用 AspectJ[18]來定義我們所需要的 Pointcut,同時也是通 用機制的一種實作,主要描述我們的測試架構原件要在何時參與系統的運作(如 Figure 3.1 圖中紅色小長方塊所示),並在其中進行驗證或是資料收集,不同的 WfMS 系統只需重新定義其中的 Pointcut,就可以快速的將整個測試平台加入到 WfMS 裡。

Table 4.1 Testing framework Pointcut definition using java with Aspect

package tw.edu.ntnu.csie.iclab.Runtime;

import java.util.Map;

import comm.RequestId;

import wfms.core.Process;

public aspect WfMSPointcutDefinition extends

AbstractPointcutDefinition {

public pointcut mainPrograme():

execution( * webapp.StartJettyServer.main(String[]));

public pointcut activityWaitUserResponce():

execution( Map<String, String>

comm.ui.component.Form.submit()) ||

execution( Map<String, String>

comm.ui.component.Page.submit());

(6)

60

public pointcut activityExecutionCodeExecute(RequestId reqId,

Map<String, String> param):

execution(public void

wfms.core.ActivityExecutionCode+.call(RequestId, Map<String, String>)) &&

args(reqId, param);

public pointcut flowInstanced():

execution( Process

wfms.core.ProcessDefinition.createProcess());

}

Table 4.2 則是定義了一個專門用來收集資料的通用介面,主要收集 Testing framework 執行中所需的資訊,不同的 WfMS 僅需重新定義這些 Pointcut 以及略 加修正因平台而異的一些資訊即可。必須注意的是這 Pointcut 中所有定義資料 攔截點的優先權順序必須比 Table 4.1 中所有的 Pointcut 優先權順序高,因為 Table 4.1 內的實作內容必須依靠這些動態資料來獲取驗證之相關資訊,最後再 傳遞給 Figure 3.1 中的各個原件來做驗證以及使用。

Table 4.2 Some runtime information which is needed by Testing framework

package tw.edu.ntnu.csie.iclab.Runtime;

import java.util.Map;

import comm.RequestId;

import comm.ui.component.Page;

public aspect GetInformationFromWfMS extends

AbstractGetInformationFromWfMS { public pointcut flowInstanced():

execution( Process

wfms.core.ProcessDefinition.createProcess());

public pointcut pageCreation(Page page):

(7)

61

initialization(comm.ui.component.Page.new(String)) &&

target(page);

public pointcut activityExecutionCodeExecute(RequestId reqId,

Map<String, String> param):

execution(public void

wfms.core.ActivityExecutionCode+.call(RequestId, Map<String, String>)) &&

args(reqId, param);

}

Table 4.3 是執行測試平台所需要的資訊,主要是在 Table 4.2 中的 Pointcut 中執行初始化以及資料的動態更動。這些動態資料的宣告必定不能在測試架構裡 面各個原件中使用,如 Agent, Execution-Collector 等,原件們必須透過 Table 4.2 以及 Table 4.1 將他們所需要的數值透過參數傳入,降低測試環境對於此份 資訊的耦合性,以便移植到不同 WfMS 時不需要更改其他原件的實作內容。

Table 4.3 Runtime information which needed by testing framework

package tw.edu.ntnu.csie.iclab.Runtime;

import java.util.List;

import java.util.Map;

import java.util.concurrent.ConcurrentSkipListMap;

public class RuntimeContainer { /**

* Key: workflow process, Value: flow name */

public static Map<String, String> workflowProcessIDMap = new ConcurrentSkipListMap<String, String>();

/**

* current applicationID

*/

public static String currentApplicationID;

(8)

62 /**

* Key: workflowProcessID, Value: List<Activity Name>

* using for check current applicationId should change or not */

public static Map<String, List<String>>

applicationIDValidationStackMap = new ConcurrentSkipListMap<String, List<String>>();

public static List<String> availableApplicationIDList;

/**

* Key: flowName, Value: List<Activity Name>

*/

public static Map<String, List<String>> workflowActivityStackMap

= new ConcurrentSkipListMap<String, List<String>>();

/**

* Key: workflowProcessID . Value: key: AvtivityName, value:

*/

public static Map<String, Map<String, Integer>> pageSeqMap = new

ConcurrentSkipListMap<String, Map<String, Integer>>();

}

AOP 的使用對於測試架構的設計有相當大的裨益,首先,他省去絕大部分 code injection 的動作,自動測試環境的運行本來需要對受測之 WfMS 系統做相當程度 的修改,但藉由 AOP 的概念,將測試架構中的各個原件視為一種 Aspect 並妥善 的重寫各個原件,將使得測試架構的可移植性大大增高;另一方面,測試完成後,

要將測試平台從系統上移除也相對容易,系統發展者僅需將我們定義的通用機制 全部註解,如此一來就完成移除測試平台的操作。

4.2 Agent implementation

Agent 是負責與 WfMS 系統溝通的主要管道,根據 Figure 3.1 的描述,他必 須接收來自 TS-WfMS 的資料,並且同時進行輸出資料到 WfMS,以及接受來自於 WfMS 的資料,此外他還必須依照 TS-WfMS 的描述與 Resource Manager 進行互動,

(9)

63

最後實作來自於 Validation tool 的一個 verifiable 介面以供 Validation tool 來執行驗證的動作。綜合以上所述,我們更明確的定義出 Agent 應該有的介面如 Table 4.4 所示,Agent 內部必須有 Resource Manager、TS-WfMS 以及如何與 WfMS 進行溝通的函式。

Table 4.4 Agent interface implement in java

package tw.edu.ntnu.csie.iclab.agent;

import tw.edu.ntnu.csie.iclab.ResourceManager.ResourceManager;

import tw.edu.ntnu.csie.iclab.dao.domain.TestScript;

public interface AgentInterface {

public void setResManager(ResourceManager resManager);

public void setTestScript(TestScript testScript);

public void beforeSubmitToWfMS(String applicationID, String

WfprocessID,

String flowName, String ActivityName, int pageCount);

public void setInformationFromTestScript(Object origMsg, String

appicationID,

String flowName, String activityName, String WfprocessID, int pageCount);

public void afterSubmitToWfMS(String applicationID, String

WfprocessID,

String flowName, String ActivityName, int pageCount);

}

上述的介面並無描述到如何傳送資料到 WfMS 裡,是因為我們採用了 AOP 的 做法,因此將部分經常異動的方式放到 advice 裡面撰寫,而不將他們放到 Agent 內部撰寫,一是集中大部分轉移 WfMS 系統時需要修改的部分到 AOP 特殊的函式 內,二是分離 Agent 中負責傳輸與負責資料處理的子程式,讓這些步驟能夠互相 分離以利往後實作不同 Agent 時能夠有效率。

(10)

64

Table 4.5 是 Agent 在我們利用 AOP 所定義的通用機制裡被呼叫的實作,在 這我們可以清楚的看到來自於 WfMS 內的資料結構類型,不同的 WfMS 在這邊便會 需 要 更 改 他 們 獨 有 的 資 料 存 取 方 式 , 而 傳 送 資 訊 回 去 WfMS 則 是 在

current.onMessage(message);這句敘述裡,我們在此利用內部實作方式,直接 將內部元件從 WfMS 內部取出來,然後讓 Agent 來傳傳送資訊。

Table 4.5 Agent invoke in our general mechanism

before(RequestId reqId, Map<String, String> param):

activityWaitUserResponce()&&

cflowbelow(activityExecutionCodeExecute(reqId, param)){

Agent agent = (Agent) IOCContainers.TestScriptParsingFactory .getBean("agent");

String pid = param.get("pid");

String flowName =

RuntimeContainer.workflowProcessIDMap.get(pid);

String activityName = param.get("aName");

String applicationId = RuntimeContainer.currentApplicationID;

Message message = new Message();

message.put("action", param.get("action"));

// validation output from WfMS

ValidationTool vTool = (ValidationTool) IOCContainers.TestScriptParsingFactory

.getBean("validationTool");

if (thisJoinPoint.getTarget().getClass().equals(Page.class))

{

Page current = (Page) thisJoinPoint.getTarget();

vTool.valid((Validation4Agent)agent, current.getComponents(), flowName, activityName, pid, RuntimeContainer.pageSeqMap.get(pid).get(activityName));

agent.beforeSubmitToWfMS(applicationId, pid, flowName, activityName,

RuntimeContainer.pageSeqMap.get(pid).get(activityName));

} else {

Form current = (Form) thisJoinPoint.getTarget();

(11)

65

vTool.valid((Validation4Agent)agent, current.getComponents(), flowName, activityName, pid, RuntimeContainer.pageSeqMap.get(pid).get(activityName));

agent.beforeSubmitToWfMS(applicationId, pid, flowName, activityName,

RuntimeContainer.pageSeqMap.get(pid).get(activityName));

agent.setInformationFromTestScript(message, applicationId, flowName, activityName, pid,

RuntimeContainer.pageSeqMap.get(pid).get(activityName));

current.onMessage(message);

}

agent.afterSubmitToWfMS(applicationId, pid, flowName, activityName,

RuntimeContainer.pageSeqMap.get(pid).get(activityName));

}

4.3 TS-WfMS Parsing

解析 TS-WfMS 的方式並不是傳統的使用 DOM[27]或是 SAX[28]從頭至尾遞迴 解析,我們將 TS-WfMS 畫分為三部分,分別是 Resource、WorkflowConstraints、

Flows 三大部分,接續再分別使用 XPath[26]去取得個別部分的節點資料後再一 一解析,這樣做的理由是我們想儘量節省不必要的時間去找尋不相關的節點,這 是考量到未來可能需要動態的從 TS-WfMS 中讀取資訊的原故。儘管我們使用 XPath 的方式來取得資訊,但我們仍定義了通用的介面以便往後更換解析方式所需。以 下分別是我們定義的介面以及現行方式的 UML 圖簡介。

Table 4.6 Interpreter interface

package tw.edu.ntnu.csie.iclab.TestScript;

(12)

66 import java.util.Collection;

import java.util.List;

import java.util.Map;

import java.util.Set;

import

tw.edu.ntnu.csie.iclab.TestScript.Unit.ConstraintUnitInterface;

import tw.edu.ntnu.csie.iclab.TestScript.Unit.FlowUnit;

import tw.edu.ntnu.csie.iclab.TestScript.Unit.ResourceUnit;

public interface Interpreter {

/**

* whatever kind of Interpreter, they may need some initialize, put here

* @throws Exception */

public void actionDo() throws Exception;

public Set<String> getApplicationIDSet();

public void resetToDefault();

/*

* perlocating up by resource */

public Map<String, List<ResourceUnit>> getResource();

/*

* perlocating up by flow */

public Map<String, List<FlowUnit>> getFlowUnit();

/*

* perlocating up by WorkflowLimitation */

public Map<String, Collection<ConstraintUnitInterface>>

getConstraints();

}

(13)

67

Figure 4.4 UML Diagram of TS-WfMS parsing component

Figure 4.5 Sequence Diagram of TS-WfMS diagram

Figure 4.4 以及 Figure 4.5 分別是解析 TS-WfMS 的 UML diagram 以及 Sequence diagram,分別描述出軟體架構以及使用這些元件時的方式。這樣設計 的主因是未來可能會將測試流程定義成每執行到一個特定的階段就重新拿取最 新的 TS-WfMS,而這個特定階段可能只需要 TS-WfMS 中的某一個特定部分,因此 我們不單純使用 DOM 或是 SAX 去整個做搜尋檢驗,利用 XPath 配合來做解析主要 是想要儘速略過那些暫時不需要的資訊,也為未來新的設計留下更多可修正的空 間。

(14)

68

4.4 Database Access Object

DAO[20]是一種 Design Pattern,目的是為了降低持久儲存媒體層與實際程 式碼間的耦合,建立出程式碼的撰寫與實際儲存媒體完全不互相干擾的架構,因 此他必須將所有對資料來源的存取加以抽象化以及封裝,且必須管理所有對資料 來源的儲存與擷取的連線。

DAO 實作了所有對於目標資料來源端的存取方式,對於使用該 DAO 的客戶端 來說,他隱藏了所有關於資料來源媒介的實作細節,因此 DAO 必須提供函式介面 給客戶端使用。因為這個介面不會因底層資料來源端的改變而改變,所以整個 DAO pattern 運作起來後像是一個中介橋接的原件,橋接了客戶端和資料來源端。以 下分別使用 UML 圖型以及 sequence diagram 來解釋 DAO 的行為。

Figure 4.6 Data Access Object[20]

(15)

69

Figure 4.7 Data Access Object sequence diagram [20]

Figure 4.6 使用 UML 描述這些物件間的關係,Figure 4.7 則是使用 sequence diagram 表示 BusinessObject 中操作 DAO 的方式,詳細各部位的名詞解釋如 下:

1. BusinessObject: 表示客戶端的實作程式碼,在此呼叫 DataAccessObject 所提供的 method。

2. DataAccessObject: 此即 DAO pattern 最重要的部分,此物件必須對持 久層儲存媒介進行封裝以及抽象化,讓 BusinessObject 可以單純對他們 所注重的 TransferObject 操作,操作完畢後再使用 DataAccessObject 所 提 供 的 method , 將 改 動 過 後 的 TransferObject 當 作 參 數 傳 給 DataAccessObject,最後 DataAccessObject 將會針對客戶端指定的資料

(16)

70

修改在持久儲存層內的相關資訊。其中 DataAccessObject 所必須提供的 基本 method 為 CRUD(Create, Read, Update, Delete)。

3. DataSource:資料來源端,可能是資料庫,也可能是 XML,或是 LDAP 等。

4. TransferObject:此即是 Domain Object,客戶端操作的抽象化資料,

DataAccessObject 藉 由 回 傳 TransferObject 給 客 戶 端 , 而 DataAccessObject 則是接收客戶端傳來的 TransferObject 來對持久層儲 存媒介進行操作。

每個客戶端可能都有各自不同的 DAO 來處理他們獨特的 TransferObject,當 客戶端程式越來越繁雜,DAO 的數量也相對的成長,為了管理 DAO 我們會使用 Factory Pattern[21] 來管理這些 DAO,如 Figure 4.8 所示,即使持久層資料來 源是不同的,他們又各自衍生不同的 DAO,但是最終皆由一個不能實體化的 DAOFactory class 來統一管理。衍生的 DAO 則是根據 TransferObject 來設計,

如此圖最下面的 DAO1、DAO2 介面。舉例來解釋之,我們可以想像 DAO1 是儲存個 人的相關資訊之 TransferObject,而 DAO2 介面則是儲存公司相關資訊,他們可 以同時/分別儲存至 Relational database、xml、Object database,因此他們皆 實作相同的 DAO1、DAO2 介面。

(17)

71

Figure 4.8 Factory for Data Access Object strategy using Abstract Factory[20]

DAO 讓客戶端程式的實作與持久層資料來源分離,而 Abstract Factory Pattern 則是提供管理數量繁雜的 DAO,使得客戶端程式能夠使用有系統的組織 規畫過後的 DAO。DAO 與 Abstract Factory 兩個 pattern 乍看似乎是相當好的搭 配,但卻會為了介面的實作品不同而導致日後更換實作品時的不便利,後面的章 節將會介紹 IOC[16],到時將會一併介紹使用 IOC 搭配 DAO pattern 與單純使用 Abstract Factory pattern 搭配 DAO pattern 的不同,並介紹他們的優劣。接 下來我們介紹本篇論文如何利用 DAO 來儲存測試資訊。

在本篇論文的實作中,我們實作了GenericDAO[25] 的介面(Table 4.7),以此 作為基本介面進而擴展到我們所使用的DAO class(Appendix A),最後再搭配使用 IOC。程式內部只需要專注於操作不同的 TransferObject(如 Table 4.8),若需要更

(18)

72

新他們在資料庫裡的狀態時,就從 IOC Container 中呼叫相對應的 DAO 出來操 作。

Table 4.7 GenericDAO interface[25]

Package tw.edu.ntnu.csie.iclab.dao;

/**

* The basic GenericDao interface with CRUD methods Finders are added with

* interface inheritance and AOP introductions for concrete implementations

*

* Extended interfaces may declare methods starting with find... list...

* iterate... or scroll... They will execute a preconfigured query that is

* looked up based on the rest of the method name

*/

public interface GenericDao<T, PK> {

/** Persist the newInstance object into database */

public PK create(T persistentObject_newInstance);

/**

* Retrieve an object that was previously persisted to the database using

* the indicated id as primary key */

public T read(PK id);

/** Save changes made to a persistent object */

public void update(T transientObject);

/** Remove an object from persistent storage in the database */

public void deleteDomainObject(T persistentObject);

}

Table 4.8 ProcessHistory TransferObject

package tw.edu.ntnu.csie.iclab.dao.domain;

(19)

73 import java.util.LinkedHashMap;

import java.util.Map;

import java.util.Set;

import tw.edu.ntnu.csie.iclab.eventHistory.WorkflowPorcessHistory;

/**

* Reachability Testing’s Event-History * @author KueiHuan-Chen

*/

public class ProcessHistory implements WorkflowPorcessHistory { private String uniq_identity_name;

private String flowName;

private Map<String, ActivityHistory> ActivityeventUnitMap = new LinkedHashMap<String, ActivityHistory>();

public ProcessHistory(String thread_name, String flowName) { this.uniq_identity_name = thread_name;

this.flowName = flowName;

}

public String getProcessUniqIdentity() { return uniq_identity_name;

}

@Override

public String toString() {

return "ThreadEventHistory " + " ( " + " flow: " + flowName

+ " activity : " + ActivityeventUnitMap + ")";

}

public String getFlowName() { return this.flowName;

}

public Set<String> getActivityNameSet() { return ActivityeventUnitMap.keySet();

}

(20)

74

public void addActivityEventNode(String activityName, EventUnit

unit) {

if( !ActivityeventUnitMap.containsKey(activityName) ){

ActivityHistory acth = new ActivityHistory(activityName);

ActivityeventUnitMap.put(activityName, acth);

}

ActivityHistory acth =

ActivityeventUnitMap.get(activityName);

acth.addEventNode(unit);

ActivityeventUnitMap.put(activityName, acth);

}

public ActivityHistory getActivityHistory(String activityName){

return this.ActivityeventUnitMap.get(activityName);

}

/**

* @return the uniq_identity_name */

public String getUniq_identity_name() { return uniq_identity_name;

}

/**

* @param uniq_identity_name the uniq_identity_name to set */

public void setUniq_identity_name(String uniq_identity_name) { this.uniq_identity_name = uniq_identity_name;

} }

4.5 IOC

IoC 為 Inversion of Control 的縮寫,與它相同意義的另一個名稱為 Dependency Injection[16]。DI 是一個工具,用來幫助你建立鬆綁的程式。其主 要精神在於為系統中的每個 component 提供介面,在程式中都使用介面呼叫,不 直接產生 component,要使用 component 時,利用 IoC container 取得 component

(21)

75

實體來使用。component 的 life cycle 均由 IoC container 控管,藉此降低系統 與 component 的耦合性。

Dependency Injection 有三種主要類別,分述如下:

1. Type 1 IOC(interface Injection):原件若使用此類型的 IOC,則該原 件需要實作由 Container 所提供的特定介面以便讓管理自己的 Container 來做設定。

2. Type 2 IOC(setter Injection):使用 Setter Injection 的 IOC 需要一 些額外的資訊來描述原件間的相依關係。相依關係可能是初始化一個物 件時必須先初始化另一個物件,或是一個物件的產生必須內含多種其他 物件,這些相依關係資訊最後必須經由設定來告知管理器。在 Spring framework[22]裡是採用 XML 設定檔來處理這些額外資訊。對於被管理的 原件,主要的特徵是這些原件內會有一些 Setter 和 Getter method,IOC Container 利用這些 method 以及設定描述檔來將與該原件有相依關係的 原件注入。

3. Type 3 IOC(constructor Injection):Type 3 IOC 與 Type 2 IOC 最大 的不同在於它將相依的原件利用建構子注入,而不是另外撰寫 Getter 和 Setter method 來設定,他們都需要額外的設定檔來描述與他們相依原件 的設定。

我們主要將 IOC 的概念用於 TS-WfMS 的解析元件、Agent、Validation tool、

Resource Manager、Execution-Collector、DAO 等的原件管理。目前在 java 上 有很多 IOC 的實作品,諸如 Spring framework[22], PicoContainer[23]等,本 篇文章中我們是採用 Spring framework 來設計我們的 Testing framework。

Table 4.9、Table 4.10 是我們的系統中 DAO 以及 TS-WfMS Parsing, Agent, Validation Tool, Resource Manager 相關元件的管理設定檔,我們主要都是採 用 Type 2 IOC 來做 Dependency Injection,以下分別介紹他們的架構原理。

(22)

76

Table 4.9 DAO implement using Spring framework (only xml configuration data)

<?xml version=”1.0” encoding=”UTF-8”?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<aop:spring-configured/>

<aop:aspectj-autoproxy/>

<!-- below is DAO Setting -->

<bean id="fileContainer"

class="org.db4ospring.ObjectContainerFactoryBean">

<property name="databaseFile" value="ReachabilityDB.yap"/>

</bean>

<bean id="db4oTemplate" class="org.db4ospring.Db4oTemplate">

<property name="objectContainer" ref="fileContainer"/>

</bean>

<bean id="db4oTransactionManager"

class="org.db4ospring.Db4oTransactionManager">

<property name="objectContainer" ref="fileContainer"/>

</bean>

<bean id="dao"

class="tw.edu.ntnu.csie.iclab.dao.GenericDaoDb4oImpl">

<property name="template" ref="db4oTemplate"/>

<property name="obC" ref="fileContainer"/>

</bean>

</beans>

(23)

77

Table 4.10 TS-WfMS Parsing、Agent、Resource Manager、Validation Tool (only xml configuration data)

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"

"http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>

<!-- TestScritp Parsing beans -->

<bean id="resourceParsing"

class="tw.edu.ntnu.csie.iclab.TestScript.ResourceParsing">

<property name="currentFileName" value="feed.xml"/>

<property name="xpathExpr"

value="//testScript//applications//application//resourses"/>

<property name="parsingApplicationList">

<list>

<value>1</value>

</list>

</property>

</bean>

<bean id="flowsParsing"

class="tw.edu.ntnu.csie.iclab.TestScript.FlowsParsing">

<property name="currentFileName" value="feed.xml" />

<property name="xpathExpr" value="//testScript//applications//

application//flows"/>

<property name="parsingApplication List">

<list>

<value>1</value>

</list>

</property>

</bean>

<bean id="WorkflowConstraintParsing"

class="tw.edu.ntnu.csie.iclab.TestScript.WorkflowConstraintParsing">

<property name="currentFileName" value="feed.xml" />

<property name="xpathExpr" value="//testScript//

applications//application//WorkflowConstraint" />

<property name="parsingApplicationList">

(24)

78

<list>

<value>1</value>

</list>

</property>

</bean>

<bean id="testScriptHandler"

class="tw.edu.ntnu.csie.iclab.TestScript.InterpreterHandler">

<property name="scriptContainer">

<list>

<ref bean="resourceParsing" />

<ref bean="WorkflowConstraintParsing" />

<ref bean="flowsParsing" />

</list>

</property>

</bean>

<!-- TestScript Domain Object -->

<bean id="testScript"

class="tw.edu.ntnu.csie.iclab.dao.domain.TestScript">

<property name="testScriptHandler" ref="testScriptHandler" />

</bean>

<!-- Validation tools -->

<bean id="validationTool"

class="tw.edu.ntnu.csie.iclab.validation.ValidationTool">

<property name="testScript" ref="testScript"/>

</bean>

<!-- Resource Manager -->

<bean id="resourceManager"

class="tw.edu.ntnu.csie.iclab.ResourceManager.ResourceManager">

<property name="testScript" ref="testScript"/>

</bean>

<!-- Agent -->

<bean id="agent" class="tw.edu.ntnu.csie.iclab.agent.Agent">

<property name="testScript" ref="testScript"/>

<property name="resManager" ref="resourceManager"/>

(25)

79

</bean>

</beans>

Figure 3.1 裡有描述到需要 TS-WfMS 的元件有 Agent, Resource Manager、

Validation tool,因此我們把管理這三個元件的 IOC 設定檔跟解析 TS-WfMS 的 元件寫在一起,讓他們可以透過 IOC 設定檔來設定相依關係(Table 4.10),如此 一來,不僅免去設定元件的相依關係,在實際使用上,我們僅須隨時向 IOC Container 索取這些元件的物件參照,他們便會自動幫我們完成相依關係的注入,

即使以後要更換 Agent 或是 Resource Manager 等的元件,我們也不需要更動到 其他地方的程式碼,僅需重新依照介面撰寫即可,大大的減少了程式元件間的耦 合性。

前述章節中,我們提到 DAO Pattern 可以搭配 IOC 來設計使得他們將更具組 織性,我們可由 Table 4.9 來探討使用 IOC 搭配實作 DAO Pattern 如何強化整體 組織性。首先,在本篇文章的實作過程中,我們採用 db4o[24]這套 Native Object Database,而按照 DAO Pattern 的特徵,我們必須將他的 DataSource,以及 DataAccessObject 分別獨立成為一個物件,最後我們還需要一個 Abstract Factory Pattern 將這些存取方法包裝。我們可以將 IOC Container 想像成為是 一個 Factory class,他代替了必須撰寫額外的 Factory class 的功用,同時由 於有 Table 4.9 的設定檔案,內部的原件,如 DataSource、DataAccessObject 等,都可以任意更換實作內容而不影響商業程式邏輯本體,但若是自己撰寫一個 Factory class 來管理所有不同的 DAO 時,一旦任何 DataAccessObject 實作要更 換底層原件或是名稱,亦或是新增 DataAccessObject,則該 Factory class 可能 必須隨著更動,相較之下,使用 IOC 來實作我們的 DAO Pattern,當底層原件有 變動時,我們僅需更改設定檔,使得整個系統架構更富有彈性。

妥善的利用 IOC 來管理測試元件可有效降低系統內部元件間的耦合,IOC 的 特點是讓這些元件間的呼叫延遲到 Runtime 決定,而不是在 Compiler time 決定,

因此對於整個系統來說可以有效的達到降低元件耦合度的功用,另一方面,他又

(26)

80

可以當作是一個 Factory class 來使用,省去以往我們為了拿取某些元件的物件 參照而必須額外撰寫一些具有 static method 的 Factory class,綜合以上觀點,

IOC 的確適合於測試架構的設計以及使用。

4.6 Reachability Testing

Reachability Testing[15] 應用在一般的並行執行程式上是一個很棒的測 試方法,因為它可以精確的將共用資源的存取順序加以列舉且重複測試直到列舉 完畢,但是在 WfMS 裡,我們發現原本的運作方式必須要經過某程度的修正才能 運行,其主要原因如下:

1. 在 WfMS 系統中,一個 workflow process 可能是由一個或是多個執行緒 所完成。

2. 即便是在相同的 workflow process 內,也有可能發生相同的資源並行競 爭。

Executed by Flow Instance

Cache Thread Pool

A1 A5

A2

A4 A3

Activity

And-Join And-Split

Figure 4.9 WfMS 的運作模式(thread pool)

我們使用 Figure 4.9 來解釋上述兩個原因,該圖大意如下,有一個實體化 的 flow instance,他有五個 Activity,其中 A1 到 A2,A3 是屬於 And-Split,而

(27)

81

A2,A3 到 A4 是屬於 And-Join,表示從 A1 執行完後必須同時執行 A2 以及 A3 兩個 Activity,而 A2 和 A3 兩個 Activity 皆執行完畢後才能進入 A4。而這些 Activity 的運作,統一由一個 Cached Thread Pool 來分配執行序執行。

因為 And-Split 的效用與 Cached Thread Pool 的運作,所以在這個範例中,

除了 A2, A3 不可能是相同的執行序所執行外,其他 Activity 的所屬執行序可能 都會重疊,這是上述的第一點;且因 A2 和 A3 是屬於 And-Split,因此他們可能 會競爭相同的資源,但他們卻是屬於相同一個 workflow process,此為第二點。

有了這些明確的不同後,我們發現這是一個極有趣的方向,這代表著原本的 Reachability Testing 在他的 RV-Generator 演算法裡需要進行一些修正,讓他 製造出來的 SYN-sequence 能夠自動辨識這樣的序列是否有符合 WfMS 內 Activity 的執行先後順序,在此我們先將這部分保留到未來的發展。目前我們先重新設計 Event History 的儲存方式使之符合 WfMS 的結構,如 Figure 4.10 所示,每個 Activity 可能都會有存取共用的 share resource,這些存取過程經過我們的 EntryProtocol 可以精確的將它們的存取順序記錄下來,成為 Process event history list , 這 個 Process event history list 及 代 表 傳 統 程 式 上 使 用 Reachability Testing 的 Process Event History,可是為了能夠滿足我們前述 的測試方法,Process event history 並不是混合了所有 Activity 的存取順序,

他只是一個抽象的 List, 事實上的儲存方法如 Figure 4.11 所示,我們的 Process event history 忠實的將每個 Activity 存取的順序記錄下來,他們的真正執行順 序則是必須遵循 flow definition 來運作。

(28)

82 Flow Instance

Process event history list

Activity Access Event

A1 A5

A2

A4 A3

Access Resource

And-Join And-Split

Figure 4.10 WfMS Event History Record

Workflow process id workflow name

Workflow process history

Activity Name1

Activity Name2

Activity Name3

Event 1 Event 1 Event 1

Event 2 Event 2 Event 2

Event End Event End Event End Event End (Activity) – (Event List) Map

order

Figure 4.11 WfMS Event history structure

數據

Figure 4.2 program flow with cross cutting concern [19]
Figure 4.3 Program flow using AOP [19]
Table 4.1 是利用 AspectJ[18]來定義我們所需要的 Pointcut,同時也是通 用機制的一種實作,主要描述我們的測試架構原件要在何時參與系統的運作(如 Figure 3.1 圖中紅色小長方塊所示),並在其中進行驗證或是資料收集,不同的 WfMS 系統只需重新定義其中的 Pointcut,就可以快速的將整個測試平台加入到 WfMS 裡。
Table 4.2 Some runtime information which is needed by Testing framework
+7

參考文獻

相關文件

那個老闆娘,從來沒有請過像我這麼高薪的人,而且他的理念跟我們不一

他們會回到中間,這是打羽毛 球很重要的一環。目標是為了 準備下一球。試想想如果你在

反之, 有了 parametric equation, 我們可利用這些在 R n 的 direction vectors, 利 用解聯立方程組的方法求出和這些 direction vectors 垂直的 normal vectors,

在這一節中, 我們介紹 change of basis 的概念, 了解到一個 linear operator 換了 ordered basis

從實際的教學實踐中,我發覺「主題說話活動」的確能讓學

最佳解裡面如果沒有greedy choice的話, 則想辦法 把最佳解裡面的一些東西和greedy choice互換. 結 果發現這個新解跟greedy choice一樣好

• 也就是 ”我的dp是n^3”這句話本身不夠表示你的dp演算法,必須 要說“我的dp是個狀態n^2,轉移n”才夠精確. •

 不過以上所提的內容幾乎都會被現在的智慧型手機取 代,因此我們覺得這些功能能夠運用在一個沒有網路