データ サービス開発者ガイド

     前  次    新しいウィンドウで目次を開く     
ここから内容の開始

データ サービスを介した更新の処理

AquaLogic Data Services Platform はリレーショナル データ ソースの更新を自動的に処理します。 Web サービスなどの非リレーショナル データ ソースも更新できます。

非リレーショナル ソースの場合、更新ロジックは常に、論理または物理データ サービスに関連付けられた更新オーバーライド クラスを通じて提供されます。 また、リレーショナル データ ソース用のカスタムの更新ロジックを提供することもできます。

この章では、データ サービスの更新オーバーライド クラス (更新動作を構成するクラス) を作成する方法について説明します。 この章の内容は以下のとおりです。

この章を読む際は、データ サービスを通じてエンタープライズ情報にアクセスおよび更新する機能をアプリケーション開発者に提供する、という全体的な目的を心に留めておくことが重要です。

アプリケーション開発者の観点からすると、サービス データ オブジェクト (SDO) Mediator API は、データ サービスを通じて情報を流すための手段です (同様に、AquaLogic Data Services Platform コントロールも同じ目的で使用できます)。 データ サービスに適用される SDO の詳細については、『クライアント アプリケーション開発者ガイド』の「データ プログラミング モデルと更新フレームワーク」を参照してください。

 


ソース データの更新

更新オーバーライド クラスは、以下のような更新フレームワーク アーティファクトにプログラム的にアクセスできます。

使用できる内容は、次のように、データ サービス コンテキストによって異なります。

図 9-1 は、更新オーバーライド内のコンテキストの可視性を示したものです。

図 9-1 更新オーバーライド内のコンテキストの可視性

更新オーバーライド内のコンテキストの可視性

更新オーバーライドと物理データ サービス

物理レベルのデータ サービスに対して更新オーバーライド クラスを実装する場合の考慮事項は以下のとおりです。

リレーショナル データ サービスの更新オーバーライドに関する追加の考慮事項は次のとおりです。

非リレーショナル物理データ サービスの場合、performChange( ) メソッドでは次のようにする必要があります。

 


更新オーバーライドとは

更新オーバーライドは、デフォルトの更新プロセスをカスタマイズするか完全に置き換えるためのメカニズムを提供します。

データ サービスに関連付けられた更新オーバーライドを使用すると、以下のことを行えます。

更新オーバーライドのより概念的な説明については、AquaLogic Data Services Platform の『コンセプト ガイド』の「サービス データ オブジェクト (SDO) の使用」の「データの更新」を参照してください。

更新オーバーライドは Java クラス

プログラミングの点から見ると、更新オーバーライドは、AquaLogic Data Services Platform API の 1 つである UpdateOverride インタフェース (<UpdateOverride>) を実装したコンパイル済みの Java ソース コード ファイルです。 この API は com.bea.ld.dsmediator.update パッケージにあります。 UpdateOverride インタフェースには performChange( ) という名前の空のメソッドが 1 つあります。

このメソッドがアプリケーション開発者にどのように使用されるのかを理解しておくことは重要です。 コード リスト 9-1 に示すように、performChange( ) メソッドは DataGraph オブジェクトを取ります (dsmediator.update パッケージまたはメディエータによって渡されます)。 更新オーバーライド クラスはこのメディエータ オブジェクトを処理します。 DataGraph にはデータ オブジェクト、オブジェクトに対する変更、およびメタデータなどの他のアーティファクトが格納されます (『クライアント アプリケーション開発者ガイド』の「データ プログラミング モデルと更新フレームワーク」を参照してください)。

コード リスト 9-1 UpdateOverride インタフェース
package com.bea.ld.dsmediator.update;

import commonj.sdo.DataGraph;
import commonj.sdo.Property;

public interface UpdateOverride
{
public boolean performChange(DataGraph sdo)
{

}
}

コード リスト 9-1 の performChange( ) メソッド シグネチャからわかるように、メソッドはブール値を返します。 この値は次のように、メディエータに対するフラグの役目を果たします。

更新オーバーライドが更新処理に与える影響

オーバーライドされるデータ サービスにバインドされているオブジェクトに対して送信が発行されると、performChange( ) メソッドが実行されます。

submit( ) で渡されるオブジェクトが DataService オブジェクトの配列である場合、配列はシングルトン DataService オブジェクトのリストに分解されます。 これらのオブジェクトは追加、削除、または変更されている可能性があるため、更新オーバーライドは複数回 (つまり、変更されたオブジェクトにつき 1 回ずつ) 実行される可能性があります。

アプリケーション開発者は、実行時に渡されるデータグラフのルート データ オブジェクトが、(更新オーバーライドがコンフィグレーションされている) データ サービスにバインドされたシングルトン データ オブジェクトのインスタンスであることを検証する必要があります。

 


更新オーバーライド クラスが必要な場合

アプリケーションがデータ サービス関数を実行して非リレーショナル データ ソースを更新する場合は、カスタム更新クラスを作成する必要があります。 Web サービス、XML ファイル、フラット ファイル、および AquaLogic Data Services Platform プロシージャでは、更新が必要な場合は、カスタム更新クラスが必要となります。

同様に、以下のような状況でも、カスタム更新クラスが必要になります。

更新オーバーライド クラスの登録

更新オーバーライド クラスを構成する Java コードを記述してコンパイルしたら、そのクラスをデータ サービスに登録する必要があります。 更新オーバーライドは物理データ サービスまたは論理データ サービスに登録できます。 各データ サービスには [更新オーバーライド クラス] プロパティがあり、そのデータ サービス用の UpdateOverride の実装を構成する特定の Java クラス ファイルと関連付けることができます。

実際の関連付けは WebLogic Workshop のデザイン ビューまたはソース ビューから行えます。 2 つの方法の詳細は次のとおりです。

