EIP / Synchronous Implementation Using Web Services


Content Filter

一言要約

  • ローンブローカーを実装することを通じて、より深く理解できるようにする。
  • 同期型のメッセージングミドルウェアとして、Axisを使用した。

Synchronus Implementation Using Web Services

この章では、JavaとXML Webサービスをもちいたローンブローカーのサンプル実装について説明する。 Webサービスを処理するために、オープンソースの Apache Axis ツールキットを使用する。 ここでは、Javaでの開発の練習をするのは望ましくないと考えているので、同期Webサービスインターフェースの実装の複雑さを取り除くために、このツールを使用することを選んだ。 その代わりに、この章の議論は、同期メッセージングソリューションを設計し決定することに着目している。

Solution Architecture

この図は、予測的(predictive)同期Webサービスを用いた、ローンブローカーサンプル実装の全体的なアーキテクチャを示している。 ここには、ローンブローカーとソリューションの他の部分との、7つの重要なインターフェースがある。 図のように、各参加者ペアの間で通信するために、SOAP over HTTP が使用されている。

最初のインターフェースは、ローンブローカーへのエントリーポイントであり、それは、クライアントアプリケーションがメッセージの中にローン申込書の情報を入れるために使用される。 そのクライアントは、同じインターフェースを通じて、ローンブローカーから戻される問い合わせ結果を受け取る。 Axisサーバはこの図の何かには示されていないけれども、それは、クライアントからメッセージを受け取り、Service Activator(532)を実装している。

2番目のインターフェースは、ローンブローカーと信用調査機関との間にある。 信用調査機関は、外部機関のひとつであり、銀行から要求されている追加の顧客データを得るためのWebサービスインターフェースを、提供している。 そのローンブローカーは、信用調査機関からのデータで入力リクエストを補強するという Content Enricher (336) を実装する。

他の5つのインターフェースは、ローンブローカーと各5つの銀行との間にある。 各インターフェースは、とある特定の銀行からの見積りレートを得るために使用されている。 各銀行インターフェースは、(見積りを得るという)同じ機能を提供しているが、SOAPメッセージは異なる形式を持っているかもしれない。 なので、ローンブローカーは、銀行に問い合わせる前に、見積要求メッセージを個々の銀行が要求するフォーマットに変換しなければならない。

ローンブローカーは、予測(predictive)ルーティングを用いて、各銀行に直接接続する。ここで、予測(predictive)ルーティングとは、銀行が見積りを求められる直前に、見積り収集に参加する銀行の集合のことである。 このステージでは、ローンブローカーアプリケーションは、Recipient List (249) を用いて選択した銀行に、その要求を送る。 各銀行は、そのリクエストのための異なるフォーマットを使うことが出来ることになっているので、ローンブローカーは、そのリクエストを各銀行から要求された形式に変換するために、Message Translators(85) の配列を使用する必要がある。

同様に、すべての返信が、ひとつの一番良い見積りに集約されるように、各返信メッセージは、Normalizer(352) を用いて、共通形式に変換されなければならない。 要求と応答メッセージは同期的に渡される。ここで、同期的とは、クライアントとローンブローカーは、各銀行が応答を返すかタイムアウトするまで、ブロックされることを意味する。 ローンブローカーはすべての応答を、ひとつの一番良い見積りに集約して、その一番良い見積りをクライアントに返す。

同期メッセージングは、単純なソリューションが望まれるような課題領域において、便利である。 同期メッセージングを用いることで、非同期イベントに煩わされることにはならないし、スレッドセーフだし、それらをサポートするインフラも必要ない。 クライアントはローンブローカー Webサービスを呼び出し、そして、サーバーからの応答を待てばよい。 このソリューションには数個のコンポーネントがあり、各コンポーネントは、次のコンポーネントを同期的に呼び出して、応答を待つ。

Web Services Design Considerations (Webサービスを設計する時の考慮点)

XML Webサービスは Simple Object Access Protocol (SOAP) に依存している。 W3C に提出された SOAP 仕様書では、非中央化・分散システム間のメッセージ交換のための、XMLベースのプロトコルを定義している。 SOAPのより詳細については、W3CのWebサイト (www.w3.org/TR/SOAP) を参照して欲しい。

