japan.internet.com The Internet & IT Network


RSSニュース検索
カテゴリ
> トップページ
> Webビジネス
> Eコマース
> Webファイナンス
> Webマーケティング
> パブリック
> Webテクノロジー
> 携帯・ワイヤレス
> Linux Today
> Linux Tutorial
> J.I.C.ブログ
キャリア
> 転職ならen
> 派遣ならen
> アルバイトならen
> IT求人情報
ヘッドライン
> 今日のヘッドライン
> 週間ヘッドライン
Special Link
> フォトコミュニティ
> ストックフォト
> クリップアート
> イラスト
> フェリカ
> Web2.0
> 写真
イベント&セミナー
> イベントカレンダー
> 書評「IT の耳」
> 出張・接待検索
> ニュースガジェット 注目
無料ニュースメール
> 新規登録
> 変更・解除
> オプトインメールの登録・変更・解除
インフォメーション
> パートナーサイト
転職ならエン
就職ならen
求人ならen
履歴書ならen
アルバイトならエン
CRM/SFAならオラクル
> 会社概要地図
> グループ会社
株式会社アエリア
(株)サンゼロミニッツ
株式会社エアネット
> お問い合わせ
> 広告掲載について
> リンクについて
> 著作権について
> その他お問い合わせ
> 利用規約
> 個人情報保護方針
デベロッパー 2008年4月22日 10:00
デベロッパー・バックナンバー
XMLデータの変更をSDOで簡単に追跡する

著者: Young Yang  オリジナル版を読む プリンター用 記事を転送
2008年4月22日 10:00 付の記事
海外internet.com発の記事
このエントリーを含むはてなブックマーク この記事をクリップ! Buzzurlにブックマーク Yahoo!ブックマークに登録 newsing it!

はじめに

 データの変更を追跡することは、多くのソフトウェア、アプリケーション、およびビジネス統合シナリオで必要とされる基本機能です。一般的な変更のデルタ(差分)をモデル化し、取り扱うことは非常に込み入った作業であり、この基本機能を厳密に実装することは比較的難しい課題です。一方で、すべてのアプリケーションにこの機能を重複して実装するのは無駄です。デルタ処理モデルは同じものをさまざまな状況に応用できますし、大半のケースで求められる機能はよく似ているからです。BEA Systems社とIBM社の主導で進められているService Data Object(SDO)は、異種データアクセスのための汎用ソリューションを定義するJSRで、開発者はこのメカニズムを使用してシステムレベルのデータ履歴追跡機能を簡単に実装できます。

 この記事では、SDOのJava実装であるApache Tuscanyバージョン1.0を使って、XMLデータをSDOで処理する方法の例を示します。SDOは(まだ)XML処理の標準ソリューションではないため、SDOの基本XMLデータ操作についても説明して、前後関係を明らかにします。

3フェーズからなるXMLデータ処理

 この記事のXMLデータ処理例では、次の3つのフェーズがそれぞれ別のグループによって担当されることを前提とします。

  1. 作成
  2. 処理
  3. 元に戻す
 XMLデータは、ファイルシステムを通じてこれらの3フェーズ(および3グループ)間でやり取りされます。この例の基本シナリオはこうです。最初のグループが作成したXMLファイルに第2のグループが変更を加え、この変更を記録します。この記録は、第3のグループがXMLデータを元に戻すときに利用されます。Microsoft Wordの変更履歴機能を使用したことがあれば、この機能の値打ちがすぐに理解できるでしょう。

 この種の機能は、多くのアプリケーションで必要とされます。たとえば、オプティミスティック同時実行制御や、オフラインアプリケーションデータと稼動中データベースとの同期、ビジネスプロセス管理(BPM)システムなどを実装するには不可欠です。以降のセクションでは、SDOを利用してこれらの機能を簡単に実装できることをサンプルコードを示して説明します。

 サンプルのXMLデータ(基はSDO 2.1.0仕様書のサンプル)は、注文処理をモデル化したものです(スキーマ「po_original.xsd」についてはリスト1を参照)。次のセクションでは、SDOを使ってこのスキーマに基づく注文処理を作成し、ファイルシステムに永続化する手順を説明します。このサンプルでは動的APIを使用します。SDOではあらゆるデータソースを扱うための静的APIもサポートされています。

リスト1 po_original.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.example.com/PO" 
    targetNamespace="http://www.example.com/PO">
    
    <xsd:import namespace="commonj.sdo/xml" schemaLocation="sdo.xsd"/>

    <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
    <xsd:element name="comment" type="xsd:string"/>
    
    <xsd:complexType name="PurchaseOrderType">
        <xsd:sequence>
            <xsd:element name="shipTo" type="USAddress"/>
            <xsd:element name="billTo" type="USAddress"/>
            <xsd:element ref="comment" minOccurs="0"/>
            <xsd:element name="items"  type="Items"/>
        </xsd:sequence>
        <xsd:attribute name="orderDate" type="xsd:date"/>
    </xsd:complexType>

    <xsd:complexType name="StatusType">
        <xsd:sequence>
            <xsd:element name="status"   type="xsd:string"/>
            <xsd:element name="contact"   type="xsd:string"/>
            <xsd:element name="changeDate" type="xsd:date"/>
        </xsd:sequence>
    </xsd:complexType>
    
    <xsd:complexType name="USAddress">
        <xsd:sequence>
            <xsd:element name="name"   type="xsd:string"/>
            <xsd:element name="street" type="xsd:string"/>
            <xsd:element name="city"   type="xsd:string"/>
            <xsd:element name="state"  type="xsd:string"/>
            <xsd:element name="zip"    type="xsd:decimal"/>
        </xsd:sequence>
        <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
    </xsd:complexType>

    <xsd:complexType name="Items">
        <xsd:sequence>
            <xsd:element name="item" minOccurs="0" 
                         maxOccurs="unbounded">
                <xsd:complexType>
                    <xsd:sequence>

                        <xsd:element name="productName" 
                                     type="xsd:string"/>
                        <xsd:element name="price"
                                     type="xsd:decimal"/>
                        <xsd:element name="quantity">
                            <xsd:simpleType>
                                <xsd:restriction 
                                     base="xsd:positiveInteger">
                                    <xsd:maxExclusive value="100"/>
                                </xsd:restriction>

                            </xsd:simpleType>
                        </xsd:element>
                        <xsd:element ref="comment"   minOccurs="0"/>
                        <xsd:element name="shipDate" 
                                     type="xsd:date" minOccurs="0"/>
                    </xsd:sequence>

                    <xsd:attribute name="partNum" 
                                   type="SKU" use="required"/>
                </xsd:complexType>
            </xsd:element>
        </xsd:sequence>
    </xsd:complexType>
    
    <xsd:simpleType name="SKU">
        <xsd:restriction base="xsd:string">
            <xsd:pattern value="¥d{3}-[A-Z]{2}"/>
        </xsd:restriction>
    </xsd:simpleType>