実行時に、データ サービスは、データサービスでプロパティ設定をもとに識別された UpdateOverride クラスを実行します。 AquaLogic Data Services Platform の『コンセプト ガイド』の「サービス データ オブジェクト (SDO) の使用」の「分解プロセス」を参照してください。

UpdateOverride クラスの開発

更新オーバーライド クラスの作成に関連する一般的な手順は次のとおりです。

  1. AquaLogic Data Services Platform プロジェクト内に新しい Java クラスを作成します。 基本のプロジェクトの場合は、単にデータ サービスと同じディレクトリにクラスを追加します。 大きなプロジェクトの場合は、更新クラスを独自のフォルダに格納することもできます。 または、Java クラス ファイルをクラスパスに追加すると、アプリケーション フォルダ内のどこにでもにクラスを配置できるようになります。
    1. 適切な AquaLogic Data Services Platform API および SDO DataGraph パッケージを、UpdateOverride インタフェースを実装しているクラスにインポートします。
    2. import com.bea.ld.dsmediator.update.UpdateOverride;
      import commonj.sdo.DataGraph;
    3. Java クラス宣言では次のように UpdateOverride インタフェースを実装する必要があります。
    4. public class SpecialOrders implements UpdateOverride
    5. performChange( ) メソッドをクラスに追加します。 このパブリックメソッドは DataGraph オブジェクト (変更されたデータ オブジェクトを格納する) を取り、ブール値を返します。 次に例を示します。
    6. public boolean performChange(DataGraph graph)
    7. performChange( ) メソッドの本文で、処理ロジックを実装します。 処理ロジックでは次のことができます。
    • 変更されたオブジェクトにアクセスする。
    • 新しいデータ オブジェクトをインスタンス化する。
    • 送信オブジェクトを変更する。
    • メディエータの更新プランと分解マップにアクセスする。
    • データ サービス プロシージャを呼び出す。
    • JPD を呼び出す。
  2. Java ソース コードをコンパイルして、クラス ファイルを作成します。
  3. データ サービスに [更新オーバーライド クラス] プロパティを設定して、クラス ファイルを特定のデータ サービスに関連付けます (「更新オーバーライド クラスの登録」を参照してください)。コード リスト 9-2 に、サンプルの更新オーバーライド実装を示します。
  4. コード リスト 9-2 更新オーバーライドのサンプル
    package RTLServices;

    import com.bea.ld.dsmediator.update.UpdateOverride;
    import commonj.sdo.DataGraph;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import retailer.ORDERDETAILDocument;
    import retailerType.LINEITEMTYPE;
    import retailerType.ORDERDETAILTYPE;

    public class OrderDetailUpdate implements UpdateOverride
    {
    public boolean performChange(DataGraph graph){
    ORDERDETAILDocument orderDocument =
    (ORDERDETAILDocument) graph.getRootObject();
    ORDERDETAILTYPE order =
    orderDocument.getORDERDETAIL().getORDERDETAILArray(0);
    BigDecimal total = new BigDecimal(0);
    LINEITEMTYPE[] items = order.getLINEITEMArray();
    for (int y=0; y < items.length; y++) {
    BigDecimal quantity =
    new BigDecimal(Integer.toString(items[y].getQuantity()));
    total = total.add(quantity.multiply(items[y].getPrice()));
    }
    order.setSubTotal(total);
    order.setSalesTax(
    total.multiply(new BigDecimal(".06")).setScale(2,BigDecimal.ROUND_UP));
    order.setHandlingCharge(new BigDecimal(15));
    order.setTotalOrderAmount(
    order.getSubTotal().add(
    order.getSalesTax().add(order.getHandlingCharge())));
    System.out.println(">>> OrderDetail.ds Exit completed");
    return true;
    }
    }

コード リスト 9-2 のサンプル クラスでは、OrderDetailUpdate クラスが UpdateOverride クラスを実装しており、このインタフェースで求められているように、performChange( ) メソッドを定義しています。 コード リストでは、更新オーバーライドの一般的なコーディング パターンが例示されています。

一般的な更新オーバーライドのプログラミング パターン」も参照してください。

リレーショナル データ ソースに対する更新オーバーライドの作成

表 9-3 に示すような場合では、更新オーバーライド ロジックがリレーショナル更新処理で必要になります。

表 9-3 リレーショナル データ ソース用に更新オーバーライドが必要となる問題
問題
説明、例、推奨事項
あいまいなデータ系統
データ サービスの分解関数には、下位レベルのデータ サービスからの代わりの分解を提供する「if-then-else」構文を含めることはできない。
変換の問題
系統に data( ) または rename 以外の変換が含まれる。 たとえば、以下は自動更新ではサポートされない。
<ACCOUNT> { sum(data($C/ACCOUNT)) }; </ACCOUNT>
構成されたプロパティの複数の系統
複数の系統またはデータ ソースを持つ 1 つのプロパティの例は次のとおり。
<customerName>{ cat(data($C/FNAME), " ", data($WS/LAST_NAME)) }; </customerName>
ネストされた一致ロジックの問題
通常、ネストされた包含は where 句を使用して XQuery で表現される。 クエリが where 句を使用してネストを実装していない場合、AquaLogic Data Services Platform は外部キーと主キーの関連付けを判別できない (ネストされた一致ロジックは where 述語句で表現する必要がある)。

