OCL的樂趣和威力 Part 1

會讓我寫這篇Blog的原因實在是因為OCL太好玩了,而且OCL的威力也逐漸讓我有愈來愈深的體認,OCL現在已經成為我個人認為最重要的語言之一,我應該稱OCL是『程式語言』?還是『正規語言』?還是『模型轉換語言』?這我也不知道,這是因為OCL雖然是OMG的標準『正規語言』,大多數的人對於OCL的觀念還停留在OCL是使用於UML模型中定義條件,限制,或是使用於MDA之中。這兩者的應用都希望藉由OCL能夠更精確的定義模型的意義,以及藉由OCL撰寫和特定平臺,語言,技術無關的企業邏輯,以便在實作或是應用MDA的模型轉換過程中能夠順利產生有意義的結果模式,例如從PIM轉換到PSM,從PSM轉換到特定的程式語言,例如JavaC#或是Delphi等。

 

不過OCL在一些軟體廠商,例如Borland,不斷的改善之下,在原本只是唯讀的OCL加入延伸的功能,以便讓OCL具備修改和寫入的能力。為什麼要這樣做? 請想一想,如果要在各種模型使用OCL做為和模型,平臺,技術無關的中立語言,那麼OCL只有唯讀能力是不足的,例如在敘述圖中使用OCL做為定義狀態改變的標準語言,那麼當狀態改變時如何能夠使用唯讀的OCL來改變狀態? 那要改變使用特定的程式語言來敘述嗎?如果是這樣的話,為什麼還要使用OCL? 再想想,於模型轉換時,我們需要有來源模型以及轉換後的結果模型。結果模型是根據轉換規則而產生的,因此如果我們決定使用OCL來定義,對映模型轉換的規則,那麼OCL必須具備建立結果模型的能力,否則我們要使用什麼語言來敘述結果模型?

 

因此BorlandECO便根據OCL加以延伸形成Action Language,其中最重要的就是允許開發人員使用OCL進行修改,寫入或是建立物件的功能。

x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBdEcWt85rBor7d_fdffz_68Vhdz0TAGLCwv0k2obTIk66cU0B8maWU32MRTstHKDVg0YwhOx0-9iT0HSUjwjZtAP3CHlGlZXU8ToibDN_RAhg

例如OCL藉由加入:=運算元而擁有了指定功能之後,在狀態圖中我們纔能夠改變應用程式執行時的狀態:

self.FirstName := home.owners->first.FirstName

 

至於Together 2006就對OCL加入了更多的能力了,因為Together 2006選擇了使用OCL語言來定義模式和模式之間轉換的規則。嚴格的說,應該是指Together 2006藉由強化OCL語法讓開發人員能夠定義MetaModelMetaModel之間對映的關係,如此一來Together 2006就能夠藉由OCLMetaModel來轉換不同的模型了。 這可以由我在上海/成都時展示的範例來說明。

 

200512月時,我在上海/成都展示瞭如何把一個由BPMN敘述的企業流程轉換為UMLUseCaseBPMN模型通常是由商業人士使用來敘述企業領域的商業流程,當領域專家(Domain Expert)使用BPMN敘述了特定的企業流程之後,必須交由IT人員來開發系統。但是對於IT人員來說,BPMN模型可能很陌生,而且大多數的IT開發工具都只接受UML模型而不是更抽象的BPMN模型。因此我們需要把領域專家實作的商業模型轉換為IT人員熟悉的UML模型。

 

當時我使用的BPMN模型如下所示:

 x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBemnQJgiKI1iGs4_v6lS3kVejFGiTeS6iD-ksaTGqdlCsKwGrEMEswqDFt4AQNmdMX_KPVjGiVyWer6EkmDi_8FRJ4tP8-qXaQbu7PTL3XYkw

我希望把這個BPMN的模型轉換為UMLUseCase,如下所示:

x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBdNk_aVwsmKmgLR5Z6xBpoCAl93KOwQu9mk8kmKxuj9MVn8H9l2vf_PMB8FSTU1yyk24yQs0B31JgaT41XWtm-o09yqChoy-UoE5N-dzH-RLg

 

這要如何做到? 其實這正是MetaModelMetaModel之間轉換的範例,要轉換這兩個特定的模型非常的簡單,我們只需要定義BPMNMetaModel之間的每一個元素如何對映到UMLMetaModel的每一個元素,那麼一旦這個對映規則定義好了之後,任何的BPMN就可以轉換為UML之間的模型了,下圖就說明瞭這個觀念。

 x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBc2xIPJMJcBHyetUIRVouwgeNskiY0m-Yz_Za8sSuuj75Tw0IYFK0g3L7yQU2SJmmDttkwAsXH5O6e5ObVVTvscuCaiY9DveY2ZFyzRltvD6Q

 