</xsd:schema> 

SDOを使ってXMLを作成、永続化する

 CreatePO.javaクラス(リスト2を参照)で、このサンプルのXML作成フェーズが完結します。このクラスで特に注目する必要があるのは、コメントが付けられた7ヶ所です。

リスト2 CreatePO.java
package com.company.sdo.po;

import commonj.sdo.DataObject;
import commonj.sdo.helper.DataFactory;

public class CreatePO {
     public static void main(String[] args) throws Exception {
     //1. Define Types and Properties with XSD
     Util.definePOTypes();
     
     //2. Create the root DataObject 
     DataObject purchaseOrder = 
     DataFactory.INSTANCE.create(Constants.PO_NAMESPACE, 
                                 "PurchaseOrderType");
     
     //3. Set data type Property for the root DataObject
     purchaseOrder.setString("orderDate", "1999-10-20");         
     
     //4. Create child DataObjects
     DataObject shipTo = purchaseOrder.createDataObject("shipTo");
     
     //5. Set data type Property for the child DataObject
     shipTo.set("country", "US");
     shipTo.set("name", "Alice Smith");
     shipTo.set("street", "123 Maple Street");
     shipTo.set("city", "Mill Valley");
     shipTo.set("state", "CA");
     shipTo.setString("zip", "90952");
     
     DataObject billTo = purchaseOrder.createDataObject("billTo");
     billTo.set("country", "US");
     billTo.set("name", "Robert Smith");
     billTo.set("street", "8 Oak Avenue");
     billTo.set("city", "Mill Valley");
     billTo.set("state", "PA");
     billTo.setString("zip", "95819");
     purchaseOrder.set("comment", "Hurry, my lawn is going wild!");    
     
     DataObject items = purchaseOrder.createDataObject("items");

     //6. Create a child DataObject for the child DataObject “items”
     DataObject item1 = items.createDataObject("item");
     item1.set("partNum", "872-AA");
     item1.set("productName", "Lawnmower");
     item1.setInt("quantity", 1);
     item1.setString("price", "148.95");
     item1.set("comment", "Confirm this is electric");
        
     DataObject item2 = items.createDataObject("item");
     item2.set("partNum", "926-AA");
     item2.set("productName", "Baby Monitor");
     item2.setInt("quantity", 1);
     item2.setString("price", "39.98");
     item2.setString("shipDate", "2007-11-21"); 
    
     DataObject item3 = items.createDataObject("item");
     item3.set("partNum", "998-AA");
     item3.set("productName", "Carpet");
     item3.setInt("quantity", 1);
     item3.setString("price", "439.98");
     item3.setString("shipDate", "2007-12-01");
     
     //7. Persist the XML data to an XML file 
     //Util.storeXML(purchaseOrder,"purchaseOrder", 
     //                             Constants.PO_XML_ORIGINAL);
     /*use the following line instead of the above 
      *                   one for tracking changes*/ 
     Util.storeXML(purchaseOrder,"purchaseOrder", Constants.PO_XML);
    }
}
  1. Define Types and Properties with XSD(XSDでデータ型とプロパティを定義する)― データはXMLスキーマによってモデル化されるため、最初に必要なことは、このスキーマに基づいてSDOのデータ型とプロパティをランタイムに定義することです。この操作を行うのは、UtilクラスのdefinePOTypes()メソッドから呼び出されるXSDHelperです。
  2. public static void definePOTypes() throws Exception {
         FileInputStream fis = new FileInputStream(PO_MODEL_ORIGINAL);
         XSDHelper.INSTANCE.define(fis, null);
         fis.close();
    }
    
    (SDO仕様書の9節に、XMLスキーマエンティティからSDOのデータ型およびプロパティへの実際のマッピングが定められています。詳細については、この節を参照してください)。
  1. Create the root DataObject(ルートデータオブジェクトを作成する)― SDOの動的APIは、データオブジェクト階層(オブジェクト別にプロパティを持つ階層)またはDataGraph(データオブジェクトのグラフをメタデータごとパッケージ化したもの)によって構造化データを表します。SDOのDataFactoryインターフェイスを使って未接続のデータオブジェクトを作成できるため、ここで必要な作業は、注文処理のルートデータオブジェクトを作成することです。
  1. Set data type Property for the root DataObject(ルートデータオブジェクトのデータ型プロパティを設定する)― SDOの場合、注文はデータ型です。スキーマの定義に従うと、注文のデータ型プロパティはorderDateであり、これは日付型です。コメント3の下の行で、orderDateに日付の文字列を設定します。これは、JavaのDateオブジェクトを作成し、DataObjectのsetDate()メソッドを使用することに相当します。
  1. Create child DataObjects(子データオブジェクトを作成する)― データオブジェクトpurchaseOrderには、複数の子データオブジェクトがあります。たとえば、コメント4の下の行では、"shipTo"と名前を指定してshipTo子オブジェクトをpurchaseOrderから直接作成します。これは、DataFactoryを使って未接続のshipToデータオブジェクトを作成し、これをDataObjectのいずれかのsetDataObject()メソッドを使ってpurchaseOrderの子として設定することに相当します。
  2. DataObject shipTo
       = DataFactory.INSTANCE.create(CONSTANTS.PO_NAMESPACE, "USAddress");
    ......
    PurchaseOrder.setDataObject("shipTo", shipTo);
    
  1. Set data type Property for the child DataObject(子データオブジェクトのデータ型プロパティを設定する)― USAddressデータ型の定義に従い、shipToデータオブジェクトにはさまざまなデータ型プロパティが与えられます。コメント5の下の行で、これらのプロパティを作成します。
  1. Create a child DataObject for the child DataObject “items”(子データオブジェクト"items"の子データオブジェクトを作成する)― ここでは、XMLをモデル化した場合のSDOデータモデルの階層的な特性について説明します。ItemsはルートデータオブジェクトpurchaseOrderの子であり、これに複数のitemデータオブジェクトの子が含まれます。
  1. Persist the XML data to an XML file(XMLデータをXMLファイルに永続化する)― SDOの動的APIに用意されたXMLHelperインターフェイスを使って、XMLデータをXMLファイルに永続化できます。コメント7の下のコードで、Utilクラスを呼び出し、メソッドを次のように定義します。
  2. public static void storeXML(DataObject data, String rootElementName,
         String xmlFile) throws Exception {
         OutputStream stream = new FileOutputStream(xmlFile);
         XMLHelper.INSTANCE.save(data, PO_NAMESPACE, 
                                 rootElementName, stream);
         }
    
 永続化した注文処理用XMLファイルは、「po_original.xml」という名前です。

 XML用のSDO動的APIは非常に簡単に使用できるため、DOM APIを使って同等の操作を行うよりもずっと便利です。

 次のセクションでは、SDOの動的APIを使って注文処理に改良を加え、変更を追跡できるようにします。