たとえば、複合型の要素が複数のソースの値を持つ場合 (つまり、データ オブジェクトに複数のソースからのフィールドが含まれる場合)、where 述語に主キーが含まれないため、where 述語は 2 つのソース間の 1-N のカーディナリティを示さない。
Payments を伴う Orders のような M 対 N の結合は、通常は一般的な結合ではなく、この場合は Orders も Payments も分解されない。
あいまいなタプル識別子
distinct-values または group-by において、重複した一連のタプルから任意のタプルが残されることがある。
冗長なインスタンス値
同じソース値インスタンス (または同じ物理データ ソース値) が SDO で出力され、SDO 内で更新される場合、そのインスタンスは自動的に分解されない。
複合型値の繰り返しの問題
Part 値や Item 値などの複合型では、Part 値が繰り返されて、そのために分解されない場合がある。 次に例を示す。
  • データ オブジェクト値を提供する 2 つのタプルの間のカーディナリティを知ることで、主キーが出力されるか、または派生可能かを判別できる。 タプル間の述部が、一方の側の主キー (tuple1) を識別し、もう一方の側の主キー (tuple2) を識別しなかった場合、tuple1 の値が繰り返される。 tuple1 の値は分解されるが、tuple2 の値は分解されない。 述部が両方のタプルの主キーが同じであると判別した場合は、両方のタプルの値が分解される。
  • データ オブジェクト内で Orders の 2 つのリストが発生した場合、それらの生成に使用された述部が、2 つのリストを切り離すかどうかは不明である。 このケースの検出は行われない。 各インスタンスからの更新は別々の更新として分解される。 データ サービスで選択されたオプティミスティック ロック方式に応じて、2 番目の更新が成功するかどうかや、最初の更新による変更が上書きされるかどうかが決まる。
型一致の問題
分解関数のクエリ プランに型一致ノードがある場合は、SDO のその箇所で分解が停止される。

キーペアを使用した主キーと外部キーの関係のマッピング

ほとんどの RDBMS では、主キーが自動的に生成されます。つまり、リレーショナル データベースをバックエンドとするデータ サービスに新しいデータ オブジェクトを追加する際は、コード内で主キーを戻り値として処理しなければならない場合があるということになります。 たとえば、送信されたオブジェクト データ グラフに新しいデータ オブジェクト (たとえば新しい Customer オブジェクト) が含まれている場合は、必要となる主キーが AquaLogic Data Services Platform によって生成されます。

自動付番主キーのデータ挿入の場合は、新しい主キー値が生成されてクライアントに返されます。 返されるのは最上位レベルのデータ オブジェクト (マルチレベル データ サービスの最上位レベル) の主キーのみで、計算された主キーを持つネストされたデータ オブジェクトは返されません。

AquaLogic Data Services Platform では、挿入されたタプルの最上位レベルの主キーを返すことで、必要に応じて新しい主キーでタプルをフェッチしなおすことを可能にしています。

メディエータは、主キーと外部キーの論理的な関係をキーペアとして保存します (Mediator API の KeyPair クラスを参照)。 KeyPair オブジェクトは、新しいデータ オブジェクトの作成プロセスの間に、外部キー フィールドを設定するために使用するプロパティ マップです。

プロパティがコンテナ内の自動付番主キー (つまり、自動付番された後のデータ ソース内の新しいレコード) である場合は、プロパティの値が親から子へ伝播されます。

KeyPair オブジェクトは、分解マップの隣接するレベル間で、対応するデータ要素を特定するために使用します。KeyPair オブジェクトを使用することで、親 (コンテナ) オブジェクト用に生成された主キー値を、子要素 (そのコンテナに含まれるオブジェクト) の外部キー フィールドに確実にマッピングできます。

例として、図 9-4 に Customers データ サービスの分解におけるプロパティ マッピングを示します。

図 9-4 キーペアによる論理データ サービスのプロパティ マッピング (主キー/外部キー マッピング)

キーペアによる論理データ サービスのプロパティ マッピング (主キー/外部キー マッピング)

AquaLogic Data Services Platform は、データ サービス間の主キーと外部キーの関係を管理します。管理の方法は、以下に示すように、マルチレイヤ データ サービスのレイヤによって異なります。

AquaLogic Data Services Platform では、変更の影響が主キーや外部キーに伝播されます。

たとえば、主キー フィールドが CustID の Customer オブジェクトの配列に、2 つの Customer を挿入したとします。ここで送信を実行すると、その Customer 型を基準とした CustID を名前とし、挿入された各 Customer の新しい主キー値を値として、2 つのプロパティの配列が返されます。

キーの依存関係の管理

AquaLogic Data Services Platform は、更新プロセスの間の主キーの依存関係を管理します。 主キーを識別し、述語文内の外部キーを推量できます。 たとえば、データを結合するクエリでは、次のように値を比較します。

where customer/id = order/id

メディエータは、データ ソースの更新時に、推量されたキーと外部キーの関係に基づいてさまざまなサービスを実行します。

2 つの SDOToUpdate インスタンス (更新プラン内のデータ オブジェクト) の間に述語依存関係があり、コンテナ SDOToUpdate インスタンスが挿入または変更されて、コンテナに含まれる SDOToUpdate インスタンスが挿入または変更された場合、コンテナ SDO が更新のために送信された後に、コンテナ SDO のどの値をコンテナに含まれる SDO に移動すべきかを示すキーペア リストが特定されます。

このキーペア リストは、コンテナ SDO とコンテナに含まれる SDO のフィールドのセットに基づいています。これらは、現在の SDO が作成されたときには等しくなければならなかったものです。キーペア リストは、述語フィールドからこれらの主キーのみを特定します。

キーペアは、コンテナの主キーをコンテナに含まれるフィールドにのみマッピングします。 そうしないと、コンテナの完全な主キーがマップから特定できず、どのプロパティもマッピングされていないと判断されてしまうためです。

キーペア リストには、1 つまたは複数の項目が含まれており、これらによってコンテナ内のノード名や、マップされているコンテナ内のオブジェクトを特定します。

外部キー

SDO の分解の送信によって計算が可能な場合、外部キーの値は親キーの値と一致するように設定されます。

外部キーは、更新プランの生成時に計算されます。

トランザクション管理