残念ながら、SOAP の S (Simple) は、すでに妥当ではなくっている。 我々は、冗談だが、SOAP は Complex Rmote Access Protocol に解明すべきと言ったりした。(頭文字をとると CRAP (糞) になる。) まじめに戻って、堅牢なWebサービスインターフェースを設計することは、数あるテクノロジーと、関連する設計のトレードオフの中に飛び込むことになる。 この本は、Webサービスの紹介をするものではないが、下のような設計時の考慮事項について、少しだけ述べておくのは重要だと感じている。

  • 転送プロトコル
  • 非同期メッセージング 対 同期メッセージング
  • コード化方法 (SOAP encoding 対 doc/literal)
  • バインド方法 (RPC 対 document-style)
  • 信頼性とセキュリティ

転送プロトコル

アプリケーションが、技術的に中立な方法で、ネットワークをまたがった同期RPC型のサービス呼び出しできるために、SOAP仕様書は作られた。 SOAPの仕様は、各Webサービスの呼び出しにおいて、(WSDLで記述されていたサービスについて)減志津の通信リクエストとレスポンスを分離するために作られた。 SOAPはメッセージングのことを考慮して作られたのだけれども、Webサービスを使うアプリケーションの多くはHTTPを転送プロトコルとして使っている。 ファイアーウォールをうまくすり抜けるHTTPは、Webの世界ではもっともよく使われるので、それを使うのは自然な選択である。 しかしながら、HTTPはハイパーテキストを転送するプロトコル(HyperText? Transfer Protocol)なのだから、インターネットからドキュメントを取り出すためのWebブラウザが使えるように設計されている。それは、アプリケーションがお互いに通信しあうためのものではない。 HTTPの出自を考えると、信頼性は低いが同期的にドキュメントを取り出すのに適した設計になっている。 クライアントアプリケーションは、同じ接続経路を、要求メッセージをサーバに送って、応答メッセージを受け取るのにも流用している。 なので、HTTPを使用しているWebサービスは、あいも変わらず、同期的な要求メッセージと応答メッセージを使っている。なぜなら、信頼性の低いチャネルで非同期メッセージングをするのは、海の中にビンを落とすのと同じくらい有用である。(drop a bottle into the ocean)

非同期 対 同期

Webサービスの同期実装において、要求メッセージがサーバに届く間、クライアントからのコネクションは開いたままに残ってしまう。また、サーバが応答メッセージを返すまで、クライアントは待つことになする。 同期RPCを用いた伝達の優位性は、非常に短い時間(応答を受け取るか、タイムアウトになるまでの間)で、Webサービス操作のステータスを知るということである。 同期メッセージングを使うことによる深刻な制限は、サーバは同時に多数のコネクションを扱わなければならないかも知れないということである。なぜなら、並列に動作している各クライアントは、結果を待っている間、コネクションがオープンされたままにし続けるからである。 これは、サーバ側のアプリケーションが徐々に複雑になることをもたらす。 もし、同期サービスの提供者への呼び出しのひとつが失敗してしまったならば、そのサーバ側のアプリケーションは、他の同期呼び出しがやってくる前に、その失敗をトラップする仕組みを提供し、処理を回復し別にまわすか、エラーフラグを立てなければならない。

今のところ、ほとんどのWebサービスツールキットは、デフォルトでは同期メッセージングのみサポートしている。 しかしながら、いくつかのベンダーは、非同期メッセージをキューイングするフレームワークのような、既存の標準やツールを使って、Webサービスのための非同期メッセージををエミュレートしている。 いくつかの組織や会社やWebサービスワーキンググループは、非同期メッセージングのサポートが必要であると認識していて、標準を定義することに着目しつつある。(例:WS-Reliable-Messaging) Webサービスの最新については、W3Cの http://www.w3.org/ の 14章を見ること。

コード化方法 (SOAP encoding 対 doc/literal)