XMLデータへの変更を記録する

 SDOに定義されたChangeSummaryメカニズムを利用して、変更を追跡し、変更の記録を注文情報と一緒に保管することができます。第二の目的を達するため、XMLスキーマファイル「po_original.xsd」を変更する必要があります(リスト3を参照)。インポートされるスキーマ「sdo.xsd」(SDO 2.1.0のもの)には、ChangeSummaryTypeなどが定義されています。このChangeSummaryTypeの要素をPurchaseOrderTypeに追加します。要素の名前は任意に決めてかまいませんが、ここでは"changes"とします。

リスト3 修正後のpo_original.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.example.com/PO"
    xmlns:sdo="commonj.sdo"
    xmlns:sdoxml="commonj.sdo/xml" 
    targetNamespace="http://www.example.com/PO">
    
    <xsd:import namespace="commonj.sdo/xml" 
        schemaLocation="C:¥¥eclipse¥¥workspace¥¥SDO¥¥src¥¥main
                        ¥¥resources¥¥sdo.xsd" />

    <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
    <xsd:element name="comment" type="xsd:string"/>
    <xsd:element name="status" type="StatusType"/>
    
    <xsd:complexType name="PurchaseOrderType">
        <xsd:sequence>
            <xsd:element name="shipTo" type="USAddress"/>
            <xsd:element name="billTo" type="USAddress"/>
            <xsd:element ref="comment" minOccurs="0"/>
            <xsd:element name="items"  type="Items"/>
            <xsd:element ref="status" minOccurs="1" maxOccurs="1"/>
            <xsd:element name="changes" type="sdo:ChangeSummaryType"/>
        </xsd:sequence>
        <xsd:attribute name="orderDate" type="xsd:date"/>
    </xsd:complexType>

   ......
 </xsd:schema>
 この新規のスキーマを適用するには、Util.javaのdefinePOTypes()メソッドで読み込む必要があります。CreatePO.javaから生成されるXMLファイルは、「po.xml」という名前で永続化されます。「po_original.xml」と異なるのは、「po.xml」に<po:purchaseOrder>の新しいサブ要素<changes logging="false" />が追加されることです。注文は、ProcessPO.javaクラス(リスト4を参照)で処理されます。このプログラムを実行すると、処理された注文が変更の記録と共に「po_processed.xml」(リスト5を参照)に永続化されます。

リスト4 ProcessPO.java
package com.company.sdo.po;

import java.io.FileInputStream;
import commonj.sdo.ChangeSummary;
import commonj.sdo.DataObject;
import commonj.sdo.helper.XMLDocument;
import commonj.sdo.helper.XMLHelper;