メディエータに対する submit( ) は、トランザクションとして動作します。 submit() が成功したか失敗したかに応じて、次のどちらかを実施する必要があります。

ネストされたトランザクション

送信では、常にデータ ソースの即時更新が実行されます。 ネストされたトランザクションのコンテキスト内でデータ オブジェクトの送信が発生した場合、ネスト内に含まれるトランザクションのコミットやロールバックは、送信されたデータ オブジェクトや更新サマリには影響しませんが、そのトランザクションに参加するすべてのデータ ソース更新には影響します。

UpdateOverride からのデータ サービス プロシージャの呼び出し

コード リスト 9-3 では、データ サービス プロシージャを呼び出す更新オーバーライド クラスの例を示します。 UpdateOverride はローカルで (つまり、AquaLogic Data Services Platform サーバ内で) 呼び出されるため、このサンプルでは型指定された Mediator API を使用しています。 ここでは、setCustomerOrder Web サービスの setCustomerOrder( ) に基づくデータ サービスが作成されます。 このサービスには更新関数が含まれていて、同じ名前の副作用関数によってデータ サービスから参照されています。 最後に、更新オーバーライドを実装するクラスが示されています。

詳細は次のとおりです。

まず、Web サービスの更新が定義されます。 更新ロジックについては、RTLApp サンプルの ElecDBTest Web サービス (ElecDBTest.jws) を参照してください。 メソッドは次のとおりです。

setCustomerOrder(String doc);

データ サービス プロシージャ (副作用関数) は以下のデータ サービスで宣言されています。

ld:DataServices/ElectronicsWS/getCustomerOrderByOrderID

宣言は次のとおりです。

(::pragma function <f:function xmlns:f="urn:annotations.ld.bea.com"
kind="hasSideEffects" nativeName="setCustomerOrder"
nativeLevel1Container="ElecDBTest"
nativeLevel2Container="ElecDBTestSoap"
style="document">
<nonCacheable/>
</f:function>::)

これで、更新ロジックを記述できるようになります。 コード リスト 9-3 に、更新ロジックをコメントとともに示します。

コード リスト 9-3 UpdateOverride からのデータ サービス プロシージャの呼び出し
public boolean performChange(DataGraph datagraph){   
String order = "ld:DataServices/ElectronicsWS/getCustomerOrderByOrderID";
System.out.println("INSIDE EXIT >>>> ");
ChangeSummary cs = datagraph.getChangeSummary();
if (cs.getChangedDataObjects().isEmpty()) {
System.out.println("WEB SERVICE EXIT COMPLETE!");
return false;
}
else {
GetCustomerOrderByOrderIDResponseDocument doc = (GetCustomerOrderByOrderIDResponseDocument) datagraph.getRootObject();
try {
Context cxt = getInitialContext();

// データ サービス プロシージャの更新関数を含むデータ サービスのハンドルを取得する

DataService creditDS =
DataServiceFactory.newDataService(cxt,
"RTLApp",
order);
// 副作用関数に渡される xmlbean オブジェクトを作成する

SetCustomerOrderDocument doc1 = SetCustomerOrderDocument.Factory.newInstance();

// xmlbean オブジェクトに SDO からの値を設定する
doc1.addNewSetCustomerOrder().setDoc(doc.getDataGraph().toString());
creditDS.invokeProcedure( "setCustomerOrder",
new Object[]{ doc1 } );
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("UPDATE ERROR: SQL ERROR: " + e.getMessage());Fine
System.out.println("WEB SERVICE EXIT COMPLETE!");
return false;
}
}

コード リスト 9-3 の例には、WebLogic Server インスタンス上でローカルに実行される Web サービスが含まれています。つまり、コンテキストと場所を取得するための設定コードは含まれていません。 Web サービスが WebLogic Server インスタンスのローカルでない場合、コードでは、InitialContext を取得して、適切な場所とセキュリティのプロパティを提供する必要があります。 『クライアント アプリケーション開発者ガイド』の「Java クライアントからのデータ サービスへのアクセス」の「AquaLogic Data Services Platform 用の WebLogic JNDI コンテキストの取得」を参照してください。

コード リスト 9-4 では、参照整合性を高めるために、製品情報をリストの中間から削除して末尾に追加することで更新プランを調整する、更新オーバーライドを示します。

コード リスト 9-4 参照整合性を高める更新オーバーライドの例
	// 項目と製品の間の参照整合性のために、注文、項目、製品を削除する
// 製品は項目の後で削除する必要がある
public boolean performChange(DataGraph graph)
{
DataServiceMediatorContext context = DataServiceMediatorContext.currentContext();
UpdatePlan up =context.getCurrentUpdatePlan( graph, false );
Collection dsCollection = up.getDataServiceList();
DataServiceToUpdate ds2u = null;
for (Iterator it=dsCollection.iterator();it.hasNext();)
{
ds2u = (DataServiceToUpdate)it.next();
if (ds2u.getDataServiceName().compareTo("ld:DataServices/PRODUCT.ds") == 0 ) {
// リストの中間から製品を削除して、末尾に追加する
up.removeContainedDataService( ds2u.getDataGraph() );
up.addDataService(ds2u.getDataGraph(), ds2u );
};
}
context.executeUpdatePlan( up );
return false;
}
}

送信結果のテスト

変更が想定どおりに行われるように、データ サービスの更新は常にテストする必要があります。 テスト ビューを使用して送信をテストできます。 テスト ビューの詳細については、「テスト ビューの使用」を参照してください。

テスト ビューでは、作成したデータ サービス内の単純な更新を素早くテストできますが、より実質的なテストとトラブルシューティングを行うために、更新オーバーライド クラスを使用して、更新の分解マッピングと更新プランを検査することができます。

 


一般的な更新オーバーライドのプログラミング パターン

この節では、一般的な更新オーバーライドのプログラミング パターンを例示するコード サンプルを紹介し、説明します。 内容は以下のとおりです。