SOAPのコード化の考え方は、かなりの討論と混乱を招いてきた。 SOAP仕様はencodingStyleにより指定されるコード化と呼ばれるある方法を定義している。 この方法では2つの値をとりうる。1つ目は Encoded で、http://schemas.xmlsoap.org/soap/encoding/ を属性値として設定し、2つめは Literal で、それとは異なる値を設定するか、何も設定しないことになる。 この方法は、アプリケーションがどのようにオブジェクトとパラメータを、電話でのXMLで(in XML on the wire)表現する。 Encoded (これは、SOAPコード化として参照される) は、SOAP仕様書の第5章に書かれていて、そこでは、プログラミング言語の型をXMLにマッピングするための、原始的なメカニズムを定義している。 Literal (doc/literal とも呼ばれる) は、そういったことをしない。 その代わりに、型の情報は、外部のメカニズムにより提供され、ありていに言えば、SOAPメッセージ中に使われている型を正確に定義するXML Schemaを使った WSDL (Web Services Description Language) ドキュメントだと、言うことができる。

(すみません。以下略)

バインド方法 (RPC 対 document-style)

WSDL仕様書は、そのSOAPバインディング中に、2つの異なるバインドスタイルを定義している。 バインディングスタイル属性の値はRPCとDocumentをとりうる。 これは、もし、とあるWSDLドキュメントが、バインディングスタイル属性がRPCとなっている操作を指定しているならば、受信者は、SOAP仕様書の第7章に記述されているルールを用いてそのメッセージを解釈しなければならない、ということを意味する。

(すみません。以下略)

信頼性とセキュリティ

第14章「Concluding Remarks」では、Sean Neville は、Webサービスの信頼性とセキュリティに関して取り組んでいる進化しつつある標準について記述している。 我々の設計は、最も基本的で、かつ、たぶんまだ最もはやっている、それらの設計の組み合わせを採用している。 つまり、ローンブローカーは、同期通信による SOAP over HTTPを使用し、また、コード化スタイルはSOAPコード化とRPCバインディングを使用している。 こうすることで、Webサービスは、ほとんど Remote Procedure Invocation (50) とそっくりに振舞う。

(すみません。以下略)

Apach Axis

この節では、設計の重要なポイントを明確にするのを助けるために、Axisアーキテクチャについて、少し説明する。 Axisの詳細については、Apache AxisのWebサイト http://ws.apache.org/axis を参照して欲しい。

Chapter 3 "Messaging Systems" では、Message Endpoint (95) を、メッセージを授受するために、アプリケーションがメッセージングチャネルに接続に用いるメカニズムとして定義している。 ローンブローカーアプリケーションにおいて、Axisフレームワーク自身はメッセージチャネルを担当していて、その主な機能は、ユーザアプリケーションの代わりに、メッセージ処理を扱うことである。

Axisサーバは Service Activator (532) パターンを実装している。 Chapter 10 "Messaging Endpoints" では、メッセージを受信したとき、サービスが呼び出されるように、どのように Service Activator (532) が Message Channel (60) をアプリケーション内の同期サービスに接続するかを説明している。

開発者がこの機能に煩わされる必要が無いように、Service Activator (532) は Axis サーバ内に実装される。 よって、そのアプリケーションコードは、アプリケーションのビジネスロジックのみを含み、Axisサーバは、メッセージを扱うすべてのサービスの面倒をみる。

(すみません。中略)

上の図は、Axisフレームワークのハイレベルな表現を示している。 Axisアーキテクチャの詳細な話は、http://ws.apache.org/axis に記述されている。

Axisは、Message Channel (60) 機能を提供するための、共に動作する、数個のサブシステムを含んでいる。 このフレームワークはクライアントとサーバの両方で利用できる。

  • Message Model サブシステムは、SOAPメッセージのXML文法を定義する。
  • Message Flow サブシステムは、メッセージを受け渡す Handler と Chain を定義する。
  • Service サブシステムは、サービスハンドラー(SOAP, XML-RPC)を定義する。
  • Transport サブシステムは、メッセージ (例: HTTP, JMS, SMTP) の転送のための代替手段を提供する。
  • Providor サブシステムは、さまざまなタイプのクラス(java:RPC, EJB, MDB といった)のプロバイダーを定義する。