001    transformation Bpmn_To_Uml;

002   

003    metamodel 'http://www.borland.com/together/2005/bpmn';

004    metamodel 'http://www.borland.com/together/uml';

005    metamodel 'http://www.borland.com/together/uml20';

006   

007    mapping main(in model: bpmn::BpmnProcessPool): uml::together::Model {

008        init {

009            var actors := model.lanes->select(lane | lane.oclIsKindOf(bpmn::BpmnLane))->oclAsType(Sequence(bpmn::BpmnLane));

010            var tasks := model.lanes.flowObjects->select(lane | lane.oclIsKindOf(bpmn::BpmnTask))->oclAsType(Sequence(bpmn::BpmnTask));

011        }

012        object {

013            ownedMembers := actors->collect(a | makeActor(a))->asOrderedSet();

014            ownedMembers += tasks->collect(t | makeUseCase(t))->asOrderedSet();

015        }

016    }

017   

018   

019    mapping makeActor(in lane: bpmn::BpmnLane): uml20::usecases::Actor {

020        object {

021            name := lane.name;

022            description := lane.documentation;

023           

024        }

025    }

026   

027    mapping makeUseCase(in task: bpmn::BpmnTask): uml20::usecases::UseCase {

028        object {

029            name := task.name;

030            description := task.documentation;

031        }

032    }

 

007行的mapping main定義了一個QVT轉換的主進入點,這是一個什麼樣的轉換呢?main signature就可以瞭解,它接受一個BPMN的流程模型,

(in model: bpmn::BpmnProcessPool)

轉換並且回傳一個Together的模型

uml::together::Model

 

接著我們定義了下面兩個對映MetaModelMetaModel之間元素的規則:

n          每一個BPMN MetaModel之中的Lane元素都對映到UMLUseCase圖形中的Actor元素

n          每一個BPMN MetaModel之中的Task元素都對映到UMLUseCase圖形中的UseCase元素

 

有了這兩個規則之後,一切就簡單了。首先我們從來源BPMN模型中找到所有Lane元素以及Task元素,接著把Lane元素轉換Actor元素,把Task元素轉換為UseCase元素,工作就完成了。讓就讓我們解釋一下前面的OCL如何完成它的工作。

一個轉換主進入點可以分為兩個部份,第一個部份稱為init區塊,它的目的主要是宣告變數或是查詢轉換過程需要使用的模型元素。因此在009行中宣告了一個actors變數,它的數值就是來源BPMN模型中所有的Lane元素。為什麼,讓我們看看它使用的OCL代表的意義。009行使用瞭如下的OCL程式碼:

model.lanes->select(lane | lane.oclIsKindOf(bpmn::BpmnLane))->oclAsType(Sequence(bpmn::BpmnLane)

 

讓我們猜拆解它的語法和009行意如下:

程式碼段

意義

model.lanes

取得來源BPMN模型中所有的Lane物件

->select

由於model.lanescollection 物件,因此使用->代表符號的左邊是collection 物件。Select 類似SQLSelect語法

(lane | lane.oclIsKindOf(bpmn::BpmnLane))

宣告一個暫時變數lane,這個lane如果是bpmn中的BpmnLane物件,也就是我們需要的Lane物件,它的代表符號是bpmn::BpmnLane。那麼就符合select條件而進入結果物件資料集中(object resultset)

->oclAsType(Sequence(bpmn::BpmnLane)

 

由於->select(lane | lane.oclIsKindOf(bpmn::BpmnLane)) collection 物件,因此使用->代表符號的左邊是collection 物件。

oclAsTypeOCL的函式,這個函式把(bpmn::BpmnLane轉換為OCLSequence資料型態

 

瞭解了009行的意義之後,您應該可以瞭解010行的意義。

 

在主進入點的init區塊之後就是主進入點的主要部份了,也就是主進入點回傳的結果物件。這第二個區塊是由object {}包圍的。在object {}區塊中,object就代表回傳的uml::together::Model模型,那麼回傳的模型中包含什麼東西呢?這就是由在object {}區塊中的OCL程式碼來決定的,也就是013014行的執行結果。看看013行在做什麼?

013            ownedMembers := actors->collect(a | makeActor(a))->asOrderedSet();

 

程式碼段

意義

ownedMembers

結果模型之中的特性值,代表結果模型中擁有的元素

:=

指定符號,把:=符號右邊的執行結果指定給:=符號左邊的特性值

actors->

009行宣告的變數,它是collection 物件,因此使用->代表符號的左邊是collection 物件

collect(a | makeActor(a))

 

collectOCL的函式,它把()中的執行結果形成一個collection 物件。而a是暫時變數,這個變數呼叫makeActor對映函式

->asOrderedSet();

把這行程式碼的執行結果轉換為一個有次序的結果collection 物件。

 

019行的makeActor是一個對映函式,它接受一個bpmn::BpmnLaneLane物件並且回傳一個UML 20UseCase模型中的  Actor物件。

 

這整個轉換流程可以使用下面的圖形來說明:

 x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBc5F9SrsXFHiA_H9j9oSZq8od3gdWZXUglH9TXdXnHu0FmoKFwfzDAWi8f1PgpylWyzsdtk9i5XbA-bj03qrCbuDdde-xEpxj9VzT6KiHdDHg

由這個範例可以看到OCL語言強大的力量,Together 2006提供的OCL支援包含了執行OCL轉換能力,除錯OCL轉換程式,更提供了MetaModel類似Code Insight的功能,可以幫助開發人員在撰寫OCL轉換程式時對於模型和語法的幫助。例如下圖就是在Together 2006OCL編輯器中打入model.之後,Code Insight視窗便可以出現指引開發人員在之後能夠撰寫的程式碼。

 x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBc5G9QWCXnLphd7ls3rm-Tb4INru9FsYZkVAqVPt7sUXqKm61oEi2eYMX-oFtOGtE8lUa-nek3lGkaPgUsx3A32Kf8ZJniZeC0Rrg8u1KFblA

除了BPMN模型之外,Together 2006也提供了其他廣泛模型轉換的能力,例如我們也可以對EclispeEMF模型進行各種不同的轉換,再結合EMF產生Java程式碼的能力最終把PIM轉換為JavaPSM

 x1pFUxp6NG29bXY4hHUvhWU938vgNEsQW76lC8_5YICKBda2EUEvutMHgsNgTETie1zhc2TCP3jRvthcF8L3gXQJTK8wa9CqwsWbPZzM8GpaWPkGXS6NgS1y86DGAYzKu8wI8KzMb0uP8KdRfF1xb433Q


x1phiCZJPhsUYg-Rf0H_plhOdt-APWUfu3CSGTnBbEv4pwpNZa2x7IfMpOc2ikrRoQPOyRLoG4E8H8mOXvs7IgegZxrx7auzsUQ76ZDqGG6zV4x1phiCZJPhsUYg-Rf0H_plhOc4eM0crqUhZ7uNjI_RjYLk8imP4ETz41-2JI-bYbDaIg1IJjFmf9qEQ8O2vodrHotLAmKsnWQj8bp0kTQZ2YCY
x1phiCZJPhsUYg-Rf0H_plhORHfbvm1n8U-0ac3kHUwoTS2kEG25zSyaAgRhgwqnX6B9SD7Fr42Wwy6K1Pd-lihKJ0wRv22vhl78p3IkJQlcKUx1phiCZJPhsUYg-Rf0H_plhOQqyV-_97EJ56MixNyMXJWmcvib_XY7_s53KOpWWrrRTyYPdDotlXeF1aa4QGC7jLOg6npr_u1w3MavajQwW_gk
x1phiCZJPhsUYg-Rf0H_plhORiacwrHuYDXh2_YmoSpMzOmmKG-WjoDELZGanlltj_9tn0sm4KEGtunGEuAMSTfu6u55O6wm1ngnZkyk7Rtvy0x1phiCZJPhsUYg-Rf0H_plhOQozoVmKMXr9GBvt-CUeSo6Ro2zMFZ1amqmlKTUvG_aivbAfdD13SV6famuy8Iq1pT9TR0T4UcqRW5MlVRC1HpI
x1phiCZJPhsUYg-Rf0H_plhOXpgoPvXuGmqcBrUdJS1ejySbbFNDTDlYs5kLhqKbCilG-mRDhVU68rrHFq4nTTXTTp8cNmRzUNR9OQh0TP6fskx1phiCZJPhsUYg-Rf0H_plhOcduZ-4ZRT3oIpe0kOburZT73gVg1JHvWPl_GR2VPz9k0Vupnu9417V2xdOq7qnZELxbWx3lfPBqls_VXJpJyIE
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章