更新オーバーライド クラスには performChange( ) メソッドの実装を含める必要があります。プログラミング タスクで必要となるすべてのカスタム コードは、このメソッドの中に用意します。 performChange( ) メソッドは、メディエータによる処理を続行または中断させるブール値を返します。『クライアント アプリケーション開発者ガイド』の「データ プログラミング モデルと更新フレームワーク」の「How It Works: The Decomposition Process」を参照してください。

分解および更新プロセスのオーバーライド

論理データ サービスが適切に更新されるようにするには (つまり、よく設計されたデータ サービスにするには)、どのデータ サービス関数がそのデータを提供しているかに関係なく、データ サービスからのデータの系統を同じにする必要があります。 たとえば、CustomerProfile データ サービスに以下の関数があるとします。

3 つの関数はすべて、同じ基底のデータ サービスから顧客データを取得する必要があります。 したがって、基底のソースに変更を戻して伝播する方法として適切なのは、ある時点で更新された顧客を取得するために 3 つのうちのどの関数を使用したか、ということに左右されない方法です。

可能な場合は、そのようなデータ サービスのデータ統合ロジックをすべて 1 つの関数 (getAllCustomers( ) など) にまとめて、残りのデータ サービス関数を定義するときにその関数を使用する、という方法をお勧めします。 次のような式があれば、

getAllCustomers( )[cid = $custId])

この目的が達成されて、データ マッピングや結合述語などのすべてをデータ サービスの関数ごとに複製する必要がなくなります。

データ サービスのデータを更新する場合、AquaLogic Data Services Platform は、影響を受けるすべてのデータ ソースに変更をどのように伝播するかを調べるために、データ系統を分析します。 このような系統分析を自動的に実行するために、指定されたデータ サービス関数が参照されます (「リバース エンジニアリング」されます)。 参照すべき関数が指定されていない場合は、データ サービス内の最上位の読み取り関数が使用されます。

データ サービス設計者は、データ サービスの指定された (またはデフォルトの) 分解関数が、同じデータ サービス内の読み取り関数に依存しないようにし、系統判別を正確に代行する関数となるように保証する必要があります。 上記の例の getAllCustomers( ) が選択すべき適切な関数となるには、データ サービス内の最初の読み取り関数であるか、プロパティ エディタで分解関数として明示的に指定される必要があります。

選択された分解関数を系統分析の目的に合ったものにすることは、データ サービス設計者の役割です。 この要件に反していると、オプティミスティック ロック エラーなどの予期しない、望ましくない実行時エラーが発生する可能性があります。

注意 : データ サービスで指定された分解関数が同じデータ サービス内の他の読み取り関数を呼び出した場合、エラー状況が生じます。 特に、更新メディエータは実行時にエラーを検出し、内部データ サービス読み取り関数の誤った依存関係についてユーザに報告する例外を送出します。

performChange( ) メソッドを使用する

分解および更新プロセス全体をカスタマイズするために、performChange( ) メソッドは以下のようなルーチンを実装できます。

performChange( ) メソッドで分解を行う場合は、メディエータが自動化された分解を実行しないようにするため、False を返すようにメソッドを設定する必要があります。

データ オブジェクトの内容の増強

performChange( ) メソッドには、変更されたデータ オブジェクト値を検査して、エラーを伝える DataServiceException を生成し、場合によってはトランザクションをロールバックする、というコードを含めることができます。

True を返すと、メディエータは変更されたオブジェクトを使用して更新の伝播を続行します。

データ サービス メディエータ コンテキストにアクセスする

更新の変更プランと分解マップにアクセスするには、最初に、データ サービスのメディエータ コンテキストを取得する必要があります。 コンテキストを使用すると、分解マップの表示、更新プランの生成、更新プランの実行、現在処理されているデータ サービス オブジェクトのコンテナ データ サービス インスタンスへのアクセスなどを行うことができます。

次のコードの抜粋はコンテキストの取得方法を示しています。

DataServiceMediatorContext context =
DataServiceMediatorContext().getInstance();

分解マップにアクセスする

コンテキストを取得したら、次のように分解マップにアクセスできます。

DecompositionMapDocument.DecompositionMap dm =
                   context.getCurrentDecompositionMap();

分解マップを取得したら、その toString( ) メソッドを使用して、XML マップの表示を文字列値として取得することができます。コード リスト 9-5 を参照してください (デフォルトの分解マップにアクセスすることはできますが、変更はできません)。

分解マップへのアクセスに加えて、オーバーライド クラスの更新プランにアクセスすることもできます。 ツリー内の値の変更、ノードの削除、ノードの再配置 (適用される順序の変更) などを行えます。 ただし、更新プランを変更した場合、その変更を保持するには、オーバーライド内でプランを実行する必要があります。 ツリー内の値の変更、ノードの削除または再配置を行うと、更新プランは変更リスト内で変更を自動的に追跡します。

コード リスト 9-5 分解マップの例 (XML の抜粋)
<xml-fragment xmlns:upd="update.dsmediator.ld.bea.com">
<Binding>
<DSName>ld:DataServices/CUSTOMERS.ds</DSName>
<VarName>f1603</VarName>
</Binding>
<AttributeLineage>
<ViewProperty>CUSTOMERID</ViewProperty>
<SourceProperty>CUSTOMERID</SourceProperty>
<VarName>f1603</VarName>
</AttributeLineage>
<AttributeLineage>
<ViewProperty>CUSTOMERNAME</ViewProperty>
<SourceProperty>CUSTOMERNAME</SourceProperty>
<VarName>f1603</VarName>
</AttributeLineage>
<upd:DecompositionMap>
<Binding>
<DSName>ld:DataServices/getCustomerCreditRatingResponse.ds</DSName>
<VarName>getCustomerCreditRating</VarName>
</Binding>
<AttributeLineage>
<ViewProperty>CREDITSCORE</ViewProperty>
<SourceProperty>
getCustomerCreditRatingResult/TotalScore
</SourceProperty>
<VarName>getCustomerCreditRating</VarName>
</AttributeLineage>
...
    </upd:DecompositionMap>