以前述べたように、開発者は、ビジネスロジックを実装するアプリケーションを作成することのみに注力すればよく、そして、それは、Axisサーバに配備されることになる。 ここに、WebサービスとしてJavaクラスを配備し、エンドポイントサービスとして利用可能にするための、3つのテクニックがあり、それを次のように名づけた。

  • 自動配備 (Automatic Deployment)
  • Webサービス配備記述子の利用 (Using a Web Services Deployment Descriptor)
  • 既存のWSDLドキュメントからプロキシを生成する。 (Generate proxies from an existing WSDL document)

(すみません。以下略)

Service Discovery

ローンブローカーアプリケーションの議論を進める前に、簡単に配備できるアプリケーションを作るのを助けるためのソリューションを実装するときに従うべき、少しの一般的なステップを説明する必要がある。 サーバ上に配備されたとあるWebサービスを呼び出すために、どんなクライアントアプリケーションもエンドポイントURLを知っている必要がある。 Webサービスモデルにおいては、あるアプリケーションは、共通サービスレジストリからアクセスしたいWebサービスの場所を探すことになっている。

UDDI (Universal Description, Discovery, and Integration) は、そういったリポジトリの標準である。 UDDI の話は、この章のスコープ外であるが、 必要ならば http://www.uddi.org から追加情報をえられる。 我々のサンプルでは、アプリケーション自身のエンドポイントURLをハードコードしている。 しかしながら、サンプルコードを配備しやすくさせるために、サーバアプリケーションとクライアントアプリケーション用のプロパティファイルを作った。 そのプロパティファイルは、ホスト名とポート番号パラメータのための、名前と値のペアを持ち、それは、Axisサーバをインストールした場所におく。 これで、自分の環境にローンブローカーアプリケーションを配備する際に、ある程度の柔軟性を得ることができる。 Axisサーバの配備パラメーターを含むファイルを読み込むために、いくつかのJavaクラスからなる、ユーティリティメソッド readProps() を提供している。 ローンブローカーアプリケーションのあらゆる機能的な側面で、readProps() メソッドを使用しているわけではない。

どんな、分散コンピューティングフレームワーク(Java RMI, CORBA, SOAP Webサービス)においても、 プリミティブ型やオブジェクトをシリアライズしネットワークから授受するために、 リモートオブジェクトのメソッドを呼出す際のパラメータを定義しなければならない。 それらのパラメータは、クライアントからサーバに送られるメッセージオブジェクトのプロパティである。 ローンブローカーの単純さを保つため、ローンブローカーからクライアントに応答を返すために Java の String オブジェクトを使用した。 もし、呼び出しパラメータがプリミティブ型(例えば int, double など)だったら、タイプラッパー(たとえば、Integer, Double など)と呼ばれるオブジェクトラッパーに定義しなおさなければならない。

融資ブローカーアプリケーション

クラス図は以下に記載。Loan BrokerのコアビジネスロジックはLoanBrokerWS内に隠蔽されている。SOAPリクエストが来たらLoanBrokerWS内のメソッドを呼び出すためにService Activatorを実装するAxisフレームワークによって提供されたクラスから委譲している。また信用機関や銀行などの外部エンティティとのインターフェースの詳細を実装するGatewayクラスのセットを参照している(CreditAgencyGateway?LenderGateway?BankQuoteGateway?)。

Loan Brokerから外の世界への唯一のサービスインターフェイスは、ローンブローカーサービスにアクセスするためのクライアントのメッセージエンドポイントである。Axisフレームワークはアプリケーションに代わってゲートウェイとして作用するため、Message Gateway?を定義する必要がない。

同期予測Webサービスのコンポーネント間の相互作用を示すシーケンス図を以下に記載。Loan Brokerは最初にCredit Agency Gatewayコンポーネントを呼び出し、顧客のクレジットスコアと信用履歴の長さで提供される最小限のデータを強化する。Loan BrokerはLender Gatewayを呼び出すために強化したデータを使用する。このコンポーネントは、融資の要求を処理できる貸し手のセットを選択するために提供される全データを使用するRecipient Listを実装している。

