隨筆-62  評(píng)論-29  文章-0  trackbacks-0

          用 Eclipse Modeling Framework 實(shí)現(xiàn)模型驅(qū)動(dòng)開發(fā),第 1 部分

          創(chuàng)建 UML 模型并生成代碼

          developerWorks
          文檔選項(xiàng)
          將打印機(jī)的版面設(shè)置成橫向打印模式

          打印本頁

          將此頁作為電子郵件發(fā)送

          將此頁作為電子郵件發(fā)送

          未顯示需要 JavaScript 的文檔選項(xiàng)


          級(jí)別: 初級(jí)

          Adrian Powell, Advisory I/T Specialist, IBM

          2004 年 4 月 01 日

          Eclipse Modeling Framework(EMF)是一個(gè)開放源代碼的模型驅(qū)動(dòng)應(yīng)用程序開發(fā)框架。它可以基于 XML Schema、UML 或經(jīng)過注釋的 Java 中指定的模型,創(chuàng)建 Java 代碼,實(shí)現(xiàn)圖形化的數(shù)據(jù)編輯、操縱、讀取和序列化。EMF 是 IBM WebSphere Studio 和 Eclipse 項(xiàng)目中很多工具的基礎(chǔ)。本文將幫助您逐步了解創(chuàng)建模型、生成代碼、使用生成的應(yīng)用程序和定制編輯器的整個(gè)過程。

          EMF 究竟是什么?


          Eclipse Modeling Framework(EMF)是一個(gè)開放源代碼的框架,它的目標(biāo)是實(shí)現(xiàn)模型驅(qū)動(dòng)架構(gòu)(Model-Driven Architecture)的開發(fā)。如果我們當(dāng)中的少數(shù)人有幸得到了某個(gè) UML 模型,那么這個(gè)框架就可以幫助我們將文檔變成代碼。至于其他人,這個(gè)工具也使您又有一次機(jī)會(huì)向老板證實(shí),把時(shí)間花在為解決方案建模上是值得的。除了可以生成令人贊嘆的 Java 代碼之外,EMF 還可以生成 Eclipse 插件,以及圖形化的可定制編輯器。當(dāng)您改變模型時(shí)(這種情況真的會(huì)出現(xiàn)),EMF 可以通過單擊一個(gè)按鈕,就使代碼和模型保持同步。

          EMF 生成的代碼也不是一種只配丟進(jìn)垃圾箱的解決方案。這種代碼支持標(biāo)準(zhǔn)的創(chuàng)建、獲取、更新和刪除操作,而且還支持元數(shù)約束、復(fù)雜關(guān)系和繼承結(jié)構(gòu)、屏蔽定義,以及一套屬性描述。生成的代碼還提供通知、參照完整性和可定制的 XMI 持久性。您所需要做的全部工作就是創(chuàng)建一個(gè)對(duì)象模型,就像您以前也想做的那樣。

          EMF 是比較新的事物,但前景廣闊,對(duì)它持續(xù)支持的力度也很強(qiáng)。它實(shí)現(xiàn)的是一項(xiàng)公共標(biāo)準(zhǔn),即對(duì)象管理組織(Object Management Group)的元對(duì)象工具(Meta-Object Facility,MOF)。現(xiàn)在 EMF 已經(jīng)對(duì) MOF 的第二版進(jìn)行了增強(qiáng)。更進(jìn)一步看,EMF 還是 EMF:XSD 以及 Hyades 等 Eclipse 項(xiàng)目的基礎(chǔ),大多數(shù) IBM WebSphere Studio 產(chǎn)品也都使用它。EMF 第二版的開發(fā)已經(jīng)開始,開發(fā)構(gòu)建應(yīng)該很快就會(huì)出爐。第二版開發(fā)計(jì)劃中包括更好的 XML Schema 支持、更靈活的代碼生成方式以及模型之間的映射機(jī)制。





          回頁首


          讓工具自己說話


          商業(yè)宣傳已經(jīng)說得夠多了。現(xiàn)在讓我們直接進(jìn)入代碼中,看看 EMF 到底能做些什么。下面的例子都是用 Eclipse 3.0M7 和 EMF 2.0.0,再加上與之匹配的 XSD 工具箱實(shí)現(xiàn)的。現(xiàn)在有四種獨(dú)立的 EMF 開發(fā)流程,每一種都適用于不同版本的 Eclipse,所以一定要保證根據(jù)您的 Eclipse 版本選擇了正確的 EMF 版本(請(qǐng)參閱 參考資料中的鏈接,獲取這些插件)。

          我們將以一個(gè)簡單的 Web 論壇為例,向您展示最重要的特性。模型的根為 Forum ,下面包括一組 MemberTopic 。每一個(gè) Topic 都具有一個(gè) TopicCategory (枚舉類型), MemberTopic 通過 Post 類間接相關(guān)聯(lián),這兩者之間也存在直接關(guān)聯(lián),因?yàn)?Member 可以創(chuàng)建 Topic

          用 UML 和 Omondo 創(chuàng)建 EMF 模型


          Omondo 的 UML 插件是在 Eclipse 中創(chuàng)建 UML 文檔的方便可靠的工具。它看起來就像是 Rational Rose 受冷落的小兄弟,但除非是您需要特別強(qiáng)大的功能,否則用它就可以工作得很好了。不過,該工具尚不支持 Eclipse 3,所以我采用 Eclipse 2.1 來創(chuàng)建 UML 類圖。

          一開始,我們創(chuàng)建一個(gè)新的 Java 項(xiàng)目 UMLForum,以及一個(gè)新包 com.ibm.example.forum 。再創(chuàng)建一個(gè)新的 EMF 類圖, forum.ucd ,存放在 src/com/ibm/example/forum 下。目錄中創(chuàng)建了兩個(gè)文件,forum.ecd 和 forum.ecore。向類圖中增加一個(gè)新類,名為 Forum ,然后單擊 Finished。向 Forum 類中增加一條屬性描述,類型為 EString (對(duì)于所有的簡單 Java 類都有相應(yīng)的 Ecore 類),如圖 1 所示。對(duì)于屬性的特性,只選擇 changeable ,并將范圍設(shè)為從 0 到 1。

          如果您過一會(huì)改主意了,想使用其他的特性,可以打開 Properties 視圖,選擇其中的類或?qū)傩浴?/p>
          圖 1. 新建的 Forum 類及其屬性的性質(zhì)
          新建的 Forum 類及其屬性的性質(zhì)

          對(duì)于下列接口重復(fù)上述步驟:

          接口 屬性 類型
          Member nickname EString
          Topic title EString
          Post comment EString

          為定義關(guān)聯(lián),我們可以選中關(guān)聯(lián)按鈕,然后單擊關(guān)聯(lián)的源( Forum )和目標(biāo)( Member )。這樣將打開關(guān)聯(lián)屬性設(shè)置對(duì)話框。在其中將名字設(shè)置為 members ,確保僅僅選擇了 changeable 和 containment,然后將上限設(shè)為 -1。在第二個(gè) Association End 選項(xiàng)卡中,取消選中的 Navigable,然后單擊 Ok。對(duì) ForumTopic 也執(zhí)行相同的操作,屬性名稱從 members 改為 topics 。取消選中的 navigable,從而創(chuàng)建一個(gè)無方向的關(guān)聯(lián),但我們想讓其他屬性都保持為雙向。

          按照下表所示完成關(guān)聯(lián)設(shè)置:

          目標(biāo) 關(guān)聯(lián) 名稱 特性 范圍
          Member Topic 1st Association topicsCreated changeable 0 到 1
          2nd Association creator changeable 0 到 1
          Topic Post 1st Association posts Containment, changeable 0 到 -1
          2nd Association topic changeable 0 到 1
          Member Post 1st Association posts changeable 0 到 -1
          2nd Association author changeable 0 到 1

          最后,我們要定義一個(gè)枚舉類型,用于表示 topic 有多少不同的類型。創(chuàng)建一個(gè)新的枚舉類型,名字叫做 TopicCategory 。Literal 中加入以下的內(nèi)容:

          • ANNOUNCEMENT , value = 0
          • GUEST_BOOK , value = 1
          • DISCUSSION , value = 2

          然后,為 Topic 定義一個(gè)新屬性,叫做 category ,類型為 TopicCategory ,changeable,范圍 0-1。如果您愿意的話,可以在屬性標(biāo)簽上對(duì)默認(rèn)值進(jìn)行修改,但我們將接受 ANNOUNCEMENT 的默認(rèn)值。


          圖 2. 完成后的 UML 類模型
          完成后的 UML 類模型

          一旦您完成了圖 2 所示的 UML 類圖,下一步就是創(chuàng)建一個(gè) EMF 模型。為此,需要先創(chuàng)建一個(gè)新的 EMF 項(xiàng)目( File > New > Project... > Eclipse Modeling Framework > EMF Project),并用 com.ibm.example.forum 作為該項(xiàng)目的名稱(這是插件名稱的基礎(chǔ),因此我們遵從 Eclipse 插件的命名規(guī)范)。在下一個(gè)頁面上,選擇 Load from an EMF core model,然后單擊 Next。從文件系統(tǒng)中加載 ecore 文件,它將自動(dòng)填充 Generator 的模型名。在最后一個(gè)頁面上,單擊包旁邊的復(fù)選框,然后單擊 Finish。這樣就創(chuàng)建好了 EMF 模型,它的名字叫做 forum.genmodel。您可以從 使用生成的 EMF 模型一節(jié)中了解到這個(gè)模型是什么,以及如何使用它。

          用 XML Schema

          創(chuàng)建 EMF 模型
          XML Schema(XSD)的表現(xiàn)能力不如 UML 或帶注釋的 Java 代碼那么強(qiáng)大,例如,它不能表達(dá)出雙向引用的關(guān)聯(lián)。但是由于默認(rèn)的的序列化方法要使用到您的方案,因此 XSD 對(duì)定制序列化來說是最快的方法。如果您希望為模型生成非常詳細(xì)的 XML/XMI,那么 XSD 就是必然的選擇。

          清單 1. forum.xsd 的片段
          <xsd:simpleType name="TopicCategory">
                                  <xsd:restriction base="xsd:NCName">
                                  <xsd:enumeration value="Announcement"/>
                                  <xsd:enumeration value="GuestBook"/>
                                  <xsd:enumeration value="Discussion"/>
                                  </xsd:restriction>
                                  </xsd:simpleType>
                                  <xsd:complexType name="Post">
                                  <xsd:sequence>
                                  <xsd:element name="comment" type="xsd:string"/>
                                  <xsd:element name="author" type="xsd:anyURI" ecore:reference="forum:Member"/>
                                  <xsd:element name="topic" type="xsd:anyURI" ecore:reference="forum:Topic"/>
                                  </xsd:sequence>
                                  </xsd:complexType>
                                  

          在清單 1 中,您可以看到枚舉是如何表示的,也能從中了解到如何定義一個(gè)具有指向其他類型的元素和引用的類型。在 Forum 這個(gè)例子中,我們僅僅使用了字符串屬性 "xsd:string" ,但是其他簡單 Java 類型也是支持的。有關(guān) XML Schema 和 forum.xsd 文件的更多信息,請(qǐng)參閱 參考資料

          一旦完成了 XSD,下一步就是創(chuàng)建 EMF 模型。方法與 UML 模型中類似,先創(chuàng)建一個(gè)新的 EMF 項(xiàng)目( File > New > Project... > Eclipse Modeling Framework > EMF Project),項(xiàng)目名稱為 com.ibm.example.forum(這是插件名稱的基礎(chǔ),因此我們遵從 Eclipse 插件的命名規(guī)范)。在下一個(gè)頁面上選擇 Load from an XML Schema,然后單擊 Next。在文件系統(tǒng)中找出 XSD 文件并加載,然后 Generator 中的模型名就會(huì)自動(dòng)填充。在最后一個(gè)頁面上,單擊包旁邊的復(fù)選框,然后單擊 Finish。這樣就創(chuàng)建了一個(gè) EMF 模型,名字叫做 forum.genmodel。 您可以從 使用生成的 EMF 模型一節(jié)中了解到這個(gè)模型是什么,以及如何使用它。

          用帶注釋的 Java 代碼創(chuàng)建 EMF 模型


          如果通過 Java 代碼定義 EMF 模型,我們可以用 Interface 列出每一個(gè)類的屬性,以及類之間的關(guān)系。這樣得到的內(nèi)容并不充足,無法定義我們想要的全部信息,所以 EMF 使用了特殊的 JavaDoc 標(biāo)簽。每一個(gè)屬性或類,如果是 EMF 模型的一部分,就必須在其 JavaDoc 中包含一個(gè) @model 標(biāo)簽,也可以包含一個(gè)附加屬性列表。比如說,如果要構(gòu)造如上面圖 2 所示的一個(gè)對(duì)象模型,我們對(duì) Forum 的定義看起來應(yīng)該像清單 2 的樣子。

          清單 2. 帶注釋的 Forum.java
          package com.ibm.example.forum;
                                  import java.util.List;
                                  /**
                                  *
                                  @model
                                  */
                                  public interface Forum {
                                  /**
                                  *
                                  @model type="Topic" containment="true"
                                  */
                                  List getTopics();
                                  /**
                                  *
                                  @model type="Member" containment="true"
                                  */
                                  List getMembers();
                                  /**
                                  *
                                  @model
                                  */
                                  String getDescription();
                                  }
                                  

          清單 2 聲明了一個(gè)叫做 Forum 的對(duì)象,它具有一條 String 類型的描述信息和兩個(gè)孩子,一個(gè)是 Topic 列表,還有一個(gè)是 Member 列表。這兩個(gè)孩子都包含在 Forum 之內(nèi)。

          對(duì)于簡單的屬性,如 描述信息@model 標(biāo)簽就足夠了,但對(duì)于 list 而言,您也需要為其指明類型。 containment 屬性是可選的,但是如果某個(gè)對(duì)象是被包含的,那么它就和其容器一起被序列化。為了簡化序列化的過程,我們要保證所有的對(duì)象都是直接或者間接包含在 Forum 中的。其他一些有用的可選屬性如下:

          • opposite (用于雙向?qū)傩裕?
          • default (屬性的默認(rèn)值)。
          • transient (該屬性不能被序列化)。

          要獲得完整的屬性列表,請(qǐng)您參閱 參考資料中的 EMF user's guide。

          惟一需要當(dāng)心的是枚舉類型。它被定義成一個(gè) Class,而不是其他模型類中的 Interface! 為了明確這一點(diǎn),清單 3 展示了 TopicCategory 枚舉類型是如何實(shí)現(xiàn)的。

          清單 3. 枚舉類型 TopicCategory.java
          package com.ibm.example.forum;
                                  /**
                                  * @model
                                  */
                                  public
                                  class TopicCategory{
                                  /**
                                  * @model name="Announcement"
                                  */
                                  public static final int ANNOUNCEMENT = 0;
                                  /**
                                  * @model name="GuestBook"
                                  */
                                  public static final int GUEST_BOOK = 1;
                                  /**
                                  * @model name="Discussion"
                                  */
                                  public static final int DISCUSSION = 2;
                                  }
                                  

          最后,生成如下所示的三個(gè)接口,模型就完成了:

          接口 方法 模型標(biāo)簽
          Member List getPosts() type="Post" opposite="author"
          List getTopicsCreated() type="Topic" opposite="creator"
          String getName()
          Topic List getPosts() type="Post" opposite="author"
          Member getCreator() opposite="topicsCreated"
          String getTitle()
          TopicCategory getCategory()
          Post Member getAuthor opposite="posts"
          Topic getTopic() opposite="posts"
          String getComment()

          模型定義完成之時(shí),可以生成 EMF 模型( File > New > Other > Eclipse Modeling Framework > EMF Models)。將父目錄設(shè)為 com.ibm.example.forum/src/model, File name設(shè)為 forum.genmodel。在下一個(gè)頁面上,選擇 Load from annotated Java,然后選中包“forum”旁邊的復(fù)選框。然后單擊 Finish。這樣就創(chuàng)建了一個(gè)名為 forum.genmodel 的 EMF 模型。





          回頁首


          使用生成的 EMF 模型


          現(xiàn)在您的工作空間中應(yīng)該有一個(gè)生成好的 EMF 模型 forum.genmodel。這個(gè)模型中包含您輸入其中的所有信息。用默認(rèn)的編輯器打開這個(gè)模型(參見圖 3),再打開 Properties 視圖,然后檢查模型樹中每一個(gè)節(jié)點(diǎn)的屬性。前面輸入的所有屬性都可以定制,但是也有一些用于定制代碼生成的屬性。為了驗(yàn)證這一點(diǎn),讓我們?cè)囍薷?#8220;Copyright Text”或“Generate Schema”之類的屬性,看看會(huì)發(fā)生什么事情。


          圖 3. 在默認(rèn)的編輯器中打開生成的 EMF 模型
          帶有生成的 EMF 模型的 Eclipse 屏幕快照

          如果對(duì)模型描述(UML、XSD、帶注釋的 Java)進(jìn)行了修改,也可以在 Package Explorer 中用右鍵單擊該模型,然后選擇 Reload,這樣就能夠重新加載模型。這實(shí)現(xiàn)了用 EMF 生成的模型與模型描述之間的同步。重新加載后將會(huì)改變您在生成的模型中修改過的屬性。





          回頁首


          生成 Java 代碼

          如果您對(duì)模型描述感到滿意,或者如果您僅僅是想看看所有這一切到底是什么意思,那么現(xiàn)在就可以生成代碼了。在根節(jié)點(diǎn)上單擊鼠標(biāo)右鍵,選擇其中一個(gè)生成選項(xiàng):Model、Edit、或 Editor code。 Generate Model將在當(dāng)前項(xiàng)目中創(chuàng)建該 EMF 模型的 Java 實(shí)現(xiàn)代碼。其中會(huì)包含下列內(nèi)容:

          • com.ibm.example.forum -- 創(chuàng)建該 Java 類的接口和工廠。
          • com.ibm.example.forum.impl -- com.ibm.example.forum 中定義的接口的具體實(shí)現(xiàn)。
          • com.ibm.example.forum.util -- AdapterFactory。

          Generate Editor Code將創(chuàng)建 com.ibm.example.forum.edit 項(xiàng)目。其中僅僅包含一個(gè)包, com.ibm.example.forum.provider ,用于控制每一個(gè)模型對(duì)象出現(xiàn)在編輯器中的方式。 Generate Editor Code將在 com.ibm.example.forum.editor 項(xiàng)目中創(chuàng)建一個(gè)插件編輯器示例,其中包含了 com.ibm.example.forum.presentation。這些類提供了一系列簡單的 JFace 編輯器,可以與您的模型進(jìn)行交互。

          為了測試生成的插件,請(qǐng)依次進(jìn)入 Run > Run... > Run Time Workbench > New。輸入一個(gè)描述性的名稱,然后在 plug-ins 選項(xiàng)卡中,選擇 launch with all workspace and enabled external plug-ins。再在 Common 頁下,單擊 Display in favorites menu > RunLaunch in background。最后保存設(shè)置并運(yùn)行。

          這時(shí)將出現(xiàn)一個(gè)新的 Eclipse 工作臺(tái),您可以在 Help > About Eclipse Platform > Plug-in Details下面驗(yàn)證您的插件是否可用,如圖 4 所示。


          圖 4. Forum 的插件詳細(xì)信息
          自定義插件列表的 Eclipse 屏幕快照

          為了測試生成的插件,您可以創(chuàng)建一個(gè)新的 Simple 項(xiàng)目,名為“Forum Demo”,然后依次進(jìn)入 New > Other... > Example EMF Model Creation Wizards > Forum Model。給文件取名叫做 sample.forum,然后選擇 Forum 作為 Model Object。這時(shí)會(huì)打開一個(gè)窗口,您可以在這里向根中增加新的模型元素。其中包含幾種視圖:Selection、Parent、List、Tree、Table 和 TreeTable。所有這些視圖都顯示相同的數(shù)據(jù),也和 Outline 視圖保持同步。雖然所有視圖都會(huì)在右鍵菜單選項(xiàng)中顯示 New Sibling/New Child,但是我發(fā)現(xiàn),有些視圖在加入兄弟節(jié)點(diǎn)或子節(jié)點(diǎn)時(shí)不能正確響應(yīng)。如果您也遇到這種情況,可以使用 TableTree 視圖,或是在 Outline 視圖中創(chuàng)建新的節(jié)點(diǎn)。圖 5 展示了所生成的插件編輯器。


          圖 5. 所生成的插件編輯器
          自定義插件列表的 Eclipse 屏幕快照




          回頁首


          定制生成的代碼


          生成的代碼都很不錯(cuò),但是這只是真正應(yīng)用程序的起點(diǎn)。為了滿足我們的需要,我們必須對(duì)其進(jìn)行調(diào)整和定制。我們可以改變所生成的模型類的實(shí)現(xiàn),也可以對(duì)編輯器進(jìn)行擴(kuò)展和定制。好在 EMF 沒有讓我們失望,我們可以按照自己的想法做任何定制,當(dāng)重新生成代碼時(shí)也不會(huì)丟掉這些內(nèi)容。我們需要做的全部工作就是刪除 @generated JavaDoc 標(biāo)簽,EMF 的 jmerge 將保證這些方法、屬性或類不被打擾。

          為著重說明您能對(duì)代碼進(jìn)行哪些修改,讓我們來看一個(gè)簡單的例子。在所生成編輯器的 Table 視圖中,兩個(gè)字段都顯示出相同的的值。這一點(diǎn)并不是完全沒有用處。為了改善一下,我們可以修改第二個(gè)字段,讓它在選中一個(gè) Topic 的時(shí)候顯示 Author,然后增加第三個(gè)字段,給出該 Topic 中的帖子數(shù)。

          第一步,向 Table 視圖中額外增加一個(gè)字段。這一步在 com.ibm.example.forum.editor 項(xiàng)目中實(shí)現(xiàn),即 createPages() 方法中的 com.ibm.example.forum.presentation.ForumEditor 。把 @generated 標(biāo)簽刪除,這樣就能持久保存我們的修改,然后定位到表瀏覽窗口所在的位置。按照清單 4 的內(nèi)容對(duì)這段代碼進(jìn)行修改。

          清單 4. 修改后的 createPages()
          TableColumn selfColumn = new TableColumn(table, SWT.NONE);
                                  layout.addColumnData(new ColumnWeightData(2, 100, true));
                                  selfColumn.setText("Author");
                                  selfColumn.setResizable(true);
                                  TableColumn numberColumn = new TableColumn(table, SWT.NONE);
                                  layout.addColumnData(new ColumnWeightData(4, 100, true));
                                  numberColumn.setText("Number of Posts");
                                  numberColumn.setResizable(true);
                                  tableViewer.setColumnProperties(new String [] {"a", "b", "c"});
                                  

          這樣就額外增加了一個(gè)字段,但是現(xiàn)在所有的三個(gè)字段都顯示相同的數(shù)據(jù)。為了定制每一個(gè)字段中的數(shù)據(jù),我們需要提供一些 ITableItemLabelProvider 的實(shí)現(xiàn)。打開 com.ibm.example.forum.provider.TopicItemProvider ,在實(shí)現(xiàn)列表中加入 ITableItemLabelProvider 。我們需要增加兩個(gè)方法, getColumnText(Object, int)getColumnImage(Object, int) ,如清單 5 所示。

          清單 5. 加入 TopicItemProvider
          public String getColumnText(Object obj, int index) {
                                  if( index == 0 ){
                                  return getText(obj);
                                  }
                                  else if( index == 1 ) {
                                  return ((Topic)obj).getCreator().getNickname();
                                  } else if( index == 2 ) {
                                  return " + ((Topic)obj).getPosts().size();
                                  }
                                  return "unknown";
                                  }
                                  public Object getColumnImage(Object obj, int index) {
                                  return getImage( obj );
                                  }
                                  

          最后,我們需要注冊(cè)這個(gè)提供程序。實(shí)現(xiàn)方法是編輯 com.ibm.example.forum.provider.ForumItemProviderAdapterFactory 的構(gòu)造函數(shù),向支持的類型中增加 ITableItemLabelProvider ,如清單 6 所示。

          清單 6. ForumItemProviderFactory 構(gòu)造函數(shù)
          public ForumItemProviderAdapterFactory() {
                                  supportedTypes.add(ITableItemLabelProvider.class);
                                  supportedTypes.add(IStructuredItemContentProvider.class);
                                  supportedTypes.add(ITreeItemContentProvider.class);
                                  supportedTypes.add(IItemPropertySource.class);
                                  supportedTypes.add(IEditingDomainItemProvider.class);
                                  supportedTypes.add(IItemLabelProvider.class);
                                  }
                                  

          現(xiàn)在我們?cè)龠\(yùn)行這個(gè)插件,打開表視圖,就能看到圖 6。請(qǐng)注意,沒有實(shí)現(xiàn)的 ITableItemLabelProvider 元素將在所有的字段中顯示相同的文本。


          圖 6. 修改后的 Table 編輯器
          修改后的 Table 編輯器




          回頁首


          在 Java 中操縱模型


          生成的模型代碼看起來就像是 Java 代碼中增加了一些有用的東西。系統(tǒng)還提供了一種靈活的定制反射 API,對(duì)工具很有用。您也許注意到了,這就是 eGet()eSet() 兩個(gè)方法。在大多數(shù)情況下,我們并不需要關(guān)心它,所以我們還是看看我們感興趣的東西:如何創(chuàng)建、保存和加載模型。讓我們從頭開始:加載 EMF 模型。

          清單 7. 加載 Forum
          // Register the XMI resource factory for the .forummodel extension
                                  Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
                                  Map m = reg.getExtensionToFactoryMap();
                                  m.put("forummodel", new XMIResourceFactoryImpl());
                                  ResourceSet resSet=new ResourceSetImpl();
                                  Resource res = resSet.getResource(URI.createURI("model/forum.forummodel"),true);
                                  Forum forum = (Forum)res.getContents().get(0);
                                  

          清單 7 展示了如何給文件關(guān)聯(lián)一個(gè)符合 XMI 格式的擴(kuò)展名“forummodel”,然后用 EMF 的 ResourceSet 解析并加載 forum 模型。我們知道,F(xiàn)orum 是惟一的根元素,所以可以想象, res.getContents().get(0) 將返回一個(gè)且僅有一個(gè) Forum 對(duì)象。如果情況不是這樣,我們還可以從 getContents().iterator() 中取出一個(gè) Iterator,然后分別檢查每一個(gè)元素。

          我們還可以換一種方法,創(chuàng)建一個(gè)新的 Forum,然后用程序組裝起來,如清單 8 所示。

          清單 8. 初始化 Forum
          // initialize model and dependencies
                                  ForumPackageImpl.init();
                                  // retrieve the default Forum factory singleton
                                  ForumFactory factory = ForumFactory.eINSTANCE;
                                  Forum forum = factory.createForum();
                                  forum.setDescription("programmatic forum example");
                                  Member adminMember = factory.createMember();
                                  adminMember.setNickname("Administrator");
                                  forum.getMembers().add( adminMember );
                                  Topic noticeTopic = factory.createTopic();
                                  noticeTopic.setTitle("Notices");
                                  noticeTopic.setCategory(TopicCategory.ANNOUNCEMENT_LITERAL);
                                  noticeTopic.setCreator(adminMember);
                                  forum.getTopic().add( noticeTopic );
                                  

          在這個(gè)例子中,我們首先初始化包,然后創(chuàng)建 ForumFactory,用它生成所有的子對(duì)象。創(chuàng)建完畢之后,就可以像標(biāo)準(zhǔn)的 JavaBean 那樣訪問這些對(duì)象。然而,由于我們把 TopicMemeber 之間的 creator/topicsCreated 關(guān)系聲明為雙向,當(dāng)我們調(diào)用 noticeTopic.setCreator(adminMember) 的時(shí)候, adminMembertopicsCreated 清單中就包括 noticeTopic

          一旦我們創(chuàng)建并操縱了 EMF 模型,就很容易將其保存為我們選定的格式(參見清單 9)。

          清單 9. 保存 Forum
          URI fileURI = URI.createFileURI("model/forum.ecore");
                                  Resource resource = new XMIResourceFactoryImpl().createResource(fileURI);
                                  resource.getContents().add( forum );
                                  try {
                                  resource.save(Collections.EMPTY_MAP);
                                  } catch (IOException e) {
                                  e.printStackTrace();
                                  }
                                  

          在本例中,我們給 URI.createFileURI() 提供了希望保存成的文件名與目標(biāo)格式。這個(gè)例子因?yàn)槭潜4鏋?XMI,所以使用了 XMIResourceFactoryImpl 。一旦創(chuàng)建完畢,所有的模型對(duì)象就如我們所愿的持久保存起來了。在這個(gè)例子中,除 Forum 之外的每一個(gè)對(duì)象都被另一個(gè)類包含,所以我們只需要對(duì)包含所有孩子的 root 增加這條命令即可。如果某些對(duì)象沒有 包含 關(guān)系,那么也必須通過 resource.getContents().add() 顯式地將它們加進(jìn)去。否則,當(dāng)您調(diào)用 resource.save() 時(shí)就會(huì)出現(xiàn)異常。



          posted on 2009-04-13 11:01 閱讀(500) 評(píng)論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 福清市| 凤庆县| 广德县| 彭州市| 隆子县| 松原市| 保亭| 武汉市| 防城港市| 英超| 焦作市| 聂荣县| 贵阳市| 巍山| 梁河县| 丰宁| 育儿| 黔江区| 肇庆市| 周宁县| 江阴市| 武安市| 旬邑县| 湖南省| 库伦旗| 海口市| 肇州县| 徐水县| 遂宁市| 门头沟区| 蒲江县| 嘉义县| 砀山县| 城口县| 嘉峪关市| 晋江市| 凤阳县| 南召县| 莱西市| 沾化县| 龙岩市|