public class ProcessPO {
     public static void main(String[] args) throws Exception {
          Util.definePOTypes();
          FileInputStream fis = new FileInputStream(Constants.PO_XML);
          //1.load the XML document
          XMLDocument xmlDoc = XMLHelper.INSTANCE.load(fis);
          
          DataObject purchaseOrder = xmlDoc.getRootObject();

          DataObject items = purchaseOrder.getDataObject("items");
          //2.get the ChangeSummary object
          ChangeSummary chngSum = purchaseOrder.getChangeSummary();
          //3.start logging changes
          chngSum.beginLogging();
          
          /*(i)send bill to Alice Smith instead of Robert Smith*/
          DataObject billTo = purchaseOrder.getDataObject("billTo");
          billTo.setString("name", "Alice Smith");
          
          /*(ii)change quantity for Baby Monitor, item 2*/          
          DataObject item2 = items.getDataObject("item.1");
          item2.setInt("quantity",2);
          
          /*
           * a potential bug in Tuscany SDO, 
           * this line reports exception 
           * when trying to print ChangeSummary in ReviewPO.java
           *      item2.set("comment", 
           *                 "Only consider electricity powered.");
           */          
          /*(iii)remove item 3 from the order*/
          DataObject item3 = (DataObject) items.getDataObject("item.2");
          item3.delete();

          /*(iv)add an item to the order for armed chair*/          
          DataObject item4 = items.createDataObject("item");
          item4.set("partNum", "999-AA");
          item4.set("productName", "Armed Chair");
          item4.setInt("quantity", 1);
          item4.setString("price", "299.95");
          item4.set("comment", "Make sure the cover is leather.");
                  //4.end logging changes 
          chngSum.endLogging();
          //5.print in system console all the changes made above
          Util.printChangeSummary(chngSum);
          Util.storeXML(purchaseOrder, "purchaseOrder", 
                        Constants.PO_PROCESSED_XML);          
     }
}
リスト5 po_processed.xml
<?xml version="1.0" encoding="ASCII"?>
<po:purchaseOrder xmlns:po="http://www.example.com/PO" 
                  orderDate="1999-10-20">
  <shipTo country="US">
    <name>Alice Smith</name>
    <street>123 Maple Street</street>
    <city>Mill Valley</city>
    <state>CA</state>
    <zip>90952</zip>
  </shipTo>
  <billTo country="US">
    <name>Alice Smith</name>
    <street>8 Oak Avenue</street>
    <city>Mill Valley</city>
    <state>PA</state>
    <zip>95819</zip>
  </billTo>
  <po:comment>Hurry, my lawn is going wild!</po:comment>
  <items>
    <item partNum="872-AA">
      <productName>Lawnmower</productName>
      <price>148.95</price>
      <quantity>1</quantity>
      <po:comment>Confirm this is electric</po:comment>
    </item>
    <item partNum="926-AA">
      <productName>Baby Monitor</productName>
      <price>39.98</price>
      <quantity>2</quantity>
      <shipDate>2007-11-21</shipDate>
    </item>
    <item partNum="999-AA">
      <productName>Armed Chair</productName>
      <price>299.95</price>
      <quantity>1</quantity>
      <po:comment>Make sure the cover is leather.</po:comment>
    </item>
  </items>
  <changes create="     ##//items/item[3]" delete="     
                        ##//changes/items[1]/item[3]" 
           logging="false" xmlns:sdo="commonj.sdo">
    <billTo sdo:ref="     ##//billTo">
      <name>Robert Smith</name>
    </billTo>
    <item sdo:ref="     ##//items/item[2]">
      <quantity>1</quantity>
    </item>
    <items sdo:ref="     ##//items">
      <item sdo:ref="     ##//items/item[1]" />
      <item sdo:ref="     ##//items/item[2]" />
      <item partNum="998-AA">
        <productName>Carpet</productName>
        <price>439.98</price>
        <quantity>1</quantity>
        <shipDate>2007-12-01</shipDate></item>
    </items>
  </changes>
</po:purchaseOrder>
 リスト5では変更がXMLファイルに永続化される過程を見ることができますが、それ以上に注目すべきは<changes>要素です。以前よりずっと複雑になっています。この要素には、このプログラムで注文に加えられた変更がすべて記録されます(<changes>要素の実際の内容は、SDO仕様書に定められています)。この要素の内容に記録された情報と変更後のデータを基に、必要であれば元のデータを復元することができます(リスト6に、コンソールに出力される情報を示します)。

リスト6 Util.javaのprintChangeSummary()からの出力
Deleted: org.apache.tuscany.sdo.impl.DynamicDataObjectImpl@19b5217
 (eClass: org.apache.tuscany.sdo.impl.ClassImpl@10a2d64 (name: item)
 (instanceClassName: null) (abstract: false, interface: false))
        --- originally contained in : Items ---
         &&&BEGNNING- deleted -BEGINNING&&& 
         &&&END- deleted -END&&& 
        --- deleted property information --- 
         $$$ name of the property deleted: productName $$$
         ### the deleted property is a data type ###
                         productName: Carpet
         $$$ name of the property deleted: price $$$
         ### the deleted property is a data type ###
                         price: 439.98
         $$$ name of the property deleted: quantity $$$
         ### the deleted property is a data type ###
                         quantity: 1
         $$$ name of the property deleted: comment $$$
                        %%%originally NOT set%%%
         $$$ name of the property deleted: shipDate $$$
         ### the deleted property is a data type ###
                         shipDate: 2007-12-01
         $$$ name of the property deleted: partNum $$$
         ### the deleted property is a data type ###
                         partNum: 998-AA
        --- deleted property information --- 

Created: org.apache.tuscany.sdo.impl.DynamicDataObjectImpl@3b1d04 
(eClass: org.apache.tuscany.sdo.impl.ClassImpl@10a2d64 (name: item) 
(instanceClassName: null) (abstract: false, interface: false))
        --- to be contained in : Items ---
         &&&BEGNNING- newly created -BEGINNING&&& 
                 productName: Armed Chair
                 price: 299.95
                 quantity: 1
                 comment: Make sure the cover is leather.
                 partNum: 999-AA
         &&&END- newly created -END&&& 

Updated:  org.apache.tuscany.sdo.impl.DynamicDataObjectImpl@176e552
 (eClass: org.apache.tuscany.sdo.impl.ClassImpl@12a0f6c
 (name: USAddress) (instanceClassName: null) (abstract: false, 
interface: false))
         &&&BEGNNING- after update -BEGINNING&&& 
                 name: Alice Smith
                 street: 8 Oak Avenue
                 city: Mill Valley
                 state: PA
                 zip: 95819
                 country: US
         &&&END- after update -END&&& 
        --- property update information --- 
         $$$ name of the property updated: name $$$
         ### the property is a data type ###
         from : Robert Smith         to : Alice Smith
        --- property update information --- 