</upd:DecompositionMap>
<ViewName>ld:DataServices/Customer.ds</ViewName>
</xml-fragment>

更新プランのカスタマイズ

送信されたデータ オブジェクト内の値を検証または変更した後で、現在のデータ オブジェクトを以下の関数に渡すことで、関数は更新プランを取得します。

	DataServiceMediatorContext.getCurrentUpdatePlan()

更新プランはいくつかの方法で拡張することができます。

更新プランを実行した後で、performChange( ) メソッドは、メディエータが更新プランを適用しないようにするため、False を返す必要があります。

更新プランを使用すると、更新される値をソースに対して変更できます。 また、更新順序を変更することもできます。

navigateUpdatePlan( ) のような独自のメソッドを使用して、更新プランの内容をプログラム的に表示することができます。 コード リスト 9-6 に示すように、navigateUpdatePlan( ) メソッドは Collection オブジェクトを取り、イテレータを使用してプランを反復的に走査します。

コード リスト 9-6 更新プランの走査
public boolean performChange(DataGraph datagraph){

UpdatePlan up = DataServiceMediatorContext.currentContext().
getCurrentUpdatePlan( datagraph );
navigateUpdatePlan( up.getDataServiceList() );
return true;
}

private void navigateUpdatePlan( Collection dsCollection ) {
DataServiceToUpdate ds2u = null;
for (Iterator it=dsCollection.iterator();it.hasNext();) {
ds2u = (DataServiceToUpdate)it.next();

// SDO の内容を出力する
System.out.println (ds2u.getDataGraph() );

// 格納されている SDO オブジェクトを走査する
navigateUpdatePlan (ds2u.getContainedDSToUpdateList() );
	}
}
単純な更新プランの場合は次のように報告します。
	UpdatePlan
SDOToUpdate
DSName: ... :PO_CUSTOMERS
DataGraph: ns3:PO_CUSTOMERS to be added
CUSOTMERID = 01
ORDERID = unset
PropertyMap = null

ここで、明細とその明細が含まれている注文を一緒に削除する例を検討してみましょう。 元のデータを示したコード リスト 9-7 では、品目 1001 が注文 100 から削除され、次にその注文が削除される更新プランを示しています。

コード リスト 9-7 明細とそのコンテナを削除する例
UpdatePlan
SDOToUpdate
DSName:...:PO_CUSTOMERS
DataGraph: ns3:PO_CUSTOMERS to be deleted
CUSTOMERID = 01
ORDERID = 100
PropertyMap = null

SDOToUpdate
DSName:...:PO_ITEMS
DataGraph: ns4:PO_ITEMS to be deleted
ORDERID = 100
ITEMNUMBER = 1001
PropertyMap = null

この場合、更新プランは次のように実行されます。PO_CUSTOMERS を削除する前に、内包される SDOToUpdates ルーチンが処理されます。 その結果 PO_ITEMS が最初に削除され、次に PO_CUSTOMERS が削除されます。

更新プランの内容が変更された場合は、新しいプランが実行可能になります。 更新終了の時点で False を返して、それ以上の自動化が行われないことを知らせる必要があります。

その後、プランはデータ ソースに伝播可能になります。

更新プランを実行する

更新プランを変更した後で、そのプランを実行することができます。 更新プランを実行すると、メディエータは指定されたデータ ソースに変更を伝播します。

up という名前の変更された更新プランがある場合、次のような文でプランを実行します。

	context.executeUpdatePlan(up);

現在のデータ オブジェクトのコンテナの取得

更新プランに対して処理されるデータ サービスがある場合は、その SDO コンテナを取得できます。 コンテナは分解されて、元の変更されたオブジェクト ツリー内に存在しているはずです。 コンテナが存在しない場合は null が返されます。 次の例を見てみましょう。

	String containerDS = context.getContainerDataServiceName();
DataObject container = context.getContainerSDO();

この例では、Orders データ サービスの更新オーバーライド クラスに対してコンテナを要求すると、処理される Order インスタンスの Customer データ サービス オブジェクトが返されます。 その Customer インスタンスが更新プラン内にある場合は、その Customer インスタンスが返されます。 更新プラン内にない場合は、CustOrders から分解されて返されます。

更新プランは変更内容を示すだけです。 場合によっては、コンテナが更新プラン内に存在しないこともあります。 コードがコンテナを要求すると、存在する場合はコンテナは更新プランから返されます。更新プランに存在しない場合、コンテナはソース SDO から分解されます。

他のデータ サービス関数とプロシージャの呼び出し

更新オーバーライドから他のデータ サービスにアクセスして更新することができます。 メディエータを使用すると、データ オブジェクトにアクセスして、データ オブジェクトの変更と送信を行えます。 または、変更されたデータ オブジェクトを更新プランに追加して、更新プランの実行時に更新することもできます。 データ オブジェクトを更新プランに追加した場合、そのデータ オブジェクトは現在のコンテキスト内で更新されます。データ オブジェクトのコンテナにはデータ サービスの更新オーバーライドの内部でアクセスできます。

DataService Mediator API を使用して更新を実行すると、クライアントから実行された場合と同様に、その送信用に新しい DataService コンテキストが確立されます。 この submit( ) はクライアント送信と同様に動作します。つまり、変更はデータ オブジェクト内に反映されません。 代わりに、この送信による変更を反映するために、オブジェクトを再フェッチする必要があります。

オーバーライドに関する実行時データのサーバ ログへの収集

