IBM WebSphere Integration Developerでは、できるだけユーザーがJavaでプログラムする必要がないように考えられていますが、それでもJavaとPOPJコンポーネントを使わざるを得ない場合があります。
POPJコンポーネントが必要となる典型的な例は、WSDLで記述されたコンポーネントしか理解しないコンポーネントを、Javaインターフェースでしか公開できないコンポーネントと統合する場合です。また、WebSphereIntegration Developerウィザードの中で操作できないデータ(anyType型など)は、POPJコンポーネントの範囲内で、SDO(ServiceData Object)APIを使って手動で処理されます。ここうしたシナリオは、POPJコンポーネントが必要であることを示す重要なユースケースと言うことができます。
この記事では、POPJコンポーネントの中でのJavaコーディングを、呼び出しスタイルの面から見た場合について、またPOPJコンポーネントの入出力データについて、基礎レベルで理解します。ただし、SCAでのPOPJの使い方に関する全てのシナリオを説明するわけではありません。
この記事では、モジュールや参照の概念を含めて、SCAの基本に慣れていることを前提にしています。
ここで導入する概念を説明するために、まず単純なHello Worldの例から説明します。この例はHWModuleという名前の単純な1つのSCAモジュールであり、HelloWorldとMessageLoggerという、2つのPOPJコンポーネントを含んでいます。MessageLoggerは、HelloWorldからのメッセージを単純にコンソールに出力し、それが成功すると戻ってきます。図1は、MessageLoggerのインターフェースを記述したWSDLを説明しています。
図1. MessageLoggerのWSDLインターフェース
図2は、HelloWorldのインターフェースを記述したWSDLを示しています。
図2. HelloWorldのWSDLインターフェース
図3は、この例に対するAssemblyダイヤグラムを示しています。
図3. HWModuleのAssemblyダイヤグラム
HelloWorldは、2つの参照を使ってMessageLoggerと対話動作を行います。1つはJava型(J型)であり、もう1つはWSDL型(W型)です。これを図4に示します。
図4. HelloWorldの参照
図5は、HelloWorldとMessageLoggerとの間で使われる、HWMessageのBO(BusinessObject)を説明しています。
図5. HWMessageのBO
この例の詳細な説明は、各セクションの適当な場所で行うことにします。
この記事では、2つの呼び出しスタイル、つまりDII(dynamic invocation interface)と、強い型定義(stronglytyped)という2つのスタイルに注目します。DIIは汎用の動的呼び出しモデルであり、必ず「invoke」型のコールが、オペレーション名とそのオペレーションの入力パラメーターを渡して終わります。強い型定義の呼び出しは、「invoke」で終わることはなく、強い型定義の呼び出しで終わります。
強い型定義の呼び出しは、J型の参照に対してのみ行うことができます。この例では、J型であるHelloWorldに対して定義される、MessageLoggerPartnerという名前の参照があります。これを図6に示します。
図6. HelloWorldの参照
リスト1は、HelloWorldのsayHello() メソッドのコードを示しています。これはJ型のMessageLoggerPartner参照を、強い型定義による方法で呼び出します。
リスト1. HelloWorldのsayHello() のサンプル・コード(強い型定義の呼び出しでJ型参照を使っています)
// j-type reference strong-typed usage
MessageLogger service = locateService_MessageLoggerPartner();
Boolean isSuc = service.logMessage(inMsg);
if (isSuc.booleanValue()) { // reuse the inMsg for our response since it's the same type
inMsg.setString("message", "Success");
} else inMsg.setString("message", "Problem consuming message sent");
inMsg.setString("sourceEmail", "service@hw.org");
return inMsg;
|
上記のコードでは、MessageLoggerにプロキシーを返すためにlocateService_MessageLoggerPartner()というメソッドが使われています。このメソッドは、POPJコンポーネントが定義する参照それぞれに対して生成されます。この場合では、MessageLoggerPartnerとMessageLoggerPartner1という2つの参照があるので、HelloWorldの中では、locateService_MessageLoggerPartner()とlocateService_MessageLoggerPartner1() という2つのメソッドが生成されます。
弱い型定義の呼び出しは、参照に定義されている型に無関係に行われます。ただし、参照がW型の場合には、クライアントはDIIを使用する必要があります。
DIIでのJ型の参照
MessageLoggerPartner参照は、弱い型定義による方法で使うこともできます。リスト2は、HelloWorldのsayHello()メソッドのコードを示しています。これはJ型のMessageLoggerPartner参照を、弱い型定義による方法で呼び出します。
リスト2. HelloWorldのsayHello() のサンプル・コード(DII呼び出しでJ型参照を使っています)
// j-type reference DII usage
Service service = (Service) locateService_MessageLoggerPartner();
Boolean isSuc = (Boolean) service.invoke("logMessage", inMsg);
if (isSuc.booleanValue()) { // reuse the inMsg for our response since it's the same type
inMsg.setString("message", "Success"); } else
inMsg.setString("message", "Problem consuming message sent");
inMsg.setString("sourceEmail", "service@hw.org");
return inMsg;
|
これは強い型定義の呼び出しとよく似ていますが、オペレーション名が、入力パラメーターと共に「invoke」コールに渡されている点が異なります。
DIIでのW型の参照
参照がW型の場合は、ユーザーが利用できる呼び出しスタイルはDIIのみです。この例では、J型の参照に加えて、もう1つの参照、つまりW型でMessageLoggerPartner1という名前のMessageLoggerPartnerを定義しています。これを図7に示します。
図7. HelloWorldの参照
リスト3は、このW型のHWMessageLoggerPartner1参照をDIIによる方法で使うための、HelloWorldのsayHello()メソッドのコードを示しています。
リスト3. HelloWorldのsayHello() のサンプル・コード(DII呼び出しでW型参照を使っています)
// w-type reference DII usage
Service service = (Service) locateService_MessageLoggerPartner1();
BOFactory bof
(BOFactory) new ServiceManager().locateService("com/ibm/websphere/bo/BOFactory");
DataObject inputWrapper =
bof.createByType(service.getReference().getOperationType("logMessage").getInputType());
inputWrapper.setDataObject("inMsg", inMsg);
DataObject outputWrapper = (DataObject) service.invoke("logMessage", inputWrapper);
boolean isSuc = outputWrapper.getBoolean("isSuccessful");
if (isSuc) { // reuse the inMsg for our response since it's the same type
inMsg.setString("message", "Success");
} else inMsg.setString("message", "Problem consuming message sent");
inMsg.setString("sourceEmail", "service@hw.org");
return inMsg;
|
リスト3のコード断片を見ても分かるように、このシナリオは今までの2つよりも変化に富んでいます。興味深い点は、呼び出しに送受信される入力の型です。
この、最後のシナリオでは、DataObject(inputWrapperとoutputWrapper)を使っています。これらは、DLW(doc-literalwrapped)パターンのWSDLでの「ラッパー」要素に対応します。
つまり、強い型定義と弱い型定義のどちらの型定義を送るべきかを判断するためには、2種類の情報が必要です。まず、WSDLのスタイルはDLWなのか、それ以外なのかです。次に、参照の型がJ型かW型かを知る必要があります。
表1. 入力/出力の型を判断するためのマトリックス
| J型の参照 | W型の参照(DLWの場合) | W型の参照(DLW以外の場合) | |
|---|---|---|---|
| 弱い型定義(DII) | 単純型の場合はJava基本型、複雑型の場合はDataObject | WSDLでのメッセージに対して規定されるラッパー要素(ペイロード・オブジェクト、HWMessageまたはブール値などをカプセル化しています)。メッセージ要素は常にDataObjectです。 | ペイロードに対して規定される型(ここではラッパーは考えません)。ペイロードが複雑型の場合にはDataObjectであり、単純型の場合はJava基本型です。 |
| 強い型定義 | 単純型の場合はJava基本型、複雑型の場合はDataObject | WSDLでのメッセージに対して規定されるラッパー要素(ペイロード・オブジェクト、HWMessageまたはブール値などをカプセル化しています)。メッセージ要素は常にDataObjectです。 | ペイロードに対して規定される型(ここではラッパーは考えません)。ペイロードが複雑型の場合にはDataObjectであり、単純型の場合はJava基本型です。 |
参照の呼び出し方法が複数あるため、突き当たりがちな問題が幾つか知られています。その中の一般的なものを挙げておきます。
ClassCastExceptionの問題
この一般的なエラー・メッセージは、受信されたデータまたは送信されたデータが、想定されたものと異なっていることを示します。例えば、あるシナリオではラッパーが必要なことをユーザーが理解しない場合、戻りオブジェクトのキャストに対して、このメッセージが送信されます。この対策としては、適切なオブジェクトに対してキャストするようにコードを修正します。
IllegalArgumentException: クラス「x」が「y」という機能を持たない問題
このエラー・メッセージも、受信されたデータ、または送信されたデータが想定と異なっていることを示しますが、キャストで発生するのではなく、後でデータにアクセスした時に発生します。例えば、DataObjectを受信するユーザーは、それをラッパーDataObjectではないと考え、データ属性に直接アクセスしようとするかも知れません。データ属性に直接アクセスすると、エラーが起こります。この対策としては、正しい属性にアクセスするようにコードを修正します。
この小記事では、POPJコンポーネントの中で強い呼び出しスタイルと弱い呼び出しスタイルのどちらを選択するかに関して、基本的な概要を説明しました。また、ClassCastExceptionとIllegalArgumentExceptionの原因となりがちな落とし穴についても説明しました。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Hello World sample project interchange | ws-soa-sca-java-inv-pi.zip | 13KB | HTTP |
- SCA(Service Component Architecture)について読んでください。SCAは、Service Component Architecture (SCA) specificationsで規定される一連の仕様です。
-
「What style of WSDL should I use?」(developerWorks, 2005年5月)は、各組み合わせに対するWSDLとSOAPのメッセージを説明した記事であり、どちらのスタイルの組み合わせを使うべきかを判断する上で役立ちます。