そしてLoan BrokerはBank Quote Gatewayを呼び出す。このコンポーネントは順番に各Bankを呼び出すことで予測ルーティング動作をふるまう。Bankコンポーネントは現実世界の銀行操作のインターフェースを形成している。例えば、Bank1クラスは銀行操作を形成するBank1WS.jws Webサービスへのインターフェース。ローン要求が来たとき​​に、全パラメータに基づいた料金見積りの生成前に行われるいくらかの事務作業がある。この例では、料金見積りは「ダミー」銀行Webサービスによって生成される。

Bank Quote Gatewayは銀行からの応答を集約し、受信した全ての見積もりからベストの見積もりを選択する。応答はLoan Brokerに返し、ベストの見積もりからデータをフォーマットし、クライアントにレポートを返す。

ここでは5つの銀行のうち2つだけ図示している。特定リクエストのために生成されたRecipient Listに基づき、Loan Brokerはクライアントの要求を処理するために正確に1つ又は5つの銀行に連絡できる。

図は、各銀行に見積もり要求のシーケンシャル処理を強調している。シーケンシャル処理はいくらかの利点があり、シングルスレッドでアプリを実行し各Bankを順番に呼び出せる。アプリケーションは各銀行からの見積もりを要求するためにスレッドを生成する必要がないので、同時実行の問題を心配する必要はない。しかしながら、貸し手リストの次のBankへの要求を送信する前に各Bankからの応答を待たないといけないため、トータルの時間は高くつく。よって顧客は結果の見積もりを得るために長い時間を待つことになる。

Loan Blokerアプリケーションのコンポーネント

Loan Brokerソリューションは以下の機能を実装する必要がある。

  • クライアント要求を受け入れる
  • 信用機関のデータを取得する
  • 信用機関のサービスを実装する
  • 見積もりを取得する
  • 銀行業務を実装する

クライアントのリクエストを受け入れる

Loan BrokerはLoanBrokerWS.jwsというJWSファイルで実装されており、単一のpublicメソッド、GetLoanQuote?を公開している。Loan Brokerはローン要求の処理を開始するため、クライアントから顧客識別番号として機能する社会保障番号(SSN)、ローンの額、ローンの期間(月)の3つのデータを必要とする。

getLoanQuotesWithScores?を呼び出しているだけであり文字列を返す。

Axisが自動生成するLoanBrokerWS.jwsファイルのWSDLファイルを以下に示す。

\<wsdl:service>はサービス名(LoanBrokerWSService)とエンドポイントの場所を定義する。<wsdl:operation>はLoanBrokerWS Webサービスにアクセスするため必要なパラメータとともにメソッド(オペレーション)名を定義する。<wsdl:message>で定義された2つのメッセージ(getLoanQuoteRequest?、getLoanQuoteResponse?)がgetLoanQuote?の要求と応答メッセージを定義する。<wsdlsoap:binding>は冒頭で述べたようにRPCバインディング·スタイルを使用していることを意味し、<wsdlsoap:body>は(ドキュメント/リテラルではなく)SOAPエンコーディング​​を使用していることを示す。

WSDLファイルを見たい場合、以下のURLを入力すればよい。

http://hostname:portnumber/axis/LoanBrokerWS.jws?wsdl

信用機関のデータを取得する

ローン要求アプリケーションを完了するためContent Enricherを実装して顧客の追加データを収集する。

SAOPコードを外に出すのと信用機関との依存性を最小限にするためGatewayパターン(EAA)を利用する。これにはアプリケーションからの通信の詳細を抽象化し、テスト時に外部サービスをService Stub(EAA)に置き換えられるメリットがある。

CreditAgencyGateway?は、CreditAgencyGateway?とCreditAgencyWS間の通信の技術的な詳細を抽象化する。必要に応じてテストスタブを使用してWebサービスを置き換えられる。ゲートウェイは顧客識別番号(SSN)を取り込み、信用機関から追加データを取得する。返されるのは、顧客のためのクレジットスコアと信用履歴の長さの2つ。