AquaLogic Data Services Platform はロギングに基底の WebLogic Server を使用します。 WebLogic ロギングは JDK 1.4 ロギング API (java.util.logging パッケージ) に基づいています。 (更新オーバーライドから) ログを開くには、次のように、DataServiceMediatorContext インスタンスを取得して、そのコンテキストの getLogger( ) メソッドを呼び出します。

DataServiceMediatorContext context =
DataServiceMediatorContext().getInstance();
Logger logger = context.getLogger()

適切なログ レベルの呼び出しを発行することで、ログへの書き込みが行えます。 WebLogic Server メッセージ カタログと NonCatalogLogger はメッセージを生成するときに、メッセージの重大度を weblogic.logging.WLLevel オブジェクトに変換します。 WLLevel オブジェクトでは、表 9-5 に影響の低い順から高い順に示された値を指定することができます。

表 9-5 WebLogic Server のログ レベルの定義
レベル
説明
DEBUG
実行時間を含むデバッグ情報。
INFO
情報提供の値を持つ正常なイベント。 このイベントによって、基底のデータベースに対して実行された SQL を確認できる。
WARNING
エラーを引き起こす可能性のあるイベント。
ERROR
エラーを引き起こすイベント。
NOTICE
正常だが重要なイベント。
CRITICAL、ALERT、EMERGENCY
直ちに介入する必要がある重要なイベント。

注意 : 開発時のロギングは以下の場所に書き込まれます。
	<bea_home>\user_projects\domains\<domain_name>

ロギング レベルを指定されると、メディエータは 表 9-6 に示す情報をログに記録します。

表 9-6 AquaLogic Data Services Platform のログ レベル
レベル
情報の対象
収集される情報
通知または要約
クライアントからの各送信
  • 完全修飾データ サービス名
  • 呼び出し時刻
  • 総実行時間
  • ユーザによる呼び出しか、グループによる呼び出しか
情報または詳細
任意のレベルのデータ サービスにおける各送信
完全修飾データ サービス名に関する以下の情報
  • 呼び出し時刻
  • 実行回数
  • 総実行時間
リレーショナル ソースの場合、テーブルごと、SQL 文タイプごとに、以下の情報
  • SQL スクリプト
  • 総実行時間
  • 実行回数
各更新オーバーライド呼び出し
  • オーバーライドされるデータ サービスの名前
  • 呼び出し回数
  • 総実行時間

コード リスト 9-8 では、サンプルのログ エントリを示します。

コード リスト 9-8 サンプル ログ エントリ
<Nov 4, 2004 11:50:10 AM PST> <Notice> <LiquidData> <000000> <Demo - begin client sumbitted DS: ld:DataServices/Customer.ds>
<Nov 4, 2004 11:50:10 AM PST> <Notice> <LiquidData> <000000> <Demo - ld:DataServices/Customer.ds number of execution: 1 total execution time:171>
<Nov 4, 2004 11:50:10 AM PST> <Info> <LiquidData> <000000> <Demo - ld:DataServices/CUSTOMERS.ds number of execution: 1 total execution time:0>
<Nov 4, 2004 11:50:10 AM PST> <Info> <LiquidData> <000000> <Demo - EXECUTING SQL: update WEBLOGIC.CUSTOMERS set CUSTOMERNAME=? where CUSTOMERID=? AND CUSTOMERNAME=? number of execution: 1 total execution time:0>
<Nov 4, 2004 11:50:10 AM PST> <Info> <LiquidData> <000000> <Demo - ld:DataServices/PO_ITEMS.ds number of execution: 3 total execution time:121>
<Nov 4, 2004 11:50:10 AM PST> <Info> <LiquidData> <000000> <Demo - EXECUTING SQL: update WEBLOGIC.PO_ITEMS set ORDERID=? , QUANTITY=? where ITEMNUMBER=? AND ORDERID=? AND QUANTITY=? AND KEY=? number of execution: 3 total execution time:91>
<Nov 4, 2004 11:50:10 AM PST> <Notice> <LiquidData> <000000> <Demo - end clientsumbitted ds: ld:DataServices/Customer.ds Overall execution time: 381>

デフォルトのオプティミスティック ロック ポリシー : 意味と変更方法

ロック メカニズムは同時実行性制御を目的として各種のマルチユーザ システムで使用されています。 同時実行性制御は、システムに同時に関わるユーザの数に関係なく、複数のトランザクションにわたってデータの一貫性を保証するものです。 オプティミスティック ロック メカニズムは、一般に、データのデフォルトの状態をロックするのではなく、更新される (書き込まれる) 時点のデータのみをロックすることから、そのように呼ばれています (「オプティミスティック ロックを有効または無効にする」を参照してください)。

AquaLogic Data Services Platform はオプティミスティック ロック同時実行性制御ポリシーを採用しており、更新が試行された時点でのみデータをロックします。

AquaLogic Data Services Platform の WebLogic Server インスタンスは、送信されたデータ グラフを受け取ると、元のデータ オブジェクトのインスタンス化に使用されたデータの値をデータ グラフ内の元の値と比較して、データ オブジェクトがクライアント アプリケーションによって変更されている間に、そのデータが別のユーザ プロセスによって変更されていないことを確認します。

メディエータは元のフィールドとソースのフィールドを比較します。デフォルトでは、比較のポイントとして [PROJECTED] が使用されます (表 9-7 を参照)。

各テーブルの更新時に比較されるフィールドを指定できます。 主キー カラムは一致する必要があること、BLOB 型と浮動小数点型は比較されない場合があることに注意してください。表 9-7 では、オプティミスティック更新ポリシー オプションについて説明します。