Updated:  org.apache.tuscany.sdo.impl.DynamicDataObjectImpl@12ad19e
 (eClass: org.apache.tuscany.sdo.impl.ClassImpl@10a2d64 (name: item)
 (instanceClassName: null) (abstract: false, interface: false))
         &&&BEGNNING- after update -BEGINNING&&& 
                 productName: Baby Monitor
                 price: 39.98
                 quantity: 2
                 shipDate: 2007-11-21
                 partNum: 926-AA
         &&&END- after update -END&&& 
        --- property update information --- 
         $$$ name of the property updated: quantity $$$
         ### the property is a data type ###
         from : 1         to : 2
        --- property update information --- 

Updated:  org.apache.tuscany.sdo.impl.DynamicDataObjectImpl@281d4b 
(eClass: org.apache.tuscany.sdo.impl.ClassImpl@89cf1e (name: Items)
 (instanceClassName: null) (abstract: false, interface: false))
         &&&BEGNNING- after update -BEGINNING&&& 
                 item (item):
                         productName: Lawnmower
                         price: 148.95
                         quantity: 1
                         comment: Confirm this is electric
                         partNum: 872-AA
                 item (item):
                         productName: Baby Monitor
                         price: 39.98
                         quantity: 2
                         shipDate: 2007-11-21
                         partNum: 926-AA
                 item (item):
                         productName: Armed Chair
                         price: 299.95
                         quantity: 1
                         comment: Make sure the cover is leather.
                         partNum: 999-AA
         &&&END- after update -END&&& 
        --- property update information --- 
         $$$ name of the property updated: item $$$
         ### the property is a DataObject ###
         ### the property is multiple valued ###
         ### total number of the property is : 3 ###
         ### and here are they with status information ### 
                 &&&BEGNNING- untouched -BEGINNING&&& 
                         productName: Lawnmower
                         price: 148.95
                         quantity: 1
                         comment: Confirm this is electric
                         partNum: 872-AA
                 &&&END- untouched -END&&& 
                 &&&BEGNNING- after update -BEGINNING&&& 
                         productName: Baby Monitor
                         price: 39.98
                         quantity: 2
                         shipDate: 2007-11-21
                         partNum: 926-AA
                 &&&END- after update -END&&& 
                 &&&BEGNNING- newly created -BEGINNING&&& 
                         productName: Armed Chair
                         price: 299.95
                         quantity: 1
                         comment: Make sure the cover is leather.
                         partNum: 999-AA
                 &&&END- newly created -END&&& 
        --- property update information --- 
 では、ProcessPO.javaクラスのコードを追って、SDOを使って変更の詳細な記録を取得する手順を細かく検討してみましょう(リスト4を参照)。

  1. コメント1の下にある行で、「po.xml」をランタイムに読み込みます。
  2. コメント2の下の行で、ChangeSummaryオブジェクトを作成し、これをpurchaseOrderデータオブジェクトに関連付けます。
  3. 変更を追跡するため、コメント3の下の行で、ChangeSummaryオブジェクトのロギングをオンにします。
  4. ここからコメント4の下の行(ロギングをオフにする場所)までの間で、purchaseOrderとその子データオブジェクトへのすべての変更をChangeSummaryオブジェクトchngSumに記録する処理を行います。
  5. 変更情報の出力は、コメント5の下の行にあるUtil.javaのprintChangeSummary()メソッドを呼び出して行います(リスト7を参照)。
リスト7 Util.javaのprintChangeSummary()メソッド
public static void printChangeSummary(ChangeSummary chngSum) {
    if (chngSum == null) {
        System.out.println("ChangeSummary is not in existence!");
        return;
    }
        
    for (Iterator it = chngSum.getChangedDataObjects().iterator(); 
         it.hasNext();) {
        DataObject changedObject = (DataObject) it.next();
        System.out.println();

        if (chngSum.isCreated(changedObject)) {
                                //is the changed object newly created
            System.out.println("Created: " + changedObject);
            if (changedObject.getContainer()!=null){
                System.out.println("¥t--- to be contained in : "
                    + changedObject.getContainer().getType().getName()
                    + " ---");
            }else{
                System.out.println(
                  "¥t--- created object has no container --- ");
            }
            printAnnotatedDataObject("newly created",changedObject, 2);
        } else if (chngSum.isDeleted(changedObject)) {
            System.out.println("Deleted: " + changedObject);         

            if (chngSum.getOldContainer(changedObject) != null){
                System.out.println(
                  "¥t--- originally contained in : "
                  + chngSum.getOldContainer(
                      changedObject).getType().getName() + " ---");
            }else{
                System.out.println(
                  "¥t--- deleted object has no container ---");
            }
            // a potential bug in Tuscany SDO, this shows nothing 
            // in ProcessPO.java
            printAnnotatedDataObject("deleted",changedObject, 2);
            
            // drill down to deleted property
            System.out.println(
               "¥t--- deleted property information --- ");
            // a potential bug in Tuscany SDO, 
            // this section shows nothing in ReviewPO.java
            for (Iterator settingIt
                  = chngSum.getOldValues(changedObject).iterator(); 
                  settingIt.hasNext();) {
                printDeletedProperty((ChangeSummary.Setting) 
                  settingIt.next());
            }
            System.out.println(
              "¥t--- deleted property information --- ");
        } else if (chngSum.isModified(changedObject)) {
            System.out.println("Updated:  " + changedObject);
                
            // print out the updated object
            printAnnotatedDataObject("after update", changedObject, 2);
            
            // drill down to changed property
            System.out.println(
               "¥t--- property update information --- ");
             
            for (Iterator settingIt
                   = chngSum.getOldValues(changedObject).iterator();
                 settingIt.hasNext();) {
                ChangeSummary.Setting changeSetting
                 = (ChangeSummary.Setting) settingIt.next();
                printUpdatedProperty(changeSetting, 
                                     changedObject,chngSum);
            }
            System.out.println(
             "¥t--- property update information --- ");
        } else
            System.out.println("Should never come here!");
    }
}
 この方式では、最初にgetChangedDataObjects()を使ってすべての変更されたデータオブジェクトを取得してから、カテゴリ(作成、削除、または変更)に基づいてこれらを処理します。新規に作成されたデータオブジェクトについては、オブジェクトとすべての関連プロパティに関する情報を出力します(SDO仕様書に添付されたサンプルであるprintDataObject()の注釈付きバージョンを呼び出します)。また、このデータオブジェクトのコンテナがあれば、それも表示します。

 削除されたデータオブジェクトについては、そのデータオブジェクトのコンテナがあればまずそれを特定し、printDataObject()を使って出力しようとします。この場合、出力を見てわかるのはApache Tuscany実装からなにも生成されないことです。ただし、削除されたデータオブジェクトを指定してChangeSummaryのgetOldValues()メソッドを呼び出すと、そのオブジェクトのすべてのプロパティと値を取得できます。変更されたデータオブジェクトのプロパティに関するこれらの情報は、内部クラスChangeSummary.Settingに保存されます。このクラスは、プロパティに値が設定されていたかどうかと、設定されていた場合にその古い値が取得できればその値を取得します。

 変更されたデータオブジェクトについては、printDataObject()を呼び出してすべてのプロパティと現在値を確認できます。ChangeSummaryのgetOldValues()メソッドを使うと、すべてのプロパティに対応するChangeSummary.Settingオブジェクトを取得できます。このプロパティ確認作業は、Util.javaのプライベートメソッドprintUpdatedProperty()で行います(リスト8を参照)。