信用機関サービスを実装する

信用機関のWebサービスは、CreditAgencyWS.jwsで実装されている。信用機関は顧客ごとにクレジットスコアと信用履歴の期間を持っており、顧客識別番号を介してアクセスできる。

\<wsdl:service>はCreditAgencyWSServiceを定義し、クライアントがアクセスするエンドポイントを公開する。<wsdl:operation>は2つのパブリックメソッドgetCreditScore?、getCreditHistoryLength?を定義する。それぞれ<wsdl:message>にて要求-応答メッセージペアが定義されている。(getCreditScoreRequest?、getCreditScoreResponse?、getCreditHistoryLengthRequest?、getCreditHistoryLengthResponse?

ファイル全体は以下のURLで参照可能。

http://hostname:portnumber/axis/CreditAgencyWS.jws?wsdl

この例では実際の機能を提供せず、スタブとしてダミーデータを返す。

見積もりを取得する

顧客データを強化(enrich)したので、ローン情報センター機能を呼び出す。ローン情報センターはローンアプリケーションのすべてのデータを受信する。

getResultsFromLoanClearingHouse(SSN, loanamount, loanduration, credit_history_length, credit_score);

ローン情報センター機能はアプリケーションが複雑化したり、外部のローン情報センターを使うよう要件が変更したりした場合に、独自の論理ユニットとして区画できるようにする。この例では3つのステップに分ける。

  • 顧客ローンサービスを提供できる貸し手のリストを取得する
  • 貸し手リスト内の各銀行から全見積もりのうち、最高の見積もりを取得する
  • 最高の見積もりからのデータをフォーマットし、融資ブローカーに返す

Loan Brokerから貸し手の選択プロセスを抽象化するため、LenderGateway?クラスを作成する。Webサービスは慎重に設計する必要があり、型がネットワーク間でシリアライズ可能でなければならなく、パラメータと返り値の型は考慮しておかなければならない。ここではシンプルにJavaクラス内に貸し手選択ロジックを組み込む。

貸し手ゲートウェイは銀行サービスエンドポイントのコレクションを返す場合、Loan Brokerには最も便利である。欠点は銀行Webサービスの識別が貸し手ゲートウェイにハードコードされていることである。これはメンテナンスの悪夢になりITアーキテクトの転職より頻繁に買収や合併が起こる。このセクションでは後述のBankQuoteGateway?内の銀行とWebサービスの堅牢なソリューションについて議論する。

getLenderList?は貸し手(銀行)のセットを返す。

このメソッドはRecipient List?を実装し、非常に単純なルールベースで構成しており、少なくとも一つの見積もりを返す。Loan Brokerは見積もりを集めて選択するために銀行見積もりゲートウェイに貸し手リストを渡す。銀行インターフェースを抽象化するためBankQuoteGateway?を作る。

BankQuote bestquote = BankQuoteGateway.getBestQuote(lenderlist, ssn, loanamount, loanduration,credit_history_length,credit_score);

BankQuoteGateway?は全銀行の見積もりを取得後、最高の見積もり(最も低料金の見積もり)を選択して返す。

最も重要な行はgetBankQuotes?への呼び出し。

貸し手リストから銀行を取り出した後、見積もりを生成するメソッドを呼び出す。メソッド呼び出しのパラメータリストの順序には特別な注意を払う。

bank.getBankQuote(ssn, loanamount, loanduration, credit_history_length, credit_score);

結果は銀行見積もりのArrayList?を使って集約される。これを繰り返し最も低料金を選択する。

前述したように、Loan Brokerの機能と結合しないよう現実の銀行業務をエミュレートするWebサービスを設計している。これはGatewayパターンを使って実現できる。

銀行クラス。

例では、銀行から見積もりを取得するプロセスは現実世界の銀行業務と同じように大まかにモデル化されている。少し事務作業を行い、料金見積もりシステムにアクセスし、追加の事務作業を行ってBankQuoteGateway?に見積もりを返す。

Bank抽象クラスと小クラス(Bank1〜Bank5)は銀行業務をモデル化する。例では、銀行がローンリクエストを受け取り、事務スタッフが適性評価を行う。waitメソッドで事務作業をモデル化している。料金見積もりシステムをモデル化するためにWebサービスを用いる。銀行(Bank N)の場合、料金見積もりシステムはBanknWSを利用してモデル化され、BanknWS.jwsというファイル名でコード化されている。5つの銀行クラス(Bank1〜Bank5)と5つの料金見積もりシステム(Bank1WS〜Bank5WS)がある。各料金見積もりシステムは異なるフォーマットのパラメータリストを用いる(実際の銀行がそれぞれ異なるデータフォーマットを使うのと同じように)。これはBankクラスはWebサービスを呼ぶ前にMessage Translatorを用いなければならない。

getBankQuote?は抽象メソッドで、特定の形式で順序づけられたパラメータを持っていることに注意。Bank1の実装を見ていく。

getBankQuote?メソッドは以下の特定の順番でパラメータを持つ。

public BankQuote getBankQuote(int ssn, double loanamount, int loanduration, int credit_history_length, int credit_score)

銀行業務を実装する

前述したように、各銀行の料金見積もりシステムのパラメータフォーマットが異なっているのでMessage Translatorで順序を変換しなければならない。各銀行のgetQuoteメソッドは以下のとおり。

Bank1WS
getQuote(int ssn, double prime_rate, double loanamount, int loanduration, int credit_history_length, int credit_score)
Bank2WS
getQuote(double prime_rate, double loanamount, int loanduration, int credit_history_length, int credit_score, int ssn)
Bank3WS
getQuote(double loanamount, int loanduration, int credit_history_length, int credit_score, int ssn, double prime_rate)
Bank4WS
getQuote(int loanduration, int credit_history_length, int credit_score, int ssn, double prime_rate, double loanamount)
Bank5WS
getQuote(int credit_history_length, int credit_score, int ssn, double prime_rate, double loanamount, int loanduration)

Bank1WS.jwsではシンプルなアルゴリズムで料金見積もりを返す。

実際の式はもっと複雑。返り値の型は倍精度の数値。

Axisサーバは各銀行のJWSファイルごとにWSDLファイルを自動生成する。Bank1WS.jws WebサービスのWSDLファイルは以下のとおり。<wsdl:operation>で定義されたgetQuoteについて、AxisはBank1WS.jwsクラスのgetQuoteメソッドにマップする。<wsdl:service>はBank1WSを定義していて要求-応答メッセージのペアが<wsdl:message>で定義している。

各銀行の料金見積もりはBankQuote? Beanにセットされ、コレクションに追加されてBankQuoteGateway?へ送り返す。Bean形式にすることで変換する(Normalizer?を通す)必要がなくなる。

BankQuoteGateway?は最も低い料金見積もりを選択し、Loan BrokerにBeanとして返す。レポートを整形するメソッドは以下の通り。

クライアントアプリケーション

クライアントアプリケーションは、Loan Brokerアプリケーションへの顧客のインターフェースで、主な要件は十分なエラーチェックを持ったユーザインターフェースで顧客情報を集めることである。クライアントアプリケーションは3つのデータを準備する。実際はWindowベースのfatクライアントやブラウザベースのthinクライアントとして実装するが、ここでは簡潔にmainメソッドを持つJavaクラスで表す。最も重要な部分を以下に示す。

重要なポイントはメソッド名(getLoanQuote?)とパラメータ(顧客ID、融資額、貸付期間)や返り値の型(string)を設定している行である。

UDDIなどWebサービスのルックアップサービスを利用していないので、WebサービスのURLはハードコードしている。JWSファイルとしてアプリケーションをデプロイしているので、エンドポイントは標準形式になっている。

http://hostname:portnumber/axis/LoanBroker.jws

クライアントアプリケーションは応答するまで待ち、フォーマットされたレポートを受け取り、GUIエリアに表示する。または保存するか印刷することもある。

ソリューションを実行する

サーバが実行されていない場合は再起動 or 起動する必要がある(Tomcatのヘルプ参照)。TomcatとAxisを起動後以下の手順を実行して確認する。

java -classpath %CLASSPATH% LoanQueryClient [customerid] [loanamount] [loanduration in months]

または

java -classpath $CLASSPATH LoanQueryClient [customerid] [loanamount] [loanduration in months]

例:

java -classpath %CLASSPATH% LoanQueryClient 199 100000.00 29

Loan BrokerWeb?サービスを呼び出すと、以下の結果を返す。

別のローン金額を入力することでLoan Brokerをテストできる。これから単一のクライアント実行による出力結果を分析する。複数クライアント実行はその後。

出力を分析する

クライアントアプリケーションはサーバー上のLoan Broker Webサービスのエンドポイントを呼び出す時間を追跡し、サーバからの応答時間も示す。

Calling the LoanBroker webservice at 1053292919270 ticks
LoanBroker service replied at 1053292925860 ticks

Total time to run the query = 6590 milliseconds

Loan Clearing House Webサービスはクライアントからの送信、顧客のリクエスト詳細をレポートしている。

Client with ssn= 199 requests a loan of amount= 100000.0 for 29 months

また、追加されたクレジットデータもレポートする。

Additional data for customer: credit score and length of credit history
Credit Score= 756 Credit History Length= 12

LoanBroker?はデータを分析し、ローン要求に適合する銀行のセットを選択する。LoanBroker?は同期アプリケーションのため、個々の形式で顧客データを送信し、応答するまで待つかタイムアウトで失敗する。

LoanBroker?は全ての見積もりを解析しベストの見積もりを選ぶ。この見積もりは整形され、関連データと一緒に返す。全銀行のベストの見積もり詳細は以下のとおり。

Out of a total of 3 quote(s), the best quote is from
Bank Name: Exclusive Country Club Bankers
Interest Rate: 6.197

コンソール出力からLoanBroker?は3つの銀行に対応しており、ベストの見積もりを提示できていることが分かる。

パフォーマンス制限

シーケンス図について議論した際、次の銀行に要求を送信する前に、前の銀行からの応答を待つ必要があるため、見積もりを取得する合計時間は重要である。要求を出すと長い時間を待たなければならない。テストを実行すると平均8秒の合計時間だった。次に別々のウインドウで4つのクライアントインスタンスを立ち上げると、それぞれ以下の平均時間だった。

Client 1: 12520 milliseconds
Client 2: 12580 milliseconds
Client 3: 15710 milliseconds
Client 4: 13760 milliseconds

このテストにより、複数クライアントが同時にアクセスしようとするとパフォーマンスが劇的に落ちることが分かる。

この例の制限

Loan Brokerの設計を議論しやすくするため、JWSファイルとしてWebサービスを実装した。これはサーバにコピーするだけでデプロイできる利点がある。一方、新しいインスタンスの要求ごとにインスタンス化され、要求が完了すると割り当てが解除されるデメリットがある。

より複雑な選択肢としてWSDDファイルを使ってデプロイする方法もある。これによりクライアントセッションもしくはアプリケーション期間などインスタンス化されたクラスをどれくらい永続化させるかを柔軟に行える。実際のアプリケーション設計において、デプロイ方法の問題は重要である。

まとめ

このセクションでは同期SOAP/HTTP Webサービスを使って融資ブローカーアプリケーションの実装を示した。銀行セットに要求を送信するのに予測ルーティングを利用し、このアプローチの長所と短所を強調した。また、設計のトレードオフを行い、デプロイの詳細を説明する際に行き詰まるのを避けた。全体的な意図としては、このアプローチの長所と短所についての議論を提供することである。また、この本に記載したパターンを多く利用し、他のビジネス領域に対して同期予測アプローチを適応させるのに役立つかもしれない。

担当者のつぶやき

  • SOAPとか、Axisとかの、前振り的な話が多かった。
  • ビジネスアプリケーションドメインにありがちな、いろんな制約を入れて欲しかった。

みんなの突っ込み