表 9-7 オプティミスティック ロック更新ポリシーのオプション
オプティミスティック ロック更新ポリシー
効果
[PROJECTED]
デフォルト設定。 SDO データ グラフ内の要素とデータ ソースとの 1 対 1 のマッピングを使用して、データ ソースの「更新可能性」を検証する。
更新が完了できることを最も詳細に検証する方法である。ただし、多くの要素が更新に関係している場合には、多数のフィールドが検証されるため時間がかかる。
[UPDATED]
SDO データ グラフ内で変更されたフィールドだけを使用して、データ ソースの変更ステータスを検証する。
[SELECTED FIELDS]
選択されたフィールドを使用して、データ ソースの変更ステータスを検証する。

注意 : AquaLogic Data Services Platform がデータベース テーブルからデータを読み取れない場合は、別のアプリケーションがテーブルをロックしているため、AquaLogic Data Services Platform が発行したクエリは、アプリケーションがロックを解放するまでキューに入れられます。 (WebLogic Server の JDBC 接続プールで) トランザクション アイソレーションを「read uncommitted」に設定することで、この問題を回避できます。 『管理ガイド』の「AquaLogic Data Services Platform アプリケーションのコンフィグレーション」の「トランザクション アイソレーション レベルの設定」を参照してください。

 


AquaLogic Data Services Platform からの JPD の呼び出し

Java カスタム更新クラスを使用すると、さまざまなデータ サービスの更新を処理する JPD ワークフローを作成することができます。 また、JpdService インタフェースを使用して、同期または非同期の JPD を開始するサーバサイド Java コードを作成することができます。

AquaLogic Data Services Platform の他の種類のサーバサイド カスタム機能と同様に、更新オーバーライド インタフェースは実装を容易にするものです。

Java 更新オーバーライドを含むデータ サービスと JPD は、同じ WebLogic Server ドメインで実行することも、別々の WebLogic Server ドメインで実行することもできます。

更新オーバーライドからの JPD の呼び出し

次の例のように、JpdService は、JPD の名前、JPD の開始メソッド、サービス URI、および JPD のサーバの場所と資格を指定して呼び出されます。

JpdService jpd = JpdService.getInstance("CustOrderV1",   "clientRequestwithReturn", env);

JPD はパブリック インタフェースを提供しています (JPD パブリック コントラクトまたはインタフェースのコンパイル済みクラス ファイルを格納した JAR ファイルとして提供されます)。 開発者にとって透過的に、JpdService オブジェクトは標準の Java リフレクション API を使用して、JPD パブリック コントラクトを実装する JPD クラスを見つけます。

サーバサイド更新は Java コードをオーバーライドしてから、メソッド呼び出しの引数として DataGraph を渡します。

Object jpd.invoke( DataGraph sdoDataGraph );

返されるオブジェクトは呼び出された JPD に依存しており、null の場合もあります。 たとえば、最上位の SDO が挿入されてその主キーが自動生成された場合、この SDO が JPD から返されるはずです (コード リスト 9-9 を参照)。

シリアライズされた UpdatePlan 内の最上位 DataObject のキーが、呼び出し側の関数に (バイト配列を構成する) Properties オブジェクトとして返されます。 したがって、次のように、ワークフローからの戻り値はシリアライズされたバイト配列である必要があります。

Properties [] jpd.invoke( byte[] serializedUpdatePlan );

返された配列は、シリアライズされてワークフローに返された UpdatePlan 内の最上位の DataObject のキーを表す、Properties オブジェクト配列です。

更新オーバーライドで JpdService API を使用して JPD を呼び出す

AquaLogic Data Services Platform による JPD のサポートは、UpdateOverride 実装から呼び出せる 2 つのサーバサイド API を通じて提供されます (表 9-8 を参照)。

表 9-8 JpdService API
データ型
シグネチャ
JpdService
JpdServicegetInstance(String jpdClass, String jpdStartMethod, Environment context)
JpdService.getInstance(String jpdClass, String jpdStartMethod, String serviceUri, Environment context);

コード リスト 9-9 に、UpdateOverride から JPD を呼び出す方法を示します。 このコード サンプルでは、ワークフローの一部としてコンフィグレーションされている一連のデータ サービスから成る JPD が存在すると仮定しています。

コード リスト 9-9 サンプル コード リスト : UpdateOverride からの JPD の呼び出し
public boolean performChange( DataGraph ) {
ChangeSummary changeSum = dataGraph.getChangeSummary();
//サイズ 0 は変更がないため何も行われないことを意味する
if (changeSum.getChangedDataObjects().size()==0) {
return true;
}
Environment env = new Environment();
env.setProviderUrl( "t3://localhost:7001" );
env.setSecurityPrincipal( "weblogic" );
env.setSecurityCredentials( "weblogic" );
try {
JpdService jpd = JpdService.getInstance(
"CustOrderV1",
"clientRequestwithReturn",
env);
UpdatePlan updatePlan = DataServiceMediatorContext.
currentContext().getCurrentUpdatePlan( dataGraph );
byte[] bytePlan = UpdatePlan.getSerializedBytes( updatePlan );
Properties (Properties) returnProps = jpd.invoke( bytePlan );
}
catch( Exception e )
{
e.printStackTrace();
throw e;
}
return false;
}
}

同期および非同期の動作

AquaLogic Data Services Platform は同期および非同期の JPD 呼び出しをサポートしています。いずれの呼び出し方式も更新オーバーライド コードで同じように処理されます。 コード リスト 9-9 に例示したように、JPD を呼び出して、バイト配列として応答を受け取ります。

エラー処理とコールバックの使用

JPD に関する独自のエラー処理コードを記述する必要があります。 存在しない JPD を呼び出すと標準の Java 例外 ClassNotFoundException が発生します。

JPD でのコールバックの使用はサポートされていません。 クライアント コールバックを含むビジネス プロセスは実行時に失敗します。コールバックは JPD を開始した側のクライアントではなく、JPD プロキシに送信されるためです。


  ページの先頭       前  次