リスト8 util.javaのprintUpdatedProperty()メソッド
private static void printUpdatedProperty(
        ChangeSummary.Setting changeSetting, 
        DataObject changedObject,
        ChangeSummary chngSum) {
    if (changeSetting == null)return;
    Property property = changeSetting.getProperty();
    System.out.println("¥t $$$ name of the property updated: "
                       + property.getName() + " $$$");
    if (!changeSetting.isSet()){
        System.out.println(
          "¥t ### the updated property is originally NOT set ###");
    }
    if (!property.getType().isDataType()) {
                                        // the property is DataObject
        System.out.println("¥t ### the property is a DataObject ###");
        if (property.isMany()) { // multiple valued
            System.out.println(
              "¥t ### the property is multiple valued ###");
            List objects = (List) changedObject.get(property);
            System.out.println(
              "¥t ### total number of the property is : "
              + objects.size() + " ###");
            System.out.println(
              "¥t ### and here are they with status information ### ");
            for (Iterator objIt = objects.iterator(); 
                 objIt.hasNext();) {
                DataObject itObj = (DataObject) objIt.next();
                if (chngSum.isCreated(itObj)) {
                    printAnnotatedDataObject("newly created", itObj, 3);
                } else if (chngSum.isModified(itObj)) {
                    printAnnotatedDataObject("after update", itObj, 3);
                } else {
                    printAnnotatedDataObject("untouched", itObj, 3);
                }
                    
            }
        } else { // single valued
            System.out.println(
              "¥t ### the property is single valued ###");
            printAnnotatedDataObject("after update",
                 (DataObject) changedObject.get(property), 2);
        }
    } else { // the property is a data type
        System.out.println("¥t ### the property is a data type ###");
        System.out.println("¥t from : "
                            + changeSetting.getValue() 
                            + "¥t to : " 
                            + changedObject.get(property));
    }
}
 printUpdatedProperty()メソッドの主要部分では、最初にプロパティがデータ型であるか、データオブジェクトであるかを判断します。データオブジェクトの場合は、複数値(アイテムなど)のプロパティであるか、単一値(billToなど)のプロパティであるかをチェックします。複数値プロパティの場合は、値が作成済み、変更済み、または未操作のいずれであるかをチェックし、最後にprintDataObjectを呼び出します。DataObject型の単一値プロパティの場合は、printDataObject()を直接呼び出します。プロパティがデータ型である場合は、printUpdatedProperty()メソッドからSetting.getValue()が呼び出されて古い値が取得され、DataObjectのget(Property prop)が呼び出されて現在の値が取得されます。

 Util.javaのプライベートメソッドprintDeletedProperty()の場合も、基本的なロジックはこれと同じです。違いは、削除されたデータオブジェクトのプロパティには現在の値が存在しないことです。

 システムコンソールの出力においては、プログラムによって直接変更されていない場合でもこのDataObjectアイテムは更新されたと見なされます。これは、子アイテムのデータオブジェクトが変更されたためです。

 次のセクションでは、変更された注文を元に戻す方法を説明します。

別のグループによる変更を元に戻す

 XMLデータ処理の3番目のフェーズでは、次の2つのタスクを実行できる必要があります。

  1. 変更された注文に関する要約情報を出力する。
  2. 処理フェーズで行われたすべての変更の情報を表示する。
 前の変更記録フェーズのように注文をさらに変更することもできますが、このセクションでは、ReviewPO.javaを使ってすべての変更を元に戻す方法を説明します(リスト9を参照)。コメント2「Shows the information in the modified purchase order」(変更された注文の情報を表示する)の下の行では、上記の最初のタスクを実行します。このコードの意味については、もう説明の必要はないでしょう。コメント3「Display changes made in the second phase」(2番目のフェーズで行われた変更を表示する)の下にあるprintChangeSummary()呼び出しによって、ProcessPO.javaで行われた変更がシステムコンソールに再度出力されます。

リスト9 ReviewPO.java
package com.company.sdo.po;

import java.io.FileInputStream;
import java.util.List;

import commonj.sdo.ChangeSummary;
import commonj.sdo.DataObject;
import commonj.sdo.helper.XMLDocument;
import commonj.sdo.helper.XMLHelper;

