ステップ 7: 取り消しと例外処理のサポートを追加する
このチュートリアルのこれまでのステップでの作業を通じて、Web サービスは機能するようになりました。この Web サービスは、理想的な条件下では相応に機能します。ただし、現段階では、サービスの稼働率が高くなった場合にまだ十分に対応できません。これには、次の問題が挙げられます。
Investigate から応答が送信される前に、クライアントがクレジット レポートを取り消す可能性がある。
長時間存続するものもある非同期通信では、この機能は特に重要になります。
特定の申込者に対してデータベース コントロールがデータを返さない場合、Investigate Web サービスは調査を中止して、クライアントに申込者について利用できるデータが存在しないことを通知しなければなりません。
非同期でアクセスされるクレジット カード Web サービスに Investigate は依存するため、総体的にクライアントへの応答時間が非常に長くなる可能性がある。
クレジット カード サービスがリクエストに応答するまでの所要時間を知る方法はありません。この問題に円滑に対応するために、タイマーを使用して、リソースからの応答に制限時間を設定できます。
操作メソッド(requestCreditReportAsynch など)から未処理の例外が送出される可能性がある。
現段階での設計では、この例外が原因でサービスおよびクライアントがハングする可能性があります。アクティブな会話は時間切れになるまで続行されるため、クライアントはリクエストの応答を受信できず、その原因を確認することもできません。このような例外は、円滑に回復できるよう処理することができます。
以下の手順では、Investigate Web サービスを強化して、これらの問題を円滑に処理できるようにします。
このステップでのタスクは次のとおりです。
クライアントが操作を取り消しできるようにするメソッドを追加するには
デザイン ビューを表示していない場合は、[デザイン ビュー] タブをクリックします。
[処理の追加] ドロップダウン リストから [メソッドの追加] を選択します。
表示されたフィールドに cancelInvestigation と入力して〔Enter〕を押すと、デザイン ビューにメソッドが表示されます。
cancelInvestigation をクリックすると、そのコードがソース ビューに表示されます。
cancelInvestigation メソッドのコードを次のように編集します。
/** * @jws:operation * @jws:conversation phase="finish" */ public void cancelInvestigation() { /* Cancel the request to the credit card company because it is now unnecessary. */ creditCardReportControl.cancelRequest(); /* Use the callback to send a message to the client. Note that this also ends * the conversation because the callback's conversation phase property is set to "finish". */ callback.onCreditReportDone(null, "Investigation canceled at client's request."); }
データベースからの null 応答を処理するコードを追加するには
デザイン ビューを表示していない場合は、[デザイン ビュー] タブをクリックします。
requestCreditReportAsync をクリックすると、そのコードがソース ビューに表示されます。
requestCreditReportAsync メソッドのコードを次のように編集します。
public void requestCreditReportAsynch(String taxID)
throws java.sql.SQLException
{
/*
* Query the database via the database control
*/
Applicant dbApplicant = bankruptciesDB.checkForBankruptcies(taxID);
/*
* If the database contains data on the current applicant,
* assign the retrieved values to m_currentApplicant.
*/
if(dbApplicant != null)
{
m_currentApplicant = dbApplicant;
creditCardReportControl.getCreditCardData(taxID);
}
/*
* If the database contains no data on the current applicant,
* inform the client.
*/
else
{
callback.onCreditReportDone(null, "No bankruptcy data found on applicant" + taxID + ".");
}
}
応答の許容時間を制限するタイマー コントロールを追加するには
非同期リソースがリクエストに応答するまでの時間を予測するのは困難です。たとえば、Investigate でクレジット カード サービスを呼び出すのに、数時間かかることもあります。ここでは、クレジット カードの Web サービスの応答時間を制限する処理を追加します。具体的には、タイマー コントロールを使用して、操作が取り消されるまでの時間を指定します。
[デザイン ビュー] タブをクリックして、デザイン ビューに戻ります。
[コントロールの追加] ドロップダウン リストから [タイマー コントロールの追加] を選択します。[タイマー コントロールの追加] ダイアログが表示されます。
以下の図に示すとおりに値を入力します。
上図の値では、タイマーの開始から 5 分後にタイマー コントロールが onTimeout コールバックを送信するよう指定しています。
[作成] をクリックして、デザイン ビューに戻ります。
requestCreditReportAsync をクリックすると、そのコードがソース ビューに表示されます。
以下に示す太字のコードを追加します。
public void requestCreditReportAsynch(String taxID)
throws java.sql.SQLException
{
/*
* Query the database via the database control
*/
Applicant dbApplicant = bankruptciesDB.checkForBankruptcies(taxID);
/*
* If the database contains data on the current applicant,
* assign the retrieved values to m_currentApplicant.
*/
if(dbApplicant != null)
{
m_currentApplicant = dbApplicant;
creditCardReportControl.getCreditCardData(taxID);
creditCardReportTimer.start();
}
/*
* If the database contains no data on the current applicant,
* inform the client.
*/
else
{
callback.onCreditReportDone(null, "No bankruptcy data found on applicant" + taxID + ".");
}
}
これにより、クレジット カード サービスが呼び出されると同時にタイマーが開始されます。タイムアウト時間までにサービスから応答がなかった場合、タイマーの onTimeout コールバック ハンドラが呼び出されます。
[デザイン ビュー] タブをクリックして、デザイン ビューに戻ります。
[creditCardDataResult](サービス コントロールのコールバック ハンドラ)をクリックすると、そのコードが [ソース ビュー] に表示されます。
creditCardReportControl_creditCardDataResult のコードを次のように編集します。
private void creditCardReportControl_creditCardDataResult(CreditCard[] cards)
{
/*
* Now that the web service has returned its results, stop the timer started
* in the requestCreditReportAsynch method.
*/
creditCardReportTimer.stop();
for(int i = 0; i < cards.length; i++)
{
m_currentApplicant.availableCCCredit += cards[i].availableCredit;
}
/*
* Use the JMS control to send the available credit and bankruptcy information to the credit
* scoring application.
*/
creditScoreJMS.sendMessage(m_currentApplicant.availableCCCredit,
m_currentApplicant.currentlyBankrupt);
}
次のように、ソース ビューの [ソース ビュー] タブのすぐ下にある クラス ドロップダウン リストから [creditCardReportTimer] を選択します。
次のように、クラス ドロップダウン リストの右側にある メンバー ドロップダウン リストから [onTimeout] を選択します。
JMS コントロールのコールバック ハンドラのソース コードが表示されます。
コールバック ハンドラのソース コードを次のように編集します。
private void creditCardReportTimer_onTimeout(long time) { /* Because the credit card service has not yet returned, cancel the request. */ creditCardReportControl.cancelRequest(); /* Send a response to the client, saying something about what happened. * Remember that this will also effectively finish the conversation. */ callback.onCreditReportDone(null, "Unable to retrieve credit card information."); }
操作(クライアントに公開されるメソッドなど)から送出された未処理の例外が原因で、サービスの動作が中断されたり、クライアントがハングしたりする場合があります。このような例外では、サービスの会話は自動的に終了されず、単純に継続されるためリソースが不必要に消費されてしまいます。したがって、このような例外に対応する際は、会話を終了するようコードで処理する必要があります。
JwsContext インタフェースには、会話を終了させる finish メソッドがあります。また、このインタフェースは、他にも便利な機能を備えています。このステップでは、JwsContext.onException コールバックのハンドラを実装するコードを追加します。このコールバック ハンドラでは、操作から送出された例外オブジェクト、例外を送出したメソッドの名前、およびメソッドに渡されたパラメータを受け取ります。
WebLogic Workshop では、テキスト ファイルに例外のログを記録して、例外に関する情報を保持することができます。このステップでは、例外をログに記録する例外処理コードを追加して、適切な応答をクライアントに送信するようにします。
次のように、ソース ビューの [ソース ビュー] タブのすぐ下にある クラス ドロップダウン リストから [context] を選択します。
次のように、クラス ドロップダウン リストの右側にある メンバー ドロップダウン リストから [onException] を選択します。
JwsContext の onException コールバック ハンドラのソース コードが表示されます。
onException コールバック ハンドラのコードを次のように編集します。
public void context_onException(Exception e, String methodName, Object[] arguments) { /* Create a logger variable to use for logging messages. Assigning it the * "Investigate" category name will make it easier to find messages from this * service in the log file. */ Logger logger = context.getLogger("Investigate"); /* Log an error message, giving the name of the method that threw the * exception and a stack trace from the exception object. */ logger.error("Exception in " + methodName + ": " + e); /* Invoke the callback to send the client a response. */ callback.onCreditReportDone(null, "Unable to respond to request at this time. " + "Please contact us at 555-5555."); }
Investigate のソース コードの先頭で import 文の最後の文として次のコードを追加します。
import weblogic.jws.util.Logger;
注意 : このコードにより、ログを記録できるようにする Logger クラスがインポートされます。
WebLogic Workshop Web サービスを開発およびデバッグするドメインの場合、デフォルトのログ ファイルの場所は、次に示す WebLogic Workshop インストール パスです。
BEA_HOME/weblogic700/samples/workshop/jws.log
ログのエントリの例を次に示します。
16:18:11 ERROR Investigate : Exception in requestCreditReportAsynch: <exceptionStackTrace> [ServiceException]
次のステップに進んで Investigate サービスの実際のクライアントを作成したい場合は、ここで追加したコードのテストはスキップしても構いません。逆に、テストしたい場合は、次のテストを行います。
取り消しコードをテストする場合は、サービスを起動して、テスト ビューで取り消しを行う。テスト ビューの起動時に、テスト用の納税者 ID を入力する。テストが開始されたら、[Continue this conversation] リンクをクリックする。ページが更新されたときに、[cancelInvestigation] ボタンをクリックする。
タイマーをテストする場合は、タイムアウト値を 1 秒に変更する。この値は、コンピュータが相当高速でない限り、クレジット カード サービスがタイムアウトまでに結果を返すには十分な時間である。タイムアウト値を変更したら、サービスを起動して 1 秒待ってから、更新リンクをクリックする。
例外ハンドラをテストする場合は、自身のコードの任意の場所から例外を送出する。
タイマー コントロール : Web サービスでタイマーを使用する
チュートリアルの前後のステップに移動するには、次のいずれかの矢印をクリックしてください。