簡單地說,SDO是一種數據應用程序開發框架,它包括一個體系結構和相應的 API。SDO 能夠實現以下操作:
簡化 J2EE 數據編程模型。
抽象面向服務體系結構(SOA)中的數據。
統一數據應用程序的開發。
支持和集成 XML。
結合 J2EE 模式和最佳實踐。
在這篇介紹 SDO 框架的文章中,我們將嘗試著解釋 SDO 背後的動機,以及 SDO 與其他規范的區別,然後描述 SDO 的組成,最後,通過一個示例 SDO 應用 程序說明 SDO 的用法。
為什麼要使用 SDO?
對於服務數據對象(SDO),大多數開發人員要問的第一個問題就是為什麼要 使用 SDO。難道 J2EE 本身還不夠龐大、不夠復雜(而且難以掌握)嗎?Java 環境中不是已經有其他支持 XML 的框架了嗎?所幸的是,該問題的答案能夠讓 我們多數人感到滿意:SDO 是作為簡化 J2EE 數據編程模型的方法出現的,它能 夠讓 J2EE 開發人員把更多的時間用於應用程序的業務邏輯。
服務數據對象框架為數據應用程序開發提供了統一的框架。通過 SDO,您不 需要熟悉特定於技術的 API,就能訪問和利用數據。您只需要知道一種 API,即 SDO API,它允許您處理來自多種數據源的數據,其中包括關系數據庫、實體 EJB 組件、XML 頁面、Web 服務、Java Connector Architecture、JavaServer Pages 頁面等。
注意,我們使用了 框架這一詞。這是比照 Eclipse 框架的說法。由於設計 的基礎堅固而且可以擴展,所以 Eclipse 能夠集成各種工具。與此類似,對於 采用 SDO 的應用程序,SDO 也是一種框架,這類應用程序在 SDO 模型上是一致 的。
與其他某些數據集成模型不同的是,SDO 沒有停留在數據抽象上。SDO 框架 還結合了很多 J2EE 模式和最佳實踐,從而使應用程序很容易結合經過驗證的體 系結構和設計。比方說,今天的多數 Web 應用程序百分之百的時間沒有(或不 能)連接到後端系統,因此 SDO 支持不連接的編程模型。同樣的,今天的應用 程序往往非常復雜,包含很多層次。如何存儲數據、如何發送數據、如何在 GUI 框架中將它們提供給終端用戶?SDO 編程模型提供的應用模式能夠清晰地劃分不 同的問題。
XML 在分布式應用程序中日漸普及。比如,XML Schema (XSD) 被用來定義應 用程序數據格式中的業務規則。XML 本身也可以用於改進交互性:Web 服務使用 基於 XML 的 SOAP 作為消息格式。XML 是推動 SDO 的一個重要原因,SDO 框架 支持並集成了 XML。
各種技術的比較
前面已經提到,SDO 並不是 提出解決分布式應用程序中數據集成問題的惟一技術。下面將分別討論 SDO 和 類似的編程框架 JDO、JAXB 和 EMF 的優劣。
SDO 和 WDO
Web 數 據對象(或 WDO)是隨著 IBM WebSphere® Application Server 5.1 和 IBM WebSphere Studio Application Developer 5.1.2 發布的 SDO 早期版本的 名稱。如果使用過 WebSphere Studio 5.1.2,那麼您對 SDO 可能已經有所了解 ,雖然您可能習慣看到將它標記為 WDO,比如在數據庫的名字中。忘掉 WDO 吧 ,它現在的名字是 SDO!
SDO 和 JDO
JDO 代表 Java Data Object(Java 數據對象)。JDO 已經通過 Java 社區進程(JCP)標准化了 1.0 版,2003 年 5 月推出了維護版 1.0.1,現在已經為 2.0 版成立了 JCP 專家組 。JDO 針對 Java 環境中的數據編程提供了一種通用 API,用於訪問存儲在不同 數據源中的數據,如數據庫、文件系統或者事務處理系統。JDO 保持了 Java 對 象(圖)之間的關系,同時允許對數據的並發訪問。
JDO 希望簡化和統 一 Java 數據編程,以便開發人員能夠專注於業務邏輯,而不是底層的技術,從 這一點上說,其目標和 SDO 是相同的。但主要的區別在於,JDO 僅考慮持久性 問題(J2EE 數據層或者企業信息系統(EIS)層),而 SDO 更具一般性,關注 的是不同 J2EE 層次間數據流的表示,比如表示層和業務層。
有趣的是 ,SDO 可以結合 JDO 一起使用,JDO 作為數據源,SDO 來訪問它,這就是 Data Transfer Object(數據傳輸對象,DTO)設計模式的具體運用。同樣,SDO 也可 以結合實體 EJB 組件和 Java Connector Architecture(Java 連接器體系結構 ,JCA)使用,目的是提供統一的數據訪問。
SDO 和 EMF
EMF 代表 Eclipse Modeling Framework(Eclipse 建模框架)。EMF 根據使 用 Java 接口、XML Schema 或者 UML 類圖定義的數據模型生成統一的元模型( 稱為 Ecore),可以將元模型與框架結合在一起使用,創建高質量的模型實現。 EMF 提供了持久性、一個有效的反射類屬對象操縱 API 和一個變更通知框架。 EMF 還包括用來構建 EMF 模型編輯器的一般的重用類。
EMF 和 SDO 都可以處理數據表示。事實上,IBM 的 SDO 參考實現就是一種 SDO 的 EMF 實現,後面我們還要用到該實現。還可以根據 UML 模型定義或者 SDO 本身,用 EMF 代碼生成來創建 SDO 實現的某些部分。SDO 實現基本上是 EMF 中的一小層(方面),它是作為 EMF 項目的一部分打包和提供的。關於 EMF 的更多信息,請參閱 參考資料。
SDO 和 JAXB
JAXB 代表 Java API for XML Data Binding(XML 數據綁定 Java API)。 JAXB 1.0 在 2003 年 1 月由 JCP 發布。JCP 專家組已經制定了 2.0 版的初步 草案。JAXB 是關於 XML 數據綁定的,也就是說,將 XML 數據表示成內存中的 Java 對象。作為 Java 語言的 XML 綁定框架,JAXB 可以節約解析和創建 XML 文檔的時間。(事實上,通過它,您完全不需要和 XML 打交道。)JAXB 為您執 行編組/序列化(Java 到 XML)和解組/並行化(XML 到 Java)。
SDO 定義了自己的 Java 綁定框架,但是走得還要遠一些。JAXB 僅關注 Java 到 XML 的綁定,而綁定到 SDO 的不僅僅是 XML 數據。如前所述,SDO 提 供了對不同類型數據的統一訪問,XML 僅是其中的一種數據類型。SDO 還提供了 靜態和動態 API *,而 JAXB 僅提供了靜態綁定。
* 注意,本文中示例應用程序僅使用了動態 SDO,雖然 EMF 代碼生成器也為 數據對象的靜態代碼生成提供了完整的支持。
SDO 和 ADO .NET
ADO 代表 ActiveX Data Objects(ActiveX 數據對象),但是在 .NET 上下 文中,其含義已經發生了變化。ADO .NET 提供了 .NET 框架下不同層次間的統 一數據訪問機制。
ADO .NET 和 SDO 具有相同的動機,都是用來支持 XML 和分布在多個層上的 應用程序。除了技術性的差異外,這兩項技術主要的不同在於:ADO .NET 用於 Microsoft .NET 平台,是一種私有的技術;而 SDO 用於 Java (J2EE) 平台, 通過 Java 社區進程實現標准化。
SDO 的組成部分
這一節將介紹 SDO 的體系結構。我們將介紹組成框架的不同組成部分和它們 之間的協作。首先要討論的三個組成部分之一是 SDO 的“概念性”特征,API 中沒有對應的接口。
SDO 客戶機
SDO 客戶機使用 SDO 框架處理數據。SDO 客戶機使用的不是特定於技術的 API 和框架,而是 SDO 編程模型和 API。SDO 客戶機處理 SDO 數據圖(參見 圖 1),不需要了解所處理的數據是如何持久保存或者序列化的。
Data 中介服務
數據中介服務(DMS)負責從數據源創建數據圖、依據數據圖的變化更新數據 源。數據中介框架不屬於 SDO 1.0 規范,換句話說,SDO 1.0 沒有涉及具體的 DMS。常見的 DMS 有 JDBC DMS、實體 EJB DMS 和 XML DMS 等。
數據源
數據源不限於後端數據源(如持久存儲數據庫)。數據源以自己的格式保存 數據。只有 DMS 訪問數據源,SDO 應用程序不訪問數據源。SDO 應用程序可能 只使用數據圖中的數據對象。
下面介紹的每個組件對應於 SDO 編程模型的一個 Java 接口。SDO 參考實現 (請參閱 參考資料)提供了這些接口基於 EMF 的實現。
數據對象
數據對象是 SDO 的基本組件。事實上,它們是規范名稱中的 服務數據對象 。數據對象是結構化數據的 SDO 表示。數據對象是通用的,它們提供了 DMS 創 建的結構化數據的公共視圖。比方說,雖然 JDBC DMS 需要知道持久性技術(比 如關系數據庫),以及如何配置和訪問數據,SDO 客戶機不需要了解這些細節。 數據對象在屬性中保存它們的“數據”(稍後還要討論屬性)。數據對象提供了 易於使用的創建和刪除方法(帶有不同簽名的 createDataObject() 和 delete () ),獲得自身類型(實例類、名稱、屬性和名稱空間)的反射方法。數據對 象都鏈接在一起,包含在數據圖中。
數據圖
數據圖提供了數據對象樹的容器。數據圖由 DMS 生成,供 SDO 客戶機使用 。修改後,數據圖被回傳給 DMS 更新數據源。SDO 客戶機可以遍歷數據圖,讀 取和修改數據圖中的數據對象。SDO 是一種 無連接的體系機構,因為 SDO 客戶 機與 DMS 和數據源沒有連接,所以 SDO 客戶機看到的只有數據圖。此外,數據 圖可以包含表示不同數據源中數據的對象。數據圖包含一個根數據對象、與根關 聯的所有數據對象和變更摘要(change summary,參見本文後面的敘述)。當在 應用程序組件(比如服務調用期間的 Web 服務請求者和提供者)之間進行傳輸 、組件到 DMS 的傳輸(或者保存到磁盤)的時候,數據圖被序列化為 XML。SDO 規范提供了序列化的 XML Schema。圖 1 顯示了一個 SDO 數據圖。
圖 1. SDO 數據圖
變更摘要
變更摘要包含在數據圖中,表示對 DMS 返回的數據圖的修改。變更摘要最初 是空的(數據圖剛返回客戶機的時候),隨著數據圖的變化逐漸填充。在後台更 新時,DMS 使用變更摘要將修改應用於數據源。變更摘要提供了數據圖中被修改 的屬性(包括原來的值)、新增和刪除的數據對象的列表,從而使 DMS 以遞增 方式高效地更新數據源。只有當變更摘要日志功能被激活時,才會將信息添加到 數據圖的變更摘要中。變更摘要提供了讓 DMS 打開和關閉日志功能的方法,後 面的例子中還將詳細對其進行介紹。
屬性、類型和序列
數據對象用一系列屬性保存其內容。每個屬性都有一個類型,該類型既可以 是基本類型(如 int )這樣的屬性類型,也可以是通用數據類型(如 Date ) ,如果引用的話,還可以是其他數據對象類型。每個數據對象都為屬性提供了訪 問和設置方法(getter 和 setter)。這些訪問器方法有不同的重載版本,可以 通過傳遞屬性名( String )、編號( int )或者屬性元對象本身來訪問屬性 。String 訪問器還允許使用類 XPath 的語法訪問屬性。比如,可以對公司數據 對象調用 get("department[number=123]") 來訪問編號為 123的第一個部門。 序列更加高級,可以保持不同種類的屬性-值對列表的順序。
SDO 和示例安裝
我們已經講了很多的概念和理論,現在要進行一些實際操作了。好消息是您 馬上就能使用 SDO,而且是免費的。這一節將介紹一個 SDO 示例應用程序,它 將在 SDO 的 IBM 參考實現上運行,這個參考實現是 Eclipse Modeling Framework (EMF) 的一部分。我們首先將說明如何安裝 EMF 2.0.1(包括 SDO) ,然後將介紹如何設置本文提供的示例應用程序。
安裝 EMF 2.0.1
如果已經安裝了 EMF 2.0.1,或者知道怎麼安裝,那麼請跳過這一節,直接 閱讀下一節。
IBM SDO 1.0 實現和 EMF 2.0.1 一起打包。要使用 SDO,則需要安裝 EMF 2.0.1 *。您可以按照 EMF 站點上的說明使用 Eclpise 更新管理器,也可以按 照下面的步驟操作。
*EMF 2.0.0 中也包含 SDO 1.0 的實現。
在 EMF 主頁中的“快速導航”部分可以找到下載鏈接頁面,選擇下載 “v2.x: EMF 和 SDO”。安裝 EMF 之前一定要閱讀安裝要求。安裝 EMF 2.0.1 之前至少要安裝了 Eclipse 3.0.1 和 Java Development Kit (JDK) 1.4。一定 要選擇 EMF 2.0.1 發行版本。打包類型建議選擇“All”:emf-sdo-xsd-SDK- 2.0.1.zip,這樣,就可以在一個文件中找到源代碼、運行文件和文檔。如果願 意,還可以下載 SDO 的最小安裝包“EMF & SDO RT”:emf-sdo-runtime- 2.0.1.zip。
在解壓 Eclipse 的目錄中解壓 zip 文件(壓縮包中的文件組織結構為 eclipse/plugins/...)。啟動 Eclipse,然後選擇 Help>About the Eclipse Platform,檢查 EMF 是否安裝成功。單擊 Plug-in Details按鈕,確 保 org.eclipse.emf.* 插件在 2.0.1 層次上。有 6 個與 SDO 有關的插件:
org.eclipse.emf.commonj.sdo
org.eclipse.emf.ecore.sdo
org.eclipse.emf.ecore.sdo.doc
org.eclipse.emf.ecore.sdo.edit
org.eclipse.emf.ecore.sdo.editor
org.eclipse.emf.ecore.sdo.source
運行時只需要兩個插件: org.eclipse.emf.commonj.sdo 和 org.eclipse.emf.ecore.sdo ,如果選擇僅安裝運行時插件,那麼您只能看到這 兩個插件。這樣就完成了 EMF 的安裝。
安裝示例 SDO 應用程序
下一步是在工作區中添加本文所用的 SDO 示例應用程序,步驟如下:
啟動 Eclipse 並創建一個新的 Plug-In Project。
將項目命名為 SDOSample,選擇源文件夾 src和輸出文件夾 bin,建立 Java 源代碼。
單擊 Next。
取消選擇“Generate the Java class that controls the plug-in's life cycle(生成控制插件生命期的 Java 類)”選項並單擊 Finish。
然後,單擊本文頂端或底端的 Code圖標(或者參閱 下載部分)下載 j- sdoSample.zip,並將其解壓縮到 SDOSample 目錄中(在 Eclipse 窗口中選擇 Import... >Zip file)。一定要保留文件夾結構並覆蓋原來的文件,這樣, 就可以用 j-sdoSample.zip 中的文件代替 SDOSample 項目。
注意:SDOSample 是作為 Eclipse 插件項目打包的,因此不需要自己設置庫 依賴關系。但是,在本例中,只包含 Java 代碼,如果在 CLASSPATH 中包含 EMF 和 SDO 庫(JAR 文件),也可將 SDOSample 作為獨立的應用程序運行。
環境設置應該與下面截屏圖中的類似。
圖 2. Eclipse 環境
現在開始使用這個示例 SDO 應用程序。
一個簡單的 SDO 應用程序
本文後面將使用的示例應用程序從功能上說很有限,但它可以幫助您更好地 理解 SDO。該應用程序包括兩部分,分別放在兩個包中:dms 和 client。
SDO 1.0 沒有規定標准 DMS API。因此我們為這個例子設計了自己的 DMS 接 口,它包含兩個方法,如清單 1 所示。
清單 1. DMS 接口
/**
* A simple Data Mediator Service (DMS) that builds
* SDO Data Graphs of Employees and updates
* a backend data source according to a Data Graph.
*/
public interface EmployeeDMS
{
/**
* @param employeeName the name of the employee.
* @return an SDO Data Graph with Data Objects for
* that employee's manager, that employee,
* and that employee's "employees".
*/
DataGraph get(String employeeName);
/**
* updates backend data source according to dataGraph.
* @param dataGraph Data Graph used to update data source.
*/
void update(DataGraph dataGraph);
}
客戶機將實例化 DMS,並調用 get() 方法訪問特定的雇員:Big Boss、 Wayne Blanchard 和 Terence Shorter。它以用戶友好的方式在控制台中打印這 些雇員的信息,然後更新 Terence Shorter 及其雇員的部門信息。最後調用 DMS 的 update() 方法,傳遞更新的 Terence Shorter 數據圖。
注意,為了便於示范,我們沒有實現數據源組件,但在 DMS 中,有一些如何 根據查詢構建數據圖的“硬編碼”知識。圖 3 顯示了 DMS 正在使用的雇員層次 結構。
圖 3. Big Boss 公司的雇員
圖中可以看出,DMS 背後的虛擬公司有 4 個雇員,層次結構如下:
Big Boss 沒有上司,Terence Shorter 是其下屬。
Terence Shorter 以 Big Boss 作為自己的上司,John Datrane 和 Miles Colvis 是其下屬。
John Datrane 的上司是 Terence Shorter,沒有下屬。
Miles Colvis 的上司是 Terence Shorter,沒有下屬。
運行示例應用程序
右擊 SDOClient.java,然後選擇 Run>Java application運行上述示例應 用程序,結果如下:
清單 2. 應用程序的控制台輸出
********* EMPLOYEE INFORMATION *********
Name: John Datrane
Number: 4
Title: Mr.
Department: Procurement
Is manager?: no
DIRECT MANAGER:
Name: Terence Shorter
Number: 2
Title: Mr.
Department: Financing
Is manager?: yes
****************************************
NO INFORMATION AVAILABLE ON EMPLOYEE Wayne Blanchard
********* EMPLOYEE INFORMATION *********
Name: Terence Shorter
Number: 2
Title: Mr.
Department: Financing
Is manager?: yes
DIRECT MANAGER:
Name: The Big Boss
Number: 1
Title: Mr.
Department: Board
Is manager?: yes
DIRECT EMPLOYEES:
Name: Miles Colvis
Number: 3
Title: Mr.
Department: Accounting
Is manager?: no
Name: John Datrane
Number: 4
Title: Mr.
Department: Procurement
Is manager?: no
[Total: 2]
****************************************
DMS updating Terence Shorter
(changed department from "Financing" to "The new department")
DMS updating Miles Colvis
(changed department from "Accounting" to "The new department")
DMS updating John Datrane
(changed department from "Procurement" to "The new department")
現在我們來分析應用程序的各個組成部分是如何工作的。
客戶機
SDO 客戶機例示了 DMS,並從中獲得不同雇員的數據圖。得到數據圖後,通 過根對象(使用 SDO 動態 API)遍歷和訪問數據對象,如下所示:
// Get the SDO DataGraph from the DMS.
DataGraph employeeGraph = mediator.get(employeeName);
...
// Get the root object
DataObject root = employeeGraph.getRootObject();
...
// get the employee under the manager
employee = theManager.getDataObject("employees.0");
客戶機調用動態 SDO 訪問器 API,從數據對象中獲得信息,並將其顯示到控制台上:
System.out.println("Name: " + employee.getString ("name"));
System.out.println ("Number: " + employee.getInt("number"));
...
System.out.println ("Is manager?: " +
(employee.getBoolean("manager") ? "yes" : "no") + "\n");
我們已經看到客戶機是如何獲取信息(讀)的,但是如何寫入信息呢?更准 確地說,客戶機如何修改對象?SDO 客戶機一般使用 DataObject 寫訪問器方法 更新數據對象。比如,下面的代碼修改從雇員 Terence Shorter 獲得的數據圖 :
employee.setString("department", newDepartmentName);
注意,客戶機沒有調用日志方法。DMS 負責對數據圖的變更摘要調用 beginLogging() 和 endLogging() 記錄日志。
數據圖
可以將數據圖的數據格式(模型)看作 DMS 與客戶機之間的抽象。客戶機期 望從 DMS 得到數據圖,DMS 也知道如何創建數據讀(包括從後端數據源中讀取 和更新數據)。如果熟悉 XML 或者 Web 服務,那麼可以將數據圖模型看作定義 數據對象 XML Schema(XSD)。數據圖本身就類似 XML 實例文檔。事實上,XML Schema 也是定義 SDO 模型的一種方法。
注意,數據圖及其模型總是能夠序列化為 XML。在 SDOClient.java 中將 debug 變量設為 true ,就可以看到運行時在控制台中顯示的數據圖的序列化版 本,與清單 3 類似。
清單 3. 數據圖的序列化版本
<?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance"
xmlns:company="http://com.example.company.ecore"
xmlns:sdo="commonj.sdo"
xmlns:sdo_1="http://www.eclipse.org/emf/2003/SDO">
<changeSummary>
<objectChanges key="#//@eRootObject">
<value xsi:type="sdo_1:EChangeSummarySetting"
featureName="department" dataValue="Board"/>
</objectChanges>
</changeSummary>
<company:Employee name="The Big Boss"
number="1" department="The new department" title="Mr."
manager="true">
<employees name="Terence Shorter" number="2"
department="The new department" title="Mr." manager="true">
<employees name="Miles Colvis" number="3"
department="The new department" title="Mr."/>
<employees name="John Datrane" number="4"
department="The new department" title="Mr."/>
</employees>
</company:Employee>
</sdo:datagraph>
在本例中,數據圖由 Employee 數據對象(以及變更摘要)組成。Employee 包含姓名、編號、部門、職務、上司(管理該雇員的另一位雇員)和下屬(該雇 員管理的其他雇員)等屬性。該例中,雇員已經位於硬編碼的數據源中時,DMS 返回的數據圖的格式總是雇員的上司(如果有的話)、雇員及其直接下屬(如果 有的話)。
DMS 構建數據圖
SDO 1.0 沒有規定 DMS API,API 應該包含數據圖模型本身的設計和創建。 因為建立對數據源的訪問要考慮很多種情況,設計數據圖本身可以作為另一篇文 章的主題。
對這個例子,我們將采用 DMS 通過動態 EMF API 定義的雇員模型。示例數 據圖沒有 XSD 這樣的模型文檔。實際上,因為對象是動態生成的,所以這意味 著沒有生成 Employee Java 類。如果使用靜態方法,就會生成這樣的類。
DMS 使用不同的數據訪問 API(JDBC、SQL 等)從不同數據源獲取的信息。 但是,一旦從後端(該例中是硬編碼的知識)檢索到信息,DMS 就轉而使用 EMF API(eSet、eGet)而非 SDO API 來創建數據對象的數據圖。這種方法能得到較 好的性能,但缺點是不能跨 SDO 實現移植。
對於主要關注性能,同樣的 DMS 設計也可使用 SDO API 實現。在這種情況 下,DMS 類( employeeClass 、 employeeNameFeature 等)中緩沖的元對象, 將代替 EMF 類型 EClass 、 EAttribute 和 EReference 等),成為 commonj.sdo.Type 和 commonj.sdo.Property 的類型。此外,如果性能不重要 ,那麼可以方便地使用基於 String 的 SDO API(如 setBoolean(String path, boolean value) ),因此不需要緩沖元對象。不幸的是,這種解決方案雖然更 方便,但運行起來也更慢。
下面的代碼片段說明了 SimpleEmployeeDataMediatorImpl.java 中 Employee 模型的定義。但這些代碼並沒有構建 SDO 對象,構建的僅僅是 SDO 對象的模型:
protected EClass employeeClass;
protected EAttribute employeeNameFeature;
protected EReference employeeEmployeesFeature;
...
employeeClass = ecoreFactory.createEClass();
employeeClass.setName("Employee");
EAttribute employeeNameFeature = ecoreFactory.createEAttribute();
...
// employees (that the employee manages)
employeeEmployeesFeature = ecoreFactory.createEReference();
employeeEmployeesFeature.setContainment(true);
...
EPackage employeePackage = ecoreFactory.createEPackage();
employeePackage.getEClassifiers().add(employeeClass);
...
注意,我們使用值 true 對 employees EReference 調用 setContainment ,因此每個雇員都“包含”他或她的下屬。否則,嵌套的雇員就不會(即被包含 )在數據圖中,變更摘要也只能包含根對象的修改,而不能包含其他雇員的修改 。
建模 SDO
您可能想“很有趣,但是這樣只能得到 EMF 對象而不是 SDO 對象,還有什 麼竅門嗎?”當然有,而且很簡單。Employee EClass 屬於 employeePackage EPackage ,並且包含下面的調用:
// Have the factory for this package build SDO Objects
employeePackage.setEFactoryInstance(
new DynamicEDataObjectImpl.FactoryImpl());
運行時,這個工廠將創建 DynamicEDataObjectImpl 類型的對象,該對象實 現了 DataObject 接口(即它是一個 SDO 數據對象),而不是默認的 DynamicEObjectImpl 接口,並且可以智能地創建普通的 EMF 對象。SDO 和 EMF 對象之間的關系就很清楚了:SDO 對象就是同時實現了 SDO DataObject 接口的 EMF 對象。事實上,這些附加方法的實現是委派給核心 EMF 方法實現的。
創建 SDO 實例
現在,已經擁有了我們的數據對象,就可以建立 Employee 的實例並設置不 同的屬性了。如前所述,我們將使用 EMF API 來最大程度地提高性能。
EObject eObject = EcoreUtil.create(employeeClass);
// Note: we could cast the object to DataObject,
// but chose to use EObject APIs instead.
eObject.eSet(employeeNameFeature, name);
eObject.eSet(employeeNumberFeature, new Integer(number));
... ...
可以使用“employees”引用把雇員“鏈接”在一起,比如:
((List)bigBoss.eGet(employeeEmployeesFeature)).add (terence);
一旦創建了數據對象,還需要將其連接到數據圖中。我們首先要調用數據圖 的 setRootObject() 方法,傳遞希望用作根的數據對象,這裡使用 Employee The Boss 。
EDataGraph employeeGraph = SDOFactory.eINSTANCE.createEDataGraph();
... ...
employeeGraph.setERootObject(rootObject);
繼續討論數據圖之前,要先開始記錄日志。如果希望使用 SDO,那麼在改動 數據圖之前,要先調用其變更摘要的 beginLogging() 方法。基本的原理就是清 除以前的變化,開始監聽新的修改。
// Call beginLogging() so that the Change Summary is
// populated when changes are applied to the Data Graph.
// The DMS should call beginLogging() and endLogging(),
// not the client.
employeeGraph.getChangeSummary().beginLogging();
DMS 的另一項任務(按照 EmployeeDataMediator 接口的定義)是根據 SDO 客戶機提供的數據圖更新後端數據源。
DMS:更新數據源
DMS 應該使用 SDO 的強大特性更新後端數據源,具體地說,就是要使用其變 更摘要。使用數據圖的變更摘要有許多不同的方法。該例中,我們將考察變更摘 要樹中引用的所有數據對象,並從中獲得新的數據對象。
清單 4. DMS 根據數據圖更新後端數據源
/** * Update the DMS's backend data to reflect changes * in the data graph. * Since this DMS has no actual backend data and therefore * has nothing to update, we will just navigate * the change summary and report (print) what's changed. */ public void update(DataGraph dataGraph) { ChangeSummary changeSummary = dataGraph.getChangeSummary(); // Call endLogging to summarize changes. // The DMS should call beginLogging() and endLogging(), // not the client. changeSummary.endLogging(); // Use SDO ChangeSummary's getChangedDataObjects() method. List changes = changeSummary.getChangedDataObjects(); for (Iterator iter = changes.iterator(); iter.hasNext();) { DataObject changedObject = (DataObject)iter.next(); System.out.print("DMS updating " + changedObject.getString("name")); for (Iterator settingIter = changeSummary.getOldValues( changedObject).iterator(); settingIter.hasNext();) { ChangeSummary.Setting changeSetting = (ChangeSummary.Setting)settingIter.next(); Property changedProperty = changeSetting.getProperty(); Object oldValue = changeSetting.getValue(); Object newValue = changedObject.get(changedProperty); System.out.print(" (changed: " + changedProperty.getName() + " from \"" + oldValue + "\" to \"" + newValue + "\")"); // If not a simple example, we could update the backend here. } System.out.println(); } }
該例中根本沒有後端更新。但在實際應用時,後端更新應該在這個方法中完 成。
DMS 首先要對數據圖的更新摘要調用 endLogging() ,從客戶機取回數據圖 ,以便進行後端更新。這樣將關閉變更記錄,從而提供自 beginLogging() 調用 以來(通常在創建之後調用)對數據圖所做修改的摘要。這種格式支持 DMS 高 效、遞增地更新後端數據源。變更摘要中的修改分為三種類型:
對象變更包含數據圖中屬性已經被修改的那些數據對象的引用、被修改的屬 性和修改之前的屬性值。DMS 可以使用原來的屬性值確保後端數據在此期間沒有 被別的人修改。
對象創建包含添加到數據圖中的數據對象。將這些對象表示了需要添加到後 端數據結構中的新數據。
對象刪除包含從數據圖中刪除的數據對象。這些對象表示了需要從後端數據 結構中刪除的數據。
注意,我們使用標准的 SDO API 檢查數據圖的變化,雖然也可以使用 EMF ChangeDescription API(而不是 SDO 的 ChangeSummary)。該例中僅僅更新簡 單的屬性值,對性能的影響不是很明顯。但在其他情況下,比方說要更新大量的 屬性,使用 EMF API 可以顯著地提高性能。比如,假設要從數百個雇員的列表 中刪除一個雇員。在這種情況下,ChangeSummary 只能提供對原有數百個雇員列 表中的原有值的訪問。而 EMF 的 ChangeDescription 接口還可以提供更具體的 信息,如“刪除某個索引位置的雇員”,這就有用得多。
還要注意的是,該變更摘要中只修改了一個對象,沒有刪除或者添加對象。 如果使用 SDO 實現從數據圖中刪除對象,還要注意類型為 objectsToAttach 的 元素。該名稱實際上是對象刪除的 EMF ChangeDescription 名。這些元素是那 些已經刪除但是在回滾時需要放回圖中的數據對象,這就是變更的 EMF 視圖。 總而言之, objectsToAttach == deleted objects(刪除的對象) 。
調試應用程序
如果在示例應用程序中將 debug 變量設為 true ,那麼就可以執行以下調用 ,查看數據圖的序列化版本。
((EDataGraph) dataGraph).getDataGraphResource().save (System.out, null);
還可以使用 Eclipse 調試環境。比如,我們建議在 SDOClient.java 第 100 行設置一個斷點,並調試 SDOClient (像在 Java 應用程序中那樣)。然後, 在調試窗口中就可以看到內存中的數據圖(在 Variables 下)和它的數據對象 (Boss、Terrence Shorter 等),如圖 4 所示。
圖 4. 在調試模式下觀察數據對象
還可以用這種方法查看變更摘要,如圖 5 所示。
圖 5. 在調試模式下觀察變更摘要
上面的截屏圖看起來很復雜,現在看來用處也不大,但是當您調試自己的 SDO 應用程序並查看數據對象和變更摘要的內容時,就會用到它。
結束語
本文簡要描述了 SDO 及其功能。我們通過一個示例應用程序說明了 SDO 的 一些功能。更多參考信息,請參閱 Eclipse 幫助系統下的 SDO API 文檔。該規 范仍在發展和改進之中。比如,SDO 1.0 強調了 SDO 的客戶機方面,而沒有指 定一個 DMS API。SDO 目前正通過 JCP 實現標准化,請關注有關的進展情況。 因為 SDO 非常靈活,設計 SDO 應用程序時需要做很多決策。這些決策將影響程 序的重用性和性能。因此,在編碼之前,應該認真考慮應用模式和應用程序數據 的特征。
本文配套源碼