public class ReviewPO {

     public static void main(String[] args) throws Exception {
          
         Util.definePOTypes();
          FileInputStream fis
            = new FileInputStream(Constants.PO_PROCESSED_XML);
          //1. load the processed purchase order
          XMLDocument xmlDoc = XMLHelper.INSTANCE.load(fis);
          
          DataObject purchaseOrder = xmlDoc.getRootObject();
          //2. Shows the information in the modified purchase order
          System.out.println();          
          System.out.println(
             "---received purchase order information---");
          System.out.println("Order date: " 
                             + purchaseOrder.get("orderDate"));
          System.out.println("Order comment: "
                              + purchaseOrder.get("comment"));
          
          DataObject shipTo = purchaseOrder.getDataObject("shipTo");
          System.out.println("Ship to name: ");
          Util.printDataObject(shipTo,1);

          DataObject billTo = purchaseOrder.getDataObject("billTo");
          System.out.println("Bill to name: ");
          Util.printDataObject(billTo,1);          

          DataObject items = purchaseOrder.getDataObject("items");     
          List itemList = items.getList("item");
          System.out.println("Ordered items: ");
          for (int i = 0; i < itemList.size(); i++) {               
               DataObject item = (DataObject) itemList.get(i);
               System.out.println("¥tItem " + (i+1) + " :" );
               Util.printDataObject(item,2);
          }
          
          //3. Display changes made in the second phase 
          System.out.println();
          System.out.println("---review changes in purchase order ---");
          ChangeSummary chngSum = purchaseOrder.getChangeSummary();
          Util.printChangeSummary(chngSum);
     
          //4. Undo all changes in the second phase
          System.out.println();
          System.out.println(
             "---action taken after reviewing the changes---");      
          /*
           * should really work on changes here, 
           * ChangeSummary only has a undoChanges() method;
           * ideally should have methods such as:
           * (1) restore() for deleted data object,
           * (2) delete() for newly added object, and
           * (3) revoke() for modified object
           * and those methods should apply directly 
           * on the data objects or properties
           */          
          System.out.println("¥t###undo all changes###");
          chngSum.undoChanges();          
          
          //5. Modify the purchase order on the original version 
          System.out.println();
          System.out.println(
            "---changes made in purchase order review---");
          chngSum.beginLogging(); 
                        //this clears old change summary information
          billTo.set("name", "Alice Smith");
          chngSum.endLogging();
          
          //6. print to the system console the new modifications
          Util.printChangeSummary(chngSum);          
          
          //7. persist the reviewed version to an XML file 
          Util.storeXML(purchaseOrder,"purchaseOrder", 
                        Constants.PO_REVIEWED_XML);
     }
}
 この2番目のタスクは、前のセクションのChangeSummaryの出力処理とは違います。前のセクションでは、JavaオブジェクトとしてのChangeSummaryに直接基づいて出力を実行しました。今回は、変更の要約がXMLファイルからランタイムに再度読み込まれます。この違いは、出力を比較すると明らかになります。前のセクションの出力では、削除アイテムに関してprintDataObject()からはなにも生成されませんが、printDeletedProperty()を呼び出すと、削除アイテムのすべてのプロパティと値が取得されます。今回の出力処理では、この正反対の結果になります。この不一致は、Apache Tuscany実装のバグと思われます(第二のバグらしきものがリスト2のCreatePO.javaのコメントに見られます)。ここからも、厳密な変更追跡メカニズムを実装することがいかに難しいかがわかります。

 プログラムの残りの部分を見ていきましょう。コメント4「Undo all changes in the second phase」(2番目のフェーズで行った変更をすべて元に戻す)以下ではChangeSummaryのundoChanges()メソッドを呼び出し、コメント5「Modify the purchase order on the original version」(元のバージョンの注文を変更する)以下では元に戻したばかりの注文に簡単な変更を加えています。永続化されたXML「po_reviewed.xml」を参照して、以上の操作の結果を確認してください。

SDOの明るい未来

 今後、SDOはEclipse、BEA AquaLogic Data Services Platform(ALDSP)、IBM WebSphere Process Serverなどの主要なオープンソースソフトウェアや商用ソフトウェアだけでなく、Java、C++、PHPなどのさまざまな言語にも実装される予定です。

 2007年、SDO界に2つの大きな前進が見られました。

  1. 3月、Open SOAはSDO仕様をOASISに提出すると発表しました。
  2. 4月、SDOをJava EEの将来のバージョンでサポートすることを検討するとJCPが公式に発表しました。
 Apache TuscanyからもSDO Java実装が最近リリースされました。以上を総合すると、SDO採用の動きはますます盛んであると言えるでしょう。

 この記事は、SDOの一機能を紹介したに過ぎません。他にも、パワーあふれる便利な機能がたくさんあります。SDOテクノロジを丹念に調べれば、サービスドメインにおけるデータ管理に広く求められる機能を簡単に実現する方法が他にも見つかることでしょう。

謝辞
 この記事の初稿とサンプルソースコードを校閲し、貴重な意見を提供していただいたLaxma Reddy氏に感謝いたします。

著者紹介

Young Yang(Young Yang)
ウォール街の金融会社に勤務する上級エンタープライズアーキテクト。数学博士号を取得。IBM社のeビジネスデザイン、DB2管理、ビジネスインテリジェンス、XMLおよび関連テクノロジ、WebSphere Application Serverの認定資格、BEA社のWebLogic Application Serverの認定資格、Sun社のエンタープライズアーキテクトその他の認定資格を保有。


関連記事
  • 日立ソフト、修正箇所の問題点のみを抽出する Java コード診断ツールを販売
  • Microsoft が EU の政府調達から最長5年間締め出される可能性
  • エス・アイ・サービス、SAPシステム専用接続アダプタ「ConnectPlus」最新版を発表
  • Java 3Dの変換処理を理解する
  • SRA、PowerBuilder から Java、C# へのマイグレーションサービスを開始


  • 関連テーマ
  • SOA


  • ★最新トップニュース
    国内 Adobe Flash Player 10 パブリックベータ版を公開(Webテクノロジー 5月16日 18:10)
    米国 Adobe Systems は、2008年5月15日、「Adobe Flash Player 10」(コードネーム:Astro)のパブリックベータ版を Adobe Labs で公開したことを発表した。
    国内 【今週の Web ミミズク】CBS の高価な買い物、グリッドは地球を救えるか、四川州地震のネット募金(Webファイナンス 5月16日 18:00)
    今週のビッグニュースは、なんといっても、CBS による CNET の買収だ。買収総額は18億ドル、だそうだが、この金額は高いか、安いか。
    国内 TI、WUXGA 対応の「.95 WUXGA DLP チップ」を発表、対応 DLP プロジェクタ製品も登場(Webテクノロジー 5月16日 17:50)
    Texas Instruments(TI)は、2008年5月13日、同社初となる1,920×1,200ピクセルの解像度を持つ WUXGA プロジェクタ向けの「.95 WUXGA DLP チップ」を発表した。
    国内 社会保険庁の国民年金保険料クレジットカード収納業務を GMO-PG が受託(パブリック - ニュース 5月16日 17:30)
    非対面クレジットカード決済事業を展開する、GMO ペイメントゲートウェイ株式会社(GMO-PG)は、2008年8月1日から2009年3月31日まで、社会保険庁の国民年金保険料のクレジットカード収納に係るカード番号管理等の業務を受託すると発表した。
    海外 【中国】中国移動、中国 TD 規格を5月末に 3.5G 規格にアップグレード(携帯・ワイヤレス 5月16日 17:00)
    5月15日、中国国内メディアの報道によれば、中国移動(チャイナ・モバイル)は5月末に TD 規格(TD-SCDMA:中国独自の 3G 通信規格)を3.5G 規格(TD-HSDPA)にアップグレードさせることを明らかにしたという。
    トピックス
    > オススメのIT系求人情報【毎週月曜日更新】
    footer_301.gif


    リサーチ
    > デイリーリサーチDLサイト
    > OnlineResearchPortal (リサーチデータバンク)
    > モバイルリサーチ with goo
    footer_301.gif
    キーワード
    > Youtube > BlackBerry
    > CGM > SaaS
    > アクセス解析 > LPO
    > テーマ一覧はこちら
    footer_301.gif
    セミナー情報
    > 第1回インターネットコムマーケティングセミナー「新規クライアントを効率的に獲得する Web マーケティング手法とは」(3月26日)多数のご参加ありがとうございました
    footer_301.gif
    デベロッパー
    > DevX
    > CodeGuru
    > developer.com
    footer_301.gif
    j.i.c.ブログ
    ブログ一覧
    Graphic Design Forum 【Graphic Design Forum】
    経済の混乱とフリーランス (5月16日)
    データメーション 【データメーション】
    IT 業界の女性について:(ハッと息をのむ)ある少女の観点(5月16日)
    ジュピターメディア創設者がITを斬る 【ジュピターメディア創設者がITを斬る】
    CNET が CBS に買収(5月16日)
    ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」 【ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」】
    「微生物、たんぱく質に隠された無限の可能性に挑戦!!」/株式会社サティス製薬(5月16日)
    japan.internet.com テクノログ 【japan.internet.com テクノログ】
    5月4日(日)〜5月10日(土)(5月13日)
    最新テクノロジーの意外な処方箋 【最新テクノロジーの意外な処方箋】
    アクセンチュア・テクノロジー・ラボプロジェクト:REST(Reducing Effort in Script-based Testingスクリプトテストの負荷軽減)(5月12日)
    footer_301.gif
    最新コラム一覧
    IT マネジメント IT マネジメント

    Steve Ballmer 氏が辞任すべき理由(5月16日)
    15 seconds 15 seconds

    AJAX SlideShowおよびTreeViewコントロールを使用してスライドショーを作成する(5月16日)
    最新アフィリエイト事例にみる成功の法則 最新アフィリエイト事例にみる成功の法則

    アフィリエイト市場動向(5月16日)
    最新ハイテク講座 最新ハイテク講座

    全自動からオゾンの力まで!ハイテク洗濯機の最新事情(5月16日)
    百式のネットビジネス研究 百式のネットビジネス研究

    手書き入力で中国語を検索できる辞書サイト「nciku」(5月16日)
    週刊-サイト別アクセス状況データ 週刊-サイト別アクセス状況データ

    ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(5月15日)
    「IT の耳」 「IT の耳」

    【書評】『ウェブを変える10の破壊的トレンド』(5月15日)
    検索エンジンマーケティング 検索エンジンマーケティング

    中国検索エンジン市場シェアを巡る攻防(5月15日)
    気になるオープンソースソフトウェア 気になるオープンソースソフトウェア

    オープンソースのアプリケーションサーバー Apache Geronimo(5月15日)
    気になるトレンド用語 気になるトレンド用語

    ネットの危機?自由が奪われる「青少年インターネット規制法案」(5月14日)
    footer_301.gif
    専門チャンネル
    > セキュリティチャネル > テレコムチャネル
    > サーチエンジンウォッチ
    footer_301.gif
    海外のインターネットコム アメリカ韓国ドイツトルコ
    関連企業のサイト:ストックフォト イラスト ネットストリート ホテル予約サイト タウン情報 出張 事業継承 シミュレーション トランクルーム 優待映画チケット 田舎暮らしガイド オリジナルTシャツ ニタコエ
    Copyright 2008 Jupitermedia Corporation All Rights Reserved. http://www.internet.com/
    space.gif space.gif