Oracle® Fusion Middleware

Oracle Coherenceチュートリアル

12c (12.1.2)

B70747-02(原本部品番号:E26053-02)

2014年1月

Oracle CoherenceベースのJavaアプリケーションを作成、設定およびデプロイするための手順について説明する、開発および設計担当者向けのドキュメント。

Oracle Fusion Middleware Oracle Coherenceチュートリアル, 12c (12.1.2)

B70747-02

Copyright © 2013, 2014, Oracle and/or its affiliates. All rights reserved.

原本著者:  Thomas Pfaeffle

原本協力著者:  Noah Arliss, Mark Falco, Alex Gleyzer, Gene Gleyzer, David Guy, Charlie Helin, Adam Leftik, Tim Middleton, Brian Oliver, Patrick Peralta, Cameron Purdy

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントが、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供される場合は、次のNoticeが適用されます。

U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are "commercial computer software" or "commercial technical data" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007). Oracle USA, Inc., 500 Oracle Parkway, Redwood City, CA 94065.

このソフトウェアまたはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアまたはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用する際、このソフトウェアまたはハードウェアを安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアまたはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

このソフトウェアおよびドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。

目次

例一覧

図一覧

表一覧

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

このガイドで説明する新機能

- 12c (12.1.2)の新機能と変更された機能

- 12c (12.1.2)に関するこのドキュメントにおけるその他の重要な変更

1 Coherenceのインストールと構成

- 1.1 Coherenceのインストール

- 1.2 Coherenceインストールのテスト

- 1.2.1 Coherenceインストールをテストするには - 主な手順

- 1.2.2 サンプル・キャッシュ・サーバー・アプリケーションの構成と実行

- 1.2.3 サンプル・キャッシュ・クライアント・アプリケーションの構成と実行

- 1.2.4 サンプル・キャッシュ・クライアント・アプリケーションの演習

- 1.2.5 キャッシュ・サーバーのクラスタ化のトラブルシューティング

- 1.2.5.1 Coherenceを自分のホストに制限する

- 1.2.5.2 Coherenceを自分のホストに制限するための詳細な手順

2 EclipseおよびOEPEのインストールとCoherenceと併用するための構成

- 2.1 EclipseおよびOEPEのインストール

- 2.2 Coherence用のEclipseおよびOEPEの構成

- 2.3 Eclipse IDEでの新規プロジェクトの作成

- 2.4 Eclipse IDEでのキャッシュ・サーバーの起動

- 2.5 Eclipse IDEの基礎について

- 2.5.1 Javaクラスの作成

- 2.5.2 ランタイム構成の作成

- 2.5.3 キャッシュ・サーバーの停止

3 Javaからデータ・グリッドへのアクセス

- 3.1 概要

- 3.2 最初のCoherenceベースのJavaプログラムの作成

- 3.2.1 キャッシュに値を挿入するプログラムの作成

- 3.2.2 キャッシュから値を取得するプログラムの作成

- 3.3 最初のCoherenceベースのJavaアプリケーションの作成

- 3.3.1 コンソール・アプリケーションの作成

- 3.3.2 コンソール・アプリケーションの実行

4 複合オブジェクトの操作

- 4.1 概要

- 4.2 複合オブジェクトの作成とキャッシュ

- 4.2.1 データ・オブジェクトの作成

- 4.2.2 複合オブジェクトの作成

- 4.2.3 ドライバ・クラスの作成

- 4.2.4 POF構成ファイルとキャッシュ構成ファイルの作成

- 4.2.5 サンプル・プロジェクトの実行

5 キャッシュへのデータのロード

- 5.1 概要

- 5.2 キャッシュへのドメイン・オブジェクトの移入

- 5.2.1 ドメイン・オブジェクトのキーを使用したクラスの作成

- 5.2.2 POF構成ファイルの編集

- 5.2.3 データ・ジェネレータの作成

- 5.2.4 キャッシュをロードするコンソール・アプリケーションの作成

- 5.2.5 キャッシュ・ロードのサンプルの実行

- 5.3 キャッシュ内のデータの問合せおよび集計

- 5.3.1 キャッシュ・データを問い合せるクラスの作成

- 5.3.2 問合せサンプルの実行

- 5.3.3 集計を実行するための問合せサンプルの編集

- 5.3.4 問合せと集計のサンプルの実行

6 キャッシュのコールおよび集計の簡略化

- 6.1 概要

- 6.2 問合せサンプルの簡略化

- 6.3 問合せサンプルの再実行

7 変更のリスニングとデータの変更

- 7.1 概要

- 7.2 キャッシュ・リスナーの作成

- 7.2.1 キャッシュ内の変更をリスニングするクラスの作成

- 7.2.2 キャッシュ・リスナー・サンプルの実行

- 7.3 キャッシュ内の変更への対応

- 7.3.1 キャッシュ内のエントリを更新するクラスの作成

- 7.3.2 POF構成ファイルの編集

- 7.3.3 キャッシュ更新サンプルの実行

8 JPAとCoherenceの併用

- 8.1 概要

- 8.2 JPAを使用したJavaオブジェクトへのリレーショナル・データのマッピング

- 8.2.1 OracleXEデータベースのロック解除

- 8.2.2 JPAに対するプロジェクトの構成

- 8.2.3 JPA永続性ユニットおよびエンティティの作成

- 8.2.4 persistance.xmlファイルの編集

- 8.2.5 JPAに対するキャッシュ構成ファイルの作成

- 8.2.6 キャッシュ・サーバー起動の構成の作成

- 8.2.7 データ・オブジェクトとやり取りするためのクラスの作成

- 8.2.8 RunEmployeeExampleの実行構成の作成

- 8.2.9 JPAサンプルの実行

9 キャッシュとデータベースの相互作用

- 9.1 概要

- 9.2 キャッシュ・アプリケーションの作成

- 9.2.1 キャッシュを構成するアプリケーションの作成

- 9.2.2 キャッシュ構成ファイルの作成

- 9.2.3 アプリケーションの実行構成の作成

- 9.2.4 キャッシュ・サーバー起動構成の作成

- 9.2.5 キャッシュ作成アプリケーションの実行

- 9.3 データベース・キャッシュの作成

- 9.3.1 Oracle Databaseキャッシュの作成

- 9.3.2 カスタム・キャッシュ・ストアを定義するクラスの作成

- 9.3.3 キャッシュ構成ファイルの変更

- 9.3.4 データベース・キャッシュを構成するクラスの作成

- 9.3.5 データベース・キャッシュ・アプリケーションの実行

10 セキュリティに関する作業

- 10.1 概要

- 10.2 トークンベース・セキュリティの有効化

- 10.2.1 セキュリティ・ヘルパー・ファイルの使用

- 10.2.2 IDトランスフォーマの作成

- 10.2.3 IDアサータの作成

- 10.2.4 パスワード・ファイルの作成

- 10.2.5 IDトランスフォーマおよびアサータの有効化

- 10.2.6 Extendクライアントのキャッシュ構成ファイルの作成

- 10.2.7 拡張プロキシのキャッシュ構成ファイルの作成

- 10.2.8 キャッシュ・サーバーの起動構成の作成

- 10.2.9 キャッシュ・サーバーでのプロキシ・サービスの起動構成の作成

- 10.2.10 パスワード・サンプルの実行

- 10.3 クラスタに対するロールベース・アクセス制御の組込み

- 10.3.1 キャッシュ・メソッドへのアクセスの資格が付与されるユーザー・ロールの定義

- 10.3.2 キャッシュ・サービスへの資格の適用

- 10.3.3 アクセス制御のサンプル・プログラムの作成

- 10.3.4 クラスタ側のキャッシュ構成ファイルの編集

- 10.3.5 アクセス制御サンプルの実行

- 10.4 起動可能オブジェクトに対するロールベース・アクセス制御の組込み

- 10.4.1 起動可能オブジェクトの作成

- 10.4.2 資格が付与される起動サービスの作成

- 10.4.3 アクセス起動サービスのサンプル・プログラムの作成

- 10.4.4 クラスタ側のキャッシュ構成ファイルの編集

- 10.4.5 POF構成ファイルの作成

- 10.4.6 サーバーの実行構成の編集

- 10.4.7 アクセス起動サービス・サンプルの実行

11 ライブ・イベントの使用

- 11.1 概要

- 11.1.1 イベント・インターセプタについて

- 11.1.2 キャッシュ・イベントについて

- 11.1.3 パーティション・サービス・イベントについて

- 11.1.4 イベント・インターセプタの登録について

- 11.2 イベント・インターセプタの作成、登録および実行

- 11.2.1 コミット前イベントとコミット後イベントの間の時間を測定するイベント・インターセプタの作成

- 11.2.2 イベントの処理を遅延するクラス

- 11.2.3 イベント時間測定イベント・インターセプタの登録

- 11.2.4 遅延プロセッサ・クラスのPOF構成ファイルの作成

- 11.2.5 イベント時間測定イベント・インターセプタを実行するクラスの作成

- 11.2.6 イベント時間測定サンプルのドライバ・ファイルの作成

- 11.2.7 キャッシュ・サーバー起動の構成の作成

- 11.2.8 イベント時間測定ドライバの起動構成の作成

- 11.2.9 イベント時間測定サンプルの実行

- 11.3 イベント・インターセプタを使用したコミット前イベントおよびコミット後イベントの拒否

- 11.3.1 イベントを検出および拒否するイベント・インターセプタの作成

- 11.3.2 イベント拒否イベント・インターセプタの登録

- 11.3.3 イベント拒否イベント・インターセプタを実行するクラスの作成

- 11.3.4 イベント拒否サンプルのドライバ・ファイルの編集

- 11.3.5 イベント拒否サンプルの実行

- 11.4 イベント・インターセプタを使用したパーティション・アクティビティのロギング

- 11.4.1 JVMの終了およびロギングの有効化と無効化を実行するクラスの作成

- 11.4.2 パーティション・アクティビティを記録するイベント・インターセプタの作成

- 11.4.3 パーティション・アクティビティ記録サンプルを実行するクラスの作成

- 11.4.4 パーティション・アクティビティ記録イベント・インターセプタの登録

- 11.4.5 POF構成ファイルの編集

- 11.4.6 パーティション・アクティビティ記録サンプルのドライバ・ファイルの編集

- 11.4.7 パーティション・アクティビティ記録サンプルの実行

12 管理対象WebLogic Serverを使用したセッションのキャッシュ

- 12.1 概要

- 12.2 Webアプリケーション・インスタンスのセッション情報のキャッシュ

- 12.2.1 WebLogic Serverの構成および起動

- 12.2.2 マシンの作成

- 12.2.3 WebLogic Serverの作成

- 12.2.4 Coherenceクラスタ構成の作成

- 12.2.5 Coherence*Webローカル記憶域に対するサーバーの有効化

- 12.2.6 カウンタWebアプリケーションの作成

- 12.2.7 WebLogic Serverの起動

- 12.2.7.1 コマンド行からWebLogic Serverを起動するには

- 12.2.7.2 WebLogic Server管理コンソールからWebLogic Serverを起動するには

- 12.2.8 アプリケーションのデプロイ

- 12.2.9 サンプルの検証

- 12.3 カスタム・セッション・キャッシュ構成ファイルの使用

例一覧

- 1-1 COHERENCE_HOMEを編集したcache-server.cmdファイル

- 1-2 Coherenceのキャッシュ・サーバー起動時の出力

- 1-3 COHERENCE_HOMEを編集したquery.cmdファイル

- 1-4 Coherenceのキャッシュ・クライアント起動時の出力

- 1-5 Coherenceのキャッシュ・クライアント起動時の出力

- 1-6 Coherenceコマンドの演習

- 2-1 Eclipseコンソール・ウィンドウでのキャッシュ・サーバーの出力

- 3-1 NamedCacheオブジェクトの作成: 値の挿入と検証

- 3-2 MyFirstSampleプログラムの出力

- 3-3 キャッシュからの値の取得

- 3-4 MyFirstSampleReaderプログラムの出力

- 3-5 キャッシュ・サーバーを実行している状態でのMyFirstSampleReaderプログラムの出力

- 3-6 キャッシュ記憶域を無効にした場合のMyFirstSampleクラスの出力

- 3-7 CoherenceベースのJavaアプリケーション

- 3-8 QueryPlusキャッシュ・クライアントの出力

- 3-9 YourFirstCoherenceApplicationクラスの出力

- 3-10 新しいキー値を含むYourFirstCoherenceApplicationクラスの出力

- 4-1 Addressクラスの実装

- 4-2 PhoneNumberクラスの実装

- 4-3 Contactクラスのサンプル

- 4-4 ContactDriverクラスのサンプル

- 4-5 POF構成ファイル

- 4-6 キャッシュ構成ファイル

- 4-7 Contactsキャッシュ・サーバーの出力

- 4-8 Eclipse IDEでのContactsの出力例

- 4-9 Contactsクライアントの参加と離脱を示すContactsキャッシュ・サーバー

- 5-1 単純な連絡先IDクラス

- 5-2 ContactIdエントリを持つPOF構成ファイル

- 5-3 データ生成クラスのサンプル

- 5-4 contacts.csvファイルの内容

- 5-5 キャッシュ・ロード・プログラムのサンプル

- 5-6 サンプル・キャッシュ・ロード・プログラムの出力

- 5-7 QueryExampleクラスのサンプル

- 5-8 QueryExampleプログラムの結果

- 5-9 キーに対する集計メソッドとフィルタ指定による集計メソッド

- 5-10 集計を使用したQueryExample

- 5-11 アグリゲータからの出力

- 6-1 編集済QueryExampleファイル

- 6-2 MA Residentsフィルタの出力

- 6-3 MA Residents, Work Elsewhereフィルタの出力

- 6-4 City Begins with Sフィルタの出力

- 6-5 Age Greater than 42フィルタの出力

- 6-6 StateアグリゲータおよびAgeアグリゲータの出力

- 7-1 NamedCacheのリスナー・メソッド

- 7-2 イベント登録のコード・パターン

- 7-3 リスナー・クラスのサンプル

- 7-4 イベントを待機するリスナー・プログラム

- 7-5 キャッシュ内のオブジェクトを更新するプログラムのサンプル

- 7-6 ObserverExampleクラスとProcessorExampleクラスからの出力

- 8-1 生成されたpersistence.xmlファイル

- 8-2 JPAに対するキャッシュ構成

- 8-3 従業員クラスのサンプル・ファイル

- 8-4 RunEmployee実行可能ファイルからの出力

- 8-5 データベースへのログインに対するキャッシュ・サーバーの応答

- 9-1 Coherenceキャッシュの実装

- 9-2 キャッシュ構成ファイル

- 9-3 Coherenceキャッシュ・アプリケーションの出力

- 9-4 データベース表を作成するSQLスクリプト

- 9-5 データベース表を作成するSQLスクリプトの実行

- 9-6 データベース・キャッシュ・ストアの実装

- 9-7 データベース・キャッシュの構成ファイル

- 9-8 データベース・キャッシュ・クラス・ファイルの実装

- 9-9 DatabaseCacheプログラムの出力

- 9-10 DatabaseCacheプログラムに対するキャッシュ・サーバーの応答

- 9-11 SELECT文からの出力

- 10-1 セキュリティ・ヘルパー・ファイル

- 10-2 IDトランスフォーマの実装例

- 10-3 IDアサータの実装例

- 10-4 パスワード・サンプルを実行する実装例

- 10-5 IDトランスフォーマとアサータの指定

- 10-6 Extendクライアント・キャッシュ構成ファイルのサンプル

- 10-7 プロキシ・サーバーのキャッシュ構成ファイルのサンプル

- 10-8 Eclipseコンソールでのパスワード・サンプルの出力

- 10-9 プロキシ・サービス・シェルを実行するキャッシュ・サーバーからの応答

- 10-10 資格が付与される名前付きキャッシュ

- 10-11 資格が付与されるキャッシュ・サービス

- 10-12 アクセス制御のサンプルを実行するサンプル・プログラム

- 10-13 クラスタ側のキャッシュ構成のキャッシュ・サービス・プロキシ構成

- 10-14 Eclipseコンソールのアクセス制御サンプルの出力

- 10-15 プロキシ・サービスを実行中のキャッシュ・サーバーの出力

- 10-16 起動可能オブジェクトのサンプル

- 10-17 資格が付与される起動サービスのサンプル

- 10-18 アクセス起動サービス・サンプルを実行するサンプル・プログラム

- 10-19 クラスタ側キャッシュの起動サービス・プロキシ構成

- 10-20 ExampleInvocableユーザー定義型のPOF構成ファイル

- 10-21 Eclipseコンソールのクライアント・プログラムの応答

- 10-22 Eclipseコンソールのプロキシ・サービスの応答

- 11-1 コミット前イベントとコミット後イベントの間のタイミングを提供するクラス

- 11-2 イベントの処理を遅延するクラスの作成

- 11-3 TimedTraceInterceptorを登録するキャッシュ構成ファイル

- 11-4 LazyProcessorクラスのPOF構成ファイル

- 11-5 TimedTraceInterceptorイベント・インターセプタを実行するクラス

- 11-6 イベント時間測定サンプルのドライバ・ファイル

- 11-7 キャッシュ・クライアントからの出力

- 11-8 イベントを検出および拒否するクラス

- 11-9 CantankerousInterceptorクラスを登録するキャッシュ構成

- 11-10 TimedTraceInterceptorイベント・インターセプタを実行するクラス

- 11-11 イベント拒否クライアントからの出力

- 11-12 キャッシュ・サーバーからの出力

- 11-13 JVMの終了およびロギングの有効化または無効化を実行するクラス

- 11-14 パーティション・イベントを記録するクラス

- 11-15 パーティション・アクティビティ記録サンプルを実行するサンプル・クラス

- 11-16 イベント・インターセプタを含むキャッシュ構成ファイル

- 11-17 パーティション記録イベント・サンプルのPOF構成ファイル

- 11-18 キャッシュ・クライアントからの出力

- 11-19 最初のキャッシュ・サーバーからの出力

- 12-1 サンプルweblogic.xmlファイル

- 12-2 サンプルMANIFEST.MFファイル

図一覧

- 2-1 「Workspace Launcher」ダイアログ・ボックス

- 2-2 メニュー・バーの「Java EE」パースペクティブ

- 2-3 「New Application Client Project」ダイアログ・ボックス

- 2-4 「Project Facets」ダイアログ・ボックスでの「Oracle Coherence」の選択

- 2-5 「Save Preset」ダイアログ・ボックスでの構成名の指定

- 2-6 Coherenceユーザー・ライブラリの作成

- 2-7 Coherenceライブラリ名の指定

- 2-8 Coherenceユーザー・ライブラリに定義されたcoherence.jarファイル

- 2-9 「Run Configurations」ダイアログ・ボックスの「Main」タブ

- 2-10 「Run Configurations」ダイアログ・ボックスの「Coherence」タブ

- 2-11 「Run Configurations」ダイアログ・ボックスの「Common」タブ

- 2-12 新しいJavaクラスの定義

- 2-13 実行可能ファイルの起動構成の定義

- 2-14 起動構成のランタイム引数の設定

- 2-15 「Windows タスク マネージャー」のJavaプロセス

- 3-1 問合せクライアント構成の「Main」タブ

- 4-1 「Generate Getters and Setters」ダイアログ・ボックス

- 4-2 「Generate Constructors using Fields」ダイアログ・ボックス

- 4-3 Contactsキャッシュ・サーバーの実行可能ファイルの「Coherence」タブ

- 5-1 プロジェクトのビルド・パスへのフォルダの追加

- 5-2 Loadingプロジェクトの「Order and Export」タブの内容

- 5-3 DataGeneratorプログラムのクラスパス

- 5-4 LoaderExampleプログラムのクラスパス

- 8-1 データベースへの接続

- 8-2 「Open Perspective」ダイアログ・ボックス内でのJPAパースペクティブの選択

- 8-3 JPAプロジェクトのプロジェクト・ファセット

- 8-4 「New JPA Project」ダイアログ・ボックスの内容

- 8-5 EclipseLink JPAライブラリの追加

- 8-6 TopLinkユーザー・ライブラリへのToplink Grid、EclipselinkおよびJava PersistenceのJARファイルの追加

- 8-7 「JPA Facet」ページへのTopLinkライブラリの追加

- 8-8 「Connection Profile」ページ

- 8-9 「New Connection Profile」ダイアログ・ボックスおよび成功メッセージ

- 8-10 新規JPAプロジェクト・ウィザードの「Coherence」ページ

- 8-11 データベース表の選択

- 8-12 EMPLOYEES表に対するアソシエーション

- 8-13 「Customize Default Entity Generation」ページ

- 8-14 「Customize Individual Entities」ページ

- 8-15 persistence.xmlエディタの「General」タブ

- 8-16 persistence.xmlエディタの「Connection Properties」タブ

- 8-17 persistence.xmlエディタの「Logging」タブ

- 8-18 persistence.xmlエディタの「Properties」タブ

- 8-19 JPAキャッシュ・サーバー用「Main」タブ

- 8-20 JPAキャッシュ・サーバー実行可能ファイルの「Classpath」タブ

- 8-21 RunEmployee実行可能ファイルの「Classpath」タブ

- 9-1 CoherenceCacheServer実行可能ファイルのクラスパス

- 9-2 Javaビルド・パスのライブラリの「Order and Export」タブ

- 9-3 相互作用プロジェクト・キャッシュ・サーバーのクラスパス

- 9-4 DatabaseCacheプログラムへのクラスパス

- 10-1 セキュリティ・キャッシュ・サーバーのクラスパス

- 10-2 セキュリティ・プロキシ・サーバーの「Arguments」タブ

- 10-3 プロキシ・サーバーのクラスパス

- 10-4 PasswordExampleプログラムの「Classpath」タブ

- 10-5 AccessControlExampleプログラムの「Classpath」タブ

- 10-6 キャッシュ・サーバーおよびプロキシ・サービスを実行するサーバーのクラスパス

- 10-7 AccessInvocationServiceExampleプログラムの「Classpath」タブ

- 11-1 イベント・サーバー起動構成の「Main」タブ

- 11-2 イベント・サーバー起動構成の「Classpath」タブ

- 11-3 イベント・クライアント起動構成の「Main」タブ

- 11-4 イベント・クライアント起動構成の「Classpath」タブ

- 12-1 新しいマシンの作成

- 12-2 マシンのサマリー

- 12-3 マシンへのサーバーの追加

- 12-4 「サーバーのサマリー」ページ

- 12-5 Coherenceクラスタの作成

- 12-6 Coherenceクラスタのユニキャスト・リスニング・ポートの指定

- 12-7 Coherenceクラスタ・ターゲットの選択

- 12-8 Coherenceクラスタのサマリー

- 12-9 Coherence*Webローカル記憶域に対するサーバーの有効化

- 12-10 管理対象WebLogic Serverの起動

- 12-11 デプロイ可能なアプリケーションの選択

- 12-12 デプロイメントのアプリケーションとしてのインストール

- 12-13 デプロイメントのターゲット指定

- 12-14 インストール・アシスタントの「オプション設定」ページ

- 12-15 デプロイされたアプリケーションが表示された「デプロイメント」ウィンドウ

- 12-16 カウンタが1に設定されたカウンタ・ページ

- 12-17 カウンタが2に設定されたカウンタ・ページ

表一覧

- 1-1 Coherenceで使用されるネットワーク・アドレスおよびポート

- 3-1 NamedCacheインタフェースのメソッド

- 3-2 CacheFactoryクラスのメソッド

- 6-1 ReflectionExtractors文およびそれと同等なcreateExtractor文

- 6-2 問合せでの*Filter文およびそれと同等なcreateFilter文

- 6-3 集計でのFilter文およびそれと同等なcreateFilter文

- 9-1 キャッシュ・タイプの説明

- 9-2 Coherenceによってサポートされる読取り/書込みキャッシュのタイプ

はじめに

Oracle Coherence (Coherence)は、頻繁に使用されるデータに対する迅速なアクセスを提供することで、組織がミッションクリティカルなアプリケーションを定期的にスケーリングできるようにするインメモリー・データ・グリッド・ソリューションです。データ・グリッド・ソフトウェアは、多数のサーバーのメモリー内に存在するデータ・オブジェクトを確実に管理するためのミドルウェアです。Coherenceでは、データを自動的かつ動的にパーティション化することで、サーバー障害の発生時においても、継続的なデータの可用性およびトランザクションの整合性が実現されます。

開発者は、標準のJavaコレクションAPIを使用してデータにアクセスまたはデータを変更したり、標準のJavaBeansイベント・モデルを使用してデータ変更通知を受け取ったりすることで、Coherenceの機能を簡単に活用できます。

対象読者

このチュートリアルは、ソフトウェア開発者、設計者および管理者を対象としています。Oracle Coherenceのデータ・グリッド用アプリケーションの開発方法を説明します。

ドキュメントのアクセシビリティについて

オラクル社のアクセシビリティへの取組みの詳細は、Oracle Accessibility ProgramのWebサイトhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=docaccを参照してください。

Oracleサポートへのアクセス

お客様は、My Oracle Supportから電子サポートにアクセスできます。詳細は、http://www.oracle.com/pls/topic/lookup?ctx=acc&id=infoまたはhttp://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs (聴覚障害者向け)を参照してください。

関連ドキュメント

詳細は、次のOracle Coherenceのドキュメントを参照してください。

- 『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』

- 『Oracle Fusion Middleware Oracle Coherenceリモート・クライアントの開発』

- 『Oracle Fusion Middleware Oracle Coherenceの統合』

- 『Oracle Fusion Middleware Oracle Coherence*WebでのHTTPセッション・マネージメントの管理』

- 『Oracle Fusion Middleware Oracle Coherenceのマネージメント』

- 『Oracle Fusion Middleware Oracle Coherenceの管理』

- 『Oracle Fusion Middleware Oracle Coherenceの保護』

- 『Oracle Fusion Middleware Oracle WebLogic Server Oracle Coherenceアプリケーションの開発』

- Oracle Fusion Middleware Oracle Coherence Java APIリファレンス

- Oracle Fusion Middleware Oracle Coherence .NET APIリファレンス

- Oracle Fusion Middleware Oracle Coherence C++ APIリファレンス

表記規則

このチュートリアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック体

イタリックは、ユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

このガイドで説明する新機能

次のトピックでは、Oracle Coherenceの新機能と変更された機能について、およびこのガイドに記載されるその他の重要な変更について紹介し、詳細情報へのリンクを提供します。このドキュメントは、旧名Oracle Coherence Oracle Coherenceチュートリアルの新版です。

12c (12.1.2)の新機能と変更された機能

Oracle Coherence 12c (12.1.2)には、このドキュメントについて次の新機能と変更された機能があります。

- ライブ・イベントのチュートリアルでは、Coherenceライブ・イベント・フレームワークの使用方法を示します。このフレームワークを使用すると、データ・グリッドで実行された操作にアプリケーションで対応できます。このフレームワークは、イベントがクラスタ操作の監視可能な発生を表すイベントベースのモデルを使用します。サポートされているイベントには、パーティション・サービス、キャッシュおよびアプリケーション・イベントがあります。第11章「ライブ・イベントの使用」を参照してください。

12c (12.1.2)に関するこのドキュメントにおけるその他の重要な変更

このガイドは12c (12.1.2)でいくつかの点が更新されました。次の表に、追加または変更された項を示します。

- ガイドのチュートリアルすべてを、Coherence 12c (12.1.2)を使用するように改訂しました。

- CoherenceおよびJPAのチュートリアルを、EclipseLink 2.4.x、TopLink Grid 12c (12.1.2)およびJava Persistence 2.0のファイルを使用するように改訂しました。第8章「JPAとCoherenceの併用」を参照してください。

- EclipseでOracle Coherenceキャッシュを作成および構成するチュートリアルを、EclipseLink 2.4.x、TopLink Grid 12c (12.1.2)およびJava Persistence 2.0のファイルを使用するように改訂しました。第9章「キャッシュとデータベースの相互作用」を参照してください。

- セッション・キャッシュおよび管理対象WebLogic Serversのチュートリアルを、WebLogic Server 12c (12.1.2)を使用するように改訂しました。第12章「管理対象WebLogic Serverを使用したセッションのキャッシュ」を参照してください。

1 Coherenceのインストールと構成

この章では、Oracle Coherence 12c (12.1.2)(Coherence)を実行するための環境をインストールおよび設定する方法について説明します。

注意:

このチュートリアルでは、Oracle Enterprise Pack for Eclipse (OEPE) 12.1.2.0.0とともにEclipse Juno 3.8.0リリースを使用します。EclipseおよびOEPE for Coherenceベースのプロジェクトの構成については、第2章「EclipseおよびOEPEのインストールとCoherenceと併用するための構成」を参照してください。

oracleユーザーとしてソフトウェアをインストールし、システム環境変数を設定するための権限が必要な他、環境変数の設定、ディレクトリの作成やディレクトリ間の移動など、端末ウィンドウの使用方法を理解している必要があります。Java SE (JDK)バージョン1.7以降の作業用インストールが必要です。また、Microsoft Windowsオペレーティング・システム(XP、Vista、2000、2003、2008のいずれか)を実行している必要があります。

この章には次の項が含まれます:

- Coherenceのインストール

- Coherenceインストールのテスト

1.1 Coherenceのインストール

Oracle Coherenceのインストールの詳細は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のOracle Coherence for Javaのインストールに関する項を参照してください。この章では、Oracle Universal Installerを使用したOracle Coherenceのインストール手順について説明します。このインストーラは、グラフィック・モードとサイレント・モードの両方をサポートします。また、Coherence Quick Installerを使用して、オプションなしでサイレント・インストールを実行するように選択することもできます。

注意:

このチュートリアルでは、Oracle Universal Installerのグラフィカル・インタフェースを使用して、C:\oracle\Middleware\Oracle_HomeにOracle Coherenceがインストールされていることを前提としています。

Oracle_Homeの下に表示されるcoherenceフォルダには次のサブフォルダが含まれます。

- bin: コマンド・スクリプトが格納されています。

- doc: 製品ドキュメントが格納されています。

- examples: Java、.NETおよびC++プラットフォームのコード例が格納されています。

- lib: 必要なライブラリ・ファイルが格納されています。

1.2 Coherenceインストールのテスト

この演習では、現在のCoherenceインストールでJavaプロセスをクラスタ化できるかどうかをテストします。これにより、Coherenceに付属しているCoherenceベースのアプリケーションが予期したとおりに稼働することを確認できます。1 つのマシンでクラスタ化できない場合は、ネットワークとファイアウォールの設定を再構成する必要があります。

この演習を実行するには、Coherence (Java Edition) 12c (12.1.2)がインストールされている必要があります。詳細は、「Coherenceのインストール」を参照してください。

Coherenceでは、クラスタ化されたプロセス間の通信を可能するために、様々なネットワーク・アドレスおよびポートを使用します。他のアプリケーションで使用されているため、またはファイアウォールが原因でこれらのアドレスやポートを使用できない場合、Coherenceは信頼性がなくなったり、クラスタ化に失敗したり、まったく動作しなかったりすることがあります。Coherenceではデフォルトで、表1-1に記載されているネットワーク・アドレスおよびポートが使用可能であると想定しています。

表1-1 Coherenceで使用されるネットワーク・アドレスおよびポート

アドレス/ポート/タイプ

目的

224.version/version/マルチキャスト

クラスタ・メンバーの検出およびブロードキャスト。変数versionは、Coherenceのリリース・バージョンを表します。たとえば、12.1.2リリースのマルチキャスト・アドレスは224.12.1.0です。ポート番号にもリリース・バージョンが反映されます。たとえば、12.1.2リリースの場合、ポート番号は12100です。アドレスをこのように設計することによって、デフォルトで、異なるバージョンのCoherenceが相互にクラスタ化されることがなくなります。

localhost/8088+/ユニキャスト

クラスタ・メンバー間のプロセス間通信。(localhostはローカルIPアドレスであり、ループバック・アドレスではありません。)

localhost / 8089 / Unicast

ユニキャスト通信に使用される追加ポート。デフォルトでは、先頭のユニキャスト・ポートの次に使用可能なポートとしてこのポートを割り当てます。

localhost / 7 / Unicast

クラスタ・メンバーのハードウェア障害の検出に使用されるIpMonitorコンポーネントのデフォルト・ポートは7です。

Coherenceには単純なコマンド行(シェルベース)アプリケーションが2つ付属しており、これらを使用して、Coherenceが正しく動作するかどうかを確認できます。

- キャッシュ・サーバーは、クラスタ内の他のアプリケーションのかわりにデータをホストして管理する、単純なアプリケーションです。

- キャッシュ・クライアントは、開発者がクラスタ内のキャッシュ・データにアクセスし、処理および更新するための単純なアプリケーションです。また、クラスタに関する情報も提供します。1つのホストまたは複数のホストでこれらのアプリケーションを実行することによって、Coherenceがローカルまたはネットワークで正しく動作しているかどうかを確認できます。
アプリケーションがCoherenceを出荷時の状態で使用すると、Coherenceのキャッシュに格納されたオブジェクトは通常、アプリケーション内でインプロセスで格納および管理されます。ただし、オブジェクトの可用性を向上させるために、Coherenceでは、インメモリーで、アプリケーション・プロセス外でオブジェクトを管理できます。これにより、(故意であるか偶然であるかにかかわらず)アプリケーションが停止した場合でもオブジェクトが失われることはありません。オブジェクトをこのように管理するために、Coherenceではキャッシュ・サーバーを使用します。Coherenceのキャッシュ・サーバーの目的は、アプリケーション・プロセス外のクラスタでアプリケーションの状態を管理することです。これはデータベース・サーバーと同様ですが、記憶域は必要ありません。

1.2.1 Coherenceインストールをテストするには - 主な手順

Coherenceインストールをテストする手順は次のとおりです。各手順の詳細は、この後の項を参照してください。

1. サンプル・キャッシュ・サーバー・アプリケーションの構成と実行

2. サンプル・キャッシュ・クライアント・アプリケーションの構成と実行

3. サンプル・キャッシュ・クライアント・アプリケーションの演習

4. キャッシュ・サーバーのクラスタ化のトラブルシューティング

1.2.2 サンプル・キャッシュ・サーバー・アプリケーションの構成と実行

サンプル・キャッシュ・サーバー・アプリケーションを設定および実行するには:

1. 端末ウィンドウを開き、PATH環境変数がJava JDK(例: C:\oracle\Middleware\jdk170\bin)を含むように設定されていることを確認します。PATH環境変数にJDKの\binフォルダが含まれていない場合は、次のように設定してください。

1. JAVA_HOME環境変数をJDKインストールのベースに設定します。

set JAVA_HOME=\oracle\Middleware\jdk170

2. PATH環境変数にJAVA_HOME\binを含めます。

set PATH=%JAVA_HOME%\bin;%PATH%

2. Coherenceがインストールされているフォルダに移動します。cache-server.cmdファイルを編集し、COHERENCE_HOME変数を、Coherenceのインストール・フォルダを指すように設定します。

cd C:\oracle\Middleware\Oracle_Home\coherence\bin

cache-server.cmdファイルで、COHERENCE_HOME環境変数を次のように設定します。

COHERENCE_HOME=C:\oracle\Middleware\Oracle_Home\coherence

例1-1に、COHERENCE_HOME環境変数の値を編集したcache-server.cmdファイルを示します。

例1-1 COHERENCE_HOMEを編集したcache-server.cmdファイル

@echo off
@
@rem This will start a cache server
@
setlocal

:config
@rem specify the Coherence installation directory
set coherence_home=c:\oracle\product\coherence

@rem specify the JVM heap size
set memory=512m

:start
if not exist "%coherence_home%\lib\coherence.jar" goto instructions

if "%java_home%"=="" (set java_exec=java) else (set java_exec=%java_home%\bin\java)

:launch

if "%1"=="-jmx" (
set jmxproperties=-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true
shift
)

set java_opts=-Xms%memory% -Xmx%memory% %jmxproperties%

%java_exec% -server -showversion %java_opts% -cp "%coherence_home%\lib\coherence.jar" -Dtangosol.coherence.clusterport=3155 com.tangosol.net.DefaultCacheServer %1

goto exit

:instructions

echo Usage:
echo   ^<coherence_home^>\bin\cache-server.cmd
goto exit

:exit
endlocal
@echo on

3. coherence\binフォルダにあるキャッシュ・サーバー・アプリケーションを実行します。

C:\oracle\product\coherence\bin>cache-server.cmd

最初のキャッシュ・サーバーを起動するときには、キャッシュ・サーバーが既存のクラスタを探すため、多少の遅延があります。キャッシュ・サーバーは参加するクラスタがないと判断すると、クラスタを1つ起動します。起動時に、キャッシュ・サーバーでは例1-2のテキストのような出力が生成されます。

この例では、次のような重要な機能が強調表示されています。

- Java JDKのバージョン番号

- 構成ファイルのロード方法に関する情報。デフォルトでは、coherence.jarファイルからロードされます。
Loaded operational configuration from resource "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/tangosol-coherence.xml"

- Coherenceのリリース番号: Oracle Coherence 12.1.0.0...

- Coherenceのエディション: Grid Edition: Development mode

- マルチキャスト・アドレス。このアドレスはCoherenceのバージョンごとに変わります。Coherence 12c (12.1.2)のアドレス内には次のように12.1.0が含まれます。Group{Address=224.12.1.0, Port=12100, TTL=4}

- メンバーIDは、クラスタ内のメンバーの数を示します。この演習では、値が1である必要があります。ThisMember=Member(Id=1...

例1-2 Coherenceのキャッシュ・サーバー起動時の出力

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Server VM (build 21.0-b17, mixed mode)

2012-08-14 15:29:26.171/0.656 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-14 15:29:26.453/0.938 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-14 15:29:26.453/0.938 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
2012-08-14 15:29:26.453/0.938 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-14 15:29:26.468/0.953 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-14 15:29:26.468/0.953 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-14 15:29:27.015/1.500 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-14 15:29:27.203/1.688 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-14 15:29:27.781/2.266 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-14 15:29:28.265/2.750 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-14 15:29:31.687/6.172 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5044, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-14 15:29:31.703/6.188 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=12100, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:
5044, Role=CoherenceServer)
OldestMember=Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,proces
s:5044, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5044, Rol
e=CoherenceServer)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-14 15:29:28.39|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-14 15:29:32.031/6.516 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-14 15:29:32.203/6.688 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-14 15:29:32.625/7.110 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2012-08-14 15:29:32.718/7.203 Oracle Coherence GE 12.1.2.0 <D5> (thread=ReplicatedCache, member=1): Service ReplicatedCache joined the cluster with senior service member 1
2012-08-14 15:29:32.718/7.203 Oracle Coherence GE 12.1.2.0 <D5> (thread=OptimisticCache, member=1): Service OptimisticCache joined the cluster with senior service member 1
2012-08-14 15:29:32.734/7.219 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:InvocationService, member=1): Service InvocationService joined the cluster with senior service member 1
2012-08-14 15:29:32.734/7.219 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1):
Services
(
ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=12.1.2, OldestMemberId=1}
PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, Ba
ckupPartitions=0}
ReplicatedCache{Name=ReplicatedCache, State=(SERVICE_STARTED), Id=3, Version=12.1.2, OldestMemberId=1}
Optimistic{Name=OptimisticCache, State=(SERVICE_STARTED), Id=4, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=InvocationService, State=(SERVICE_STARTED), Id=5, Version=12.1.2, OldestMemberId=1}
)

Started DefaultCacheServer...

注意:

Coherenceはデフォルトで、マルチキャストを使用してクラスタに参加したり、クラスタ・イベントを配布するように構成されます。マルチキャストを使用すると、クラスタ内の複数のノードにメッセージを効率的に配布することもできます。マルチキャストを使用しないようにCoherenceを構成することもできます。

cache-server.cmdファイルの出力は、クラスタ内のメンバーが1つであるか複数であるかを示します。Member Idの値は1である必要があります。

...
In MasterMemberSet
ThisMember=Member(Id should be equal to 1)
...

ThisMemberのIdが1より大きい場合、キャッシュ・サーバーがネットワーク内の既存のクラスタに参加していることを意味します。この演習では、クラスタのメンバーは1つのみである必要があります。「Coherenceを自分のホストに制限する」の手順に従って、Coherenceを自分のホストに制限してください。

1.2.3 サンプル・キャッシュ・クライアント・アプリケーションの構成と実行

サンプル・キャッシュ・クライアント・アプリケーションを設定および実行するには:

1. キャッシュ・クライアントを起動するために、別の端末ウィンドウを開きます。

PATH環境変数が%JAVA_HOME%\binフォルダを含むように設定されていることを確認します。PATH環境変数に%JAVA_HOME%\binフォルダが含まれていない場合は、「サンプル・キャッシュ・サーバー・アプリケーションの構成と実行」の説明に従って変数を設定してください。

2. \oracle\Middleware\Oracle_Home\coherence\binフォルダに移動します。query.cmdファイルを編集して、COHERENCE_HOME変数を、Coherenceのインストール・フォルダを指すように設定します。
query.cmdファイルには、JLine JARファイル(jline.jar)への参照が含まれています。JLineは、コンソール・コマンドの操作を簡素化するJavaライブラリです。jline.jarファイルは、coherence\libフォルダにあります。

例1-3に、COHERENCE_HOME=\oracle\product\coherenceと設定したquery.cmdファイルを示します。JLINE_HOMEが%jline_home%\libに設定されています。

例1-3 COHERENCE_HOMEを編集したquery.cmdファイル

@echo off
@
@rem This will start a console application
@rem demonstrating the functionality of the Coherence(tm) API
@
setlocal

:config
@rem specify the Coherence installation directory
set coherence_home=C:\oracle\Middleware\Oracle_Home\coherence

@rem specify the jline installation directory
set jline_home=%coherence_home%\lib

@rem specify if the console will also act as a server
set storage_enabled=false

@rem specify the JVM heap size
set memory=64m

:start
if not exist "%coherence_home%\lib\coherence.jar" goto instructions

if "%java_home%"=="" (set java_exec=java) else (set java_exec=%java_home%\bin\java)

:launch

if "%storage_enabled%"=="true" (echo ** Starting storage enabled console **) else (echo **
Starting storage disabled console **)

set java_opts="-Xms%memory% -Xmx%memory%
-Dtangosol.coherence.distributed.localstorage=%storage_enabled%"

"%java_exec%" -server -showversion "%java_opts%" -cp
"%coherence_home%\lib\coherence.jar;%jline_home%\jline.jar"
com.tangosol.coherence.dslquery.QueryPlus %*

goto exit

:instructions

echo Usage:
echo   ^<coherence_home^>\bin\query.cmd
goto exit

:exit
endlocal
@echo on

3. query.cmdファイルを実行して、キャッシュ・クライアントを起動します。

query.cmd

キャッシュ・クライアント起動時の出力(例1-4を参照)には、Coherence内に構築されている基本的な分散キャッシュ機能が表示されます。出力の最後には、CohQL>プロンプトが表示されます。

例1-4 Coherenceのキャッシュ・クライアント起動時の出力

C:\oracle\Middleware\Oracle_Home\coherence\bin>query.cmd
** Starting storage disabled console **
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Server VM (build 21.0-b17, mixed mode)

Coherence Command Line Tool

CohQL>

1.2.4 サンプル・キャッシュ・クライアント・アプリケーションの演習

様々なコマンドを入力し、出力を調べることによって、キャッシュ・クライアント・アプリケーションの演習を行います。

1. キャッシュ・クライアントで次のCoherenceコマンドを実行します。

- helpと入力して、使用可能なコマンドのリストを表示します。

- create cache "products"と入力して、productsという名前のキャッシュを作成します。
キャッシュproductsは、com.tangosol.net.NamedCacheインタフェースを実装します。1つのクラスタに複数の名前付きキャッシュを含めることができます。

例1-5は、指定したcoherence.jarファイル内のデフォルトの構成ファイル(coherence-cache-config.xml)を使用すると、分散スキームを使用してproductsという名前のNamedCacheが作成されることを示しています。

例1-5 Coherenceのキャッシュ・クライアント起動時の出力

2012-08-14 16:15:28.828/26.485 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/
Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-14 16:15:29.062/26.719 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Midd
leware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-14 16:15:29.062/26.719 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override
.xml" is not specified
2012-08-14 16:15:29.062/26.719 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is
not specified
2012-08-14 16:15:29.062/26.719 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config
.xml" is not specified
2012-08-14 16:15:29.062/26.719 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not s
pecified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-14 16:15:31.296/28.953 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Mid
dleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-14 16:15:31.984/29.641 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Mid
dleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-14 16:15:35.484/33.141 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigu
rableCacheFactory
2012-08-14 16:15:37.125/34.782 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8090 using SystemDatagramSock
etProvider
2012-08-14 16:15:37.703/35.360 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2012-08-14 16:15:37.687,
Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3796, Role=TangosolCoherenceQueryPlus, Edition=Grid Edition,
Mode=Development, CpuCount=2, SocketCount=1) joined cluster "cluster:0x47DB" with senior Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.3
5.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5044, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCo
unt=2, SocketCount=1)
2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1

2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedCache with senior me
mber 1
2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service ReplicatedCache with senior mem
ber 1
2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service OptimisticCache with senior mem
ber 1
2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service InvocationService with senior m
ember 1
2012-08-14 16:15:37.828/35.485 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=2, Timestamp=2012-08-14 16:15:37.687, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process
:3796, Role=TangosolCoherenceQueryPlus)
OldestMember=Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,proces
s:5044, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2012-08-14 15:29:28.39, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5044, Rol
e=CoherenceServer)
Member(Id=2, Timestamp=2012-08-14 16:15:37.687, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3796, Ro
le=TangosolCoherenceQueryPlus)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-14 15:29:28.39|JOINED,
2|12.1.2|2012-08-14 16:15:37.687|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2012-08-14 16:15:38.125/35.782 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with
senior service member 1
2012-08-14 16:15:38.640/36.297 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/oracle/Mi
ddleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-14 16:15:40.593/38.250 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=2): Service DistributedCache joined the cluster with
senior service member 1

CohQL>

2. キャッシュ・クライアントのCohQLプロンプトで次のコマンドを実行します。これらのコマンドの定義は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のCoherence問合せ言語に関する項を参照してください。

- エントリ(キーと値のペア)をproductsキャッシュに挿入します。

insert into "products" key "television" value "ID-5070"

- キーの値を変更します。

update "products" set value() = "ID-5080" where key() like "television"

- キャッシュ内の値を取得します。

select * from "products"

- 存在しないキーの値を取得します。空の結果セットが返されます。

select key(), value() from "products" where key() is "radio"

- キャッシュ内の既存のキーを削除します。空の結果セットが返されます。

delete from "products" where key() = "television"

- productsキャッシュの内容を削除します。空の結果セットが返されます。

delete from "products"

- productsキャッシュを破棄します。

drop cache "products"

- productsキャッシュを再作成します。

create cache "products"

- さらに多くのエントリをキャッシュに挿入します。

insert into "products" key "television" value "ID-5080"
insert into "products" key "radio" value "ID-5090"
insert into "products" key "MP3 Player" value "ID-5100"
insert into "products" key "laptop" value "ID-5110"

- productsキャッシュ内のキーと値を取得します。

select key(), value() from "products"

- キャッシュのシリアライズされた形式をファイルに保存します。

backup cache "products" to "products.bkup"

- キャッシュからキーを削除します。

delete from "products" where key() = "television"

- キャッシュの内容を再度取得し、削除されたキーと値が存在しないことを確認します。

select key(), value() from "products"

- キャッシュの内容を削除します。

delete from "products"

- キャッシュの内容を取得します。空の結果セットが返されます。

select * from "products"

- バックアップ・ファイルからキャッシュの内容をリストアします。

restore cache "products" from file "products.bkup"

- キャッシュの内容を取得します。すべてのエントリがリストアされ、返されることを確認します。

select key(), value() from "products"

- productsキャッシュを破棄します。

drop cache "products"

- コマンド行ツールを終了します。

bye

例1-6に、これらの各コマンドの出力を示します。

例1-6 Coherenceコマンドの演習

CohQL> create cache "products"

CohQL> insert into "products" key "television" value "ID-5070"

CohQL> update "products" set value() = "ID-5080" where key() like "television
Results
television: true

CohQL> select * from "products"
Results
ID-5080

CohQL> select key(), value() from "products" where key() is "radio"
Results

CohQL> delete from "products" where key() = "television"
Results

CohQL> delete from "products"
Results

CohQL> drop cache "products"

CohQL> create cache "products"

CohQL> insert into "products" key "television" value "ID-5080"

CohQL> insert into "products" key "radio" value "ID-5090"

CohQL> insert into "products" key "MP3 Player" value "ID-5100"

CohQL> insert into "products" key "laptop" value "ID-5110"

CohQL> select key(), value() from "products"
Results
"television", "ID-5080"
"radio", "ID-5090"
"MP3 Player", "ID-5100"
"laptop", "ID-5110"

CohQL> backup cache "products" to "products.bkup"
WARNING: The backup command should not be used on active data set,
as it makes no provisions that ensure data consistency during the backup.
Please see the documentation for more detailed information.

CohQL> delete from "products" where key() = "television"
Results

CohQL> select key(), value() from "products"
Results
"radio", "ID-5090"
"MP3 Player", "ID-5100"
"laptop", "ID-5110"

CohQL> delete from "products"
Results

CohQL> select * from "products"
Results

CohQL> restore cache "products" from file "products.bkup"

CohQL> select key(), value() from "products"
Results
"television", "ID-5080"
"radio", "ID-5090"
"MP3 Player", "ID-5100"
"laptop", "ID-5110"

CohQL> drop cache "products"

CohQL> bye

キャッシュ・サーバー・ウィンドウでは、クライアント(member 2)がクラスタから離脱したことを示す、次のようなレスポンスが表示されます。

2012-08-14 16:57:54.953/5309.438 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2012-08-14 16:15:37.687, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3796, Role=TangosolCoherenceQueryPlus) due to a peer departure; removing the member.
2012-08-14 16:57:54.953/5309.438 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2012-08-14 16:57:54.953/5309.438 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service DistributedCache with senior member 1
2012-08-14 16:57:54.953/5309.438 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-14 16:57:54.953, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3796, Role=TangosolCoherenceQueryPlus) left Cluster with senior member 1

3. 別の端末ウィンドウを開き、PATH環境変数を、%JAVA_HOME%および%JAVA_HOME%\binを含むように設定します。新しい端末ウィンドウでquery.cmdコマンドを入力して、キャッシュ・クライアントのインスタンスを起動します。

4. query.cmdコマンドを使用して最初のクライアントを再起動します。create cache "products"コマンドを入力します。端末ウィンドウに、最初のクライアントが実行されている場所を示す、次のようなメッセージが表示されます。member 1はキャッシュ・サーバー、member 3は再起動された最初のクライアントです。

2012-08-14 16:58:01.990/1562.468 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2012-08-14 16:48:01.85, Address=130.35.99.165:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:2804, Role=TangosolCoherenceQueryPlus) joined Cluster with senior member 12012-08-14 16:58:02.256/1562.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 12012-08-14 16:58:02.740/1563.218 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 3 joined Service DistributedCache with senior member 1

CohQL>

5. 新しい端末ウィンドウでcreate cache "products"コマンドを入力して、productsキャッシュに接続します。ここでは、クラスタがMember 4と入力されています。様々なセッションで値の取得や挿入を行ってみてください。各クライアントは、もう一方のクライアントで行われた変更を監視できます。

6. query.cmdクライアント・シェルの一方を終了します(bye)。メンバーがクラスタから離脱したことを示すメッセージがもう一方のシェルに表示されます。次に例を示します。

CohQL> 2012-08-14 16:56:43.912/714.109 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=3): TcpRing disconnected from Member(Id=4, Timestamp=2012-08-14 16:53:08.709, Address=130.35.99.165:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4656, Role=TangosolCoherenceQueryPlus) due to a peer departure; removing the member.2012-08-14 16:56:43.912/714.109 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=3): Member 4 left service Management with senior member 12012-08-14 16:56:43.912/714.109 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=3): Member 4 left service DistributedCache with senior member 12012-08-14 16:56:43.912/714.109 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=3): Member(Id=4, Timestamp=2012-08-14 16:56:43.912, Address=130.35.99.165:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4656, Role=TangosolCoherenceQueryPlus) left Cluster with senior member 1

7. それぞれのキャッシュ・クライアントを終了し(bye)、再起動しても、前のセッションのデータは引き続き使用可能です。これは、データがキャッシュ・サーバーに保持されているためです。

8. 別のCoherenceキャッシュ・サーバーを起動し、起動されている最初のサーバーを終了しても([Ctrl]+[C]キーを使用するか、コマンド・ウィンドウを閉じる)、データは引き続き使用可能です。

9. query.cmdシェルとcache-server.cmdシェルの両方を終了します。query.cmdを再起動します。コマンドcreate cache testを使用して、testという名前のキャッシュを作成します。これまでと同様に、値をキャッシュに挿入してみてください。キャッシュ・クライアントは記憶域無効モードで起動するように構成されているため、次のようなメッセージが表示されます。

com.tangosol.net.RequestPolicyException: No storage-enabled nodes exist for service DistributedCache

10. cache-server.cmdファイルを実行して、キャッシュ・サーバーを起動します。もう一度、値を挿入してみてください。今度は値が受け付けられます。

11. すべてのキャッシュ・サーバーを終了します。

1.2.5 キャッシュ・サーバーのクラスタ化のトラブルシューティング

cache-server.cmdの出力のメンバーIDの値が1以外の場合、キャッシュ・サーバーが、Coherenceを実行している1つ以上の他のキャッシュ・サーバーまたはプロセスとともにクラスタ化されていることを示します。これらのサーバーまたはプロセスは、ネットワーク上で実行されている場合もあれば、自分のホスト上でローカルで実行されている場合もあります。Coherenceをローカルまたはネットワークで実行している他のプロセスとともにクラスタ化することはCoherenceのデフォルトの動作ですが、このチュートリアルを実施している間は、Coherenceを自分のホストに制限することを強くお薦めします。

注意:

Coherenceを1 つのホストに制限するために、このチュートリアルで使用するキャッシュ・サーバーおよびキャッシュ・クライアントの実行可能ファイルでは、3155に設定されたtangosol.coherence.clusterportコマンド行プロパティを使用します。

1.2.5.1 Coherenceを自分のホストに制限する

cache-server.cmdキャッシュ・サーバー・コマンドの出力におけるメンバーIDの値は、クラスタ内のメンバーが1つであるか複数であるかを示します。このチュートリアルでは、メンバーIDの値は1である必要があります。

...
In MasterMemberSet
ThisMember=Member(Id should be equal to 1)
...

メンバーIDの値が1より大きい場合、サブネット内に複数のクラスタが形成されていることを意味します。

Coherenceを自分のホストに制限するには、いくつかの方法があります。最も簡単な方法は、tangosol.coherence.clusterportシステム・プロパティを使用して、キャッシュ・サーバーの起動ファイルで一意のクラスタ・ポート値を宣言する方法です。たとえば、cache-server.cmdファイルに次のJavaオプションを追加します。このシステム・プロパティに割り当てる値には、電話番号の下4桁など、任意の一意の値を使用できます。

-Dtangosol.coherence.clusterport=3155

1.2.5.2 Coherenceを自分のホストに制限するための詳細な手順

「Coherenceを自分のホストに制限する」の手順を実行しても、cache-server.cmdコマンドから返されるメンバーIDの値が1でない場合は、解決の必要な問題が他にもある可能性があります。

ネットワークから切断するか、ホスト上でネットワークを無効にします。キャッシュ・サーバーの起動時にエラーや例外が発生する場合は、ネットワークの設定の変更が必要である可能性があります。次の手順をそれぞれ1つずつ試し、それぞれの手順が終わるたびにキャッシュ・サーバーを再起動してください。

- 仮想プライベート・ネットワーク(VPN)に接続している場合は切断します。デフォルトでは、ほとんどのVPNはマルチキャスト・トラフィックおよび一部のユニキャスト・トラフィックを許可しないように構成されています。この環境では、出荷時の構成のままではCoherenceが動作しない場合があります。VPN経由で稼働するようにCoherenceを構成することもできますが、それにはいくつかの高度な設定が必要です。

- ファイアウォールを実行している場合は、指定したアドレスおよびポートを使用できるように構成します。

- 引き続き問題が発生する場合は、すべてのネットワークから切断します。これには、無線ネットワークと有線ネットワークが含まれます。

- 前述のオプションがすべて失敗した場合は、1つのホストで稼働するようにCoherenceを設定します。

2 EclipseおよびOEPEのインストールとCoherenceと併用するための構成

この章では、Eclipse IDE for Java EE Developers (Eclipse)のIndigoリリースとOracle Enterprise Pack for Eclipse 12.1.2.0.0 (OEPE)を設定して、CoherenceベースのJavaアプリケーションをビルドおよび実行する方法について説明します。

この章には次の項が含まれます:

- EclipseおよびOEPEのインストール

- Coherence用のEclipseおよびOEPEの構成

- Eclipse IDEでの新規プロジェクトの作成

- Eclipse IDEでのキャッシュ・サーバーの起動

- Eclipse IDEの基礎について

2.1 EclipseおよびOEPEのインストール

Eclipse Junoの構成済バージョンとOEPEプラグインがバンドルされたOEPE (12.1.2.0.0)のオールインワン・バージョンをダウンロードできます。オールインワン・バージョンをインストールすることをお薦めします。

また、OEPEディストリビューションを単独でダウンロードし、既存のEclipse Junoインストールにインストールすることもできます。OEPEのインストーラには、Oracle WebLogic Server、Oracle CoherenceおよびOracle ADF Runtimeが含まれています。

どちらかのバージョンをダウンロードするには、次のOracle Enterprise Pack for Eclipseページの「Downloads」タブを選択します。

http://www.oracle.com/technetwork/developer-tools/eclipse/overview/index.html

インストーラの指示に従ってください。次のURLでインストール手順を参照することもできます。

http://docs.oracle.com/cd/E27086_01/help/oracle.eclipse.tools.common.doc/html/install.html

このチュートリアルは、次のようなファイル・システムのルートに作成したeclipseフォルダにEclipseをインストールすることを前提としています。

C:\eclipse\*

2.2 Coherence用のEclipseおよびOEPEの構成

Eclipseを起動して、Coherenceとともに使用できるように構成するには:

1. 端末ウィンドウを開き、PATH環境変数がJava JDK(例: C:\oracle\Middleware\jdk170\bin)を含むように設定されていることを確認します。Java SE (JDK)バージョン1.7以降の作業用インストールが必要です。
PATH環境変数にJava JDKの\binフォルダが含まれていない場合は、変数を次のように設定してください。

1. JAVA_HOME環境変数をJDKインストールのベースに設定します。次に例を示します。

set JAVA_HOME=\oracle\Middleware\jdk170

2. PATH環境変数に%JAVA_HOME%\binを含めます。次に例を示します。

set PATH=%JAVA_HOME%\bin;%PATH%

2. Eclipseを起動します。
Eclipseの実行可能ファイルはeclipse.exeです。eclipseというディレクトリにEclipseを抽出した場合、eclipse.exeは次の場所にあります。

C:\eclipse\eclipse.exe

3. Eclipseにより、「Workspace Launcher」ダイアログ・ボックスでワークスペースを設定または選択するよう求められたら、C:\home\oracle\workspaceと入力します。
図2-1に、パスC:\home\oracle\workspaceを選択した「Workspace Launcher」ダイアログ・ボックスを示します。

図2-1 「Workspace Launcher」ダイアログ・ボックス

4. Eclipseが起動したら、「Java EE」パースペクティブを選択します。

- 「Window」を選択し、「Open」→「Perspective」→「Java EE」を選択します。または、

- メニュー・バーの「Java EE」パースペクティブ・アイコンを選択します。

図2-2に、「Java EE」パースペクティブ・アイコンの場所を示します。

図2-2 メニュー・バーの「Java EE」パースペクティブ

2.3 Eclipse IDEでの新規プロジェクトの作成

Eclipse IDEで新しいプロジェクトを作成するには:

1. 「File」→「New」→「Application Client Project」を選択します。

2. 「New Application Client Project」ダイアログ・ボックスで、「Project name」に値(Coherenceなど)を入力します。

図2-3 「New Application Client Project」ダイアログ・ボックス

3. 「Configuration」セクションで「Modify」をクリックします。「Project Facets」ダイアログ・ボックスで、「Oracle Coherence」チェック・ボックスを選択します。ドロップダウン・リストからバージョン「12.1.2」を選択します(表示されていない場合)。
Oracle Coherenceファセットを追加すると、coherence.jarがプロジェクト・クラス・パスに自動的に追加されます。また、Project Explorerで使用可能な、よく使用される次の構成ファイルが作成されます。

- coherence-cache-config.xml: デフォルトのキャッシュ構成ファイル

- pof-config.xml: Portable Object Formatシリアライズの構成ファイル

- tangosol-coherence-override.xml: Coherenceで使用される操作設定およびランタイム設定のオーバーライド・ファイル

注意:

次の図は、最新の12.1.2ベータ・リリース用に更新されていません。

図2-4 「Project Facets」ダイアログ・ボックスでの「Oracle Coherence」の選択

4. 「Save As」をクリックして、「Save Preset」ダイアログ・ボックスで構成の名前を入力します。たとえば、「Name」フィールドにCoherenceConfigと入力し、「Description」フィールドにIncludes Coherence Facetと入力します。
図2-5に、「Save Preset」ダイアログ・ボックスを示します。

図2-5 「Save Preset」ダイアログ・ボックスでの構成名の指定

「OK」をクリックして、「Save Preset」ダイアログ・ボックスを閉じます。「OK」をクリックして、「Project Facets」ダイアログ・ボックスを閉じます。

5. 「New Application Client Project」ダイアログ・ボックスの「Java」ページで「Next」をクリックして、デフォルト値を受け入れます。

6. 「New Application Client Project」ダイアログ・ボックスの「Application Client Module」ページで「Next」をクリックします。

7. 「New Application Client Project」ダイアログ・ボックスの「Application Client Module」ページで「 Create a default Main class」を選択解除します。「Next」をクリックします。

8. 「Coherence」ページ(図2-6を参照)で、Coherence 12.1.2ライブラリをユーザー・ライブラリとしてプロジェクトに追加します。

図2-6 Coherenceユーザー・ライブラリの作成

1. 「Manage Libraries...」アイコンをクリックし、「Preferences」ダイアログ・ボックスで「New」をクリックします。

2. 「New User Library」ダイアログ・ボックス(図2-7を参照)でCoherence12.1.2と入力します。「System library (added to the boot class path)」チェック・ボックスを選択します。「OK」をクリックして、「New User Library」ダイアログ・ボックスを閉じます。

図2-7 Coherenceライブラリ名の指定

3. 「Preferences」ダイアログ・ボックスで、「Add External JARs」をクリックしてcoherence.jarファイルをライブラリに追加します。「Coherenceのインストール」でファイル・システムにダウンロードしたCoherenceディストリビューションのcoherence.jarファイルの場所に移動します。
「Preferences」ダイアログ・ボックスは図2-8のようになります。「OK」をクリックして、「Preferences」ダイアログ・ボックスを閉じます。

図2-8 Coherenceユーザー・ライブラリに定義されたcoherence.jarファイル

9. 「Coherence」ページで「Coherence12.1.2」ライブラリを選択し、「Finish」をクリックします。

Eclipse IDEの「Project Explorer」ウィンドウに新しいプロジェクトと関連ファイルが表示されます。

2.4 Eclipse IDEでのキャッシュ・サーバーの起動

1. Eclipse IDEでプロジェクトを右クリックします。「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」→「New launch configuration」アイコンを選択します。キャッシュ・サーバー構成の名前としてDefaultCacheServerを入力します。

2. 「Project」で「Browse」をクリックし、「Project Selection」ダイアログ・ボックスでプロジェクトの名前を選択します。

3. 「Main class」で、「Include system libraries when searching for a main class」チェック・ボックスを選択します。「Search」ボタンをクリックし、「Select Main Type」ダイアログ・ボックスでDefaultCacheServerと入力します。「com.tangosol.net.DefaultCacheServer」を選択し、「OK」をクリックします。「Apply」をクリックします。「Main」タブは図2-9のようになります。

図2-9 「Run Configurations」ダイアログ・ボックスの「Main」タブ

4. 「Coherence」タブで「General」タブを選択します。まだ選択されていない場合は、「Browse」アイコンをクリックしてキャッシュ構成ファイルに移動します。ローカル記憶域を有効(キャッシュ・サーバー)にするように選択します。「Cluster port」に一意の値(3155など)を入力します。「Apply」をクリックします。「Coherence」タブは図2-10のようになります。

図2-10 「Run Configurations」ダイアログ・ボックスの「Coherence」タブ

5. 「Arguments」タブを開きます。「VM Arguments」フィールドに-showversionと入力します。「Apply」をクリックします。

6. ダイアログ・ボックスの「Common」タブを開きます。「Shared file」ラジオ・ボタンをクリックし、「Browse」をクリックしてプロジェクトに移動します。「Apply」をクリックします。「Common」タブは図2-11のようになります。

図2-11 「Run Configurations」ダイアログ・ボックスの「Common」タブ

7. 「Run」をクリックして、キャッシュ・サーバーを起動します。キャッシュ・サーバーが起動し、例2-1のような出力が表示されます。

例2-1 Eclipseコンソール・ウィンドウでのキャッシュ・サーバーの出力

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

2012-08-15 14:30:18.244/3.250 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-15 14:30:18.307/3.313 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-15 14:30:18.338/3.344 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Coherence/build/classes/tangosol-coherence-override.xml"
2012-08-15 14:30:18.354/3.360 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-15 14:30:18.354/3.360 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-15 14:30:18.354/3.360 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-15 14:30:18.885/3.891 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 14:30:19.260/4.266 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 14:30:20.541/5.547 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 14:30:21.307/6.313 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-15 14:30:24.760/9.766 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-15 14:30:21.432, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3956, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-15 14:30:24.760/9.766 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-15 14:30:21.432, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3956, Role=CoherenceServer)
OldestMember=Member(Id=1, Timestamp=2012-08-15 14:30:21.432, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3956, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-15 14:30:21.432, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3956, Role=CoherenceServer)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-15 14:30:21.432|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-15 14:30:24.916/9.922 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-15 14:30:24.994/10.000 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 14:30:25.322/10.328 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2012-08-15 14:30:25.401/10.407 Oracle Coherence GE 12.1.2.0 <D5> (thread=ReplicatedCache, member=1): Service ReplicatedCache joined the cluster with senior service member 1
2012-08-15 14:30:25.401/10.407 Oracle Coherence GE 12.1.2.0 <D5> (thread=OptimisticCache, member=1): Service OptimisticCache joined the cluster with senior service member 1
2012-08-15 14:30:25.401/10.407 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:InvocationService, member=1): Service InvocationService joined the cluster with senior service member 1
2012-08-15 14:30:25.416/10.422 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1):
Services
(
ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=12.1.2, OldestMemberId=1}
PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
ReplicatedCache{Name=ReplicatedCache, State=(SERVICE_STARTED), Id=3, Version=12.1.2, OldestMemberId=1}
Optimistic{Name=OptimisticCache, State=(SERVICE_STARTED), Id=4, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=InvocationService, State=(SERVICE_STARTED), Id=5, Version=12.1.2, OldestMemberId=1}
)

Started DefaultCacheServer...

2.5 Eclipse IDEの基礎について

ここでは、Eclipse IDEでのプロジェクトのビルドに含まれる一般的な作業について説明します。

- Javaクラスの作成

- ランタイム構成の作成

- キャッシュ・サーバーの停止

2.5.1 Javaクラスの作成

Eclipse IDEで新しいJavaクラスを作成するには:

1. 「Project Explorer」ウィンドウでプロジェクト・エントリを右クリックします。「New」→「Class」を選択します。

2. 「New Java Class」ダイアログ・ボックスでパッケージ名を入力します。このチュートリアルでは通常、値はcom.oracle.handsonになります。

3. 「Name」フィールドにクラスの名前を入力します。

4. 「Which method stubs would you like to cretae?」で、次の操作を行います。

- ファイルを実行可能にするには、「public static void main(String[]args)」を選択します。

- 新しいクラスのスーパークラス内のコンストラクタのスタブを追加するには、「Constructors from superclass」チェック・ボックスを選択します。

- 「Inherited abstract methods」がデフォルトで選択されています。このオプションを選択すると、実装する必要があるインタフェースのスーパークラスまたはメソッド内の抽象メソッドのスタブが追加されます。

5. 「OK」をクリックして、Javaクラスを作成します。

図2-12に、「New Java Class」ダイアログ・ボックスを示します。

図2-12 新しいJavaクラスの定義

2.5.2 ランタイム構成の作成

実行可能ファイルのランタイム構成を作成するには:

1. 「Project Explorer」ウィンドウで実行可能ファイルの名前を右クリックします。「Run As」→「Run Configurations」を選択します。

2. 「Oracle Coherence」→「New Launch Configuration」アイコンをクリックします。「Java Application」ノードを選択します。「New Launch Configuration」ボタンをクリックします。

3. 新規構成の名前を入力します。「Main」タブの「Project」で、「Browse」ボタンをクリックして現在のプロジェクトの名前に移動します。「Search」ボタンをクリックして、ランタイム構成を作成している実行可能ファイルの名前に移動します。「Apply」をクリックします。
次の図に、「Run Configurations」ダイアログ・ボックスの「Main」タブを示します。

図2-13 実行可能ファイルの起動構成の定義

4. 「Coherence」タブをクリックします。「General」タブで、よく使用する、構成のVMランタイム引数の多くを設定できます。ランタイム引数の例としては、キャッシュ構成ディスクリプタへのパスのほか、ローカル記憶域、ログ・レベル、クラスタ・ポートの値などがあります。
図2-14に、「Run Configurations」ダイアログ・ボックスの「Coherence」タブの「General」タブを示します。

図2-14 起動構成のランタイム引数の設定

2.5.3 キャッシュ・サーバーの停止

Eclipse IDEでは、Eclipseコンソールで「Terminate」アイコンおよび「Remove all terminated launches」アイコンをクリックすることによって、実行中のキャッシュ・サーバーまたはクライアントを停止できます。

しかし、「Windows タスク マネージャー」ウィンドウを調べると、サーバーまたはクライアントに関連するJavaプロセス(java.exe)がまだ実行中になっている場合があります。サーバーまたはクライアントの再起動時にエラーがスローされないようにするには、関連するJavaプロセスを削除する必要があります。「Windows タスク マネージャー」ウィンドウでJavaプロセスを選択し、「プロセスの終了」をクリックしてください。

図2-15に、Javaプロセスを選択した「Windows タスク マネージャー」ウィンドウを示します。

図2-15 「Windows タスク マネージャー」のJavaプロセス

3 Javaからデータ・グリッドへのアクセス

この演習では、Coherenceクラスタ化キャッシュの単純なタイプの情報にアクセスし、それらの情報を更新および削除するJavaコンソール・ベースの単純なアプリケーションを開発します。また、Coherence Java APIのNamedCacheおよびCacheFactoryについても学習します。

Eclipse IDEを使用して、次の作業を行います。

- 新規プロジェクトの作成

- 新しい名前付きキャッシュ(NamedCacheオブジェクト)の作成

- キャッシュへの情報の挿入と取得

- キャッシュに関する情報の取得

この章には次の項が含まれます:

- 概要

- 最初のCoherenceベースのJavaプログラムの作成

- 最初のCoherenceベースのJavaアプリケーションの作成

3.1 概要

Coherenceのキャッシュはすべて名前が付いており、それらのキャッシュが存在するクラスタ・インスタンスによって存続期間が調べられ、com.tangosol.net.NamedCacheインタフェースを実装します。NamedCacheインタフェースはjava.util.Mapインタフェースを拡張したもので、クラスタ・メンバー間で共有しているデータおよびリソースを保持します。各NamedCacheオブジェクトは、キーと値のペアとしてデータを保持します。キーと値のオブジェクト・タイプは単純でも複合でもかまいません。NamedCacheインタフェースは、ロックおよび同期、記憶域統合、問合せ、イベント集計、トランザクションなどの拡張機能をMapインタフェースに提供します。表3-1に、NamedCacheインタフェースでよく使用されるメソッドをいくつか示します。

表3-1 NamedCacheインタフェースのメソッド

メソッド名

説明

void clear()

NamedCacheオブジェクトからすべてのエントリを削除します。

boolean containsKey(Object key)

NamedCacheオブジェクトにキーのエントリが格納されている場合、trueを返します。

boolean containsValue(Objectvalue)

この値を含むエントリがNamedCacheオブジェクトに1つ以上ある場合、trueを返します。

Object get(Object key)

NamedCacheオブジェクトからそのキーのエントリを取得します。

Object put(Object key,Objectvalue)

オブジェクトをキャッシュに挿入し、前の値を返します(ある場合)。

Object remove(Object key)

このマップからこのkeyのマッピングを削除します(存在する場合)。ConcurrentMapインタフェースからの継承です。

Set entrySet()

一連のキーと値のペアを返します。

Collection values()

すべての値をコレクションとして取得しなおします。

CacheService getCacheService()

このNamedCacheが属するCacheServiceを返します。

com.tangosol.net.CacheFactoryクラスは通常、NamedCacheオブジェクトのインスタンスを取得するために使用します。表3-2に、CacheFactoryクラスでよく使用されるメソッドをいくつか示します。

表3-2 CacheFactoryクラスのメソッド

メソッド名

説明

static Cluster ensureCluster()

Coherenceのサービスを実行しているクラスタ・オブジェクトを取得します。

static void shutdown()

すべてのクラスタ化されたサービスをシャットダウンします。

static NamedCache getCache(String cache)

キャッシュのインスタンスを返します。クラスタ内の既存のキャッシュに参加するか、これが最初のメンバーである場合はキャッシュを作成します。

NamedCacheインタフェースおよびCacheFactoryクラスのメソッドの詳細な一覧は、C:\oracle\product\coherence\docにあるJavadocを参照してください。

3.2 最初のCoherenceベースのJavaプログラムの作成

ここでは、Coherenceクラスタ化キャッシュの単純なタイプの情報にアクセスし、それらの情報を更新および削除するJavaプログラムの作成方法について説明します。

1. キャッシュに値を挿入するプログラムの作成

2. キャッシュから値を取得するプログラムの作成

3.2.1 キャッシュに値を挿入するプログラムの作成

CoherenceのJavaベース・アプリケーションを作成するには:

1. Eclipseで新しいアプリケーション・クライアント・プロジェクトを作成します。プロジェクトにInsertValueという名前を付けます。フォルダがC:\home\oracle\workspace\InsertValueであることを確認してください。
「New Application Client Project」ダイアログ・ボックスの「Configuration」セクションで、「Modify」をクリックします。「Project Facets」ダイアログ・ボックスで、「Configuration」ドロップダウン・リストから「CoherenceConfig」を選択します。

詳細な手順は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。

2. 最初のCoherence Javaプログラムを作成します。「New Java Class」ダイアログ・ボックスで、クラスにMyFirstSampleという名前を付け、「public static void main(String[] args)」チェック・ボックスを選択します。
詳細は、「Javaクラスの作成」を参照してください。

3. Eclipseエディタで、NamedCacheオブジェクトの作成、キャッシュの値の入力および入力した値の検証を実行するコードを記述します。例3-1にサンプル・プログラムを示します。

例3-1 NamedCacheオブジェクトの作成: 値の挿入と検証

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class MyFirstSample {
public MyFirstSample() {
}

public static void main(String[] args) {

// create or get a named cache called mycache
NamedCache myCache = CacheFactory.getCache("mycache");

// put key, value pair into the cache.
myCache.put("Name","Gene Smith");

System.out.println("Value in cache is " + myCache.get("Name"));

}
}

4. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

5. Eclipse IDEでプログラムを実行します。エディタでMyFirstSample.javaクラスを右クリックし、「Run As」→「Run Configuration」を選択します。「Oracle Coherence」をダブルクリックして、Coherenceの構成を作成します。「Run Configuration」ダイアログ・ボックスの「Name」フィールドにMyFirstSampleと入力します。
「Main」タブで、「Project」フィールドにInsertValueと入力し、「Main class」フィールドにcom.oracle.handson.MyFirstSampleと入力します。

「Coherence」タブで、「Cluster port」フィールドに一意の値(3155など)を入力して、Coherenceが自分のホストに制限されるようにします。「Local storage」で「Enabled (cache server)」を選択します。

「Classpath」タブでは、「Bootstrap Entries」リストにcoherence.jarファイルが表示されているはずです。「Apply」、「Run」の順にクリックします。

例3-2のようなメッセージが表示されます。

例3-2 MyFirstSampleプログラムの出力

2012-08-15 15:53:41.041/0.515 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-15 15:53:41.088/0.562 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-15 15:53:41.135/0.609 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/InsertValue/build/classes/tangosol-coherence-override.xml"
2012-08-15 15:53:41.135/0.609 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-15 15:53:41.135/0.609 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-15 15:53:41.135/0.609 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-15 15:53:41.369/0.843 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 15:53:41.526/1.000 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 15:53:43.197/2.671 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 15:53:44.197/3.671 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-15 15:53:47.635/7.109 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-15 15:53:44.338, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4920, Role=OracleHandsonMyFirstSample, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-15 15:53:47.635/7.109 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-15 15:53:44.338, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4920, Role=OracleHandsonMyFirstSample)
OldestMember=Member(Id=1, Timestamp=2012-08-15 15:53:44.338, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4920, Role=OracleHandsonMyFirstSample)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-15 15:53:44.338, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4920, Role=OracleHandsonMyFirstSample)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-15 15:53:44.338|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-15 15:53:47.838/7.312 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-15 15:53:47.901/7.390 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 15:53:48.276/7.750 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
Value in cache is Gene Smith
2012-08-15 15:53:48.432/7.906 Oracle Coherence GE 12.1.2.0 <D4> (thread=ShutdownHook, member=1): ShutdownHook: stopping cluster node
2012-08-15 15:53:48.447/7.921 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Service Cluster left the cluster
2012-08-15 15:53:48.447/7.921 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=n/a): Service DistributedCache left the cluster

3.2.2 キャッシュから値を取得するプログラムの作成

putメソッドやgetメソッドを使用せずに、キャッシュから値を取得するJavaクラスを作成するには:

1. mainメソッドを持つ、MyFirstSampleReaderという名前の別のJavaクラスを作成します。詳細は、「Javaクラスの作成」を参照してください。例3-3にサンプル・プログラムを示します。

例3-3 キャッシュからの値の取得

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class MyFirstSampleReader {

public MyFirstSampleReader() {
}

public static void main(String[] args) {
// ensure we are in a cluser
CacheFactory.ensureCluster();

// create or get a named cache called mycache
NamedCache myCache = CacheFactory.getCache("mycache");

System.out.println("Value in cache is " + myCache.get("Name"));
}
}

2. Eclipse IDEでMyFirstSampleReaderクラスを実行します。エディタでMyFirstSampleReader.javaクラスを右クリックし、「Run As」→「Run Configuration」を選択します。
「Run Configuration」ダイアログ・ボックスの「Name」フィールドにMyFirstSampleReaderと入力します。「Main」タブの「Project」フィールドにInsertValueが表示されていることを確認し、「Coherence」タブで、ローカル記憶域が有効になっていること、およびCoherenceを自分のホストに制限するために「Cluster port」が3155に設定されていることを確認します。「Apply」、「Run」の順にクリックします。

例3-4にプログラムの出力を示します。NULL値が返されています。MyFirstSampleプログラムによってNamedCacheキャッシュが正常に作成され、値が移入されますが、このキャッシュはMyFirstSampleプロセス・メモリー内にのみ存在します。MyFirstSampleプログラムが終了すると、キャッシュも終了します。

例3-4 MyFirstSampleReaderプログラムの出力

2012-08-15 16:00:43.229/0.328 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-15 16:00:43.291/0.390 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-15 16:00:43.322/0.421 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/InsertValue/build/classes/tangosol-coherence-override.xml"
2012-08-15 16:00:43.338/0.437 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-15 16:00:43.338/0.437 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-15 16:00:43.338/0.437 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-15 16:00:43.932/1.031 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-15 16:00:47.338/4.437 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-15 16:00:44.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3752, Role=OracleHandsonMyFirstSampleReader, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-15 16:00:47.338/4.437 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-15 16:00:44.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3752, Role=OracleHandsonMyFirstSampleReader)
OldestMember=Member(Id=1, Timestamp=2012-08-15 16:00:44.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3752, Role=OracleHandsonMyFirstSampleReader)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-15 16:00:44.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3752, Role=OracleHandsonMyFirstSampleReader)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-15 16:00:44.057|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-15 16:00:47.385/4.484 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-15 16:00:47.447/4.546 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 16:00:47.635/4.734 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 16:00:47.744/4.843 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 16:00:47.854/4.953 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 16:00:47.963/5.062 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
Value in cache is null

3. 「Eclipse IDEでのキャッシュ・サーバーの起動」で作成したDefaultCacheServerを起動します。「Main」タブの「Project」フィールドにInsertValueが表示されていることと、「Coherence」タブでローカル記憶域が有効になっていることを確認します。「Apply」、「Run」の順にクリックします。

4. MyFirstSampleを実行してNamedCacheに値を挿入し、MyFirstSampleReaderを実行してキャッシュから値を読み取ります。例3-5に示す出力を参照してください。MyFirstSampleによって格納されたGene Smithという値がMyFirstSampleReaderによって返されています。

例3-5 キャッシュ・サーバーを実行している状態でのMyFirstSampleReaderプログラムの出力

2012-08-15 16:13:52.760/0.313 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-15 16:13:52.807/0.360 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-15 16:13:52.854/0.407 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/InsertValue/build/classes/tangosol-coherence-override.xml"
2012-08-15 16:13:52.854/0.407 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-15 16:13:52.854/0.407 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-15 16:13:52.854/0.407 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-15 16:13:53.416/0.969 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8090 using SystemDatagramSocketProvider
2012-08-15 16:13:53.776/1.329 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): This Member(Id=3, Timestamp=2012-08-15 16:13:53.596, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5544, Role=OracleHandsonMyFirstSampleReader, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) joined cluster "cluster:0x47DB" with senior Member(Id=1, Timestamp=2012-08-15 16:13:03.869, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3468, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedCache with senior member 1
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service ReplicatedCache with senior member 1
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service OptimisticCache with senior member 1
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service InvocationService with senior member 1
2012-08-15 16:13:53.979/1.532 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=3, Timestamp=2012-08-15 16:13:53.596, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5544, Role=OracleHandsonMyFirstSampleReader)
OldestMember=Member(Id=1, Timestamp=2012-08-15 16:13:03.869, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3468, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2012-08-15 16:13:03.869, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3468, Role=CoherenceServer)
Member(Id=3, Timestamp=2012-08-15 16:13:53.596, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5544, Role=OracleHandsonMyFirstSampleReader)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-15 16:13:03.869|JOINED,
3|12.1.2|2012-08-15 16:13:53.596|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2012-08-15 16:13:54.010/1.563 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2012-08-15 16:13:54.026/1.579 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 16:13:54.104/1.657 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 16:13:54.260/1.813 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 16:13:54.385/1.938 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 16:13:54.479/2.032 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=3): Service DistributedCache joined the cluster with senior service member 1
2012-08-15 16:13:54.541/2.094 Oracle Coherence GE 12.1.2.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for primary ownership of PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}
Value in cache is Gene Smith
2012-08-15 16:13:54.619/2.172 Oracle Coherence GE 12.1.2.0 <D4> (thread=ShutdownHook, member=3): ShutdownHook: stopping cluster node

これは、MyFirstSampleのように、1つの操作(値を入力して終了するなど)を実行するためにのみクラスタに参加するプロセスには該当しません。デフォルトでは、すべてのプロセスが、記憶域が有効な状態で起動します。このようなプロセスではクラスタの一部としてデータを格納できます。記憶域が無効になるようにプロセスを変更してください。

1. MyFirstSampleクラスを右クリックし、「Run As」→「Run Configurations」を選択します。詳細は、「ランタイム構成の作成」を参照してください。

2. 「Coherence」タブの「Local storage」で、「Disabled (cache client)」を選択します。
これは、Javaパラメータ-Dtangosol.coherence.distributed.localstorage=falseを設定するのと同様です。

5. 実行中のキャッシュ・サーバーをシャットダウンし、MyFirstSampleクラスを再実行します。
例3-6のように、クラスタで記憶域が有効でないことを示すメッセージが表示されます。これは、このメンバーを記憶域が無効になるように設定したためです。

例3-6 キャッシュ記憶域を無効にした場合のMyFirstSampleクラスの出力

2012-08-15 16:22:38.994/0.328 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-15 16:22:39.041/0.375 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-15 16:22:39.088/0.422 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/InsertValue/build/classes/tangosol-coherence-override.xml"
2012-08-15 16:22:39.088/0.422 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-15 16:22:39.088/0.422 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-15 16:22:39.088/0.422 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-15 16:22:39.307/0.641 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 16:22:39.401/0.735 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 16:22:39.713/1.047 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 16:22:39.947/1.281 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-15 16:22:43.338/4.672 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-15 16:22:40.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3348, Role=OracleHandsonMyFirstSample, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-15 16:22:43.338/4.672 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-15 16:22:40.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3348, Role=OracleHandsonMyFirstSample)
OldestMember=Member(Id=1, Timestamp=2012-08-15 16:22:40.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3348, Role=OracleHandsonMyFirstSample)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-15 16:22:40.057, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3348, Role=OracleHandsonMyFirstSample)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-15 16:22:40.057|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-15 16:22:43.416/4.750 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-15 16:22:43.494/4.828 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 16:22:43.651/4.985 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
Exception in thread "main" com.tangosol.net.RequestPolicyException: No storage-enabled nodes exist for service DistributedCache
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache$BinaryMap.onMissingStorage(PartitionedCache.CDB:32)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache$BinaryMap.ensureRequestTarget(PartitionedCache.CDB:50)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache$BinaryMap.put(PartitionedCache.CDB:22)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache$BinaryMap.put(PartitionedCache.CDB:1)
at com.oracle.common.collections.ConverterCollections$ConverterMap.put(ConverterCollections.java:1534)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.partitionedService.PartitionedCache$ViewMap.put(PartitionedCache.CDB:1)
at com.tangosol.coherence.component.util.SafeNamedCache.put(SafeNamedCache.CDB:1)
at com.oracle.handson.MyFirstSample.main(MyFirstSample.java:16)

6. DefaultCacheServerキャッシュ・サーバーを再起動し、MyFirstSampleおよびMyFirstSampleReaderを再度実行します。2つのJavaサンプルを実行する間、データが保持されていることがわかります。

3.3 最初のCoherenceベースのJavaアプリケーションの作成

この演習では、Coherenceクラスタ化キャッシュの単純なタイプの情報にアクセスし、更新および削除を行うJavaコンソール・ベースの単純なアプリケーションを開発します。

この演習を実行するには、「Coherenceインストールのテスト」を完了している必要があります。

一般にクライアント・アプリケーションとサーバー・アプリケーションとの間で接続および切断が行われるクライアント/サーバー・アプリケーションとは異なり、Coherenceベースのクラスタ化されたアプリケーションはクラスタ内にあることを確認するのみで、その後もクラスタのサービスを使用できます。Coherenceベースのアプリケーションは通常、アプリケーションのクラスタに接続するのではなく、クラスタの一部になります。

1. コンソール・アプリケーションの作成

2. コンソール・アプリケーションの実行

3.3.1 コンソール・アプリケーションの作成

Coherenceクラスタ化キャッシュの単純なタイプの情報にアクセスし、それらの情報を更新および削除するJavaコンソール・ベースのアプリケーションを作成するには:

1. ...\coherence\docフォルダにあるCoherence Javaドキュメント(Javadoc)を使用して、CacheFactoryクラスのメソッドを調べます。

2. CacheFactoryクラスを使用してクラスタに参加し(ensureClusterメソッドを使用)、その後、クラスタから離脱する(shutdownメソッドを使用)、YourFirstCoherenceApplicationという単純なJavaコンソール・アプリケーション(Javaクラス)を記述します。Javaクラスの作成の詳細は、「Javaクラスの作成」を参照してください。

1. Javadocを使用して、NamedCacheインタフェースで使用可能なメソッドを調べます。

2. CacheFactoryメソッドgetCacheを使用して、mycacheというキャッシュ(「Coherenceインストールのテスト」の演習で使用したものと同じキャッシュ名)のNamedCacheを取得するようにアプリケーションを拡張します。

3. NamedCacheインスタンスで、getメソッドを使用してmessageキー(「Coherenceインストールのテスト」の演習で使用したものと同じキー)の値を取得します。

4. System.out.println(….)メソッドを使用して、値を標準出力に書き込みます。
例3-7に、CoherenceベースのサンプルJavaアプリケーションを示します。

例3-7 CoherenceベースのJavaアプリケーション

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class YourFirstCoherenceApplication {
public YourFirstCoherenceApplication() {
}

public static void main(String[] args) {

CacheFactory.ensureCluster();

NamedCache myCache = CacheFactory.getCache("mycache");

String message = (String)myCache.get("message");

System.out.println(message);

CacheFactory.shutdown();
YourFirstCoherenceApplication yourfirstcoherenceapplication = new YourFirstCoherenceApplication();
}

}

3.3.2 コンソール・アプリケーションの実行

Coherenceアプリケーションを実行するには:

1. 「Eclipse IDEでのキャッシュ・サーバーの起動」で作成したDefaultCacheServerキャッシュ・サーバーを起動します。

2. Coherence問合せ言語およびQueryHelper APIを使用するキャッシュ・クライアントの実行構成を作成します。プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。

注意:

Coherence問合せ言語の詳細は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のCoherence問合せ言語の使用に関する項を参照してください。

1. 「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」→「New launch configuration」アイコンをクリックします。構成の名前としてQueryPlusを入力します。

2. 「Main」タブの「Project」で、「Browse」ボタンをクリックし、「InsertValue」プロジェクトを選択します。「Main class」で、「Include system libraries when searching for a main class」を選択し、「Search」ボタンをクリックします。「Select Main Type」ダイアログ・ボックスで、QueryPlusと入力し、「QueryPlus - com.tangosol.coherence.dslquery」を選択します。「OK」をクリックします。「Main」タブは図3-1のようになります。

図3-1 問合せクライアント構成の「Main」タブ

3. 「Coherence」タブの「Local storage」で、「Disabled (cache client)」を選択します。「Cluster port」に一意の値を入力します(この値は、前の項で定義したキャッシュ・サーバーに定義された値と同じである必要があります)。

4. 「Arguments」タブで、「VM arguments」フィールドに-showversionと入力します。

5. 「Common」タブで、「Shared file」を選択し、「Browse」ボタンをクリックして\InsertValueプロジェクト名に移動します。「Allocate console」チェック・ボックスが選択されていることを確認します。「Apply」をクリックします。

3. 「Run」をクリックして、QueryPlusクライアントを起動します。例3-8のような出力がEclipseコンソールに表示されます。

例3-8 QueryPlusキャッシュ・クライアントの出力

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

Coherence Command Line Tooljline library cannot be loaded, so you cannot use the arrow keys for line editing and history.

CohQL>

4. CohQL>プロンプトで、次のコマンドを入力して、mycacheという名前のキャッシュを作成し、そのキャッシュに接続します。

CohQL> create cache "mycache"

5. YourFirstCoherenceApplicationの実行構成を作成します。「Run Configurations」ダイアログ・ボックスで、「Name」フィールドにYourFirstCoherenceApplicationと入力します。「Main」タブで、「Project」フィールドにInsertValueと入力し、「メイン・クラス」にcom.oracle.handson.YourFirstCoherenceApplicationと入力します。
「Coherence」タブの「Local storage」で「Enabled (cache server)」を選択し、「Cluster port」に一意の値を入力します(これは、キャッシュ・サーバーおよびキャッシュ・クライアントに使用したものと同じ値である必要があります)。

6. Eclipse IDEからYourFirstCoherenceApplicationを実行し、結果を確認します。
例3-9に、YourFirstCoherenceApplicationの出力を示します。この出力は、messageキーのデータがキャッシュにないことを示しています。

例3-9 YourFirstCoherenceApplicationクラスの出力

...
TcpRing{Connections=[2]}
IpMonitor{AddressListSize=0}

2012-08-15 17:20:53.276/1.625 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2012-08-15 17:20:53.307/1.656 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 17:20:53.463/1.812 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 17:20:53.604/1.953 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 17:20:53.744/2.093 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 17:20:53.838/2.187 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=3): Service DistributedCache joined the cluster with senior service member 1
2012-08-15 17:20:53.885/2.234 Oracle Coherence GE 12.1.2.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for primary ownership of PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}
null
2012-08-15 17:20:54.041/2.390 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=n/a): Service Management left the cluster
2012-08-15 17:20:54.057/2.406 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache, member=n/a): Remains to transfer before shutting down: 0 primary partitions, 129 backup partitions
2012-08-15 17:20:54.088/2.437 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=n/a): Service DistributedCache left the cluster
2012-08-15 17:20:54.135/2.484 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Service Cluster left the cluster

7. Eclipseコンソールで実行中のQueryPlusキャッシュ・クライアントを使用して、messageキーを変更します。たとえば、CohQL>プロンプトで次のコマンドを入力します。

CohQL> insert into "mycache" key "message" value "hello"

Eclipse IDEからYourFirstCoherenceApplicationを再実行して、変更された値を確認します。例3-10は、messageキーの値helloがキャッシュに保持されていることを示しています。

例3-10 新しいキー値を含むYourFirstCoherenceApplicationクラスの出力

...
TcpRing{Connections=[2]}
IpMonitor{Addresses=0}

2012-08-15 17:37:39.760/2.109 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2012-08-15 17:37:39.807/2.156 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-15 17:37:40.244/2.593 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-cache-config.xml"
2012-08-15 17:37:40.338/2.687 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded cache configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/internal-txn-cache-config.xml"
2012-08-15 17:37:40.541/2.890 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-15 17:37:40.729/3.078 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=3): Service DistributedCache joined the cluster with senior service member 1
hello
2012-08-15 17:37:40.838/3.187 Oracle Coherence GE 12.1.2.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for primary ownership of PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127}
2012-08-15 17:37:40.979/3.328 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=n/a): Service Management left the cluster
2012-08-15 17:37:41.010/3.359 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache, member=n/a): Remains to transfer before shutting down: 0 primary partitions, 129 backup partitions
2012-08-15 17:37:41.041/3.390 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache, member=n/a): Service DistributedCache left the cluster
2012-08-15 17:37:41.104/3.453 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Service Cluster left the cluster

8. YourFirstCoherenceApplicationの実行構成で、「Local storage」の値を「Enabled」から「Disabled」に変更します。出力は前回の実行と同じです。

9. キャッシュ・サーバーおよびキャッシュ・クライアントのインスタンスをシャットダウンします。キャッシュ・サーバーを再起動し、(「Local storage」に新しい値を指定して)YourFirstCoherenceApplicationを再実行します。今回は出力がNULLになります。

10. アプリケーションで(putメソッドを使用して)messageキーの値を変更した場合、新しい値がキャッシュ・クライアントで使用可能であることを確認します。

1. たとえば、getメソッドをコメント・アウトし、putメソッドを追加します。

//String message = (String)myCache.get("message");
String message = (String)myCache.put("message", "bye");

2. YourFirstCoherenceApplicationを実行します。

3. QueryPlusキャッシュ・クライアントでgetコマンドを実行します。

select key(), value() from "mycache" where key() is "message"

出力としてbyeが表示されます。

4 複合オブジェクトの操作

この演習では、キャッシュ内にある複合オブジェクトを操作します。ここでは、Coherence APIのPofReader、PofWriterおよびPortableObjectの使用について取り上げます。Eclipseを使用して新しいContactクラスを作成し、Portable Object Format (POF)シリアライズを使用してキャッシュにContactオブジェクトを格納し、格納したオブジェクトを取得します。

この章には次の項が含まれます:

- 概要

- 複合オブジェクトの作成とキャッシュ

4.1 概要

これまで、NamedCacheキャッシュでStringオブジェクトを値として挿入および取得してきました。Coherence Java APIのgetメソッドおよびputメソッドの実装の多くでは、値とキーをObjectタイプとして定義します。次に例を示します。

public java.lang.Object get(java.lang.Object oKey)
public void put(java.lang.Object oKey, java.lang.Object oValue)

どのオブジェクトも値またはキーとして使用できます。これにより、複合オブジェクトを値としてキャッシュに格納できます。

Coherenceではオブジェクトをワイヤ経由で送信することがあるため、オブジェクトはシリアライズ可能である必要があります。オブジェクトのシリアライズは、オブジェクトの状態を一連のバイトとして保存し、その後、バイトを再ビルド(デシリアライズ)してアクティブなオブジェクトにするプロセスです。たとえば、java.io.Serializableインタフェースを実装するオブジェクトはシリアライズ可能です。

Javaのjava.io.Serializableインタフェースを使用するかわりに、高性能のシリアライズを目的としたCoherence独自のクラスcom.tangosol.io.pof.PortableObjectを使用することによってパフォーマンスを向上させることができます。PortableObject形式は、標準のSerializableと比べると速度が最大6倍で、シリアライズ後の結果セットは小さくなります。

PortableObjectインタフェースにはreadExternalおよびwriteExternalという2つの単純なメソッドが用意されており、提供されているPofReaderストリームおよびPofWriterストリームからそれぞれ、シリアライズされたオブジェクト属性の読取りと書込みを明示的に行うことができます。シリアライズ形式を制御することによって、Coherenceではプロセスのパフォーマンスを向上させることができます。POFを使用すると、生成されるバイナリ・ファイルのサイズが縮小されます。多くの場合、バイナリ・ファイルのサイズは5分の1 - 10分の1になり、バイナリ・ファイルとの間の変換速度は、オブジェクトのサイズに応じて5 - 20倍になることがあります。

4.2 複合オブジェクトの作成とキャッシュ

この演習では、従業員の名前、住所、誕生日および電話番号を格納するContactオブジェクトを作成します。また、POFシリアライズを使用して、PortableObjectインタフェースを実装することによりキャッシュにオブジェクトを挿入し、挿入したオブジェクトを取得します。

1. データ・オブジェクトの作成

2. 複合オブジェクトの作成

3. ドライバ・クラスの作成

4. POF構成ファイルとキャッシュ構成ファイルの作成

5. サンプル・プロジェクトの実行

4.2.1 データ・オブジェクトの作成

ここでは、後で別のデータ・オブジェクトに組み込まれる2つのデータ・オブジェクトの作成方法について説明します。Addressオブジェクトは従業員の住所情報を提供し、PhoneNumberオブジェクトは電話連絡先情報を提供します。

1. 従業員の住所情報を格納するAddressオブジェクトを作成します。

1. Eclipseで、Contactsという新しいアプリケーション・クライアント・プロジェクトを作成します。開始ページの「Configuration」フィールドでCoherenceConfigが選択されていることと、「Application Client module」ページで「Create a default main」が選択されていないことを確認します。
詳細は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。

2. Addressという新しいJavaクラスを作成します。「Default Package」がcom.oracle.handsonであることを確認します。「Main Method」チェック・ボックスは選択しないでください。詳細は、「Javaクラスの作成」を参照してください。

3. データのシリアライズにPortableObjectインタフェースを使用するようにクラスを記述します。Eclipseコード・エディタで、生成したAddressクラスを、com.tangosol.io.pof.PortableObjectを実装するように変更します。PortableObjectインタフェースのimport文を追加します。

4. PortableObjectインタフェースで必要なcom.tangosol.io.pof.PofReaderクラス、com.tangosol.io.pof.PofWriterクラスおよびjava.io.IOExceptionクラスをインポートします。

5. PortableObjectインタフェースで必要なAddressのパブリックなデフォルト・コントラクタを追加します。

6. Addressクラスの次のプライベート属性を入力します。必要に応じて他の属性を追加することもできます。
— String Street1

— String Street2

— String City

— String State

— String Country

この時点で、Addressクラスは次のようになります。

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PortableObject;
import com.tangosol.io.pof.PofWriter;

import java.io.IOException;

public class Address  implements PortableObject
{
private String Street1;
private String Street2;
private String City;
private String State;
private String Zip;
private String Country;
/**
* Default constructor (necessary for PortableObject implementation).    */
public Address()
{
}
}

7. Eclipseでは、作成した属性についてデフォルトのgetメソッドおよびsetメソッドを生成できます。「Source」メニューから、「Generate Getters and Setters」を選択します。「Select All」をクリックして、クラス内のすべての属性を選択します。すべての属性が自動的に選択されます。「OK」をクリックして続行します。
図4-1に、Addressクラスのアクセッサを生成する「Generate Getters and Setters」ダイアログ・ボックスを示します。

図4-1 「Generate Getters and Setters」ダイアログ・ボックス

8. デフォルトのコンストラクタおよびequalsメソッドを自動的に生成することもできます。「Source」メニューから、「Generate Constructor using Fields」を選択し、「Select All」をクリックして、「OK」をクリックします。
図4-2に、Street1、Street2、City、State、ZipおよびCountryの各フィールドを選択した「Generate Constructor using Fields」ダイアログ・ボックスを示します。

図4-2 「Generate Constructors using Fields」ダイアログ・ボックス

生成されたコンストラクタのメンバーにthisを追加します。生成されたコンストラクタは次のようになります。

public Address(String Street1, String Street2, String City, String State, String Zip, String Country) {
super();
this.Street1 = Street1;
this.Street2 = Street2;
this.City = City;
this.State = State;
this.Zip = Zip;
this.Country = Country;
}

9. PortableObjectインタフェースでの必要に応じて、readExternalメソッドおよびwriteExternalメソッドを実装します。たとえば、readExternalメソッドを次のように実装すると、street、city、stateおよびcountryの値をPOFオブジェクトとして読み取ることができます。

public void readExternal(PofReader reader)
throws IOException
{
setStreet1(reader.readString(0));
setStreet2(reader.readString(1));
setCity(reader.readString(2));
setState(reader.readString(3));
setZip(reader.readString(4));
setCountry(reader.readString(5));
}

10. equals、hashCodeおよびtoStringの各オブジェクト・メソッドを実装します。

注意:

キャッシュのキーと値は、シリアライズ可能(たとえば、java.io.Serializable)である必要があります。さらに、キャッシュ・キーはhashCode()メソッドとequals()メソッドの実装を提供する必要があり、これらのメソッドはクラスタ・ノード間で一貫性のある結果を返す必要があります。これは、hashCode()およびequals()の実装は、オブジェクトのシリアライズ可能な状態(つまり、オブジェクトの一時的でないフィールド)にのみ基づいている必要があることを示しています。String、Integer、Dateなどのほとんどの組込みのJava型はこの要件を満たしています。一部のキャッシュの実装(特にパーティション・キャッシュ)では、等価の検証にキー・オブジェクトのシリアライズされた形式を使用します。つまり、equals()メソッドでtrueを返すキーは、同様の方法でシリアライズされる必要があります。ほとんどの組込みのJava型はこの要件を満たしています。

これらのメソッドをサポートするには、com.tangosol.util.Baseクラスとcom.tangosol.util.HashHelperクラスをインポートします。Baseクラスは、equalsメソッドのサポートを提供します。HashHelperクラスには、任意のグループのJava組込み関数のハッシュ・コード値を計算するためのヘルパー関数が格納されています。

次のコードは、equals()メソッドの実装例を示しています。

public boolean equals(Object oThat)
{
if (this == oThat)
{
return true;
}
if (oThat == null)
{
return false;
}

Address that = (Address) oThat;
return Base.equals(getStreet1(), that.getStreet1()) &&
Base.equals(getStreet2(), that.getStreet2()) &&
Base.equals(getCity(),    that.getCity())    &&
Base.equals(getState(),   that.getState())   &&
Base.equals(getZip(),     that.getZip())     &&
Base.equals(getCountry(), that.getCountry());
}

次のコードは、hashCode()メソッドの実装例を示しています。

public int hashCode()
{
return HashHelper.hash(getStreet1(),
HashHelper.hash(getStreet2(),
HashHelper.hash(getZip(), 0)));
}

次のコードは、toString()メソッドの実装例を示しています。

public String toString()
{
return  getStreet1() + "\n" +
getStreet2() + "\n" +
getCity() + ", " + getState() + " "  + getZip() + "\n" +
getCountry();
}

11. 作成されたクラスは例4-1のようになります。

例4-1 Addressクラスの実装

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PortableObject;
import com.tangosol.io.pof.PofWriter;

import com.tangosol.util.Base;
import com.tangosol.util.HashHelper;

import java.io.IOException;

public class Address  implements PortableObject
{
private String Street1;
private String Street2;
private String City;
private String State;
private String Zip;
private String Country;
/**
* Default constructor (necessary for PortableObject implementation).
*/
public Address() {
}

public Address(String Street1, String Street2, String City, String State,
String Zip, String Country)
{
super();
this.Street1 = Street1;
this.Street2 = Street2;
this.City    = City;
this.State   = State;
this.Zip     = Zip;
this.Country = Country;
}

//------------ accessors--------------------------------

public void setStreet1(String Street1)
{
this.Street1 = Street1;
}

public String getStreet1()
{
return Street1;
}

public void setStreet2(String Street2)
{
this.Street2 = Street2;
}

public String getStreet2()
{
return Street2;
}

public void setCity(String City)
{
this.City = City;
}

public String getCity()
{
return City;
}

public void setState(String State)
{
this.State = State;
}

public String getState()
{
return State;
}

public void setZip(String Zip)
{
this.Zip = Zip;
}

public String getZip()
{
return Zip;
}

public void setCountry(String Country)
{
this.Country = Country;
}

public String getCountry()
{
return Country;
}
// -------- PortableObject Interface------------------------------

public void readExternal(PofReader reader)
throws IOException
{
setStreet1(reader.readString(0));
setStreet2(reader.readString(1));
setCity(reader.readString(2));
setState(reader.readString(3));
setZip(reader.readString(4));
setCountry(reader.readString(5));
}

public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeString(0, getStreet1());
writer.writeString(1, getStreet2());
writer.writeString(2, getCity());
writer.writeString(3, getState());
writer.writeString(4, getZip());
writer.writeString(5, getCountry());
}
// ----- Object methods --------------------------------------------------

public boolean equals(Object oThat)
{
if (this == oThat)
{
return true;
}
if (oThat == null)
{
return false;
}

Address that = (Address) oThat;
return Base.equals(getStreet1(), that.getStreet1()) &&
Base.equals(getStreet2(), that.getStreet2()) &&
Base.equals(getCity(),    that.getCity())    &&
Base.equals(getState(),   that.getState())   &&
Base.equals(getZip(),     that.getZip())     &&
Base.equals(getCountry(), that.getCountry());
}

public int hashCode()
{
return HashHelper.hash(getStreet1(),
HashHelper.hash(getStreet2(),
HashHelper.hash(getZip(), 0)));
}

public String toString()
{
return  getStreet1() + "\n" +
getStreet2() + "\n" +
getCity() + ", " + getState() + " "  + getZip() + "\n" +
getCountry();
}
}

2. 電話連絡先データを格納するPhoneNumberクラスを作成します。

1. PhoneNumberという新しいJavaクラスを作成します。mainメソッドは含めないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. データのシリアライズにPortableObjectインタフェースを使用します。Eclipseコード・エディタで、生成したPhoneNumberクラスを、PortableObjectを実装するように変更します。com.tangosol.io.pof.PortableObjectインタフェースのimport文を追加します。

3. PortableObjectインタフェースで必要なcom.tangosol.io.pof.PofReaderクラス、com.tangosol.io.pof.PofWriterクラスおよびjava.io.IOExceptionクラスをインポートします。

4. PortableObjectインタフェースで必要なPhoneNumberクラスのパブリックなデフォルト・コントラクタを追加します。

5. PhoneNumberクラスの次のプライベート属性を入力します。他の属性を追加することもできます。
—short AccessCode

—short CountryCode

—short AreaCode

—int LocalNumber

6. Eclipseでは、作成した属性についてデフォルトのgetメソッドおよびsetメソッドを生成できます。「Source」メニューから、「Generate Getters and Setters」を選択します。「Select All」をクリックして、クラス内のすべての属性を選択します。すべての属性が自動的に選択されます。「OK」をクリックして続行します。

7. デフォルトのコンストラクタおよびequalsメソッドを自動的に生成することもできます。「Source」メニューから、「Generate Constructor using Fields」を選択し、「Select All」をクリックして、「OK」をクリックします。
生成されたコンストラクタのメンバーにthisを追加します。生成されたコンストラクタは次のようになります。

public PhoneNumber(short AccessCode, short CountryCode, short AreaCode,
int LocalNumber) {
super();
this.AccessCode = AccessCode;
this.CountryCode = CountryCode;
this.AreaCode = AreaCode;
this.LocalNumber = LocalNumber;
}

8. PortableObjectインタフェースでの必要に応じて、readExternalメソッドおよびwriteExternalメソッドを実装します。

9. equals、hashCodeおよびtoStringの各オブジェクト・メソッドを実装します。

10. 作成されたクラスは例4-2のようになります。

例4-2 PhoneNumberクラスの実装

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import com.tangosol.util.HashHelper;

import java.io.IOException;

public class PhoneNumber implements PortableObject
{

private short AccessCode;
private short CountryCode;
private short AreaCode;
private int LocalNumber;

//------------ constructors --------------------------------

/**
* Default constructor (necessary for PortableObject implementation).
*/
public PhoneNumber() {
}

public PhoneNumber(short AccessCode, short CountryCode, short AreaCode,
int LocalNumber)
{
super();
this.AccessCode = AccessCode;
this.CountryCode = CountryCode;
this.AreaCode = AreaCode;
this.LocalNumber = LocalNumber;
}

//------------ accessors--------------------------------

public void setAccessCode(short AccessCode)
{
this.AccessCode = AccessCode;
}

public short getAccessCode()
{
return AccessCode;
}

public void setCountryCode(short CountryCode)
{
this.CountryCode = CountryCode;
}

public short getCountryCode()
{
return CountryCode;
}

public void setAreaCode(short AreaCode)
{
this.AreaCode = AreaCode;
}

public short getAreaCode()
{
return AreaCode;
}

public void setLocalNumber(int LocalNumber)
{
this.LocalNumber = LocalNumber;
}

public int getLocalNumber()
{
return LocalNumber;
}
// -------- PortableObject Interface------------------------------

public void readExternal(PofReader reader)
throws IOException
{
setAccessCode(reader.readShort(0));
setCountryCode(reader.readShort(1));
setAreaCode(reader.readShort(2));
setLocalNumber(reader.readInt(3));
}

public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeShort(0, getAccessCode());
writer.writeShort(1, getCountryCode());
writer.writeShort(2, getAreaCode());
writer.writeInt(3, getLocalNumber());
}
// ----- Object methods -------------------------------------------------

/**
* {@inheritDoc}
*/
public boolean equals(Object oThat)
{
if (this == oThat)
{
return true;
}
if (oThat == null)
{
return false;
}

PhoneNumber that = (PhoneNumber) oThat;
return getAccessCode()  == that.getAccessCode()  &&
getCountryCode() == that.getCountryCode() &&
getAreaCode()    == that.getAreaCode()    &&
getLocalNumber() == that.getLocalNumber();
}

/**
* {@inheritDoc}
*/
public int hashCode()
{
return HashHelper.hash(getAreaCode(),
HashHelper.hash(getLocalNumber(), 0));
}

/**
* {@inheritDoc}
*/
public String toString()
{
return "+" + getAccessCode() + " " + getCountryCode() + " "
+ getAreaCode()   + " " + getLocalNumber();
}
}

4.2.2 複合オブジェクトの作成

Contactオブジェクトは、Addressデータ・オブジェクトとPhoneNumberデータ・オブジェクトを組み込むことによって、従業員の名前、住所および電話番号の情報を提供します。

1. Contactという新しいJavaクラスを作成します。mainメソッドは含めないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. このクラスではデータのシリアライズにPortableObjectインタフェースを使用するため、Eclipseコード・エディタで、生成したContactクラスを、PortableObjectを実装するように変更します。com.tangosol.io.pof.PortableObjectインタフェースのimport文を追加します。

3. PortableObjectで必要なcom.tangosol.io.pof.PofReaderクラス、com.tangosol.io.pof.PofWriterクラスおよびjava.io.IOExceptionクラスをインポートします。

4. PortableObjectで必要なContactのパブリックなデフォルト・コントラクタを追加します。

5. Contactクラスの次のプライベート属性を入力します。他の属性を追加することもできます。

- String FirstName

- String LastName

- Address HomeAddress

- Address WorkAddress

- Map TelephoneNumbers

- java.sql.Date BirthDate

6. Eclipseでは、作成した属性についてデフォルトのgetメソッドおよびsetメソッドを生成できます。「Source」メニューから、「Generate Getters and Setters」を選択します。「Select All」をクリックして、クラス内のすべての属性を選択します。「OK」をクリックして続行します。

7. 従業員の年齢を計算するアクセッサgetAgeを作成します。

public int getAge()
{
return (int) ((System.currentTimeMillis() - BirthDate.getTime()) /  MILLIS_IN_YEAR);
}

8. MILLIS_IN_YEARの定義を追加します。

public static final long MILLIS_IN_YEAR = 1000L * 60L * 60L * 24L * 365L;

9. デフォルトのコンストラクタを自動的に生成できます。「Source」メニューから、「Generate Constructor using Fields」を選択し、「Select All」をクリックして、「OK」をクリックします。
生成されたコンストラクタは次のようになります。

public Contact(String FirstName, String LastName, Address HomeAddress,
Address WorkAddress, Map TelephoneNumbers, Date BirthDate) {
super();
this.FirstName = FirstName;
this.LastName = LastName;
this.HomeAddress = HomeAddress;
this.WorkAddress = WorkAddress;
this.TelephoneNumbers = TelephoneNumbers;
this.BirthDate = BirthDate;
}

10. PortableObjectインタフェースでの必要に応じて、readExternalメソッドおよびwriteExternalメソッドを実装します。

11. equals、hashCodeおよびtoStringの各オブジェクト・メソッドを実装します。

12. 作成されたクラスは例4-3のようになります。

例4-3 Contactクラスのサンプル

package com.oracle.handson;

import com.tangosol.io.pof.PortableObject;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;

import java.io.IOException;

import java.sql.Date;

import java.util.Iterator;
import java.util.Map;

public class Contact implements PortableObject
{
private String FirstName;
private String LastName;
private Address HomeAddress;
private Address WorkAddress;
private Map TelephoneNumbers;
private java.sql.Date BirthDate;

// ----- constructors ---------------------------------------------------

/**
* Default constructor (necessary for PortableObject implementation).
*/
public Contact()
{
}

public Contact(String FirstName, String LastName, Address HomeAddress,
Address WorkAddress, Map TelephoneNumbers, Date BirthDate)
{
super();
this.FirstName = FirstName;
this.LastName = LastName;
this.HomeAddress = HomeAddress;
this.WorkAddress = WorkAddress;
this.TelephoneNumbers = TelephoneNumbers;
this.BirthDate = BirthDate;
}

// -------- accessors --------------------------------------------

public void setFirstName(String FirstName)
{
this.FirstName = FirstName;
}

public String getFirstName()
{
return FirstName;
}

public void setLastName(String LastName)
{
this.LastName = LastName;
}

public String getLastName()
{
return LastName;
}

public void setHomeAddress(Address HomeAddress)
{
this.HomeAddress = HomeAddress;
}

public Address getHomeAddress()
{
return HomeAddress;
}

public void setWorkAddress(Address WorkAddress)
{
this.WorkAddress = WorkAddress;
}

public Address getWorkAddress()
{
return WorkAddress;
}

public void setTelephoneNumbers(Map TelephoneNumbers)
{
this.TelephoneNumbers = TelephoneNumbers;
}

public Map getTelephoneNumbers()
{
return TelephoneNumbers;
}

public void setBirthDate(Date BirthDate)
{
this.BirthDate = BirthDate;
}

public Date getBirthDate()
{
return BirthDate;
}
/**
* Get age.
*
* @return age
*/
public int getAge()
{
return (int) ((System.currentTimeMillis() - BirthDate.getTime()) /
MILLIS_IN_YEAR);
}

// ----- PortableObject interface ---------------------------------------

/**
* {@inheritDoc}
*/
public void readExternal(PofReader reader)
throws IOException
{
setFirstName(reader.readString(0));
setLastName(reader.readString(1));
setHomeAddress((Address) reader.readObject(2));
setWorkAddress((Address) reader.readObject(3));
setTelephoneNumbers(reader.readMap(4, null));
setBirthDate(new Date(reader.readLong(5)));
}

/**
* {@inheritDoc}
*/
public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeString(0, getFirstName());
writer.writeString(1, getLastName());
writer.writeObject(2, getHomeAddress());
writer.writeObject(3, getWorkAddress());
writer.writeMap(4, getTelephoneNumbers());
writer.writeLong(5, getBirthDate().getTime());
}

// ----- Object methods -------------------------------------------------

/**
* {@inheritDoc}
*/
public String toString()
{
StringBuffer sb = new StringBuffer(getFirstName())
.append(" ")
.append(getLastName())
.append("\nAddresses")
.append("\nHome: ").append(getHomeAddress())
.append("\nWork: ").append(getWorkAddress())
.append("\nTelephone Numbers");

for (Iterator iter = TelephoneNumbers.entrySet().iterator();
iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
sb.append("\n")
.append(entry.getKey()).append(": ").append(entry.getValue());
}
return sb.append("\nBirth Date: ").append(getBirthDate()).toString();
}
/**
* Approximate number of millis in a year ignoring things such as leap
* years. Suitable for example use only.
*/
public static final long MILLIS_IN_YEAR = 1000L * 60L * 60L * 24L * 365L;

}

4.2.3 ドライバ・クラスの作成

Contactエントリをキャッシュに挿入し、挿入したエントリを取得する、ContactDriverというドライバ・クラスを作成します。

1. Contactsプロジェクト内にContactDriverという新しいJavaクラスを作成します。mainメソッドを含むようにしてください。
詳細は、「Javaクラスの作成」を参照してください。

2. ContactDriverクラスで、contactという新しいNamedCacheを作成し、Contactオブジェクトの新しいインスタンスを挿入します。キャッシュからContactオブジェクトを取得し、2つのオブジェクトが同一であることを確認します。例4-4は、このクラスの実装例を示しています。

例4-4 ContactDriverクラスのサンプル

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import java.sql.Date;

import java.util.GregorianCalendar;
import java.util.Map;
import java.util.HashMap;

public class ContactDriver {

public ContactDriver()
{
}

public static void main(String[] args) {
NamedCache contact = CacheFactory.getCache("contact");

Address homeAddress = new Address ("4157 Wash Ave", "Suite 4",
"Burlingame", "CA", "94407", "USA");
Address workAddress = new Address ("500 Oracle Pkwy", "MS989",
"Redwood Shores", "CA", "94065", "USA");
Date date = new java.sql.Date(new GregorianCalendar(2011, 05, 01).getTime().getTime());
PhoneNumber phonenumber = new PhoneNumber ((short)11, (short)650, (short)506, 7000);
Map map = new HashMap();
map.put("home", phonenumber);

Contact con1 = new Contact("Tom", "Dunn", homeAddress, workAddress,
map, date);

contact.put(con1.getFirstName(),con1);

Contact con2 = (Contact)contact.get(con1.getFirstName());

if (con2.getFirstName().equals(con1.getFirstName()))
{
System.out.println("They are the same!!");
}
}
}

4.2.4 POF構成ファイルとキャッシュ構成ファイルの作成

POFシリアライズを使用するには、ユーザー定義オブジェクトをPOF構成ファイルに登録する必要があります。この構成によって、ユーザー定義オブジェクトのクラスが数値に関連付けられます。また、POFシリアライズおよびPOF構成ファイル名をキャッシュ構成ファイルで指定する必要があります。

1. Contactオブジェクト、AddressオブジェクトおよびPhoneNumberオブジェクトのPOF構成ファイルを作成します。

1. 独自のデータ型のPOF構成ファイルを作成するには、プロジェクトで作成したpof-config.xmlファイルを使用します。

2. Contactオブジェクト、AddressオブジェクトおよびPhoneNumberオブジェクトの<user-type>要素を定義し、これらに型ID1001、1002および1003を割り当てて、完全なクラス名を指定します。このファイルには、Coherenceデータ型の最初の1000個のIDを予約するcoherence-pof-config.xmlファイルが含まれている必要があります。

3. ファイル名を変更し、contacts-pof-config.xmlとして保存します(このファイルは、C:\home\oracle\workspace\Contacts\appClientModuleフォルダに保存されます)。例4-5に、contacts-pof-config.xmlファイルのサンプルを示します。

例4-5 POF構成ファイル

<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">

<user-type-list>

<!-- coherence POF user types -->
<include>coherence-pof-config.xml</include>

<!-- com.tangosol.examples package -->
<user-type>
<type-id>1001</type-id>
<class-name>com.oracle.handson.Contact</class-name>
</user-type>
<user-type>
<type-id>1002</type-id>
<class-name>com.oracle.handson.Address</class-name>
</user-type>
<user-type>
<type-id>1003</type-id>
<class-name>com.oracle.handson.PhoneNumber</class-name>
</user-type>
</user-type-list>
<allow-interfaces>true</allow-interfaces>
<allow-subclasses>true</allow-subclasses>
</pof-config>

2. キャッシュ構成ファイルを作成します。Project Explorerでcoherence-cache-config.xmlファイルを使用できます。このファイルはcoherence-cache-config.xsdファイルに基づいています。また、coherence.jarファイルにcoherence-cache-config.xmlのコピーがあります。

1. scheme-nameとしてExamplesPartitionedPocSchemeを、service-nameとしてPartitionedPofCacheを使用します。

2. serializerセクションでは、POFシリアライズ・オブジェクトを適切なシリアライズ・ルーチン(PofSerializer、またはPortableObjectインタフェースを介したコールによる)にマップします。この場合は、com.tangosol.io.pof.ConfigurablePofContextクラスを使用します。

3. <init-param>セクションで、POF構成ファイルの名前(この場合はcontacts-pof-config.xml)を指定します。

4. Project Explorerでファイル名を変更し、contacts-cache-config.xmlとして保存します(このファイルはC:\home\oracle\workspace\Contacts\appClientModuleフォルダに保存されます)。例4-6に、contacts-cache-config.xmlファイルのサンプルを示します。

例4-6 キャッシュ構成ファイル

<?xml version="1.0"?>

<!--
Note: This XML document is an example Coherence Cache Configuration deployment descriptor that should be customized (or replaced) for your particular caching requirements. The cache mappings and schemes declared in this descriptor are  strictly for demonstration purposes and are not required.

For detailed information on each of the elements that can be used in this descriptor please see the Coherence Cache Configuration deployment descriptor guide included in the Coherence distribution or the "Cache Configuration Elements" page on the Coherence Wiki (http://wiki.tangosol.com).
-->

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config http://xmlns.oracle.com/coherence/coherence-cache-config/1.2/coherence-cache-config.xsd">
<!--
The defaults element defines factory-wide default settings.
-->
<defaults>
<!--
Note: This element defines the default serializer for all services defined within this cache configuration descriptor.

Valid values include full serializer definitions, as well as named references to serializers defined within the "serializers" element of the operational configuration.

Example values include: java, pof. Default value is java.
-->
<serializer system-property="tangosol.coherence.serializer"/>

<!--
Note: This element defines the default socket-provider for all Coherence    Extend services defined within this cache configuration descriptor.

Valid values include full socket-provider definitions, as well as named    references to providers defined within the "socket-providers" element of the    operational configuration.

This setting only specifies the default socket-provider for Coherence    Extend services; TCMP's socket-provider is specified within the "unicast-listener" of the operational configuration.

Example values include: system, ssl. Default value is system.
-->
<socket-provider system-property="tangosol.coherence.socketprovider"/>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>*</cache-name>
<scheme-name>ExamplesPartitionedPofScheme</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<distributed-scheme>
<scheme-name>ExamplesPartitionedPofScheme</scheme-name>
<service-name>PartitionedPofCache</service-name>
<serializer>
<instance>
<class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
<init-params>
<init-param>
<param-type>String</param-type>
<param-value>contacts-pof-config.xml</param-value>
</init-param>
</init-params>
</instance>
</serializer>
<backing-map-scheme>
<local-scheme>
<!-- each node will be limited to 250MB -->
<high-units>250M</high-units>
<unit-calculator>binary</unit-calculator>
</local-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>

4.2.5 サンプル・プロジェクトの実行

Contactsプロジェクトでは、キャッシュ・サーバーが実行されている必要があります。キャッシュ・サーバーとアプリケーションは、同じPOF構成ファイルおよびキャッシュ構成ファイルを参照する必要があります。ここでは、キャッシュ・サーバーとアプリケーションの実行構成を作成する方法について説明します。

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. キャッシュ・サーバーを起動する実行可能ファイルを作成します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「Name」フィールドにContactsCacheServerと入力します。

2. 「Main」タブで、「Project」フィールドに「Contacts」が表示されていることを確認します。「Include system libraries when searching for a main class」チェック・ボックスを選択し、「Search」ボタンをクリックします。「Select Main Type」ダイアログ・ボックスで、DefaultCacheServerと入力し、「DefaultCacheServer - com.tangosol.net」クラスを選択します。「Select Main Type」ダイアログ・ボックスで「OK」をクリックし、「Run Configurations」ダイアログ・ボックスで「Apply」をクリックします。

3. 「Coherence」タブの「General」タブで、「Topology」フィールドの「Absolute File Path」を選択し、C:\home\oracle\workspace\Contacts\appClientModuleディレクトリのcontacts-cache-config.xmlファイルを参照します。「Enabled (cache server)」が選択されていることを確認します。「Cluster port」に一意の値を入力します。「Apply」をクリックします。「General」タブは図4-3のようになります。

図4-3 Contactsキャッシュ・サーバーの実行可能ファイルの「Coherence」タブ

4. 「Coherence」タブの「Other」タブで、tangosol.pof.config項目までスクロールダウンします。POF構成ファイルへのパス(C:\home\oracle\workspace\Contacts\appClientModule\contacts-pof-config.xml)を入力します。

5. 「Arguments」タブで、「VM Arguments」に-showversionと入力します。

6. 「Classpath」タブで、「User Entries」にContactsプロジェクトが表示されていることを確認します。表示されていない場合は、「Add Projects」ボタンをクリックしてContactsプロジェクトを追加します。

7. 「Common」タブで、「Shared file」を選択し、\Contactsプロジェクトを参照します。

8. 「Run」をクリックして、Contactsキャッシュ・サーバーを起動します。出力は例4-7のようになります。

例4-7 Contactsキャッシュ・サーバーの出力

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

2012-08-16 15:09:26.380/1.718 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-16 15:09:26.427/1.765 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-16 15:09:26.474/1.812 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Contacts/build/classes/tangosol-coherence-override.xml"
2012-08-16 15:09:26.474/1.812 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-16 15:09:26.474/1.812 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-16 15:09:26.474/1.812 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-16 15:09:26.896/2.234 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Contacts/appClientModule/contacts-cache-config.xml"
2012-08-16 15:09:27.427/2.765 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-16 15:09:29.240/4.578 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-16 15:09:32.693/8.031 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-16 15:09:32.693/8.031 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer)
OldestMember=Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-16 15:09:29.365|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-16 15:09:32.880/8.218 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-16 15:09:32.959/8.297 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-16 15:09:33.459/8.797 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=1): Loaded POF configuration from "file:/C:/home/oracle/workspace/Contacts/build/classes/contacts-pof-config.xml"
2012-08-16 15:09:33.537/8.875 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=1): Loaded included POF configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2012-08-16 15:09:33.740/9.078 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Service PartitionedPofCache joined the cluster with senior service member 1
2012-08-16 15:09:33.802/9.140 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1):
Services
(
ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=12.1.2, OldestMemberId=1}
PartitionedCache{Name=PartitionedPofCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
)

Started DefaultCacheServer...

3. ContactDriver実行可能ファイルの実行構成を作成します。

- 「Project Explorer」でContactDriver.javaファイルを右クリックし、「Run As」→「Run Configurations」を選択します。

- 「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」ノードをダブルクリックします。「Name」フィールドにContactsDriverと入力します。「Main」タブの「Project」フィールドでContactsを参照し、「Main class」フィールドでcom.oracle.handson.ContactDriverを参照します。「Apply」をクリックします。

- 「Coherence」タブの「General」タブの「Cache configuration descriptor」フィールドで、contacts-cache-config.xmlファイルへの絶対パスを参照します。「Disable (cache client)」ラジオ・ボタンを選択します。「Cluster port」フィールドに3155と入力します。

- 「Coherence」タブの「Other」タブで、「tangosol.pof.config」フィールドまでスクロールダウンし、値をcontacts-pof-config.xml POF構成ファイルへの絶対パスに置き換えます。

- 「Classpath」タブで、「User Entries」に「Contacts (default classpath)」が表示されていることを確認します。

4. 「Run」をクリックして、ContactDriverの構成を実行します。Contactsの出力例は例4-8のようになります。
この例では、Contactオブジェクトが実行時にPOFに変換されます。POFを使用すると、CPU時間と生成されるバイナリ・ファイルのサイズにおいて、パフォーマンスが大幅に向上します。

例4-8 Eclipse IDEでのContactsの出力例

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) Client VM (build 21.0-b17, mixed mode, sharing)

2012-08-16 15:15:22.568/0.500 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-16 15:15:22.615/0.547 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-16 15:15:22.662/0.594 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Contacts/build/classes/tangosol-coherence-override.xml"
2012-08-16 15:15:22.662/0.594 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-16 15:15:22.662/0.594 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-16 15:15:22.662/0.594 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-16 15:15:23.099/1.031 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Contacts/appClientModule/contacts-cache-config.xml"
2012-08-16 15:15:23.490/1.422 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-16 15:15:24.693/2.625 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8090 using SystemDatagramSocketProvider
2012-08-16 15:15:25.068/3.000 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Failed to satisfy the variance: allowed=16, actual=31
2012-08-16 15:15:25.068/3.000 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Increasing allowable variance to 17
2012-08-16 15:15:25.396/3.328 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2012-08-16 15:15:25.193, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) joined cluster "cluster:0x47DB" with senior Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-16 15:15:25.630/3.562 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2012-08-16 15:15:25.630/3.562 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service PartitionedPofCache with senior member 1
2012-08-16 15:15:25.630/3.562 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=2, Timestamp=2012-08-16 15:15:25.193, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver)
OldestMember=Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2012-08-16 15:09:29.365, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5792, Role=CoherenceServer)
Member(Id=2, Timestamp=2012-08-16 15:15:25.193, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-16 15:09:29.365|JOINED,
2|12.1.2|2012-08-16 15:15:25.193|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2012-08-16 15:15:25.755/3.687 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2012-08-16 15:15:25.849/3.781 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-16 15:15:26.224/4.156 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=2): Loaded POF configuration from "file:/C:/home/oracle/workspace/Contacts/build/classes/contacts-pof-config.xml"
2012-08-16 15:15:26.302/4.234 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=2): Loaded included POF configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2012-08-16 15:15:26.427/4.359 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=2): Service PartitionedPofCache joined the cluster with senior service member 1
They are the same!!

5. キャッシュ・サーバーの出力をもう一度参照すると、Contactsキャッシュ・クライアントがクラスタに参加し、処理を完了した後にクラスタから離脱したことを示すメッセージを確認できます。例4-9を参照してください。

例4-9 Contactsクライアントの参加と離脱を示すContactsキャッシュ・サーバー

...
Started DefaultCacheServer...

2012-08-16 15:15:25.396/360.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-16 15:15:25.193, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver) joined Cluster with senior member 1
2012-08-16 15:15:25.755/361.093 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-08-16 15:15:26.490/361.828 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service PartitionedPofCache with senior member 1
2012-08-16 15:15:26.646/361.984 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2012-08-16 15:15:25.193, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver) due to a peer departure; removing the member.
2012-08-16 15:15:26.646/361.984 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2012-08-16 15:15:26.646/361.984 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service PartitionedPofCache with senior member 1
2012-08-16 15:15:26.646/361.984 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-16 15:15:26.646, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4572, Role=OracleHandsonContactDriver) left Cluster with senior member 1

5 キャッシュへのデータのロード

この演習では、テキスト・ファイルから読み取ったドメイン・オブジェクトをCoherenceキャッシュに移入する方法を学習します。ここでは、Coherenceのaggregator、extractorおよびfilterの各パッケージからAPIを使用することについて取り上げます。

この章には次の項が含まれます:

- 概要

- キャッシュへのドメイン・オブジェクトの移入

- キャッシュ内のデータの問合せおよび集計

5.1 概要

これまで、オブジェクトをキャッシュに格納したりキャッシュから取得したりする場合には、個別に実行してきました。この方法では、特にパーティション化されたりレプリケートされたりしたキャッシュで、putメソッドをコールするたびにネットワーク・トラフィックが増加することがあります。また、putメソッドをコールするたびに、キャッシュ内で置き換えられたばかりのオブジェクトが返され、不要なオーバーヘッドがさらに増えます。putAllメソッドを使用すると、キャッシュのロードを大幅に効率化できます。

この章のタスクを実行するには、最初に第4章「複合オブジェクトの操作」で説明しているプロジェクトを完了する必要があります。また、テキスト・ファイルを読み取るにはjava.io.BufferedReader、テキスト・ファイルを解析するにはjava.lang.String.splitメソッド、日付を解析するにはjava.text.SimpleDateFormatの使用について理解しておく必要があります。

5.2 キャッシュへのドメイン・オブジェクトの移入

この演習では、Coherenceキャッシュにドメイン・オブジェクトを移入するコンソール・アプリケーションを作成する方法を示します。このアプリケーションはCoherenceのcom.tangosol.io.pof.PortableObject実装を使用して、Portable Object format (POF)にオブジェクトをシリアライズします。

この演習では、Contactオブジェクトを取得できるキー、キャッシュにデータを提供するジェネレータおよびキャッシュをロードするローダーを作成します。

1. ドメイン・オブジェクトのキーを使用したクラスの作成

2. POF構成ファイルの編集

3. データ・ジェネレータの作成

4. キャッシュをロードするコンソール・アプリケーションの作成

5. キャッシュ・ロード・サンプルの実行

5.2.1 ドメイン・オブジェクトのキーを使用したクラスの作成

ドメイン・オブジェクトのキーを持つクラスを作成するには:

1. Loadingという名前の新規アプリケーション・クライアント・プロジェクトを作成します。「Configuration」ドロップダウン・リストから「CoherenceConfig」を選択します。「New Application Client Project」ウィザードの「Application Client Module」ページで、「Create a default Main class」チェック・ボックスの選択を解除します。
新規プロジェクトの作成の詳細は、「複合オブジェクトの作成とキャッシュ」を参照してください。

2. 前の演習(Contacts)で作成したAddressクラス、PhoneNumberクラスおよびContactクラスに関連するクラスとファイルを追加します。これらのファイルは、c:\home\oracle\workspace\Contacts\appClientModuleディレクトリおよびc:\home\oracle\workspace\Contacts\build\classesディレクトリにあります。
「Project Explorer」でLoadingプロジェクトを右クリックして、「Properties」を選択します。「Properties for Loading」ダイアログ・ボックスで、「Java Build Path」を選択します。「Projects」タブで、「Add」をクリックします。図5-1に示されているように、「Required Project Selection」ダイアログ・ボックスから「Contacts」プロジェクトを選択します。

図5-1 プロジェクトのビルド・パスへのフォルダの追加

「Order and Export」タブで、「Up」ボタンと「Down」ボタンを使用して「Contacts」をリストの先頭に移動します。タブの内容は図5-2のようになります。

図5-2 Loadingプロジェクトの「Order and Export」タブの内容

3. 情報追跡の対象となる従業員のキーを提供するContactIdクラスを作成します。Javaクラスの作成の詳細は、「Javaクラスの作成」を参照してください。
従業員の姓名に基づいた連絡先IDを作成します。このオブジェクトは、Contactオブジェクトを取得するキーとして機能します。

このクラスはPOFシリアライズを使用するので、PortableObjectインタフェース、writeExternalメソッドとreadExternal PortableObjectメソッドのほか、equalsオブジェクト、hashCodeオブジェクトおよびtoStringオブジェクトのメソッドを実装する必要があります。

注意:

キャッシュのキーと値は、シリアライズ可能(たとえば、java.io.Serializable)である必要があります。また、キャッシュ・キーはhashCodeメソッドとequalsメソッドの実装を提供する必要があり、これらのメソッドはクラスタ・ノード間で一貫性のある結果を返す必要があります。つまり、hashCodeオブジェクト・メソッドとequalsオブジェクト・メソッドの実装はオブジェクトのシリアライズ可能な状態(オブジェクトの一時的でないフィールド)にのみ基づいている必要があります。String、Integer、Dateなどの大半の組込みJavaタイプはこの要件を満たしています。一部のキャッシュの実装(特にパーティション・キャッシュ)では、等価の検証にキー・オブジェクトのシリアライズされた形式を使用します。つまり、equalsメソッドによりtrueが返されるキーは、同様の方法でシリアライズされる必要があります。ほとんどの組込みのJavaタイプはこの要件を満たしています。

例5-1は、考えられるContactIdクラスの実装を示しています。

例5-1 単純な連絡先IDクラス

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import com.tangosol.util.Base;
import com.tangosol.util.HashHelper;

import java.io.IOException;

/**
* ContactId is a key to the person for whom information is
* tracked.
*/
public class ContactId implements PortableObject
{
// ----- constructors ---------------------------------------------------

/**
* Default constructor (necessary for PortableObject implementation).
*/
public ContactId()
{
}

/**
* Construct a contact person.
*
*/
public ContactId(String FirstName, String LastName)
{
super();
this.FirstName = FirstName;
this.LastName  = LastName;
}

// ----- accessors ------------------------------------------------------

/**
* Return the first name.
*
*/
public String getFirstName()
{
return FirstName;
}

/**
* Return the last name.
*
*/
public String getLastName()
{
return LastName;
}

// ----- PortableObject interface ---------------------------------------

public void readExternal(PofReader reader)
throws IOException
{
FirstName = reader.readString(0);
LastName = reader.readString(1);
}

public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeString(0, FirstName);
writer.writeString(1, LastName);
}

// ----- Object methods -------------------------------------------------

public boolean equals(Object oThat)
{
if (this == oThat)
{
return true;
}
if (oThat == null)
{
return false;
}

ContactId that = (ContactId) oThat;
return Base.equals(getFirstName(), that.getFirstName()) &&
Base.equals(getLastName(),  that.getLastName());
}

public int hashCode()
{
return HashHelper.hash(getFirstName(),
HashHelper.hash(getLastName(), 0));
}

public String toString()
{
return getFirstName() + " " + getLastName();
}

// ----- data members ---------------------------------------------------

/**
* First name.
*/
private String FirstName;

/**
* Last name.
*/
private String LastName;
}

5.2.2 POF構成ファイルの編集

POF構成ファイルを編集します。ContactIdクラスの<user-type>エントリをcontacts-pof-config.xmlファイルに追加します。ファイルは例5-2のようになります。

例5-2 ContactIdエントリを持つPOF構成ファイル

<?xml version="1.0"?>

<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">
<user-type-list>

<!-- coherence POF user types -->
<include>coherence-pof-config.xml</include>

<!-- com.tangosol.examples package -->
<user-type>
<type-id>1001</type-id>
<class-name>com.oracle.handson.Contact</class-name>
</user-type>
<user-type>
<type-id>1002</type-id>
<class-name>com.oracle.handson.Address</class-name>
</user-type>
<user-type>
<type-id>1003</type-id>
<class-name>com.oracle.handson.PhoneNumber</class-name>
</user-type>
<user-type>
<type-id>1004</type-id>
<class-name>com.oracle.handson.ContactId</class-name>
</user-type>
</user-type-list>
<allow-interfaces>true</allow-interfaces>
<allow-subclasses>true</allow-subclasses>
</pof-config>

5.2.3 データ・ジェネレータの作成

ランダムな従業員の連絡先の名前やアドレスを生成するDataGeneratorという名前のJavaクラスを作成します。詳細は、「Javaクラスの作成」を参照してください。

前の演習で作成したAddressクラス、PhoneNumberクラスおよびContactクラスを使用します。ランダムな名前、アドレス、電話番号および年齢を生成するには、java.util.Randomを使用します。

例5-3は、考えられるデータ生成の実装を示しています。この実装では、従業員の連絡先情報が記載されたテキスト・ファイル(contacts.cvs)を作成します。

例5-3 データ生成クラスのサンプル

package com.oracle.handson;

import com.oracle.handson.Address;
import com.oracle.handson.Contact;
import com.oracle.handson.PhoneNumber;
import com.tangosol.util.Base;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import java.sql.Date;

import java.util.Collections;
import java.util.Random;

/**
* DataGenerator is a generator of sample contacts.
*/
public class DataGenerator
{
// ----- static methods -------------------------------------------------

/**
* Generate contacts.
*/
public static void main(String[] asArg)
throws IOException
{
String       sFile = asArg.length > 0 ? asArg[0] : FILENAME;
int          cCon  = asArg.length > 1 ? Integer.parseInt(asArg[1]) : 1000;
OutputStream out   = new FileOutputStream(sFile);

generate(out, cCon);
out.close();
}

/**
* Generate the contacts and write them to a file.
*/
public static void generate(OutputStream out, int cContacts)
throws IOException
{
PrintWriter writer = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(out)));

for (int i = 0; i < cContacts; ++i)
{
StringBuffer sb = new StringBuffer(256);

//contact person
sb.append("John,")
.append(getRandomName())
.append(',');

// home and work addresses
sb.append(Integer.toString(Base.getRandom().nextInt(999)))
.append(" Beacon St.,,") /*street1,empty street2*/
.append(getRandomName()) /*random city name*/
.append(',')
.append(getRandomState())
.append(',')
.append(getRandomZip())
.append(",US,Yoyodyne Propulsion Systems,")
.append("330 Lectroid Rd.,Grover's Mill,")
.append(getRandomState())
.append(',')
.append(getRandomZip())
.append(",US,");

// home and work telephone numbers
sb.append("home,")
.append(Base.toDelimitedString(getRandomPhoneDigits(), ","))
.append(",work,")
.append(Base.toDelimitedString(getRandomPhoneDigits(), ","))
.append(',');

// random birth date in millis before or after the epoch
sb.append(getRandomDateInMillis());

writer.println(sb);
}
writer.flush();
}

/**
* Return a random name.
*
*/
private static String getRandomName()
{
Random rand = Base.getRandom();
int    cCh  = 4 + rand.nextInt(7);
char[] ach  = new char[cCh];

ach[0] = (char) ('A' + rand.nextInt(26));
for (int of = 1; of < cCh; ++of)
{
ach[of] = (char) ('a' + rand.nextInt(26));
}
return new String(ach);
}

/**
* Return a random phone muber.
* The phone number includes access, country, area code, and local
* number.
*
*/
private static int[] getRandomPhoneDigits()
{
Random rand = Base.getRandom();
return new int[]
{
11,                   // access code
rand.nextInt(99),     // country code
rand.nextInt(999),    // area code
rand.nextInt(9999999) // local number
};
}

/**
* Return a random Phone.
*
*/
private static PhoneNumber getRandomPhone()
{
int[] anPhone = getRandomPhoneDigits();

return new PhoneNumber((short)anPhone[0], (short)anPhone[1],
(short)anPhone[2], anPhone[3]);

}
/**
* Return a random Zip code.
*
*/
private static String getRandomZip()
{
return Base.toDecString(Base.getRandom().nextInt(99999), 5);
}

/**
* Return a random state.
*
*/
private static String getRandomState()
{
return STATE_CODES[Base.getRandom().nextInt(STATE_CODES.length)];
}

/**
* Return a random date in millis before or after the epoch.
*
*/
private static long getRandomDateInMillis()
{
return (Base.getRandom().nextInt(40) - 20) * Contact.MILLIS_IN_YEAR;
}

/**
* Generate a Contact with random information.
*
*/
public static Contact getRandomContact()
{
return new Contact("John",
getRandomName(),
new Address("1500 Boylston St.", null, getRandomName(),
getRandomState(), getRandomZip(), "US"),
new Address("8 Yawkey Way", null, getRandomName(),
getRandomState(), getRandomZip(), "US"),
Collections.singletonMap("work", getRandomPhone()),
new Date(getRandomDateInMillis()));
}

// ----- constants ------------------------------------------------------

/**
* US Postal Service two letter postal codes.
*/
private static final String[] STATE_CODES =
{
"AL", "AK", "AS", "AZ", "AR", "CA", "CO", "CT", "DE", "OF", "DC",
"FM", "FL", "GA", "GU", "HI", "ID", "IL", "IN", "IA", "KS", "KY",
"LA", "ME", "MH", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE",
"NV", "NH", "NJ", "NM", "NY", "NC", "ND", "MP", "OH", "OK", "OR",
"PW", "PA", "PR", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VI",
"VA", "WA", "WV", "WI", "WY"
};
/**
* Default contacts file name.
*/
public static final String FILENAME = "contacts.csv";
}

DataGeneratorクラスは、従業員に関する情報をランダムに生成します。たとえば、従業員の名前、自宅の住所、勤務先の住所、自宅の電話番号、勤務先の電話番号および従業員の年齢などの情報です。情報は、contacts.csvという名前のCSV形式のファイルに保存されます。このファイルはCSV形式のファイルの標準ルールに従っているため、1行ごとに1つのレコードが記載され、レコード内の個々のフィールドはカンマで区切られています。

例5-4は、contacts.csvファイルの最初の数エントリを示しています。

例5-4 contacts.csvファイルの内容

John,Dvcqbvcp,669 Beacon St.,,Tetuvusz,CA,68457,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,KS,30344,US,home,11,98,183,8707139,work,11,96,425,1175949,63072000000
John,Fxsr,549 Beacon St.,,Jutaswmaby,MI,16315,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,CT,60309,US,home,11,20,40,3662989,work,11,41,187,3148474,-189216000000
John,Gmyrolvfyd,73 Beacon St.,,Lpnztf,AR,82667,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,NY,42297,US,home,11,22,17,8579970,work,11,35,338,9286245,-567648000000
John,Efmpjlbj,85 Beacon St.,,Wyswpb,AK,29590,US,Yoyodyne Propulsion Systems,330 Lectroid Rd.,Grover's Mill,NJ,06219,US,home,11,20,744,4331451,work,11,39,911,9104590,-157680000000
...

5.2.4 キャッシュをロードするコンソール・アプリケーションの作成

LoaderExampleという名前のJavaクラスを作成します。詳細は、「Javaクラスの作成」を参照してください。

クラスを実装して、「データ・ジェネレータの作成」の項で説明したプログラムで生成された従業員のデータを含むキャッシュをロードします。入力ストリームおよびバッファ済リーダーを使用して、contacts.csvファイルの従業員の情報を単一のCoherenceキャッシュにロードします。

データ・ファイルの従業員の情報を解析するコードを追加します。この情報を取得したら、個々の連絡先を作成してキャッシュに挿入します。処理作業を軽減し、ネットワーク・トラフィックを最低限に抑えるには、putAllメソッドを使用してキャッシュをロードします。

例5-5は、考えられるLoaderExampleクラスの実装を示しています。

例5-5 キャッシュ・ロード・プログラムのサンプル

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.oracle.handson.ContactId;
import com.oracle.handson.Address;
import com.oracle.handson.PhoneNumber;
import com.oracle.handson.Contact;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.sql.Date;

import java.util.HashMap;
import java.util.Map;

/**
* LoaderExample loads contacts into the cache from a file.
*
*/
public class LoaderExample
{
// ----- static methods -------------------------------------------------

/**
* Load contacts.
*/
public static void main (String[] asArg)
throws IOException
{
String sFile  = asArg.length > 0 ? asArg[0] : DataGenerator.FILENAME;
String sCache = asArg.length > 1 ? asArg[1] : CACHENAME;

System.out.println("input file: " + sFile);
System.out.println("cache name: " + sCache);

new LoaderExample().load(CacheFactory.getCache(sCache),
new FileInputStream(sFile));
CacheFactory.shutdown();
}

/**
* Load cache from stream.
*
*/
public void load(NamedCache cache, InputStream in)
throws IOException
{
BufferedReader reader   = new BufferedReader(new InputStreamReader(in));
Map            mapBatch = new HashMap(1024);
String         sRecord;
int            cRecord  = 0;

while ((sRecord = reader.readLine()) != null)
{
// parse record
String[]      asPart     = sRecord.split(",");
int           ofPart     = 0;
String        sFirstName =  asPart[ofPart++];
String        sLastName  =  asPart[ofPart++];
ContactId          id    = new ContactId(sFirstName, sLastName);
Address       addrHome   = new Address(
/*streetline1*/ asPart[ofPart++],
/*streetline2*/ asPart[ofPart++],
/*city*/        asPart[ofPart++],
/*state*/       asPart[ofPart++],
/*zip*/         asPart[ofPart++],
/*country*/     asPart[ofPart++]);
Address       addrWork   = new Address(
/*streetline1*/ asPart[ofPart++],
/*streetline2*/ asPart[ofPart++],
/*city*/        asPart[ofPart++],
/*state*/       asPart[ofPart++],
/*zip*/         asPart[ofPart++],
/*country*/     asPart[ofPart++]);
Map           mapTelNum  = new HashMap();

for (int c = asPart.length - 1; ofPart < c; )
{
mapTelNum.put(/*type*/ asPart[ofPart++], new PhoneNumber(
/*access code*/  Short.parseShort(asPart[ofPart++]),
/*country code*/ Short.parseShort(asPart[ofPart++]),
/*area code*/    Short.parseShort(asPart[ofPart++]),
/*local num*/    Integer.parseInt(asPart[ofPart++])));
}
Date dtBirth = new Date(Long.parseLong(asPart[ofPart]));

// Construct Contact and add to batch
Contact con1 = new Contact(sFirstName, sLastName, addrHome,
addrWork, mapTelNum, dtBirth);
System.out.println(con1);
mapBatch.put(id, con1);

++cRecord;
if  (cRecord % 1024 == 0)
{
// load batch
cache.putAll(mapBatch);
mapBatch.clear();
System.out.print('.');
System.out.flush();
}
}

if (!mapBatch.isEmpty())
{
// load final batch
cache.putAll(mapBatch);
}

System.out.println("Added " + cRecord + " entries to cache");
}

// ----- constants ------------------------------------------------------

/**
* Default cache name.
*/
public static final String CACHENAME = "ContactsCache";

}

5.2.5 キャッシュ・ロードのサンプルの実行

キャッシュ・ロードのサンプルを実行するには:

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. ContactsCacheServerファイルを使用して、キャッシュ・サーバーを起動します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択し、ContactsCacheServer構成を編集します。「Main」タブで、「Browse」をクリックしてLoadingプロジェクトを選択します。

2. 「Classpath」タブで、「User Entries」を選択して「Add Projects」をクリックします。「Project Selection」ダイアログ・ボックスで、Loadingプロジェクトを選択します。「OK」をクリックします。

3. 「Common」タブで、「Shared file」をクリックしてLoadingプロジェクトを参照します。

4. 「Apply」→「Run」をクリックします。

3. DataGeneratorの実行構成を作成します。「Project Explorer」のDataGeneratorを右クリックし、「Run As」を選択します。「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」を選択して「New Configuration」アイコンをクリックします。

1. 「Name」フィールドにDataGeneratorと入力します。

2. 「Main」タブの「Project」フィールドにLoadingと入力します。「Main class」フィールドにcom.oracle.handson.DataGeneratorと入力します。

3. 「Coherence」タブの「Generalタブで、「Cache configuration descriptor」フィールドのc:\home\oracle\workspace\Contacts\appClientModule\contacts-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、「tangosol.pof.config」フィールドまで下方へスクロールします。POF構成ファイルcontacts-pof-config.xmlへの絶対パスを入力します。「Apply」をクリックします。

4. 「Common」タブで、「Shared file」を選択してLoadingディレクトリを参照します。

5. 「Classpath」タブのLoadingの内容を確認します。図5-3のように、「Contacts」が「Loading」の下にエントリの1つとして表示されます。

図5-3 DataGeneratorプログラムのクラスパス

4. LoaderExampleの実行構成を作成します。

- 「Name」フィールドにLoaderGeneratorと入力します。

- 「Main」タブの「Project」フィールドにLoadingと入力します。「Main class」フィールドにcom.oracle.handson.LoaderExampleと入力します。

- 「Coherence」タブの「Generalタブで、「Cache configuration descriptor」フィールドのc:\home\oracle\workspace\Contacts\appClientModule\contacts-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、「tangosol.pof.config」フィールドまで下方へスクロールします。POF構成ファイルcontacts-pof-config.xmlへの絶対パスを入力します。「Apply」をクリックします。

- 「Classpath」タブの内容を確認します。図5-4のように、「Contacts」が「Loading」の下にエントリの1つとして表示されます。表示されない場合は、「User Entries」をクリックし、「Add Project」ボタンでプロジェクトを追加します。

図5-4 LoaderExampleプログラムのクラスパス

5. 「Run Configurations」ダイアログ・ボックスからDataGenerator構成を実行します。次にLoaderExample構成を実行します。
DataGenerator実行構成によりデータ・ファイルが生成されます。Eclipseコンソールのウィンドウには出力や応答は表示されません。LoaderGenerator実行構成により、例5-6のような従業員の連絡先情報のストリームがEclipseコンソール・ウィンドウに送信されます。

例5-6 サンプル・キャッシュ・ロード・プログラムの出力

...
2012-08-16  15:47:04.413/2.266 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2012-08-16  15:47:04.413/2.266 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=2): Loaded POF configuration from "file:/C:/home/oracle/workspace/Contacts/appClientModule/contacts-pof-config.xml"
2012-08-16  15:47:04.413/2.266 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=2): Loaded included POF configuration from "jar:file:/C:/coherence360/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2012-08-16  15:47:04.413/2.266 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=2): Service PartitionedPofCache joined the cluster with senior service member 1
2012-08-16  15:47:04.413/2.266 Oracle Coherence GE 12.1.2.0 <D4> (thread=DistributedCache:PartitionedPofCache, member=2): Asking member 1 for 128 primary partitions
John Hwolru
Addresses
Home: 742 Beacon St.

Icymz, OH 74135
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, WY 20222
US
Telephone Numbers
work: +11 50 928 2637858
home: +11 72 403 7946780
Birth Date: 1981-12-28

...

John Unglg
Addresses
Home: 973 Beacon St.

Cgarhej, MI 10517
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, GA 81835
US
Telephone Numbers
work: +11 8 925 5233805
home: +11 95 108 2947077
Birth Date: 1965-01-01
John Lkkwgw
Addresses
Home: 806 Beacon St.

Zlpft, GU 55786
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, WV 88125
US
Telephone Numbers
work: +11 45 321 6385646
home: +11 87 371 2109053
Birth Date: 1987-12-27
Added 1000 entries to cache
2012-08-16 15:47:04.575/2.625 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=n/a): Service Management left the cluster
2012-08-16 15:47:04.591/2.641 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=n/a): Service PartitionedPofCache left the cluster
2012-08-16 15:47:04.622/2.672 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=n/a): Service Cluster left the cluster

5.3 キャッシュ内のデータの問合せおよび集計

この演習では、キャッシュ内のデータの問合せおよび集計について紹介します。この演習では、次の方法を説明します。

- キャッシュでの特定データの問合せ

- キャッシュ内の情報の集計

名前を持つキャッシュに複合オブジェクトを挿入すると、グリッド内の情報を問い合せたり集計したりできます。com.tangosol.util.QueryMapインタフェースにより、キャッシュ内の値やキーを管理できます。フィルタを使用して結果を制限できます。また、索引を定義して問合せを最適化することもできます。

Coherenceでは格納時に情報がシリアライズされるため、情報の問合せの際にデシリアライズによるオーバーヘッドも発生します。索引が追加されると、索引自体に保存されている値はデシリアライズされるため、アクセスが速くなります。索引付けされるオブジェクトは、常にシリアライズされています。

QueryMapインタフェースには、よく使用される次のようなメソッドがあります。

- Set entrySet(Filterfilter)は、マップ内のエントリのうちフィルタ条件を満たす一連のエントリを返します。

- addIndex(ValueExtractorextractor,booleanfOrdered, Comparator comparator)は、索引を追加します。

- Set keySet(Filter filter)は、entrySetに似ていますが、値ではなくキーを返します。

フィルタリングはキャッシュ・エントリ・オーナー・レベルで発生することに注意してください。パーティション化されたトポロジでは、フィルタリングを実行するのはプライマリ・パーティションであるため、フィルタリングは並行して実行できます。QueryMapインタフェースでは、Filterクラスが使用されます。これらのクラスの詳細は、com.tangosol.util.filterパッケージのAPIを参照してください。

CoherenceのNamedCacheオブジェクトはすべて、com.tangosol.util.QueryMapインタフェースを実装します。これにより、NamedCacheオブジェクトでは、キャッシュ内の指定された条件を満たすキーやエントリの検索がサポートされます。この条件は、com.tangosol.util.Filterインタフェースを実装するオブジェクトとして表すことができます。

com.tangosol.util.filterパッケージには、標準的な問合せ式を実装する事前定義された複数のクラスが含まれています。このようなクラスの例には、GreaterFilter、GreaterEquals、LikeFilter、NotEqualsFilter、InFilterなどがあります。これらのフィルタを使用して、大半のSQL WHERE句式をオブジェクトベースで表現した式を構成できます。

注意:

CoherenceにはSQLFilterがありません。これは、キャッシュ内に配置されたオブジェクトがリレーショナル形式で、つまり行と列を使用してモデル化される可能性が低いためです(オブジェクトは通常、データベースで表現されます)。さらに、キャッシュ内に配置されたオブジェクトは、通常、大型のBLOBSなどのリレーショナル・モデルを使用して容易にモデル化できません。

Filterクラスは、標準的なJavaメソッド・リフレクションを使用してテスト条件を表現します。たとえば、次のフィルタは、キャッシュ内のオブジェクトでgetHomeAddress.getStateメソッドから返される値がMassachusetts (MA)に対する値であるという条件を表しています。

(new EqualsFilter("getHomeAddress.getState", "MA");

このフィルタを使用してテストしたオブジェクトにgetメソッドが指定されていない場合、テストは失敗します。

Filterクラスを使用したその他の例は、次のとおりです。

- 名前がSで始まる都市に住む人のセットを返します。

Set sPeople = cache.entrySet(new LikeFilter("getHomeAddress.getCity","S%");

- 年齢が42歳を超える人のセットを返します。

final int nAge = 42;// Find all contacts who are older than nAge
Set sSeniors = cache.entrySet(new GreaterFilter("getAge", nAge));

QueryMapインタフェースで定義されたentrySetメソッドとkeySetメソッド以外に、CoherenceではaddIndexメソッドを使用して索引を定義し、問合せのパフォーマンスを改善できます。よく知られている、厳密に適用された名前付き列のコレクション(スキーマ)に従って索引を定義する、リレーショナル・データベース・システムとは異なり、Coherenceにはスキーマがありません。スキーマがないため、従来のデータベースとは異なる方法で索引を定義します。

キャッシュに配置されている各オブジェクトに対する索引を付ける値を定義するために、Coherenceではvalue extractorの概念が導入されています。com.tangosol.util.ValueExtractorインタフェースはextractメソッドを定義します。オブジェクトのパラメータを指定すると、ValueExtractor実装はパラメータに基づいて値を返します。

ValueExtractor実装の簡単な例であるcom.tangosol.util.extractor.ReflectionExtractorインタフェースでは、リフレクションを使用して、オブジェクトに対するメソッド・コールの結果を返します。たとえば、次のとおりです。

new ReflectionExtractor("getCity")

値エクストラクタは、Coherence API全体で使用できます。ただし通常は、索引を定義するために使用されます。

特に便利なエクストラクタのタイプは、ChainedExtractorです。これは、エクストラクタの配列に基づく複合的なValueExtractor実装です。配列内のエクストラクタは、左から右に順次適用されます。前のエクストラクタの結果が次のエクストラクタのターゲット・オブジェクトになります。たとえば、次のとおりです。

new ChainedExtractor(new ReflectionExtractor("getHomeAddress"), new ReflectionExtractor("getState"))

この例では、HomeAddressオブジェクトとStateオブジェクトが複合Contactオブジェクトに属していることが前提となっています。ChainedExtractorは、まずリフレクションを使用して、キャッシュされた各ContactオブジェクトにgetHomeAddressメソッドをコールします。次に、リフレクションを使用して、返されたHomeAddressオブジェクトのセットにgetStateメソッドをコールします。

1. キャッシュ・データを問い合せるクラスの作成

2. 問合せサンプルの実行

3. 集計を実行するための問合せサンプルの編集

4. 問合せおよび集計のサンプルの実行

5.3.1 キャッシュ・データを問い合せるクラスの作成

問合せを実行するQueryExampleという新規Javaクラスを作成します。このクラスにmainメソッドが存在することを確認します。詳細は、「Javaクラスの作成」を参照してください。

entrySetメソッドを使用して、次のように従業員の連絡先情報を取得します。

- マサチューセッツに住むすべての従業員:

cache.entrySet(new EqualsFilter("getHomeAddress.getState", "MA"));

- マサチューセッツに住み、勤務先が別の場所であるすべての従業員:

cache.entrySet(new AndFilter(
new EqualsFilter("getHomeAddress.getState", "MA"),
new NotEqualsFilter("getWorkAddress.getState", "MA")));

- 名前がSで始まる都市に住むすべての従業員:

cache.entrySet(new LikeFilter("getHomeAddress.getCity", "S%"));

- 姓がSで始まり、マサチューセッツに住むすべての従業員。問合せにキーと値の両方を使用します。キャッシュ・エントリでは、キーとしてContactIdオブジェクトが使用されます。KeyExtractorを使用して、これらの値を取得できます。KeyExtractorは値ではなく主要なオブジェクトに対して問合せを実行する必要があることを示す、特別な値エクストラクタ:

cache.entrySet(new AndFilter(
new LikeFilter(new KeyExtractor("getLastName"), "S%",
(char) 0, false),
new EqualsFilter("getHomeAddress.getState", "MA")));

- 指定された年齢を超えるすべての従業員。ヒント:

final int nAge = 42;
setResults = cache.entrySet(new GreaterFilter("getAge", nAge));

索引を使用して、パフォーマンスを向上させます。ヒント: QueryMapインタフェースのJavadocでaddIndexメソッドに関する記述を検索します。

例5-7は、考えられるQueryExampleクラスの実装を示しています。

例5-7 QueryExampleクラスのサンプル

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.extractor.KeyExtractor;
import com.tangosol.util.extractor.ReflectionExtractor;

import com.tangosol.util.filter.AlwaysFilter;
import com.tangosol.util.filter.AndFilter;
import com.tangosol.util.filter.EqualsFilter;
import com.tangosol.util.filter.GreaterFilter;
import com.tangosol.util.filter.LikeFilter;
import com.tangosol.util.filter.NotEqualsFilter;

import java.util.Iterator;
import java.util.Set;

/**
* QueryExample runs sample queries for contacts.
*
*/
public class QueryExample{

// ----- QueryExample methods ---------------------------------------

public static void main(String[] args) {
NamedCache cache = CacheFactory.getCache("ContactsCache");
query(cache);
}
/**
* Perform the example queries
*
*/
public static void query(NamedCache cache)
{
// Add indexes to make queries more efficient
ReflectionExtractor reflectAddrHome =
new ReflectionExtractor("getHomeAddress");

// Add an index for the age
cache.addIndex(new ReflectionExtractor("getAge"), true, null);

// Add index for state within home address
cache.addIndex(new ChainedExtractor(reflectAddrHome,
new ReflectionExtractor("getState")), true, null);

// Add index for state within work address
cache.addIndex(new ChainedExtractor(
new ReflectionExtractor("getWorkAddress"),
new ReflectionExtractor("getState")), true, null);

// Add index for city within home address
cache.addIndex(new ChainedExtractor(reflectAddrHome,
new ReflectionExtractor("getCity")), true, null);

// Find all contacts who live in Massachusetts
Set setResults = cache.entrySet(new EqualsFilter(
"getHomeAddress.getState", "MA"));
printResults("MA Residents", setResults);

// Find all contacts who live in Massachusetts and work elsewhere
setResults = cache.entrySet(new AndFilter(
new EqualsFilter("getHomeAddress.getState", "MA"),
new NotEqualsFilter("getWorkAddress.getState", "MA")));
printResults("MA Residents, Work Elsewhere", setResults);

// Find all contacts whose city name begins with 'S'
setResults = cache.entrySet(new LikeFilter("getHomeAddress.getCity",
"S%"));
printResults("City Begins with S", setResults);

final int nAge = 42;
// Find all contacts who are older than nAge
setResults = cache.entrySet(new GreaterFilter("getAge", nAge));
printResults("Age > " + nAge, setResults);

// Find all contacts with last name beginning with 'S' that live
// in Massachusetts. Uses both key and value in the query.
setResults = cache.entrySet(new AndFilter(
new LikeFilter(new KeyExtractor("getLastName"), "S%",
(char) 0, false),
new EqualsFilter("getHomeAddress.getState", "MA")));
printResults("Last Name Begins with S and State Is MA", setResults);

}

/**
* Print results of the query
*
* @param sTitle      the title that describes the results
* @param setResults  a set of query results
*/
private static void printResults(String sTitle, Set setResults)
{
System.out.println(sTitle);
for (Iterator iter = setResults.iterator(); iter.hasNext(); )
{
System.out.println(iter.next());
}
}
}

5.3.2 問合せサンプルの実行

問合せサンプルを実行するには:

1. すべての稼動しているキャッシュ・サーバーを停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. QueryExampleクラスに対する実行構成を作成します。

1. 「Project Navigator」でQueryExampleを右クリックし、「Run As」→「Run Configurations」を選択します。「Oracle Coherence」を選択して、「New launch configuration」アイコンをクリックします。

2. 「Name」フィールドにQueryExampleと入力します。

3. 「Main」タブの「Project」フィールドにLoadingと入力します。「Main class」フィールドにcom.oracle.handson.QueryExampleと入力します。

4. 「Coherence」タブの「Generalタブで、「Cache configuration descriptor」フィールドのc:\home\oracle\workspace\Contacts\appClientModule\contacts-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、「tangosol.pof.config」フィールドまで下方へスクロールします。POF構成ファイルcontacts-pof-config.xmlへの絶対パスを入力します。「Apply」をクリックします。

5. 「Classpath」タブの内容を確認します。Contactsプロジェクトが、「User Entries」のLoadingプロジェクトの下に表示されます。

3. ContactsCacheServerを再起動します。

4. DataGeneratorクラス、LoaderExampleクラスおよびQueryExampleクラスを実行します。

キャッシュ内のすべての連絡先情報を印刷すると、QueryExampleファイルで問合せの結果が表示されます。結果は、例5-8のようになります。

例5-8 QueryExampleプログラムの結果

TcpRing{Connections=[1]}
IpMonitor{AddressListSize=0}

2012-08-16 16:15:01.778/2.094 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=5): Service Management joined the cluster with senior service member 1
2012-08-16 16:15:01.825/2.141 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=5): Loaded Reporter configuration from "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-16 16:15:02.137/2.453 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=5): Loaded POF configuration from "file:/C:/home/oracle/workspace/Contacts/build/classes/contacts-pof-config.xml"
2012-08-16 16:15:02.169/2.485 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=5): Loaded included POF configuration from "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2012-08-16 16:15:02.231/2.547 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=5): Service PartitionedPofCache joined the cluster with senior service member 1
MA Residents
ConverterEntry{Key="John Ueccc", Value="John Ueccc
Addresses
Home: 285 Beacon St.

Oxtqwisgti, MA 41063
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, VA 28107
US
Telephone Numbers
work: +11 48 835 1876678
home: +11 78 482 1247744
Birth Date: 1972-12-30"}
...
MA Residents, Work Elsewhere
ConverterEntry{Key="John Ueccc", Value="John Ueccc
Addresses
Home: 285 Beacon St.

Oxtqwisgti, MA 41063
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, VA 28107
US
Telephone Numbers
work: +11 48 835 1876678
home: +11 78 482 1247744
Birth Date: 1972-12-30"}
...
City Begins with S
ConverterEntry{Key="John Frepojf", Value="John Frepojf
Addresses
Home: 851 Beacon St.

Swnsfng, PR 00734
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, AR 97794
US
Telephone Numbers
work: +11 10 474 781020
home: +11 29 575 9284939
Birth Date: 1985-12-27"}
...
Age > 42
ConverterEntry{Key="John Qghbguyn", Value="John Qghbguyn
Addresses
Home: 49 Beacon St.

Dvftzpq, PR 34220
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, MD 28247
US
Telephone Numbers
work: +11 39 563 7113013
home: +11 58 910 4667915
Birth Date: 1961-01-02"}
...
Last Name Begins with S and State Is MA
ConverterEntry{Key="John Smnfg", Value="John Smnfg
Addresses
Home: 178 Beacon St.

Hbpeak, MA 64081
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, OK 92191
US
Telephone Numbers
work: +11 56 322 7307404
home: +11 33 928 3075361
Birth Date: 1978-12-29"}
...

5.3.3 集計を実行するための問合せサンプルの編集

コードをQueryExample.javaファイルに追加して、キャッシュ・データに対して集計を実行します。エントリ・アグリゲータ(com.tangosol.util.InvocableMap.EntryAggregator)を使用すると、すべてのオブジェクトまたは特定のオブジェクトのセットに対して操作を実行し、集計を返すことができます。EntryAggregatorインタフェースは、クラスタ内のデータに対して並行してサービスを実行するエージェントです。集計は並行して実行され、クラスタ・メンバーの追加によるメリットを得ることができます。

集計には、キーのコレクションに対する集計と、フィルタの指定による集計の2つの方法があります。例5-9は、これらのタスクを実行するEntryAggregatorメソッドを示しています。

例5-9 キーに対する集計メソッドとフィルタ指定による集計メソッド

Object aggregate(Collection keys, InvocableMap.entryAggregator agg)

Object aggregate(Filter filter, InvocableMap.entryAggregator agg)

フィルタリングに対してデータを返すために集計を追加するには:

1. 集計を使用し、QueryExampleクラスにコードを記述して次の項目を計算します。

- 指定した年齢を超える従業員の数。GreaterFilterクラスおよびCountクラスを使用します。

cache.aggregate(new GreaterFilter("getAge", nAge), new Count())

- 従業員セット内の最低年齢。AlwaysFilterクラスおよびLongMinクラスを使用使用します。

cache.aggregate(AlwaysFilter.INSTANCE, new LongMin("getAge"))

- 従業員セット内の最高年齢。AlwaysFilterクラスおよびLongMaxクラスを使用します。

cache.aggregate(AlwaysFilter.INSTANCE, new LongMax("getAge"))

- 従業員の平均年齢。AlwaysFilterクラスおよびDoubleAverageクラスを使用します。

cache.aggregate(AlwaysFilter.INSTANCE, new DoubleAverage("getAge")

2. Count、DoubleAverage、LongMaxおよびLongMinアグリゲータ・クラスをインポートします。

import com.tangosol.util.aggregator.Count;
import com.tangosol.util.aggregator.DoubleAverage;
import com.tangosol.util.aggregator.LongMax;
import com.tangosol.util.aggregator.LongMin;

QueryExample.javaファイルは例5-10のようになります。

例5-10 集計を使用したQueryExample

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.tangosol.util.aggregator.Count;
import com.tangosol.util.aggregator.DoubleAverage;
import com.tangosol.util.aggregator.LongMax;
import com.tangosol.util.aggregator.LongMin;

import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.extractor.KeyExtractor;
import com.tangosol.util.extractor.ReflectionExtractor;

import com.tangosol.util.filter.AlwaysFilter;
import com.tangosol.util.filter.AndFilter;
import com.tangosol.util.filter.EqualsFilter;
import com.tangosol.util.filter.GreaterFilter;
import com.tangosol.util.filter.LikeFilter;
import com.tangosol.util.filter.NotEqualsFilter;

import java.util.Iterator;
import java.util.Set;

/**
* QueryExample runs sample queries for contacts.
*/
public class QueryExample{

// ----- QueryExample methods ---------------------------------------

public static void main(String[] args) {
NamedCache cache = CacheFactory.getCache("ContactsCache");
query(cache);
}
/**
* Perform the example queries
*
*/
public static void query(NamedCache cache)
{
// Add indexes to make queries more efficient
ReflectionExtractor reflectAddrHome =
new ReflectionExtractor("getHomeAddress");

cache.addIndex(new ReflectionExtractor("getAge"), true, null);
cache.addIndex(new ChainedExtractor(reflectAddrHome,
new ReflectionExtractor("getState")), true, null);
cache.addIndex(new ChainedExtractor(
new ReflectionExtractor("getWorkAddress"),
new ReflectionExtractor("getState")), true, null);
cache.addIndex(new ChainedExtractor(reflectAddrHome,
new ReflectionExtractor("getCity")), true, null);

// Find all contacts who live in Massachusetts
Set setResults = cache.entrySet(new EqualsFilter(
"getHomeAddress.getState", "MA"));
printResults("MA Residents", setResults);

// Find all contacts who live in Massachusetts and work elsewhere
setResults = cache.entrySet(new AndFilter(
new EqualsFilter("getHomeAddress.getState", "MA"),
new NotEqualsFilter("getWorkAddress.getState", "MA")));
printResults("MA Residents, Work Elsewhere", setResults);

// Find all contacts whose city name begins with 'S'
setResults = cache.entrySet(new LikeFilter("getHomeAddress.getCity",
"S%"));
printResults("City Begins with S", setResults);

final int nAge = 42;
// Find all contacts who are older than nAge
setResults = cache.entrySet(new GreaterFilter("getAge", nAge));
printResults("Age > " + nAge, setResults);

// Find all contacts with last name beginning with 'S' that live
// in Massachusetts. Uses both key and value in the query.
setResults = cache.entrySet(new AndFilter(
new LikeFilter(new KeyExtractor("getLastName"), "S%",
(char) 0, false),
new EqualsFilter("getHomeAddress.getState", "MA")));
printResults("Last Name Begins with S and State Is MA", setResults);

// Count contacts who are older than nAge
System.out.println("count > " + nAge + ": "+ cache.aggregate(
new GreaterFilter("getAge", nAge), new Count()));

// Find minimum age
System.out.println("min age: " + cache.aggregate(AlwaysFilter.INSTANCE,
new LongMin("getAge")));

// Calculate average age
System.out.println("avg age: " + cache.aggregate(AlwaysFilter.INSTANCE,
new DoubleAverage("getAge")));

// Find maximum age
System.out.println("max age: " + cache.aggregate(AlwaysFilter.INSTANCE,
new LongMax("getAge")));
}

/**
* Print results of the query
*
*/
private static void printResults(String sTitle, Set setResults)
{
System.out.println(sTitle);
for (Iterator iter = setResults.iterator(); iter.hasNext(); )
{
System.out.println(iter.next());
}
}
}

5.3.4 問合せと集計のサンプルの実行

キャッシュを問い合せて結果を集計するには:

1. Contactsキャッシュ・サーバー、ContactsCacheServerを停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. ContactsCacheServerを再起動します。

3. DataGeneratorアプリケーション、LoaderExampleアプリケーションおよびQueryExampleアプリケーションを実行します。
Eclipseコンソールに、例5-11のように出力されます。

例5-11 アグリゲータからの出力

...
Last Name Begins with S and State Is MA
ConverterEntry{Key="John Sqmyas", Value="John Sqmyas
Addresses
Home: 594 Beacon St.

Jxaxt, MA 10081
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, NJ 95236
US
Telephone Numbers
work: +11 70 837 4723938
home: +11 2 227 6816592
Birth Date: 1977-12-29"}
count > 42: 482
min age: 22
avg age: 41.627
max age: 61

6 キャッシュのコールおよび集計の簡略化

この演習では、QueryHelperクラスでCoherenceのcreateFilterおよびcreateExtractorファクトリ・メソッドを使用することによって、集計およびフィルタを使用するJava式を簡素化する方法について説明します。

第5章「キャッシュへのデータのロード」では、AlwaysFilter、LikeFilterおよびEqualsFilterなどの様々なフィルタを使用したファイルQueryExample.javaを作成し、キャッシュから情報を取得して集計しました。また、このファイルでは、様々な特化されたValueExtractors: ChainedExtractors、KeyExtractorsおよびReflectionExtractorsを使用して、データに索引を作成しました。その結果、冗長なJava文がいくつか作成されました。そのような文を簡略化するには、QueryHelper APIを使用します。

この章には次の項が含まれます:

- 概要

- 問合せサンプルの簡略化

- 問合せサンプルの再実行

6.1 概要

フィルタ文やエクストラクタ文を簡略化するほか、Coherenceキャッシュとのやり取りを簡略化するために、CoherenceではQueryHelper APIが用意されています。QueryHelper (com.tangosol.util.QueryHelper)はユーティリティ・クラスであり、これによってcreateFilterおよびcreateExtractorファクトリ・メソッドのセットが提供され、FilterとValueExtractorのインスタンスをビルドできるようになります。このクラス内のメソッドは、Stringデータ・タイプを受け入れるので、SQLのWHERE句について理解しているユーザーにとっては使い慣れた形式で豊富なフィルタの作成を指定することができます。

たとえば、次の文はcreateFilter(String s)を使用して、マサチューセッツに住み別の州で働く従業員のフィルタを構築します。

..
QueryHelper.createFilter("homeAddress.state = 'MA' and workAddress.state !='MA'")
...

この文は、次のCoherence APIを使用した同等のフィルタおよびエクストラク文よりシンプルで簡単です。

new AndFilter(new EqualsFilter("getHomeAddress.getState", "MA"),
new NotEqualsFilter("getWorkAddress.getState", "MA"))

詳細は、QueryHelper APIのJavadocを参照してください。Coherenceの問合せ言語におけるWHERE句の構文については、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のCoherence問合せ言語の使用に関する項を参照してください。

6.2 問合せサンプルの簡略化

この項では、前章で作成したQueryExample.javaファイルの索引付け、キャッシュ・コールおよび集計を簡略化する方法について説明します。

1. QueryHelper APIを静的クラスとしてQueryExample.javaファイルにインポートします。

import static com.tangosol.util.QueryHelper.*;

2. ChainedExtractorクラス、KeyExtractorクラスおよびReflectionExtractorクラスのインポートをコメント・アウトします。

3. AlwaysFilterクラス、AndFilterクラス、EqualsFilterクラス、GreaterFilterクラス、LikeFilterクラスおよびNotEqualsFilterクラスのインポートをコメント・アウトします。

4. cache.addIndex文で、ReflectionExtractorのインスタンスをQueryHelper APIのcreateExtractorに置き換えます。
表6-1に、ReflectionExtractorのインスタンスおよびそれと同等なcreateExtractorのリストを示します。

表6-1 ReflectionExtractors文およびそれと同等なcreateExtractor文

置き換えるReflectionExtractor文

置き換えられる同等のcreateExtractor文

cache.addIndex(new ReflectionExtractor("getAge"), true, null);

cache.addIndex(createExtractor("age"), true, null);

cache.addIndex(new ChainedExtractor(reflectAddrHome, new ReflectionExtractor("getState")), true, null);

cache.addIndex(createExtractor("homeAddress.state"), false, null);

cache.addIndex(new ChainedExtractor(new ReflectionExtractor("getWorkAddress"), new ReflectionExtractor("getState")), true, null);

cache.addIndex(createExtractor("workAddress.state"),false, null);

cache.addIndex(new ChainedExtractor(reflectAddrHome, new ReflectionExtractor("getCity")), true, null);

cache.addIndex(createExtractor("homeAddress.city"), true, null);

5. setResults文の*Filterメソッドへのコールを適切なCoherence問合せ言語を使用したcreateFilterへのコールに置き換えます。
表6-2に、*Filterのインスタンスおよびそれと同等なcreateFilterのリストを示します。

表6-2 問合せでの*Filter文およびそれと同等なcreateFilter文

置換える*Filter文

置き換えられる同等のcreateFilter文

Set setResults = cache.entrySet(new EqualsFilter("getHomeAddress.getState", "MA"));

Set setResults = cache.entrySet(createFilter("homeAddress.state = 'MA'"));

Set setResults = cache.entrySet(new AndFilter(new EqualsFilter("getHomeAddress.getState", "MA"), new NotEqualsFilter("getWorkAddress.getState", "MA")));

setResults = cache.entrySet( createFilter("homeAddress.state is 'MA' and workAddress is not 'MA'"));

Set setResults = cache.entrySet(new LikeFilter("getHomeAddress.getCity", "S%"));

Set setResults = cache.entrySet(createFilter("homeAddress.city like 'S%'"));

Set setResults = cache.entrySet(new GreaterFilter("getAge", nAge));

// Initialize nAge and aEnv

final int nAge = 42;

Object[] aEnv = new Object[] {new Integer(nAge)};

...

Set setResults = cache.entrySet(createFilter("age > ?1",aEnv));

Set setResults = cache.entrySet(new AndFilter(new LikeFilter(new KeyExtractor("getLastName"), "S%", (char) 0, false), new EqualsFilter("getHomeAddress.getState", "MA")));

Set setResults = cache.entrySet(createFilter("key(lastName) like 'S%' and homeAddress.state = 'MA'"));

6. aggregate文の*Filterメソッドへのコールを適切なCoherence問合せ言語を使用したcreateFilterへのコールに置き換えます。
表6-3に、*Filterのインスタンスおよびそれと同等なcreateFilterのリストを示します。

表6-3 集計でのFilter文およびそれと同等なcreateFilter文

置換える*Filter文

置き換えられる同等のcreateFilter文

System.out.println("count > " + nAge + ": "+ cache.aggregate(new GreaterFilter("getAge", nAge), new Count()));

System.out.println("count > " + nAge + ": " + cache.aggregate(createFilter("age > ?1", aEnv), new Count()));

System.out.println("min age: " + cache.aggregate(AlwaysFilter.INSTANCE, new LongMin("getAge")));

Filter always = createFilter("true");

System.out.println("min age: " + cache.aggregate(always, new LongMin("getAge")));

System.out.println("avg age: " + cache.aggregate(AlwaysFilter.INSTANCE, new DoubleAverage("getAge")));

System.out.println("avg age: " + cache.aggregate(always, new DoubleAverage("getAge")));

System.out.println("max age: " + cache.aggregate(AlwaysFilter.INSTANCE, new LongMax("getAge")));

System.out.println("max age: " + cache.aggregate(always, new LongMax("getAge")));

コードの置換えが終了すると、QueryExample.javaは例6-1のようになります。

例6-1 編集済QueryExampleファイル

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.tangosol.util.Filter;
import static com.tangosol.util.QueryHelper.*;

import com.tangosol.util.aggregator.Count;
// import com.tangosol.util.extractor.ChainedExtractor;
// import com.tangosol.util.extractor.KeyExtractor;
// import com.tangosol.util.extractor.ReflectionExtractor;

// import com.tangosol.util.aggregator.Count;
import com.tangosol.util.aggregator.DoubleAverage;
import com.tangosol.util.aggregator.LongMax;
import com.tangosol.util.aggregator.LongMin;

// import com.tangosol.util.filter.AlwaysFilter;
// import com.tangosol.util.filter.AndFilter;
// import com.tangosol.util.filter.EqualsFilter;
// import com.tangosol.util.filter.GreaterFilter;
// import com.tangosol.util.filter.LikeFilter;
// import com.tangosol.util.filter.NotEqualsFilter;

import java.util.Iterator;
import java.util.Set;

/**
* QueryExample runs sample queries for contacts.
*
*/
public class QueryExample{

// ----- QueryExample methods ---------------------------------------

public static void main(String[] args) {
NamedCache cache = CacheFactory.getCache("ContactsCache");
query(cache);
}
/**
* Perform the example queries
*
*/
public static void query(NamedCache cache)
{
// Add indexes to make queries more efficient
// ReflectionExtractor reflectAddrHome =
//     new ReflectionExtractor("getHomeAddress");

// Add an index for the age
// cache.addIndex(new ReflectionExtractor("getAge"), true, null);
cache.addIndex(createExtractor("age"), true, null);

// Add index for state within home address
// cache.addIndex(new ChainedExtractor(reflectAddrHome,
//        new ReflectionExtractor("getState")), true, null);
cache.addIndex(createExtractor("homeAddress.state"), false, null);

// Add index for state within work address
// cache.addIndex(new ChainedExtractor(
//        new ReflectionExtractor("getWorkAddress"),
//        new ReflectionExtractor("getState")), true, null);
cache.addIndex(createExtractor("workAddress.state"),false, null);

// Add index for city within home address
// cache.addIndex(new ChainedExtractor(reflectAddrHome,
//        new ReflectionExtractor("getCity")), true, null);
cache.addIndex(createExtractor("homeAddress.city"), true,  null);

// Find all contacts who live in Massachusetts
// Set setResults = cache.entrySet(new EqualsFilter(
//         "getHomeAddress.getState", "MA"));
Set setResults = cache.entrySet(createFilter("homeAddress.state = 'MA'"));
printResults("MA Residents", setResults);

// Find all contacts who live in Massachusetts and work elsewhere
// setResults = cache.entrySet(new AndFilter(
//        new EqualsFilter("getHomeAddress.getState", "MA"),
//        new NotEqualsFilter("getWorkAddress.getState", "MA")));
setResults = cache.entrySet(createFilter("homeAddress.state is 'MA' and workAddress is not 'MA'"));
printResults("MA Residents, Work Elsewhere", setResults);

// Find all contacts whose city name begins with 'S'
// setResults = cache.entrySet(new LikeFilter("getHomeAddress.getCity",
//         "S%"));
setResults = cache.entrySet(createFilter("homeAddress.city like 'S%'"));
printResults("City Begins with S", setResults);

final int nAge = 42;
Object[] aEnv  =  new Object[] {new Integer(nAge)};
// Find all contacts who are older than nAge
// setResults = cache.entrySet(new GreaterFilter("getAge", nAge));
setResults = cache.entrySet(createFilter("age > ?1",aEnv));
printResults("Age > " + nAge, setResults);

// Find all contacts with last name beginning with 'S' that live
// in Massachusetts. Uses both key and value in the query.
// setResults = cache.entrySet(new AndFilter(
//     new LikeFilter(new KeyExtractor("getLastName"), "S%",
//   (char) 0, false),
//         new EqualsFilter("getHomeAddress.getState", "MA")));
setResults = cache.entrySet(createFilter("key(lastName) like 'S%' and homeAddress.state = 'MA'"));
setResults = cache.entrySet(createFilter("key().lastName like 'S%' and homeAddress.state = 'MA'"));
printResults("Last Name Begins with S and State Is MA", setResults);

// Count contacts who are older than nAge
// System.out.println("count > " + nAge + ": "+
//  cache.aggregate(new GreaterFilter("getAge", nAge), new Count()));
System.out.println("count > " + nAge + ": " + cache.aggregate(
createFilter("age > ?1", aEnv), new Count()));

// Find minimum age
// System.out.println("min age: " + cache.aggregate(AlwaysFilter.INSTANCE, new LongMin("getAge")));
Filter always = createFilter("true");
System.out.println("min age: " + cache.aggregate(always, new LongMin("getAge")));

// Calculate average age
// System.out.println("avg age: " + cache.aggregate(AlwaysFilter.INSTANCE, new DoubleAverage("getAge")));
System.out.println("avg age: " + cache.aggregate(always, new DoubleAverage("getAge")));

// Find maximum age
// System.out.println("max age: " +
// cache.aggregate(AlwaysFilter.INSTANCE, new LongMax("getAge")));
System.out.println("max age: " + cache.aggregate(always, new LongMax("getAge")));

System.out.println("------QueryLanguageExample completed------");

}

/**
* Print results of the query
*
* @param sTitle      the title that describes the results
* @param setResults  a set of query results
*/
private static void printResults(String sTitle, Set setResults)
{
System.out.println(sTitle);
for (Iterator iter = setResults.iterator(); iter.hasNext(); )
{
System.out.println(iter.next());
}
}
}

6.3 問合せサンプルの再実行

問合せサンプルを再実行するには:

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. ContactsCacheServerを再起動します。

3. DataGeneratorファイル、LoaderExampleファイルおよびQueryExampleファイルを実行します。

4. キャッシュ内のすべての連絡先情報を出力すると、問合せの結果が表示されます。結果は次の例のようになります。

注意:

DataGeneratorプログラムでは、名前、都市および生年月日がランダムに生成されます。ユーザーの出力は異なる可能性があります。

例6-2は、MA Residentsフィルタの出力を示しています。

例6-2 MA Residentsフィルタの出力

...
MA Residents
ConverterEntry{Key="John Hwdrrls", Value="John Hwdrrls
Addresses
Home: 369 Beacon St.

Fetggv, MA 24372
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, NE 84499
US
Telephone Numbers
work: +11 88 331 2307913
home: +11 64 86 2489621
Birth Date: 1976-12-29"}
...

例6-3は、MA Residents, Work Elsewhereフィルタの出力を示しています。

例6-3 MA Residents, Work Elsewhereフィルタの出力

...
MA Residents, Work Elsewhere
ConverterEntry{Key="John Hwdrrls", Value="John Hwdrrls
Addresses
Home: 369 Beacon St.

Fetggv, MA 24372
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, NE 84499
US
Telephone Numbers
work: +11 88 331 2307913
home: +11 64 86 2489621
Birth Date: 1976-12-29"}
...

例6-4は、City Begins with Sフィルタの出力を示しています。

例6-4 City Begins with Sフィルタの出力

...
City Begins with S
ConverterEntry{Key="John Pzek", Value="John Pzek
Addresses
Home: 309 Beacon St.

Saqrgy, OH 81353
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, CT 78117
US
Telephone Numbers
work: +11 28 790 2035988
home: +11 61 470 7634708
Birth Date: 1971-12-31"}
...

例6-5は、42歳を過ぎた従業員のフィルタの出力を示しています。

例6-5 Age Greater than 42フィルタの出力

...
Age > 42
ConverterEntry{Key="John Gddurqqziy", Value="John Gddurqqziy
Addresses
Home: 613 Beacon St.

Cxyskdo, DE 28968
US
Work: Yoyodyne Propulsion Systems
330 Lectroid Rd.
Grover's Mill, SD 07959
US
Telephone Numbers
work: +11 31 768 5136041
home: +11 87 22 3851589
Birth Date: 1958-01-03"}
...

例6-6は、Last Name Begins with SフィルタとState is MAフィルタの出力およびアグリゲータの出力を示しています。

例6-6 StateアグリゲータおよびAgeアグリゲータの出力

Last Name Begins with S and State Is MA
ConverterEntry{Key="John Syaqlojl", Value="John SyaqlojlAddressesHome: 810 Beacon St.Rgtaljwph, MA 07471USWork: 200 Newbury St.Yoyodyne, Ltd.Boston, MA 02116USTelephone Numberswork: +11 37 18 1767648home: +11 98 155 1073866Birth Date: 1974-12-30"}
...
count > 42: 446
min age: 22
avg age: 41.126
max age: 61

7 変更のリスニングとデータの変更

この演習では、リスナーを設定してCoherenceキャッシュ内のデータ変更を監視します。ここでは、Coherence APIのObservableMap、MapEvent、EventListener、EntryProcessorおよびAbstractMapListenerの使用について取り上げます。また、エントリ・プロセッサを使用してCoherenceキャッシュ内のエントリを変更したり処理したりする方法を学習します。

この章には次の項が含まれます:

- 概要

- キャッシュ・リスナーの作成

- キャッシュ内の変更への対応

7.1 概要

com.tangosol.util.ObservableMapインタフェースを使用すると、キャッシュ・エントリに対する変更を監視して、変更に対応できます。このインタフェースはjava.util.EventListenerを拡張し、標準のJavaBeansイベント・モデルを使用します。すべてのタイプのNamedCacheインスタンスがこのインタフェースを実装します。イベントをリスニングするには、MapListener(com.tangosol.util.MapListener)インスタンスをキャッシュに登録します。MapListenerインスタンスがクライアントでコールされます。つまり、リスナー・コードがクライアント・プロセスで実行されます。

イベントをリスニングするには、次のような方法があります。

- すべてのイベントのリスニング

- フィルタの条件を満たす、すべてのイベントのリスニング

- 特定のオブジェクト・キーのイベントのリスニング

これらのリスナー・タスクは、例7-1に示したaddMapListenerメソッドを使用してNamedCacheで実行できます。

例7-1 NamedCacheのリスナー・メソッド

void addMapListener(MapListener listener)

void addMapListener(MapListener listener, Filter filter, boolean fLite)

void addMapListener(MapListener listener, Object oKey, boolean fLite)

com.tangosol.util.MapEventクラスは、オブジェクト・キーおよび以前の値と新しい値を取得します。Liteイベントを指定することができますが、このイベントには新しい値や以前の値が存在しない可能性があります。例7-2では、これらのメソッドをNamedCacheに登録するパターンを示しています。これは、無名クラスとして実行されています。MapEventクラスのgetOldValueメソッドやgetNewValueメソッドを使用して、イベントを起動する対象となるエントリを取得できます。

例7-2 イベント登録のコード・パターン

namedCache.addMapListener(new MapListener() {
public void entryDeleted(MapEvent mapEvent)
{
// TODO... handle deletion event
}
public void entryInserted(MapEvent mapEvent)
{
// TODO... handle inserted event
}
public void entryUpdated(MapEvent mapEvent)
{
// TODO... handle updated event } }
)

7.2 キャッシュ・リスナーの作成

この項では、NamedCacheでリスニングして、検出したあらゆる変更に対応する、Javaクラスの作成方法を説明します。

1. キャッシュ内の変更をリスニングするクラスの作成

2. キャッシュ・リスナー・サンプルの実行

7.2.1 キャッシュ内の変更をリスニングするクラスの作成

Loadingプロジェクトでは、新規Contactオブジェクトのエントリをリスニングするクラスを作成します。このクラスをObserverExampleと名付け、そのクラスにmainメソッドが存在することを確認します。詳細は、「Javaクラスの作成」を参照してください。

このクラス内に、新しいContactがキャッシュを更新されるたびにメッセージを表示するリスナーを追加します。たとえば、次のコードを使用すると、コンソールから読み取るまでJavaプロセスを実行させたままにできます。そうしないと、プログラムはただちに終了します。

BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); String text = console.readLine();

このクラス内に、内部クラスを作成してAbstractMapListnerを拡張します。メソッドを実装して、キャッシュの値を挿入、更新および削除します。この場合、大半の処理はMapEventに含まれる新旧の値に基づいて、entryUpdatedメソッドで実行されます。

例7-3は、リスナー・クラスの実装例を示しています。

例7-3 リスナー・クラスのサンプル

package com.oracle.handson;

import com.tangosol.net.NamedCache;

import com.tangosol.util.AbstractMapListener;
import com.tangosol.util.MapEvent;

import com.oracle.handson.Contact;

import com.tangosol.net.CacheFactory;

import java.io.IOException;

/**
* ObserverExample observes changes to contacts.
*/
public class ObserverExample
{

public ObserverExample()
{
}
// ----- ObserverExample methods -------------------------------------

public static void main(String[] args) {
NamedCache cache = CacheFactory.getCache("ContactsCache");
new ObserverExample().observe(cache);
try {
System.in.read();
} catch (IOException e) {
}
}
/**
* Observe changes to the contacts.
*
* @param cache  target cache
*/
public void observe(NamedCache cache)
{
cache.addMapListener(new ContactChangeListener());
}

// ----- inner class: ContactChangeListener -------------------------

public class ContactChangeListener
extends AbstractMapListener
{
// ----- MapListener interface ------------------------------------------

public void entryInserted(MapEvent event)
{
System.out.println(event);
}

public void entryUpdated(MapEvent event)
{
Contact contactOld = (Contact)event.getOldValue();
Contact contactNew = (Contact)event.getNewValue();
StringBuffer sb  = new StringBuffer();

if (!contactOld.getHomeAddress().equals(
contactNew.getHomeAddress()))
{
sb.append("Home address ");
}
if (!contactOld.getWorkAddress().equals(
contactNew.getWorkAddress()))
{
sb.append("Work address ");
}
if (!contactOld.getTelephoneNumbers().equals(
contactNew.getTelephoneNumbers()))
{
sb.append("Telephone ");
}
if (contactOld.getAge() != contactNew.getAge())
{
sb.append("Birthdate ");
}
sb.append("was updated for ").append(event.getKey());
System.out.println(sb);
}

public void entryDeleted(MapEvent event)
{
System.out.println(event.getKey());
}
}
}

7.2.2 キャッシュ・リスナー・サンプルの実行

キャッシュ・リスナー・サンプルを実行するには:

1. ObserverExampleの実行構成を作成します。「Project Explorer」のObserverExampleを右クリックし、「Run As」を選択します。「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」を選択して「New Configuration」アイコンをクリックします。

1. 「Name」フィールドにObserverExampleと入力します。

2. 「Main」タブの「Project」フィールドにLoadingと入力します。「Main class」フィールドにcom.oracle.handson.ObserverExampleと入力します。

3. 「Coherence」タブの「Generalタブで、「Cache configuration descriptor」フィールドのc:\home\oracle\workspace\Contacts\appClientModule\contacts-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、「tangosol.pof.config」フィールドまで下方へスクロールします。POF構成ファイルcontacts-pof-config.xmlへの絶対パスを入力します。「Apply」をクリックします。

4. 「Common」タブで、「Shared file」を選択してLoadingディレクトリを参照します。

2. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

3. ContactsCacheServerを起動します。

4. EclipseからLoaderExampleプログラムを実行してキャッシュをロードします。ObserverExampleを実行していれば、例7-4に示すようにプログラムは入力を待機しています。
「キャッシュ内の変更への対応」では、キャッシュのエントリを変更して変更済の記録を返すプログラムを作成します。

例7-4 イベントを待機するリスナー・プログラム

...
MasterMemberSet(
ThisMember=Member(Id=3, Timestamp=2012-08-17 13:51:15.468, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3964, Role=OracleHandsonObserverExample)
OldestMember=Member(Id=1, Timestamp=2012-08-17 13:50:44.093, Address=10.159.220.86:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3344, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2012-08-17 13:50:44.093, Address=10.159.220.86:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3344, Role=CoherenceServer)
Member(Id=3, Timestamp=2012-08-17 13:51:15.468, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3964, Role=OracleHandsonObserverExample)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-17 13:50:44.093|JOINED,
3|12.1.2|2012-08-17 13:51:15.468|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2012-08-17 13:51:15.890/2.031 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2012-08-17 13:51:15.921/2.062 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=3): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-17 13:51:16.046/2.187 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=3): Loaded POF configuration from "file:/C:/home/oracle/workspace/Contacts/build/classes/contacts-pof-config.xml"
2012-08-17 13:51:16.109/2.250 Oracle Coherence GE 12.1.2.0 <Info> (thread=DistributedCache:PartitionedPofCache, member=3): Loaded included POF configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2012-08-17 13:51:16.187/2.328 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=3): Service PartitionedPofCache joined the cluster with senior service member 1

7.3 キャッシュ内の変更への対応

この項では、キャッシュ内のエントリを変更して変更済の記録を返すJavaクラスを作成します。

これまで、キャッシュ内のエントリにおけるアクションを実行するために、put操作とget操作を使用しました。しかし、データへの同時アクセが必要な場合に確実に動作の一貫性が保たれる、より優れたデータ操作方法があります。エントリ・プロセッサ(com.tangosol.util.InvocableMap.EntryProcessor)はエントリに対する処理を実行するエージェントです。エントリは、データが保存されている場所で直接処理されます。実行する処理によりデータが変更されることがあり、データが作成、更新および削除されたりする場合も、計算のみが実行されたりする場合もあります。複数のノードを持つパーティション化されたキャッシュ内で並行して処理が実行できるため、スケーラブルになります。また、処理のためにデータがクライアントに取得されないため、キャッシュ内の処理でI/Oの消費を節約できます。

同じキーで機能するエントリ・プロセッサは、論理的にはキューに入れられます。これにより、ロックされない(高パフォーマンス)処理が可能になります。com.tangosol.util.InvocableMapインタフェース(NamedCacheの実装による)には、データ操作に対して次のメソッドがあります。

• Object invoke(Object oKey, InvocableMap.EntryProcessor processor)。個々のオブジェクトに対して渡されたEntryProcessorを起動し、その起動の結果を返します。

• Map invokeAll(Collection keys, InvocableMap.EntryProcessor processor)。キーのコレクションに対してEntryProcessorを起動し、各起動の結果を返します。

• Map invokeAll(Filter filter, InvocableMap.EntryProcessor processor)。フィルタに一致するエントリに対してEntryProcessorを起動し、各起動の結果を返します。

注意:

各クラスタ・ノードのクラス・パスで、EntryProcessorクラスを使用できる必要があります。

エントリ・プロセスを作成するには、com.tangosol.util.processes.AbstractProcessorを拡張してprocess()メソッドを実装します。たとえば、次のコードはContactsデータ・セット内の従業員の勤務先アドレスを変更するためのEntryProcessorインスタンスを作成します。

public static class OfficeUpdater extends AbstractProcessor
implements PortableObject
...
public Object process(InvocableMap.Entry entry)
{
Contact contact = (Contact) entry.getValue();
contact.setWorkAddress(m_addrWork);
entry.setValue(contact);
return null;
}

OfficeUpdaterクラスを起動するには、OfficeUpdaterクラスの名前を持つinvokeAllメソッドをその引数の1つとして使用します。

cache.invokeAll(new EqualsFilter("getHomeAddress.getState", "MA"),
new OfficeUpdater(addrWork));

この演習では、キャッシュ内のエントリを更新するEntryProcessorインスタンスを備えたJavaクラスを作成します。「キャッシュ内の変更をリスニングするクラスの作成」で作成したObserverExampleクラスは、これらの変更を検出して変更済の記録を表示します。

1. キャッシュ内のエントリを更新するクラスの作成

2. POF構成ファイルの編集

3. キャッシュ更新サンプルの実行

7.3.1 キャッシュ内のエントリを更新するクラスの作成

キャッシュ内のエントリを更新するためのファイルを作成するには:

1. キャッシュ内のエントリを更新するクラスを作成します。
Loadingプロジェクトで、キャッシュ内のContactオブジェクトの住所を更新するmainメソッドを備えたProcessorExampleという名前のクラスを作成します。詳細は、「Javaクラスの作成」を参照してください。

2. マサチューセッツ州に住み、勤務先の住所を州内のオフィスに更新するContactsオブジェクトの記録を検索するコードを記述します。
PortableObjectインタフェース(キャッシュからのデータのシリアライズおよびデシリアライズ用)を実装し、勤務先住所を設定するためのEntryProcessorインスタンスを持つ内部クラスを追加します。Filterクラスのメソッドを使用して、マサチューセッツ州内に自宅住所があるContactsメンバーを分離します。

例7-5は、考えられるProcessorExampleクラスの実装を示しています。

例7-5 キャッシュ内のオブジェクトを更新するプログラムのサンプル

package com.oracle.handson;

import com.tangosol.net.NamedCache;

import com.tangosol.util.filter.EqualsFilter;
import com.tangosol.util.processor.AbstractProcessor;
import com.tangosol.util.InvocableMap;

import com.tangosol.io.pof.PortableObject;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;

import com.oracle.handson.Address;
import com.oracle.handson.Contact;

import com.tangosol.net.CacheFactory;

import java.io.IOException;

/**
* ProcessorExample executes an example EntryProcessor.
*
*/
public class ProcessorExample
{
public ProcessorExample()
{
}
public static void main(String[] args)
{
NamedCache cache = CacheFactory.getCache("ContactsCache");
new ProcessorExample().execute(cache);
}
// ----- ProcessorExample methods -----------------------------------

public void execute(NamedCache cache)
{
// People who live in Massachusetts moved to an in-state office
Address addrWork = new Address("200 Newbury St.", "Yoyodyne, Ltd.",
"Boston", "MA", "02116", "US");

cache.invokeAll(new EqualsFilter("getHomeAddress.getState", "MA"),
new OfficeUpdater(addrWork));
}
// ----- nested class: OfficeUpdater ------------------------------------

/**
* OfficeUpdater updates a contact's office address.
*/
public static class OfficeUpdater
extends AbstractProcessor
implements PortableObject
{
// ----- constructors -------------------------------------------

/**
* Default constructor (necessary for PortableObject implementation).
*/
public OfficeUpdater()
{
}

public OfficeUpdater(Address addrWork)
{
m_addrWork = addrWork;
}

// ----- InvocableMap.EntryProcessor interface ------------------

public Object process(InvocableMap.Entry entry)
{
Contact contact = (Contact) entry.getValue();

contact.setWorkAddress(m_addrWork);
entry.setValue(contact);
System.out.println("Work address was updated for " + contact.getFirstName() + " " + contact.getLastName());
return null;
}

// ----- PortableObject interface -------------------------------

public void readExternal(PofReader reader)
throws IOException
{
m_addrWork = (Address) reader.readObject(0);
}

public void writeExternal(PofWriter writer)
throws IOException
{
writer.writeObject(0, m_addrWork);
}

// ----- data members -------------------------------------------

private Address m_addrWork;
}
}

7.3.2 POF構成ファイルの編集

contacts-pof-config.xmlファイルを編集して、OfficeUpdaterエントリのユーザー定義型IDを追加します。ここでは、ProcessorExample$OfficeUpdaterクラスの定義型ID106を追加します。

...
<user-type>
<type-id>1006</type-id>
<class-name>com.oracle.handson.
ProcessorExample$OfficeUpdater</class-name>
</user-type>
...

7.3.3 キャッシュ更新サンプルの実行

キャッシュ更新サンプルを実行するには:

1. ProcessorExampleの実行構成を作成します。「Project Explorer」のObserverExampleを右クリックし、「Run As」を選択します。「Run Configurations」ダイアログ・ボックスで、Oracle Coherenceを選択して「New Configuration」アイコンをクリックします。

- 「Name」フィールドにProcessorExampleと入力します。

- 「Main」タブの「Project」フィールドにLoadingと入力します。「Main class」フィールドにcom.oracle.handson.ProcessorExampleと入力します。

- 「Coherence」タブの「Generalタブで、「Cache configuration descriptor」フィールドのc:\home\oracle\workspace\Contacts\appClientModule\contacts-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。
「Other」タブで、「tangosol.pof.config」フィールドまで下方へスクロールします。POF構成ファイルcontacts-pof-config.xmlへの絶対パスを入力します。「Apply」をクリックします。

- 「Common」タブで、「Shared file」を選択してLoadingディレクトリを参照します。

2. 次の手順を実行して、ObserverExampleクラスとProcessorExampleクラスをテストします。

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. ContactsCacheServerを再起動します。

3. LoaderExampleクラスを実行して、キャッシュをロードします。

4. ObserverExampleクラスを実行します。

5. ProcessorExampleを実行して、キャッシュ内の記録を更新します。
キャッシュ・サーバーのコンソール・ウィンドウに表示される例7-6のようなメッセージを確認してください。そのメッセージには、特定の従業員の勤務先住所が更新されたことについて記載されています。

例7-6 ObserverExampleクラスとProcessorExampleクラスからの出力

...
Started DefaultCacheServer...

2012-08-17 14:25:40.531/31.953 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-17 14:25:40.366, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4568, Role=OracleHandsonLoaderExample) joined Cluster with senior member 1
2012-08-17 14:25:40.765/32.187 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-08-17 14:25:41.078/32.500 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service PartitionedPofCache with senior member 1
2012-08-17 14:25:41.421/32.843 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2012-08-17 14:25:41.437/32.859 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 left service PartitionedPofCache with senior member 1
2012-08-17 14:25:41.453/32.875 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2012-08-17 14:25:40.366, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4568, Role=OracleHandsonLoaderExample) due to a peer departure; removing the member.
2012-08-17 14:25:41.453/32.875 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-17 14:25:41.453, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4568, Role=OracleHandsonLoaderExample) left Cluster with senior member 1
2012-08-17 14:25:58.875/50.297 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2012-08-17 14:25:58.695, Address=10.159.220.86:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4576, Role=OracleHandsonObserverExample) joined Cluster with senior member 1
2012-08-17 14:25:59.109/50.531 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 1
2012-08-17 14:25:59.390/50.812 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 3 joined Service PartitionedPofCache with senior member 1
2012-08-17 14:26:16.656/68.078 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-08-17 14:26:16.453, Address=10.159.220.86:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:416, Role=OracleHandsonProcessorExample) joined Cluster with senior member 1
2012-08-17 14:26:16.906/68.328 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
2012-08-17 14:26:17.218/68.640 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 4 joined Service PartitionedPofCache with senior member 1
Work address was updated for John Lfyovf
Work address was updated for John Jptrpajked
Work address was updated for John Mtqdln
Work address was updated for John Mstaugiw
Work address was updated for John Olfezqse
Work address was updated for John Qjefjgtgj
Work address was updated for John Kuhgkzn
Work address was updated for John Jpby
Work address was updated for John Cekuea
Work address was updated for John Guhkam
Work address was updated for John Ijwj
Work address was updated for John Trlb
Work address was updated for John Hnfcwxjq
Work address was updated for John Kizifh
Work address was updated for John Rqlhgboi
Work address was updated for John Ipphab
2012-08-17 14:26:17.312/68.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=4, Timestamp=2012-08-17 14:26:16.453, Address=10.159.220.86:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:416, Role=OracleHandsonProcessorExample) due to a peer departure; removing the member.
2012-08-17 14:26:17.312/68.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 4 left service Management with senior member 1
2012-08-17 14:26:17.312/68.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 4 left service PartitionedPofCache with senior member 1
2012-08-17 14:26:17.312/68.734 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-08-17 14:26:17.312, Address=10.159.220.86:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:416, Role=OracleHandsonProcessorExample) left Cluster with senior member 1

8 JPAとCoherenceの併用

この演習では、Java Persistence API (JPA)を使用してオブジェクト・リレーショナル・マッピングを実行する方法を学習します。ここでは、Coherenceのメモリーベースのバッキング・マップとOracle TopLink Gridの使用について取り上げます。

この章には次の項が含まれます:

- 概要

- JPAを使用したJavaオブジェクトへのリレーショナル・データのマッピング

実用バージョンのOracle Database Express Edition (OracleXE データベース)がシステムにインストールされている必要があります。このデータベースがない場合には、次のURLからダウンロードできます。

http://www.oracle.com/technetwork/database/database-technologies/express-edition/downloads/index.html

8.1 概要

JPAでは、リレーショナル・データをJavaオブジェクト(永続性エンティティ)にマップする方法や、これらのオブジェクトをリレーショナル・データベースに格納して後でアクセスできるようにする方法のほか、エンティティを使用するアプリケーションが終了してもそのエンティティの状態を存続させる方法を定義します。エンティティ永続性モデルを簡略化する以外に、JPAはオブジェクト・リレーショナル・マッピングを標準化します。

Coherenceクラスタ内にデータを格納する方法を決定するには、バッキング・マップを使用します。デフォルトでは、Coherenceではメモリーベースのバッキング・マップが使用されます。データを永続化するために実装されるバッキング・マップには、複数のものがあります。

この演習で使用するJPA実装には、Java環境からデータベース環境へのオブジェクト・リレーショナル・マッピング(ORM)が用意されています。そのため、標準的なCoherenceのgetメソッドやputメソッドを使用したり、JPAおよび(オープン・ソースのEclipseLinkプロジェクトに基づき)Oracle TopLinkを使用してCoherenceコールをデータベース・コールに変換したりすることもできます。

Oracle TopLinkとは

Oracle TopLinkは、Java SEおよびJava EE環境で変換、マッピング、永続性操作を提供するための開発ツールと実行時機能を含む永続性フレームワークです。TopLinkのコア・テクノロジは、Eclipse Foundationのオープンソースの永続性フレームワークであるEclipseLinkによって提供されます。

TopLinkには、EclipseLinkにはない追加機能が含まれています。TopLinkで提供される追加コンポーネントの1つはTopLink Gridです。

Oracle TopLink Gridとは

Oracle TopLink Gridは、EclipseLinkによって提供されるTopLink JPA実装とOracle Coherenceとを統合するために使用される機能です。

Coherence APIをTopLink Gridによって支援されたキャッシュとともに使用して、JPAに対して実装された特殊なキャッシュ・ローダーおよびキャッシュ・ストア・インタフェースでリレーショナル・データにアクセスできます。この従来のCoherenceアプローチでは、TopLink GridはEclipseLink JPA用に最適化されたoracle.eclipselink.coherence.standaloneパッケージにCacheLoaderおよびCacheStore実装を提供します。

JPAを使用してアプリケーションを構築し、データ・グリッドの機能を透過的に使用してスケーラビリティとパフォーマンスを向上させることができます。TopLink Gridは、Oracle Coherenceを使用してJPAアプリケーションをスケーリングするための手段を提供します。アプリケーションは、Coherenceを分散共有(L2)キャッシュとして使用することから、JP QL問合せをCoherenceに送ってグリッド全体でパラレル実行してデータベース負荷を削減することまで、様々な方法でスケーリングできます。このようなグリッド基盤のJPAアプローチにおいては、TopLink Gridが、キャッシュのセットと、EclipseLink JPAでのCoherenceの使用方法を制御できる問合せ構成オプションを提供します。これらの実装は、oracle.eclipselink.coherence.integratedパッケージ内にあります。

TopLink Gridのキャッシュ・ストア実装およびキャッシュ・ローダー実装は、toplink-grid.jarファイルに含まれています。TopLink Gridは、標準のJPAランタイム構成ファイルpersistence.xmlとJPAマッピング・ファイルorm.xmlを使用します。Coherenceのキャッシュ構成ファイルcoherence-cache-config.xmlを、デフォルトのCoherence設定をオーバーライドし、キャッシュ・ストア・キャッシング・スキームを定義するように指定する必要があります。

このプロジェクトでは、EclipseLink JPAにあわせて最適化され、Coherenceアプリケーションで使用できるように設計されているTopLink Gridのキャッシュ・ストア・クラスとキャッシュ・ローダー・クラスが使用されます。これらのクラスはoracle.eclispelink.coherence.standaloneパッケージにあります。詳細は、『Oracle Fusion Middleware Oracle Coherenceの統合』のTopLink Gridによって支援されたCoherenceキャッシュの使用に関する項を参照してください。

グリッド基盤のJPAのアプローチは、このプロジェクトでは説明しません。この技術の詳細は、『Oracle Fusion Middleware Oracle Coherenceの統合』のTopLink GridとOracle Coherenceの統合に関する項を参照してください。

8.2 JPAを使用したJavaオブジェクトへのリレーショナル・データのマッピング

この演習では、Eclipseを使用して次のタスクを実行します。

1. OracleXEデータベースのロック解除

2. JPAに対するプロジェクトの構成

3. JPA永続ユニットとエンティティの作成

4. persistance.xmlファイルの編集

5. JPAに対するキャッシュ構成ファイルの作成

6. キャッシュ・サーバーの起動構成ファイルの作成

7. データ・オブジェクトとやり取りするクラスの作成

8. RunEmployeeExampleの実行構成の作成

9. JPAサンプルの実行

8.2.1 OracleXEデータベースのロック解除

インストール済のOracleXEデータベースでHRアカウントのロックを解除します。

使用するシステムにOracleXEデータベースをインストールし、HRスキーマにアクセスできるようにしておく必要があります。HRアカウントのロックを解除するには:

1. 「Start」→「All Programs」→「Oracle Database 11g Express Edition」→「Run SQL Command Line」の順に移動します。

2. connect system as sysdbaと入力し、パスワードを要求されたらwelcome1と入力します(注意: ユーザー名はsystem、パスワードはwelcome1です。)

3. 次のコマンドを入力してアカウントのロックを解除します。

alter user hr identified by hr account unlock;

これらのコマンドは図8-1に示されています。

図8-1 データベースへの接続

8.2.2 JPAに対するプロジェクトの構成

Eclipse IDE内にJPAProjectという新規プロジェクトを作成します。詳細は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。

1. Eclipse IDEで、「Window」→「Open Perspective」→「Other」をクリックし、「Open Perspective」ダイアログ・ボックスを開きます。図8-2に示されているように、「JPA」パースペクティブを選択します。

図8-2 「Open Perspective」ダイアログ・ボックス内でのJPAパースペクティブの選択

2. 「File」→「New」→「JPA Project」を選択します。プロジェクト名にJPAProjectと入力します。デフォルトの場所がhome\oracle\workspace\JPAProjectをポイントしていることを確認します。「Configuration」フィールドで「Modify」をクリックし、「Project Facets」ダイアログ・ボックスを開きます。

3. 「Oracle Coherence」ファセットを選択します。JPAとJavaファセットがすでに選択されていることを確認します。

4. 「Configuration」フィールドで「Save As」をクリックします。「Save Preset」ダイアログ・ボックスでJPAConfigurationと入力し、「OK」をクリックします。「Project Facets」ダイアログ・ボックスの内容は図8-3のようになります。

図8-3 JPAプロジェクトのプロジェクト・ファセット

「New JPA Project」ダイアログ・ボックスの内容は、図8-4のようになります。「Next」をクリックして「Java」ページへ移動します。

図8-4 「New JPA Project」ダイアログ・ボックスの内容

5. 「Java」ページで「Next」をクリックして、デフォルトの出力先フォルダの場所を受け入れます。

6. 「JPA Facet」ページの「Platform」ドロップダウン・リストで「EclipseLink 2.4.x」を選択します。「Manage Libraries」アイコンをクリックして、TopLink Grid、EclipseLinkおよびJava Persistenceのファイルを追加します。

7. 「Preferences」ダイアログ・ボックスで「New」をクリックします。「New User Library」ダイアログ・ボックスで、TopLinkと入力します。図8-5に示すように、「System library」チェック・ボックスを選択します。

図8-5 EclipseLink JPAライブラリの追加

8. 「OK」をクリックして「New User Library」ダイアログ・ボックスを閉じます。

9. 「Preference」ダイアログ・ボックスで、「TopLink[system library]」を選択し、「Add External JARS」をクリックします。

10. Oracle_Home\oracle_common\modules\oracle.toplink_12.1.2フォルダに移動します。toplink-grid.jarおよびeclipselink.jarファイルを選択し、「Open」をクリックします。toplink-grid.jarおよびeclipselink.jarファイルが「TopLink」ライブラリに追加されます。「Add External JARS」を再度クリックし、Oracle_Home\oracle_common\modulesフォルダに移動します。javax.persistence_2.0.0.0_2-0.jarファイルを選択し、「Open」をクリックします。終了すると、「User Libraries」は図8-6のようになります。

図8-6 TopLinkユーザー・ライブラリへのToplink Grid、EclipselinkおよびJava PersistenceのJARファイルの追加

11. 「OK」をクリックして「Preferences」ダイアログ・ボックスを閉じます。「TopLink」ユーザー・ライブラリを選択します。「JPA Facet」ページが図8-7のように表示されます。

図8-7 「JPA Facet」ページへのTopLinkライブラリの追加

12. Oracle XEデータベースへの接続を作成します。「Add connection」をクリックします。

1. 「Connection Profile」ダイアログ・ボックスで、図8-8に示されるように「Oracle Database Connection」を選択して、「Name」フィールドにXE_HRと入力します。「Next」をクリックします。

図8-8 「Connection Profile」ページ

2. 「Drivers」フィールドで「Oracle Database 11g Driver Default」を選択します。「General」タブを編集します。「User name」フィールドにhr、「Password」フィールドにhrと入力します。「Save Password」チェック・ボックスを選択します。「Host」フィールドにlocalhostと入力します。「Connect when the wizard completes」チェック・ボックスを選択します。「Test Connection」ボタンをクリックします。テストで、図8-9に示されているような成功メッセージが表示された警告ボックスが返されます。「OK」→「Next」をクリックすると、「Summary」ページが表示されます。「Finish」をクリックします。

図8-9 「New Connection Profile」ダイアログ・ボックスおよび成功メッセージ

3. 「JPA Facet」ページで、「Add driver library to build path」→「Next」をクリックします。

13. 「Coherence」ページで、「Coherence 12.1.2」および「TopLink」ユーザー・ライブラリが存在し、選択されていることを確認します。「Finish」をクリックします。

図8-10 新規JPAプロジェクト・ウィザードの「Coherence」ページ

8.2.3 JPA永続性ユニットおよびエンティティの作成

永続性ユニットには、メタデータ・ファイル、クラス、およびグループとしての永続に必要なすべてのクラスを含むJARのセットを識別する簡単な方法が備わっています。永続性ユニットは、その名前によって識別されます。エンティティは永続データを含み、永続データ・ストアに保存できます。JPAエンティティは、永続性ユニットに属することができます。永続性ユニットは、persistence.xmlファイルにより記述されています。

JPA永続性ユニットとJPAエンティティを作成するには:

1. JPAProjectプロジェクトを右クリックして、「New」→「JPA Entities from Tables」を選択します。「Select Tables」ダイアログ・ボックスが開きます。

2. 図8-11に示されているようにEMPLOYEES表を選択し、「Next」をクリックします。

図8-11 データベース表の選択

3. 「Table Associations」ページで、図8-12に示されているように、「Next」をクリックしてデフォルト設定を受け入れます。

図8-12 EMPLOYEES表に対するアソシエーション

4. 「Customize Defaults」ページで、「Collection properties type」のjava.util.Listを選択し、「Package」フィールドにcom.oracle.handsonと入力します。「Associations fetch」フィールドで、「Lazy」を選択します。
終了すると、「Customize Default Entity Generation」ページは図8-13のようになります。「Next」をクリックします。

図8-13 「Customize Default Entity Generation」ページ

5. 「Customize Individual Entities」ページで、「Superclass」フィールドにjava.lang.Objectと入力します。図8-14に示すとおり、「Class name」をEmployeeからEmployeesに変更します。

図8-14 「Customize Individual Entities」ページ

6. 「Finish」をクリックしてJPAエンティティを生成します。「Project Explorer」のJPAProject/src/com.oracle.handsonノードにEmployees.javaファイルが生成されます。

8.2.4 persistance.xmlファイルの編集

persistence.xmlファイルは1つまたは複数の永続性ユニットを定義します。Eclipse IDEでpersistence.xml Editorツールを使用して、persistence.xmlファイルを編集します。

1. Eclipseエディタでpersistence.xmlファイルを開きます。

2. 「一般」タブをクリックします。まだ指定していない場合は、永続性プロバイダの名前を入力します。org.eclipse.persistence.jpa.PersistenceProviderと入力ます。

図8-15 persistence.xmlエディタの「General」タブ

3. 「Connection」タブで、「Transaction type」ドロップダウン・リストから「Resource Local」を選択します。
「EclipseLink connection pool」セクションで、「Populate from connection」リンクをクリックしてから、「Connection Selection」ダイアログ・ボックスのXE_HR項目をクリックします。このフィールドの値は、「JPAに対するプロジェクトの構成」で定義したデータベース接続に基づいて設定されます。「Connection Properties」タブは、図8-16のようになります。

図8-16 persistence.xmlエディタの「Connection Properties」タブ

4. 「Logging」タブを開き、「Logging level」ドロップダウン・リストから「Fine」を選択します。
「Exceptions」チェック・ボックスを選択します。「Timestamp」、「Thread」、「Session」および「Connection」チェック・ボックスの選択を解除します。終了すると、「Logging」タブは次のようになります。

図8-17 persistence.xmlエディタの「Logging」タブ

5. 「Properties」タブを調べます。内容は図8-18のようになります。

図8-18 persistence.xmlエディタの「Properties」タブ

6. 「Source」タブを開きます。persistence.xmlファイルは例8-1のようになります。ファイルを保存します。

例8-1 生成されたpersistence.xmlファイル

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPAProject" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.oracle.handson.Employees</class>
<properties>
<property name="eclipselink.target-server" value="None"/>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="javax.persistence.jdbc.user" value="hr"/>
<property name="javax.persistence.jdbc.password" value="hr"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.logging.timestamp" value="false"/>
<property name="eclipselink.logging.thread" value="false"/>
<property name="eclipselink.logging.session" value="false"/>
<property name="eclipselink.logging.connection" value="false"/>
<property name="eclipselink.logging.exceptions" value="true"/>
</properties>
</persistence-unit>
</persistence>

8.2.5 JPAに対するキャッシュ構成ファイルの作成

JPAプロジェクトに対するキャッシュ構成ファイルを作成します。

1. プロジェクト内のcoherence-cache-config.xmlファイルを右クリックし、「Open」を選択します。

2. 例8-2のようにコードを入力します。「Rename」または「Save As」を使用して、ファイルをjpa-cache-config.xmlとして保存します。ファイルはhome\oracle\workspace\JPAProject\srcフォルダに保存されます。

3. 「Project Explorer」に元のcoherence-cache-config.xmlファイルが表示されていないことを確認します。
例8-2で、scheme-name要素の値としてdistributed-eclipselink、service-name要素の値としてEclipseLinkJPA、およびcachestore-scheme要素のclass-nameサブ要素の値としてoracle.eclipselink.coherence.standalone.EclipseLinkJPACacheStoreが使用されていることに注意してください。

例8-2 JPAに対するキャッシュ構成

<?xml version="1.0"?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config http://xmlns.oracle.com/coherence/coherence-cache-config/1.2/coherence-cache-config.xsd">

<defaults>
<serializer system-property="tangosol.coherence.serializer"/>
<socket-provider system-property="tangosol.coherence.socketprovider"/>
</defaults>
<caching-scheme-mapping>
<cache-mapping>
<!-- Set the name of the cache to be the entity name  -->
<cache-name>Employees</cache-name>
<!-- Configure this cache to use the scheme defined below  -->
<scheme-name>distributed-eclipselink</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>distributed-eclipselink</scheme-name>
<service-name>EclipseLinkJPA</service-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<!--
Define the cache scheme
-->
<internal-cache-scheme>
<local-scheme/>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>oracle.eclipselink.coherence.standalone.EclipseLinkJPACacheStore</class-name>
<init-params>
<!--
This param is the entity name
This param should match the value of the
persistence unit name in persistence.xml
-->
<init-param>
<param-type>java.lang.String</param-type>
<param-value>{cache-name}</param-value>
</init-param>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>JPAProject</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>

8.2.6 キャッシュ・サーバー起動の構成の作成

JPAプロジェクト用キャッシュ・サーバーを起動するための構成を作成します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで「Oracle Coherence」アイコンをダブルクリックして、新しい起動構成を作成します。

2. 「Main」タブで、「Name」フィールドにJPAServerと入力します。「Project」フィールドの「Browse」をクリックし、「Project Selection」ダイアログ・ボックスでJPAProjectプロジェクトを選択します。「Include system libraries when searching for a main class」チェック・ボックスを選択し、「Search」をクリックします。「Select Type」フィールドにDefaultCacheServerと入力して、com.tangosol.net.DefaultCacheServerを選択します。「Apply」をクリックします。「Main」タブは図8-19のようになります。

図8-19 JPAキャッシュ・サーバー用「Main」タブ

3. 「Coherence」タブの「General」タブで、「Cache configuration descriptor」の下にあるキャッシュ構成ファイルへのパスを指定します。「Browse」ボタンをクリックして、JPAキャッシュ構成ファイルの絶対ファイル・パスC:\home\oracle\workspace\JPAProject\src\jpa-cache-config.xmlに移動します。「Local storage」の下の「Enabled (cache server)」を選択します。「Cluster port」には3155などの一意の値を入力します。
「Other」タブで、tangosol.pof.configの項目がデフォルトのpof-config.xmlに設定されていることを確認します。

4. 「Common」タブで、「Shared file」を選択して\JPAプロジェクトを参照します。

5. 「Classpath」タブは図8-20のようになります。

図8-20 JPAキャッシュ・サーバー実行可能ファイルの「Classpath」タブ

キャッシュ・サーバーの起動は、後の手順「JPAサンプルの実行」で実行します。

8.2.7 データ・オブジェクトとやり取りするためのクラスの作成

JPAProjectプロジェクト内にEmployeesオブジェクトとやり取りするための新規クラスを作成します。このクラスは、従業員のサラリーの値を変更する目的で作成されます。

1. RunEmployeeExampleというmainメソッドを持つ新規クラスを作成します。詳細は、「Javaクラスの作成」を参照してください。

2. 次のタスクを実行するコードを作成します。

1. EMPLOYEE_ID属性を使用して従業員を取得します。EMPLOYEE_IDはlongデータ・タイプです。

2. サラリーを表示します。

3. 従業員の昇給を10%にします。

4. 値を再度取得して、昇給を確定します。

例8-3は、考えられるRunEmployeeExampleクラスの実装を示しています。

例8-3 従業員クラスのサンプル・ファイル

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import java.math.BigDecimal;

public class RunEmployeeExample
{
public RunEmployeeExample()
{
}

public static void main(String[] args)
{
long empId = 190L;  // emp 190 - Timothy Gates

NamedCache employees = CacheFactory.getCache("Employees");

Employees emp = (Employees)employees.get(empId);

System.out.println("Employee " + emp.getFirstName() + " " +
emp.getLastName() + ", salary = $" + emp.getSalary() );

// give them a 10% pay rise
emp.setSalary(emp.getSalary().multiply(BigDecimal.valueOf(1.1)));

employees.put(empId, emp);

Employees emp2 = (Employees)employees.get(empId);

System.out.println("New Employee details are " + emp2.getFirstName() + " " + emp2.getLastName() + ", salary = $" + emp2.getSalary() );
}
}

8.2.8 RunEmployeeExampleの実行構成の作成

実行構成を作成するには、実行時のプロパティを変更してEclipseのクラス・パスを編集します。

1. 「Project Explorer」のRunEmployeeExample.javaを右クリックし、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「Oracle Coherence」アイコンをダブルクリックして、新しい起動構成を作成します。

2. 「Main」タブで、「Name」フィールドにRunEmployeeと入力します。「Browse」をクリックし、JPAProjectプロジェクトを選択します。「Main class」フィールドで、「Search」をクリックしてcom.oracle.handson.RunEmployeeExampleを選択します。「Apply」をクリックします。

3. 「Coherence」タブの「General」タブで、「Cache configuration descriptor」フィールドのC:\home\oracle\workspace\JPAProject\src\jpa-cache-config.xmlファイルを参照します。「Disabled (cache client)」ボタンを選択します。「Cluster port」フィールドに3155と入力します。「Apply」をクリックします。

4. 「Other」タブで、デフォルトのpof-config.xmlがtangosol.pof.configフィールドに表示されていることを確認します。

5. 「Common」タブで、「Shared file」を選択して\JPAProjectプロジェクトを参照します。
「Classpath」タブは図8-21のようになります。

図8-21 RunEmployee実行可能ファイルの「Classpath」タブ

8.2.9 JPAサンプルの実行

Employeeクラスに対してJPAを使用してデータベースに永続化するように注釈を付け、データベースの場所をJPAに知らせるpersistence.xmlファイルを追加したため、CoherenceではCacheStore実装が採用され、TopLink Gridを使用してオブジェクトがデータベースにロードおよび格納されます。get(Object key)メソッドを使用すると、次のことが実行されます。

- Coherenceで、キーを持つエントリが検索されます。

- エントリがまだキャッシュされていない場合や、期限切れでキャッシュから削除されている場合には、バッキング・マップがコールされ、TopLink Gridキャッシュ・ストアを使用してデータが取得されます。

- エントリがキャッシュされている場合は、TopLink Gridキャッシュ・ストアを介さずにそのエントリがアプリケーションに直接返されます。put(object key,object value)メソッドを使用する場合は、データベースに変更を永続化するために、TopLink Gridを介してEclipseLink JPAが使用されます。

「Run Configurations」ダイアログ・ボックスで、JPAServer起動構成を選択し、「Run」をクリックしてキャッシュ・サーバーを起動します。キャッシュ・サーバーの起動後、RunEmployee構成を選択し、「Run」をクリックします。実行可能ファイルからの出力は例8-4のようになります。

例8-4 実行可能ファイルからの出力

...
Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=2, Timestamp=2013-02-22 13:59:12.203, Address=192.168.0.102:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5436, Role=OracleHandsonRunEmployeeExample)
OldestMember=Member(Id=1, Timestamp=2013-02-22 13:58:41.89, Address=192.168.0.102:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4152, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2013-02-22 13:58:41.89, Address=192.168.0.102:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4152, Role=CoherenceServer)
Member(Id=2, Timestamp=2013-02-22 13:59:12.203, Address=192.168.0.102:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5436, Role=OracleHandsonRunEmployeeExample)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2013-02-22 13:58:41.89|JOINED,
2|12.1.2|2013-02-22 13:59:12.203|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2013-02-22 13:59:12.625/1.860 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2013-02-22 13:59:12.656/1.891 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/reports/report-group.xml"
2013-02-22 13:59:12.843/2.078 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:EclipseLinkJPA, member=2): Service EclipseLinkJPA joined the cluster with senior service member 1
Employee Timothy Gates, salary = $4245.89
New Employee details are Timothy Gates, salary = $4670.47

キャッシュ・サーバーからの応答によりログインの成功が表示され、例8-5に示すようにデータベースからの情報が取得されます。返されるロギング情報(太字)に注意してください。

例8-5 データベースへのログインに対するキャッシュ・サーバーの応答

...
Started DefaultCacheServer...

2013-02-22 13:59:12.390/31.953 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-22 13:59:12.203, Address=192.168.0.102:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5436, Role=OracleHandsonRunEmployeeExample) joined Cluster with senior member 1
2013-02-22 13:59:12.640/32.203 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 joined Service Management with senior member 1
2013-02-22 13:59:12.875/32.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:EclipseLinkJPA, member=1): Member 2 joined Service EclipseLinkJPA with senior member 1
[EL Config]: metadata: The access type for the persistent class [class com.oracle.handson.Employees] is set to [FIELD].
[EL Config]: metadata: The target entity (reference) class for the many to one mapping element [field employee] is being defaulted to: class com.oracle.handson.Employees.
[EL Config]: metadata: The target entity (reference) class for the one to many mapping element [field employees] is being defaulted to: class com.oracle.handson.Employees.
[EL Config]: metadata: The alias name for the entity class [class com.oracle.handson.Employees] is being defaulted to: Employees.
[EL Config]: metadata: The table name for entity [class com.oracle.handson.Employees] is being defaulted to: EMPLOYEES.
[EL Config]: metadata: The column name for element [email] is being defaulted to: EMAIL.
[EL Config]: metadata: The column name for element [salary] is being defaulted to: SALARY.
[EL Config]: metadata: The primary key column name for the mapping element [field employee] is being defaulted to: EMPLOYEE_ID.
[EL Info]: EclipseLink, version: Eclipse Persistence Services - 2.4.2.v20130131-a7b9798
[EL Fine]: connection: Detected database platform: org.eclipse.persistence.platform.database.oracle.Oracle11Platform
[EL Config]: connection: connecting(DatabaseLogin(
platform=>OraclePlatform
user name=> "hr"
datasource URL=> "jdbc:oracle:thin:@localhost:1521:xe"
))
[EL Config]: connection: Connected: jdbc:oracle:thin:@localhost:1521:xe
User: HR
Database: Oracle  Version: Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
Driver: Oracle JDBC driver  Version: 11.1.0.7.0-Production
[EL Warning]: metadata: Reverting the lazy setting on the OneToOne or ManyToOne attribute [employee] for the entity class [class com.oracle.handson.Employees] since weaving was not enabled or did not occur.
[EL Info]: connection: file:/C:/home/oracle/workspaceNov/JPAProject/build/classes/_JPAProject login successful
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [190]
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [122]
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [100]
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [190]
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [122]
[EL Fine]: sql: SELECT EMPLOYEE_ID, COMMISSION_PCT, DEPARTMENT_ID, EMAIL, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, PHONE_NUMBER, SALARY, MANAGER_ID FROM EMPLOYEES WHERE (EMPLOYEE_ID = ?)
bind => [100]
[EL Fine]: sql: UPDATE EMPLOYEES SET SALARY = ? WHERE (EMPLOYEE_ID = ?)
bind => [4670.47, 190]
2013-02-22 13:59:20.875/40.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2013-02-22 13:59:12.203, Address=192.168.0.102:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5436, Role=OracleHandsonRunEmployeeExample) due to a peer departure; removing the member.
2013-02-22 13:59:20.875/40.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-22 13:59:20.875, Address=192.168.0.102:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5436, Role=OracleHandsonRunEmployeeExample) left Cluster with senior member 1
2013-02-22 13:59:20.875/40.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:EclipseLinkJPA, member=1): Member 2 left service EclipseLinkJPA with senior member 1
2013-02-22 13:59:20.875/40.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 left service Management with senior member 1

9 キャッシュとデータベースの相互作用

この演習では、EclipseでOracle Coherenceのキャッシュを作成および構成します。ここでは、Coherence APIのCacheStore、ContinuousQueryCache、IdentityExtractorおよびFilterの使用について取り上げます。

この演習では、次の3つのアイテムを作成します。

- NamedCacheインスタンスを作成し、キャッシュ・エントリの挿入と取得が可能なJavaクラス。

- キャッシュ名、キャッシュ・タイプおよびネーミング・パターンのマッピングを定義する、キャッシュ構成ファイル。

- Oracle Databaseへの接続を作成し、表データの取得と格納が可能なJavaクラス。

- データベース・キャッシュ。このクラスは、キャッシュ・エントリの追加、データベース・キャッシュの問合せ、エントリの取得を行います。

この章には次の項が含まれます:

- 概要

- キャッシュ・アプリケーションの作成

- データベース・キャッシュの作成

9.1 概要

Coherenceキャッシュは、データベースとクライアント・アプリケーションの仲介として機能するデータ・オブジェクトのコレクションです。データベース・データはキャッシュにロードされ、別のアプリケーションでの利用が可能になります。このようにしてCoherenceキャッシュはデータベースに対する負荷を軽減し、データベース・データへのアクセスを高速化します。

Coherenceキャッシュは、データベースの分離とデータ・レプリケーションによって、可用性を向上させます。データベースが利用可能であれば常に、キャッシュに対する変更をデータベースと同期できます。データベースまたはアプリケーション・サーバー・ノードが利用できない場合でも、Coherenceキャッシュで使用される遅延ロードと遅延書込み方式およびCoherenceが提供するフェイルオーバーとフェイルバックによって、データベース更新の信頼性が確保されます。

Coherenceキャッシュは、データ・オブジェクトに対してデータ変更操作を実行できるため、アプリケーション・サーバー・ノードのクラスタ間のみではなく、キャッシュ内のデータ・オブジェクト間にも分散処理を提供します。

Coherenceでは、イベントベースの処理も可能です。キャッシュ内のデータ・オブジェクトの状態はモニター可能で、Business Process Execution Language (BPEL)プロセスの開始など、他のプロセスによってアクションを起動できます。

Coherenceでは、様々なタイプのキャッシュがサポートされます。

- クラスタ内のアプリケーション・サーバー・ノードのそれぞれにデータがレプリケートされる、レプリケート・キャッシュ。このタイプのキャッシュは、高速読取りアクセスが必要な場合にお薦めしますが、データをノードのそれぞれに書き込む必要があるため、書込み操作には向きません。レプリケート・キャッシュの短所は、すべてのノードにすべてのオブジェクトのコピーが保持されるため、大量のメモリーを必要とすることです。

- データが複数のノード間で分散される(ロード・バランシング)、分散(またはパーティション)キャッシュ。フェイルオーバーはバックアップを使用して分散キャッシュに実装され、これもクラスタ・ノード間に分散されます。

Coherenceは、クラスタ・サービス、分散キャッシュ・サービスおよびレプリケート・キャッシュ・サービスなどのサービスを使用して実装されます。どちらのタイプのキャッシュを使用しても、アプリケーションでは同じAPIを使用してデータのアクセスと格納を行います。

キャッシュの構成には、キャッシュ構成デプロイメント・ディスクリプタが使用されます。キャッシュ構成ファイルのルート要素は、cache-configです。キャッシュ名と名前パターンは、サブ要素cache-mappingを使用して、caching-scheme-mapping要素内のキャッシュ・タイプにマップされます。キャッシュ・タイプはcaching-schemes要素で定義されます。表9-1は、Coherenceで一般的に使用されるキャッシュ・タイプの一部を示しています。

表9-1 キャッシュ・タイプの説明

キャッシュ・タイプ

説明

分散スキーム

ノードのクラスタ間でデータが格納される分散キャッシュを定義します。

レプリケート・スキーム

キャッシュ・エントリがすべてのクラスタ・ノードにレプリケートされるキャッシュを定義します。

read-write-backing-mapスキーム

リレーショナル・データベースなどの永続的ストアのキャッシュを提供するマップを定義します。

外部スキーム

ディスクなどの外部キャッシュを定義します。

クラス・スキーム

java.util.Mapインタフェースの実装に必要な、カスタム・キャッシュ実装を定義します。

9.2 キャッシュ・アプリケーションの作成

この項では、データをキャッシュに挿入して取得するアプリケーションの作成および実行方法を説明します。

1. キャッシュを構成するアプリケーションの作成

2. キャッシュ構成ファイルの作成

3. アプリケーションの実行構成の作成

4. キャッシュ・サーバー起動構成の作成

5. キャッシュ作成アプリケーションの実行

9.2.1 キャッシュを構成するアプリケーションの作成

Coherenceキャッシュを構成するJavaクラスを作成するには:

1. Eclipseで、プロジェクトを作成します。

1. EclipseでJPAパースペクティブを使用して、Interactionと呼ばれるJPAプロジェクトを作成します。第8章「JPAとCoherenceの併用」で作成したJPAConfigurationを選択します。

2. 「JPA Facet」ページで、「Platform」フィールドに「EclipseLink 2.4.x」が表示されていることを確認します。「User Libraries」の下で、「Coherence12.1.2」および「TopLink」が選択されていることを確認します。「Connection」フィールドで、「Connection」ドロップダウン・リストから「JPAに対するプロジェクトの構成」(XE_HR)で作成した接続を選択します。必要に応じて、「Connect」リンクをクリックしてOracle XEデータベースに接続します。(ここでは作成したデータベース接続が稼働中であると想定していることに注意してください。)「Add Driver Library to Build Path」を選択し、ドロップダウン・リストから「Oracle Database 11g Driver」を選択します。「Next」をクリックします。

3. 「Coherence」ページで、「Coherence12.1.2」および「TopLink」が選択されていることを確認します。「Finish」をクリックします。

2. Coherenceキャッシュの作成に使用するJavaクラスCoherenceCacheを作成します。クラスにmainメソッドをインクルードします。クラス作成の詳細は、「Javaクラスの作成」を参照してください。

1. CoherenceCache Javaクラスでキャッシュを作成します。CacheFactoryクラスとNamedCacheインタフェースをインポートします。

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

2. CacheFactory.getCacheメソッドを使用して、キャッシュ(NamedCache)インスタンスを作成します。キャッシュ名VirtualCacheを使用します。これは分散キャッシュ・スキームにマップされます。

NamedCache cache = CacheFactory.getCache ( "VirtualCache");

3. NamedCacheは、クラスタ内のノード間で共有されるリソースを保持するjava.util.Mapインスタンスです。putメソッドを使用してキャッシュ・エントリを追加します。

cache.put (key, "Hello Cache");

4. getメソッドを使用してキャッシュ・エントリを取得します。

System.out.println((String)cache.get("hello"));

例9-1は、考えられるCoherenceCacheクラスの実装を示しています。このコードは、EclipseでCoherenceCacheファイルにコピーできます。

例9-1 Coherenceキャッシュの実装

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class CoherenceCache
{
NamedCache cache;
public CoherenceCache()
{
}
public void putCache()
{
cache = CacheFactory.getCache ( "VirtualCache");
String key = "hello";
cache.put (key, "Hello Cache");
}

public void retrieveCache()
{
System.out.println((String)cache.get("hello"));
}

public static void main (String [] args)
{
CoherenceCache cache = new CoherenceCache();
cache.putCache();
cache.retrieveCache();
}
}

9.2.2 キャッシュ構成ファイルの作成

「Project Explorer」で、coherence-cache-config.xmlキャッシュ構成ファイルの名前をcache-config.xmlに変更します。Eclipseエディタでファイルを開きます。

キャッシュ構成ファイルで次のようにします。

- caching-scheme-mapping要素内のcache-mapping要素を使用して、キャッシュ名とネーミング・パターンのマッピングを定義します。

- キャッシュ名VirtualCacheをキャッシュ・タイプdistributed-eclipselinkにマップします。

- EclipseLinkJPAサービスを使用して、distributed-scheme要素で分散キャッシュ・スキームを定義します。

例9-2は、キャッシュ構成ファイルを示しています。この例のコンテンツをcache-config.xmlにコピーします。

例9-2 キャッシュ構成ファイル

<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<caching-scheme-mapping>

<cache-mapping>
<cache-name>VirtualCache</cache-name>
<scheme-name>distributed-eclipselink</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<!--
Default Distributed caching scheme.
-->
<distributed-scheme>
<scheme-name>distributed-eclipselink</scheme-name>
<service-name>EclipseLinkJPA</service-name>
<backing-map-scheme>
<class-scheme>
<scheme-ref>default-backing-map</scheme-ref>
</class-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
<class-scheme>
<scheme-name>default-backing-map</scheme-name>
<class-name>com.tangosol.util.SafeHashMap</class-name>
</class-scheme>
</caching-schemes>
</cache-config>

9.2.3 アプリケーションの実行構成の作成

アプリケーションの実行構成を作成して、ランタイムJavaオプションとしてキャッシュ構成ファイルを追加します。

1. 「Project Explorer」でCoherenceCache.javaを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「New launch configuration」アイコンをクリックします。

2. 「Name」フィールドにCoherenceCacheServerと入力します。「Project」フィールドにInteractionが、「Main class」フィールドにcom.oracle.handson.CoherenceCacheが存在することを確認します。

3. 「Coherence」タブで、キャッシュ構成ファイルへのパス(C:\home\oracle\workspace\Interaction\src\cache-config.xml)を入力します。Select the 「Enabled (cache server)」ボタンを選択します。「Cluster port」フィールドに3155などの一意の値を入力します。「Apply」をクリックします。
「Classpath」タブが図9-1のように表示されます。

図9-1 CoherenceCacheServer実行可能ファイルのクラスパス

9.2.4 キャッシュ・サーバー起動構成の作成

相互作用プロジェクトのキャッシュ・サーバーの起動構成を作成するには:

1. 「Interaction」プロジェクトを右クリックして、「Properties」を選択します。「Properties for Interact」ダイアログ・ボックスで、「Java Build Path」を選択します。「Order and Export」タブに、Interactionプロジェクト、JRE、Coherence12.1.2、TopLinkおよびOracle Database 11g Driver Defaultライブラリが存在している必要があります。すべてが選択されていることを確認します。「Order and Export」タブが図9-2のように表示されます。

図9-2 Javaビルド・パスのライブラリの「Order and Export」タブ

2. 第8章「JPAとCoherenceの併用」で作成したJPAキャッシュ・サーバー起動構成(JPAServer)を編集します。

1. 「Interaction」プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Main」タブで、「Browse」をクリックして「Project Selection」ダイアログ・ボックスから「Interaction」プロジェクトを選択します。

2. 「Coherence」タブの「General」タブで、構成ファイルの名前とパスをC:\home\oracle\workspace\Interaction\cache-config.xmlに置換します。

3. 「Classpath」タブで、「JPA (default classpath)」フォルダを削除します。「Add Project」をクリックして、「Interaction」プロジェクトを追加します。「Classpath」タブが図9-3のように表示されます。

図9-3 相互作用プロジェクト・キャッシュ・サーバーのクラスパス

4. 「Common」タブの「Shared file」フィールドで、「Browse」をクリックして「Interaction」プロジェクトを選択します。「Apply」をクリックし、「Close」をクリックします。

9.2.5 キャッシュ作成アプリケーションの実行

キャッシュ作成アプリケーションCoherenceCache.javaを実行するには:

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. JPAServerを実行して、キャッシュ・サーバーを起動します。

3. CoherenceアプリケーションCoherenceCache.javaを右クリックし、「Run As」→「Run Configurations」をクリックします。CoherenceCacheServer構成を選択して、「Run」をクリックします。Eclipseコンソール・ウィンドウに出力が表示されます。

- 操作構成がtangosol-coherence.xmlファイルから読み込まれます。このファイルは、Coherenceがクラスタ化、通信およびデータ管理サービスに使用するオペレーションおよびランタイム設定を指定します。

- キャッシュ構成がcache-config.xmlファイルからロードされます。

- 新規クラスタが作成され、DistributedCacheサービスによってこのクラスタが結合されます。

- CoherenceCache.javaプログラム、Hello Cacheの出力が表示されます。

例9-3 Coherenceキャッシュ・アプリケーションの出力

...
2013-02-14 16:30:37.735/0.735 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspaceNov/Interaction/src/cache-config.xml"
2013-02-14 16:30:37.891/0.891 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2013-02-14 16:30:38.110/1.110 Oracle Coherence GE 12.1.2.0.0 <Warning> (thread=main, member=n/a): Local address "127.0.0.1" is a loopback address; this cluster node will not connect to nodes located on different machines
2013-02-14 16:30:38.250/1.250 Oracle Coherence GE 12.1.2.0.0 <D4> (thread=main, member=n/a): TCMP bound to /127.0.0.1:8090 using SystemDatagramSocketProvider
2013-02-14 16:30:38.610/1.610 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2013-02-14 16:30:38.469, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5400, Role=OracleHandsonCoherenceCache, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) joined cluster "cluster:0x47DB" with senior Member(Id=1, Timestamp=2013-02-14 16:30:11.094, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:5024, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2013-02-14 16:30:38.844/1.844 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=2, Timestamp=2013-02-14 16:30:38.469, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5400, Role=OracleHandsonCoherenceCache)
OldestMember=Member(Id=1, Timestamp=2013-02-14 16:30:11.094, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:5024, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2013-02-14 16:30:11.094, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:5024, Role=CoherenceServer)
Member(Id=2, Timestamp=2013-02-14 16:30:38.469, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5400, Role=OracleHandsonCoherenceCache)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2013-02-14 16:30:11.094|JOINED,
2|12.1.2|2013-02-14 16:30:38.469|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2013-02-14 16:30:38.891/1.891 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2013-02-14 16:30:38.938/1.938 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/reports/report-group.xml"
2013-02-14 16:30:39.125/2.125 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:EclipseLinkJPA, member=2): Service EclipseLinkJPA joined the cluster with senior service member 1
2013-02-14 16:30:39.172/2.172 Oracle Coherence GE 12.1.2.0.0 <D4> (thread=DistributedCache:EclipseLinkJPA, member=2): Asking member 1 for primary ownership of PartitionSet{0..127}
Hello Cache

9.3 データベース・キャッシュの作成

この項では、Oracle Databaseによってバッキングされるキャッシュを作成します。これは、Oracle Databaseキャッシュとも呼ばれます。

1. Oracle Databaseキャッシュの作成

2. カスタム・キャッシュ・ストアを定義するクラスの作成

3. キャッシュ構成ファイルの変更

4. データベース・キャッシュを構成するクラスの作成

5. データベース・キャッシュ・アプリケーションの実行

9.3.1 Oracle Databaseキャッシュの作成

SQL*PlusおよびOracle Database Express Edition (Oracle XE)を使用してOracle Databaseキャッシュを作成する手順は次のとおりです。システムにデータベースがインストールされている必要があります。

1. SQL*Plusを起動します。
「スタート」→「すべてのプログラム」→「Oracle Database Express Edition」→「SQLコマンド行の実行」と移動します。

2. ユーザーhr、パスワードhrを使用して接続します。

connect hr/hr;

3. Oracle Database表を作成します。
テキスト・エディタを開き、次のSQLコードをコピーします。これを、/home/oracle/workspace/フォルダに、dbscript.sqlと名前を付けて保存します。

例9-4 データベース表を作成するSQLスクリプト

CREATE TABLE HR.CATALOG(id VARCHAR(25) PRIMARY KEY, value VARCHAR(96));
INSERT INTO HR.CATALOG VALUES('catalog1', 'Tuning Undo Tablespace');
INSERT INTO HR.CATALOG VALUES('catalog2', 'Tuning Your View Objects');

4. SQLスクリプトを実行します。
例9-5は、スクリプトからの出力を示しています。

例9-5 データベース表を作成するSQLスクリプトの実行

SQL*Plus: Release 11.2.0.2.0 - Production on Wed Dec 19 17:42:21 2012
Copyright (c) 1982, 2010, Oracle.  All rights reserved.

SQL> connect hr/hr;
Connected.
SQL> @/home/oracle/workspace/dbscript.sql

Table created

1 row created

1 row created

9.3.2 カスタム・キャッシュ・ストアを定義するクラスの作成

データベースに接続し、表データを取得するJavaクラスを作成するには:

1. Eclipseで、「Interaction」プロジェクトにJava classのDBCacheStoreを作成します。詳細は、「Javaクラスの作成」を参照してください。

2. データベースに接続し、表データを取得するコードを作成します。
例9-6は、考えられるDBCacheStoreクラスの実装を示しています。Eclipse IDEで、このコードをDBCacheStoreアプリケーションにコピーします。DBCacheStoreアプリケーションは、Java Database Connectivity (JDBC)を使用してOracle Databaseにアクセスしますが、HibernateやJava Data Objects (JDO)などの別のメカニズムを使用することもできます。

例9-6 データベース・キャッシュ・ストアの実装

package com.oracle.handson;

import com.tangosol.net.cache.CacheStore;import com.tangosol.util.Base;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class DBCacheStore

extends Base
implements CacheStore {

protected Connection m_con;
protected String m_sTableName;
private static final String DB_DRIVER   = "oracle.jdbc.OracleDriver";

private static final String DB_URL      = "jdbc:oracle:thin:@localhost:1521:XE";
private static final String DB_USERNAME = "hr";
private static final String DB_PASSWORD = "hr";

public DBCacheStore(String sTableName)
{
m_sTableName = sTableName;

configureConnection();        }
protected void configureConnection()
{
try
{
Class.forName("oracle.jdbc.OracleDriver");
m_con = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD);
m_con.setAutoCommit(true);
}
catch (Exception e)
{
throw ensureRuntimeException(e, "Connection failed");
}
}

public String getTableName()        {
return m_sTableName;
}

public Connection getConnection()
{
return m_con;
}

public Object load(Object oKey)
{
Object     oValue = null;
Connection con    = getConnection();
String     sSQL   = "SELECT id, value FROM " + getTableName()
+ " WHERE id = ?";
try
{
PreparedStatement stmt = con.prepareStatement(sSQL);

stmt.setString(1, String.valueOf(oKey));
ResultSet rslt = stmt.executeQuery();
if (rslt.next())
{
oValue = rslt.getString(2);
if (rslt.next())
{
throw new SQLException("Not a unique key: " + oKey);
}                }
stmt.close();
}
catch (SQLException e)
{
throw ensureRuntimeException(e, "Load failed: key=" + oKey);
}
return oValue;
}

public void store(Object oKey, Object oValue)
{
Connection con     = getConnection();
String     sTable  = getTableName();
String     sSQL;

if (load(oKey) != null)
{

sSQL = "UPDATE " + sTable + " SET value = ? where id = ?";
}
else
{

sSQL = "INSERT INTO " + sTable + " (value, id) VALUES (?,?)";
}
try
{
PreparedStatement stmt = con.prepareStatement(sSQL);
int i = 0;
stmt.setString(++i, String.valueOf(oValue));
stmt.setString(++i, String.valueOf(oKey));
stmt.executeUpdate();
stmt.close();
}
catch (SQLException e)
{
throw ensureRuntimeException(e, "Store failed: key=" + oKey);
}
}
public void erase(Object oKey)
{
Connection con  = getConnection();
String     sSQL = "DELETE FROM " + getTableName() + " WHERE id=?";
try
{
PreparedStatement stmt = con.prepareStatement(sSQL);

stmt.setString(1, String.valueOf(oKey));
stmt.executeUpdate();
stmt.close();
}
catch (SQLException e)
{
throw ensureRuntimeException(e, "Erase failed: key=" + oKey);
}
}
public void eraseAll(Collection colKeys)
{
throw new UnsupportedOperationException();
}

public Map loadAll(Collection colKeys)        {
throw new UnsupportedOperationException();
}

public void storeAll(Map mapEntries)
{
throw new UnsupportedOperationException();
}

public Iterator keys()
{
Connection con  = getConnection();
String     sSQL = "SELECT id FROM " + getTableName();
List       list = new LinkedList();

try
{
PreparedStatement stmt = con.prepareStatement(sSQL);
ResultSet         rslt = stmt.executeQuery();
while (rslt.next())
{
Object oKey = rslt.getString(1);
list.add(oKey);
}
stmt.close();
}
catch (SQLException e)
{
throw ensureRuntimeException(e, "Iterator failed");
}

return list.iterator();
}

}

9.3.3 キャッシュ構成ファイルの変更

前の手順でデータベース・キャッシュに作成したキャッシュ構成ファイル(cache-config.xml)を変更します。キャッシュをデータベースに接続するには、com.tangosol.net.cache.CacheLoaderまたはcom.tangosol.net.cache.CacheStoreのいずれかのインタフェースを実装するカスタム・クラスでcachestore-scheme要素を構成する必要があります。

Eclipseに既存のcache-config.xmlファイル内のコードを、例9-7のデータベース・キャッシュのキャッシュ構成コードに置換します。

例9-7 データベース・キャッシュの構成ファイル

<?xml version="1.0" encoding="UTF-8" ?>
<cache-config>
<caching-scheme-mapping>

<!--
Caches with names that start with 'DBBacked' will be created
as distributed-db-backed.
-->
<cache-mapping>
<cache-name>DBBacked*</cache-name>
<scheme-name>distributed-db-backed</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<!--
DB Backed Distributed caching scheme.
-->
<distributed-scheme>
<scheme-name>distributed-db-backed</scheme-name>
<service-name>DistributedCache</service-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<internal-cache-scheme>
<class-scheme>
<class-name>com.tangosol.util.ObservableHashMap</class-name>
</class-scheme>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>com.oracle.handson.DBCacheStore</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>CATALOG</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
<read-only>false</read-only>
<!--
To make this a write-through cache just change the value below to 0 (zero)
-->
<write-delay-seconds>0</write-delay-seconds>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>

キャッシュ構成ファイルで、次のように実行されています。

- キャッシュ名パターンDBBacked*を定義しました。これは分散キャッシュ・スキームdistributed-db-backedにマップされています。

- CacheStoreインタフェースを実装するクラスcoherence.DBCacheStoreを使用して、分散スキームでCacheStoreを指定しました。

- DBCacheStoreクラスに、キャッシュのバック・エンドにあるデータベース表のinitパラメータを指定しました。表の名前はinit-param要素で指定されています。DBCacheStoreクラスは、キャッシュ・エントリの読取り、書込みなどのデータベース操作を実行します。

- バッキング・マップとして、read-write-backing-map-schemeを指定しました。このスキームは、バッキング・マップを定義し、永続ストアにサイズ制限のあるキャッシュを提供します。ここで、write-delay-secondsパラメータを0に設定すると、ライトスルー・メカニズムが指定されます。
表9-2は、Coherenceで使用可能な読取り/書込みキャッシュのタイプを示しています。

表9-2 Coherenceによってサポートされる読取り/書込みキャッシュのタイプ

読取り/書込みキャッシュのタイプ

アクション

リードスルー

要求されアプリケーションでの利用が可能になると、キャッシュ・エントリがデータベースからキャッシュに読み取られます。

ライトスルー

キャッシュ・エントリの更新が遅延なくデータベースと同期します。

リフレッシュアヘッド

キャッシュ・エントリが定期的にリフレッシュされます。

ライトビハインド

キャッシュ構成ファイルのwrite-delay-seconds要素で指定された遅延の後、キャッシュ・エントリへの更新が非同期でデータベースに書き込まれます。

9.3.4 データベース・キャッシュを構成するクラスの作成

Eclipseで、「Interaction」プロジェクトにデータベース・キャッシュ用Java classのDatabaseCacheを作成します。このクラスにはmainメソッドが格納されている必要があります。詳細は、「Javaクラスの作成」を参照してください。

クラス・ファイルで、キャッシュ・エントリの追加、データベース・キャッシュの問合せ、キャッシュ・エントリの取得を実行するコードを指定します。メソッドcreateCache()、addEntry()、retrieveEntry()、eraseEntry()およびqueryCache()を追加します。例9-8は、考えられる実装を示しています。

例9-8 データベース・キャッシュ・クラス・ファイルの実装

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.net.cache.ContinuousQueryCache;
import com.tangosol.util.Filter;
import com.tangosol.util.extractor.IdentityExtractor;
import com.tangosol.util.filter.LikeFilter;

import java.util.HashSet;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class DatabaseCache {
NamedCache cache;
public DatabaseCache() {
}

public void createCache()
{
cache = CacheFactory.getCache("DBBackedCache");
}

public void addEntry()
{
cache.put(new String("catalog3"), new String("Tuning Grid Management"));
cache.put(new String("catalog4"), new String("Tuning Coherence"));
cache.put(new String("catalog5"), new String("Tuning Database"));
}

public void retrieveEntry()
{
System.out.println((String) cache.get( "catalog3"));
}

public void eraseEntry()
{
cache.remove(new String("catalog3"));
}

public void queryCache()
{
Filter filter = new LikeFilter(IdentityExtractor.INSTANCE, "Tuning%", '\\', true);
HashSet hashSet=new HashSet();
hashSet.add(new String("catalog3"));
hashSet.add(new String("catalog4"));
hashSet.add(new String("catalog5"));

Map map=cache.getAll(hashSet);
Set results = cache.entrySet(filter);

for (Iterator i = results.iterator(); i.hasNext();)
{
Map.Entry e = (Map.Entry) i.next();
System.out.println("Catalog ID: "+e.getKey() + ", Title: "+e.getValue());
}
}

public static void main(String[] args)
{
DatabaseCache databaseCache = new DatabaseCache();
databaseCache.createCache();
databaseCache.addEntry();
databaseCache.queryCache();
}
}

データベース・キャッシュ・クラス・ファイルの次の機能に注意してください。

- NamedCacheオブジェクトは、createCacheメソッド内のCacheFactoryクラスのgetCacheメソッドを使用して作成されます。

NamedCache cache = CacheFactory.getCache("DBBackedCache");

- DBBackedCacheは、キャッシュ・パターンDBBacked*と一致するため、cache-config.xmlファイルの分散キャッシュ・スキームdistributed-db-backedにマップされます。NamedCacheオブジェクトのput()メソッドを使用してキャッシュ・エントリを追加します。

cache.put(new String("catalog3"), new String("Tuning Grid Management"));

- ライトスルー・メカニズムが使用されるため、新しいキャッシュ・エントリはデータベースと同期し、CATALOG表に新規行が追加されます。メソッドcreateCacheおよびaddEntryを除くすべてのメソッドをコメント・アウトします。

- putメソッドが起動されると、DBCacheStoreクラスで、JDBCを使用してデータベース表CATALOGに新規のキャッシュ・エントリをマップするstoreメソッドが起動されます。Coherenceアプリケーションからの出力が「ログ」ウィンドウに表示され、新しいキャッシュ・エントリが追加されます。出力には、操作構成デプロイメント・ディスクリプタがロードされたこと、新しいクラスタが作成されたことおよびDistributedCacheサービスがクラスタに結合されたことが示されます。

- 新規のキャッシュ・エントリは、NamedCacheオブジェクトのremoveメソッドを使用して削除できます。

cache.remove(new String("catalog3"));

- キャッシュ・エントリのバルク・アップロードは、putAllメソッドを使用して実行されます。

- NamedCacheオブジェクトのgetメソッドを使用してキャッシュ・エントリが取得されます。たとえば、ID catalog1のキャッシュ・エントリを取得する方法は次のとおりです。

System.out.println((String) cache.get("catalog1"));

- get()メソッドが起動されると、DBCacheStoreクラスでJDBCを使用してデータベース表データを取得するloadメソッドが起動されます。

- バルク取得は、NamedCacheオブジェクトのgetAllメソッドを使用して実行されます。

- Coherenceでは、フィルタを使用して、検索基準に基づくキャッシュ・エントリの検索がサポートされます。Coherenceのフィルタは、com.tangosol.util.filterパッケージで提供されています。Oracle Coherence Enterprise EditionおよびGrid Editionでは、Coherenceキャッシュに索引を追加してパフォーマンスを向上できます。キャッシュ・エントリを指定パターンと照合するLikeFilterフィルタを使用してデータベース・キャッシュに問合せを実行します。データベース・キャッシュへの問合せを実行するには、問合せの前にキャッシュ・エントリを作成し、フィルタを使用した問合せの実行を可能にするには、事前にget()またはgetAll()メソッドを使用してキャッシュ・エントリをキャッシュに取得しておく必要があります。したがって、getAll()メソッドを使用すると、データベース・データの取得とキャッシュ・エントリのコレクションの作成を実行できます。

HashSet hashSet=new HashSet();
hashSet.add(new String("catalog1"));
hashSet.add(new String("catalog2"));
hashSet.add(new String("catalog3"));
Map map=cache.getAll(hashSet);

- Tuningで開始するキャッシュ・エントリ検索のためのフィルタLikeFilterを作成します。

Filter filter = new LikeFilter(IdentityExtractor.INSTANCE, "Tuning%", '\\', true);

- LikeFilterフィルタを指定し、entrySet()メソッドを使用してデータベース・キャッシュへの問合せを実行します。

Set results = cache.entrySet(filter);

- 問合せの結果に対して反復処理を行います。取得されたキャッシュ・エントリのキーと値を表示します。

for (Iterator i = results.iterator(); i.hasNext();)
{
Map.Entry e = (Map.Entry) i.next();
System.out.println("Catalog ID: "+e.getKey() + ", Title: "+e.getValue());
}

- Coherenceでは、com.tangosol.net.cache.ContinuousQueryCacheクラスを使用した連続問合せがサポートされます。連続問合せは、連続的問合せキャッシュを使用して最新の状態に保持される問合せです。ContinuousQueryCacheでは、問合せの結果を変更する可能性があるイベントに対するイベント・リスナーを使用して、問合せの結果が更新されます。NamedCacheオブジェクトおよびLikeFilterオブジェクトを使用して、ContinuousQueryCacheオブジェクトを作成します。

ContinuousQueryCache queryCache = new ContinuousQueryCache(cache, filter);

- entrySet()メソッドを使用して結果セットを作成します。

Set results = queryCache.entrySet(filter);

9.3.5 データベース・キャッシュ・アプリケーションの実行

Oracle Databaseキャッシュ・アプリケーションを実行するには:

1. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

2. キャッシュ・サーバー(JPAServer)を起動します。プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、JPACacheServerを選択してその構成を表示します。「Run」をクリックします。

3. DatabaseCacheプログラムの実行構成を作成します。

1. 「Run Configurations」ダイアログ・ボックスで、「New launch configuration」アイコンをクリックします。

2. 「Name」フィールドにDatabaseCacheClientと入力します。「Project」フィールドにInteractionが、「Main class」フィールドにcom.oracle.handson.DatabaseCacheが存在することを確認します。

3. 「Coherence」タブの「Cache configuration descriptor」フィールドに、キャッシュ構成ファイルへのパスC:\home\oracle\workspace\Interaction\cache-config.xmlを入力します。「Local storage: Disabled (cache client)」」を選択します。「Cluster port」フィールドに3155などの一意の値を入力します。

4. 「Classpath」タブを開きます。「Classpath」タブが図9-4のように表示されます。

図9-4 DatabaseCacheプログラムへのクラスパス

5. 「Apply」をクリックし、「Run」をクリックします。
例9-9は、予測される結果を示しています。

例9-9 DatabaseCacheプログラムの出力

...
Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=2, Timestamp=2013-02-14 17:55:03.149, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5544, Role=OracleHandsonDatabaseCache)
OldestMember=Member(Id=1, Timestamp=2013-02-14 17:49:57.125, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:5644, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=2
Member(Id=1, Timestamp=2013-02-14 17:49:57.125, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:5644, Role=CoherenceServer)
Member(Id=2, Timestamp=2013-02-14 17:55:03.149, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5544, Role=OracleHandsonDatabaseCache)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2013-02-14 17:49:57.125|JOINED,
2|12.1.2|2013-02-14 17:55:03.149|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[1]}
IpMonitor{Addresses=0}

2013-02-14 17:55:03.532/1.719 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2013-02-14 17:55:03.563/1.750 Oracle Coherence GE 12.1.2.0.0 <Info> (thread=main, member=2): Loaded Reporter configuration from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/reports/report-group.xml"
2013-02-14 17:55:03.782/1.969 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache, member=2): Service DistributedCache joined the cluster with senior service member 1
Catalog ID: catalog3, Title: Tuning Grid Management
Catalog ID: catalog4, Title: Tuning Coherence
Catalog ID: catalog5, Title: Tuning Database

例9-10は、DatabaseCacheプログラムに対するキャッシュ・サーバーの応答を示しています。

例9-10 DatabaseCacheプログラムに対するキャッシュ・サーバーの応答

...
Started DefaultCacheServer...

2013-02-14 17:55:03.250/307.297 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-14 17:55:03.149, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5544, Role=OracleHandsonDatabaseCache) joined Cluster with senior member 1
2013-02-14 17:55:03.532/307.579 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 joined Service Management with senior member 1
2013-02-14 17:55:03.813/307.860 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache, member=1): Member 2 joined Service DistributedCache with senior member 1
2013-02-14 17:55:06.750/310.797 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2013-02-14 17:55:03.149, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5544, Role=OracleHandsonDatabaseCache) due to a peer departure; removing the member.
2013-02-14 17:55:06.750/310.797 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-14 17:55:06.75, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:5544, Role=OracleHandsonDatabaseCache) left Cluster with senior member 1
2013-02-14 17:55:06.766/310.813 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=1): Member 2 left service Management with senior member 1
2013-02-14 17:55:06.766/310.813 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache, member=1): Member 2 left service DistributedCache with senior member 1

次のような例外が表示された場合:

java.lang.IllegalArgumentException: No scheme for cache: "cachename,

cache-config.xmlファイルを編集し、<cache-name>要素のDBBacked*を*に置換することによって、これらを解消できる場合があります。EclipseでDatabaseCacheアプリケーションを再実行します。例外が表示されないはずです。

4. ライトスルー・キャッシュを使用しているため、データベース表も更新されることに注意してください。SQLプロンプトから、次のコードを入力します。

select * from hr.catalog;

例9-11は、結果を示しています。

例9-11 SELECT文からの出力

SQL> select * from hr.catalog;
ID
-------------------------
VALUE
-------------------------------------------------------------------------------

catalog1
Tuning Undo Tablespace

catalog2
Tuning Your View Objects

catalog3
Tuning Grid Management

ID
-------------------------
VALUE
-------------------------------------------------------------------------------

catalog4
Tuning Coherence

catalog5
Tuning Database

SQL>

10 セキュリティに関する作業

この演習では、Oracle Coherence*Extendクライアントにセキュリティを適用する方法について説明します。ここでは、Coherence APIのSecurityHelper、PofPrincipal、IdentityTransformer、IdentityAsserterおよびWrapperCacheServiceの使用について取り上げます。

Coherence*Extendでは、Coherenceキャッシュに対する広範なアクセスが許可されます。これには、デスクトップ・アプリケーション、リモート・サーバーおよびWide Area Network (WAN)接続を介して配置されているマシンが含まれます。

この章には次の項が含まれます:

- 概要

- トークンベース・セキュリティの有効化

- クラスタに対するロールベース・アクセス制御の組込み

- 起動可能オブジェクトに対するロールベース・アクセス制御の組込み

10.1 概要

Coherence*Extendは、クラスタの外部で実行されるExtendクライアントと、1台以上のキャッシュ・サーバーでホストされ、クラスタ内で実行されるプロキシ・サービスで構成されます。クライアントAPIにより、すべてのリクエストがプロキシにルーティングされます。プロキシは、パーティション化またはレプリケートされたキャッシュ・サービス、起動サービスなどのCoherenceのクラスタ化されたサービスに委任することによって、クライアント・リクエストに応答します。

Extendクライアントはクラスタの外部に存在するため、クラスタへのアクセス保護の問題が非常に重要になります。この章では、クライアントとクラスタ間のアクセス保護に使用可能な3つの技術を説明します。その技術とは、IDトークンベース・パスワード、資格が付与されるキャッシュ・サービスおよび起動サービスの使用などです。

これらのセキュリティ技術およびExtendクライアントの詳細な解説は、このチュートリアルの対象範囲ではありません。これらのトピックの詳細は、『Oracle Fusion Middleware Oracle Coherenceの保護』を参照してください。

10.2 トークンベース・セキュリティの有効化

トークンベースのセキュリティを実装すると、Extendクライアントとクラスタ内の拡張プロキシ間のアクセスを有効化できます。一般に、Extendクライアントと拡張プロキシ間のアクセスを有効化するには、次のファイルが必要です。

- クライアント・アプリケーション・ファイル。クラスタにアクセスする機能を記述します。

- キャッシュ構成ファイル。Extendクライアントと拡張プロキシのそれぞれに独自のキャッシュ構成がある場合。

- オペレーション・オーバーライド・ファイル。デフォルトのオペレーショナル・デプロイメント・ディスクリプタの操作時および実行時の設定をオーバーライドします。

- サーバー起動ファイル。拡張プロキシおよびクラスタ内のキャッシュ・サーバーに対して起動ファイルが存在する場合。

- POF構成デプロイメント・ディスクリプタ。POFを使用してオブジェクトをシリアライズする際にカスタム・データ型を指定します。

トークンベース・セキュリティを追加するには、IDトランスフォーマおよびアサータの実装を指定する必要があります。このトランスフォーマは、クライアント側でトークンを生成し、アサータはクラスタ側でそれを検証します。

トークンベース・セキュリティを使用してクラスタにアクセスするExtendクライアントのアプリケーションを作成し、実行する手順は次のとおりです。

1. セキュリティ・ヘルパー・ファイルの使用

2. IDトランスフォーマの作成

3. IDアサータの作成

4. パスワード・ファイルの作成

5. IDトランスフォーマおよびアサータの有効化

6. Extendクライアントのキャッシュ構成ファイルの作成

7. 拡張プロキシのキャッシュ構成ファイルの作成

8. プロキシ・サービスを含むキャッシュ・サーバーの起動構成の作成

9. キャッシュ・サーバーの起動構成の作成

10. パスワード・サンプルの実行

10.2.1 セキュリティ・ヘルパー・ファイルの使用

この章の例では、ロールベース・セキュリティ・ポリシーおよびキャッシュへのアクセス制御を定義するヘルパー・ファイルを参照します。これらの例に使用するための簡略マッピングのファイルが用意されています。

キャッシュ・アクセスはユーザーのロールによって決定されます。セキュリティ・ヘルパー・ファイルによっていくつかのロール(role_reader、role_writerおよびrole_admin)が定義されます。BuckarooBanzaiをROLE_ADMINにマッピングするなど、様々なユーザーのロールへのマッピングが定義されます。ROLE_ADMINを9にマッピングするなど、ロールの整数IDへのマッピングが定義されます。また、ヘルパー・ファイルでは、例で使用されるキャッシュ名および起動サービス名も定義されます。

このファイルの主要機能は、loginおよびcheckAccessのメソッドです。loginメソッドは、ユーザー名を取得して、簡略化された識別名(DN)を構成します。その後、ロールを名前と関連付けます。PofPrincipalは、Principal実装を提供します。

checkAccessメソッドは、認可コードが配置されている場所を示します。これによって、提供されたユーザー・ロールに基づいてユーザーがキャッシュにアクセス可能であるかどうかが判定されます。

新規のプロジェクトおよびセキュリティ・ヘルパー・ファイルを作成するには:

1. Eclipse IDEで、Java EEパースペクティブを選択してSecurityという名前の新規アプリケーション・クライアント・プロジェクトを作成します。「Configuration」ドロップダウン・リストから「CoherenceConfig」を選択します。「Application Client」モジュール・ページで、「Create a default main」が選択されていないことを確認します。
「Coherence」ページで、「Coherence12.1.2」のみを選択します。

プロジェクト作成の詳細は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。

2. SecurityExampleHelper.javaという名前で新規Javaファイルを作成します。パッケージ・パスがcom.oracle.handsonであることを確認します。
Javaクラスの作成の詳細は、「Javaクラスの作成」を参照してください。

3. 例10-1に示されたコードをファイルにコピーします。

例10-1 セキュリティ・ヘルパー・ファイル

package com.oracle.handson;

import com.tangosol.io.pof.PofPrincipal;

import com.tangosol.net.security.SecurityHelper;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import java.security.Principal;

import javax.security.auth.Subject;

/**
* This class provides extremely simplified role based policies and access control.
*
*/
public class SecurityExampleHelper
{
// ----- static methods -------------------------------------------------

/**
* Login the user.
*
* @param sName  the user name
*
* @return the authenticated user
*/
public static Subject login(String sName)
{
// For simplicity, just create a Subject. Normally, this would be
// done using JAAS.
String sUserDN       = "CN=" + sName + ",OU=Yoyodyne";
Set setPrincipalUser = new HashSet();

setPrincipalUser.add(new PofPrincipal(sUserDN));
// Map the user to a role
setPrincipalUser.add(new PofPrincipal((String) s_mapUserToRole.get(sName)));

return new Subject(true, setPrincipalUser, new HashSet(), new HashSet());
}

/**
* Assert that a Subject is associated with the calling thread with a
* Principal representing the required role.
*
* @param sRoleRequired  the role required for the operation
*
* @throws SecurityException if a Subject is not associated with the
*         calling thread or does not have the specified role Principal
*/
public static void checkAccess(String sRoleRequired)
{
checkAccess(sRoleRequired, SecurityHelper.getCurrentSubject());
}

/**
* Assert that a Subject contains a Principal representing the required
* role.
*
* @param sRoleRequired  the role required for the operation
*
* @param subject        the Subject requesting access
*
* @throws SecurityException if a Subject is null or does not have the
* specified role Principal
*/
public static void checkAccess(String sRoleRequired, Subject subject)
{
if (subject == null)
{
throw new SecurityException("Access denied, authentication required");
}

Map     mapRoleToId   = s_mapRoleToId;
Integer nRoleRequired = (Integer) mapRoleToId.get(sRoleRequired);

for (Iterator iter = subject.getPrincipals().iterator(); iter.hasNext();)
{
Principal principal = (Principal) iter.next();
String    sName     = principal.getName();

if (sName.startsWith("role_"))
{
Integer nRolePrincipal = (Integer) mapRoleToId.get(sName);

if (nRolePrincipal == null)
{
// invalid role
break;
}

if (nRolePrincipal.intValue() >= nRoleRequired.intValue())
{
return;
}
}
}

throw new SecurityException("Access denied, insufficient privileges");
}

// ----- constants  -----------------------------------------------------

public static final String ROLE_READER = "role_reader";

public static final String ROLE_WRITER = "role_writer";

public static final String ROLE_ADMIN  = "role_admin";

/**
* The cache name for security examples
*/
public static final String SECURITY_CACHE_NAME = "security";

/**
* The name of the InvocationService used by security examples.
*/
public static String INVOCATION_SERVICE_NAME = "ExtendTcpInvocationService";

// ----- static data  ---------------------------------------------------

/**
* The map keyed by user name with the value being the user's role.
* Represents which user is in which role.
*/
private static Map s_mapUserToRole = new HashMap();

/**
* The map keyed by role name with the value the role id.
* Represents the numeric role identifier.
*/
private static Map s_mapRoleToId = new HashMap();

// ----- static initializer ---------------------------------------------

static
{
// User to role mapping
s_mapUserToRole.put("BuckarooBanzai", ROLE_ADMIN);
s_mapUserToRole.put("JohnWhorfin", ROLE_WRITER);
s_mapUserToRole.put("JohnBigboote", ROLE_READER);

// Role to Id mapping
s_mapRoleToId.put(ROLE_ADMIN, Integer.valueOf(9));
s_mapRoleToId.put(ROLE_WRITER, Integer.valueOf(2));
s_mapRoleToId.put(ROLE_READER, Integer.valueOf(1));
}
}

10.2.2 IDトランスフォーマの作成

IDトランスフォーマ(com.tangosol.net.security.IdentityTransformer)は、クライアント側のコンポーネントで、サブジェクトまたはプリンシパルをIDトークンに変換します。このトークンは、Coherenceでシリアライズ可能なデータ型である必要があります。Coherenceは、実行時にこのトークンを自動的にシリアライズして、接続リクエストの一部としてプロキシに送信します。

IDトランスフォーマの実装を作成するには:

1. Securityプロジェクトに、PasswordIdentityTransformerという名前のJavaクラスを新規作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. IdentityTransformerインタフェースをインポートします。PasswordIdentityTransformerクラスがIdentityTransformerインタフェースを実装することを確認します。

3. transformIdentityメソッドを実装して、次のタスクを実行するようにします。

- サブジェクトが存在し、完全であるかどうかのテスト

- サブジェクトからのプリンシパル名の取得およびString配列への保存

- POFデータ型としてシリアライズ可能な、パスワードとプリンシパル名の組合せによるトークンの構成

例10-2は、考えられるPasswordIdentityTransformerクラスの実装を示しています。

例10-2 IDトランスフォーマの実装例

package com.oracle.handson;

import com.tangosol.net.security.IdentityTransformer;

import java.security.Principal;
import java.util.Iterator;
import java.util.Set;

import javax.security.auth.Subject;
import com.tangosol.net.Service;

/**
* PasswordIdentityTransformer creates a security token that contains the
* required password and then adds a list of Principal names.
*
*/
public class PasswordIdentityTransformer
implements IdentityTransformer

{
// ----- IdentityTransformer interface ----------------------------------

/**
* Transform a Subject to a token that asserts an identity.
*
* @param subject the Subject representing a user.
*
* @return the token that asserts identity.
*
* @throws SecurityException if the identity transformation fails.
*/
public Object transformIdentity(Subject subject, Service service)
throws SecurityException
{
// The service is not needed so the service argument is being ignored.
// It could be used, for example, if there were different token types
// required per service.

if (subject == null)
{
throw new SecurityException("Incomplete Subject");
}

Set setPrincipals = subject.getPrincipals();

if (setPrincipals.isEmpty())
{
throw new SecurityException("Incomplete Subject");
}

String[] asPrincipalName = new String[setPrincipals.size() + 1];
int      i                = 0;

asPrincipalName[i++] = System.getProperty("coherence.password",
"secret-password");

for (Iterator iter = setPrincipals.iterator(); iter.hasNext();)
{
asPrincipalName[i++] = ((Principal) iter.next()).getName();
}

// The token consists of the password plus the principal names as an
// array of pof-able types, in this case strings.
return asPrincipalName;
}
}

10.2.3 IDアサータの作成

IDアサータ(com.tangosol.net.security.IdentityAsserter)は、拡張プロキシ・サービスをホストするキャッシュ・サーバー上のクラスタ側のコンポーネントです。アサータは、ExtendクライアントでIDトランスフォーマによって作成されたトークンに、クラスタへのアクセスに必要な資格証明が格納されているかを検証します。

IDアサータの実装を作成するには:

1. Securityプロジェクトに、PasswordIdentityAsserterという名前のJavaクラスを新規作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. IdentityAsserterインタフェースをインポートします。PasswordIdentityAsserterクラスがIdentityAsserterインタフェースを実装することを確認します。

3. 次のタスクが実行されるように、assertIdentityメソッドを実装します。

- トークンに正しいパスワードが格納されていることおよびパスワードがトークン内の最初の名前であることを検証します。

例10-3は、考えられるPasswordIdentityAsserterクラスの実装を示しています。

例10-3 IDアサータの実装例

package com.oracle.handson;

import com.tangosol.io.pof.PofPrincipal;

import com.tangosol.net.security.IdentityAsserter;

import java.util.HashSet;
import java.util.Set;

import javax.security.auth.Subject;
import com.tangosol.net.Service;

/**
* PasswordIdentityAsserter asserts that the security token contains the
* required password and then constructs a Subject based on a list of
* Principal names.
*
*/
public class PasswordIdentityAsserter
implements IdentityAsserter
{
// ----- IdentityAsserter interface -------------------------------------

/**
* Asserts an identity based on a token-based identity assertion.
*
* @param oToken the token that asserts identity.
*
* @return a Subject representing the identity.
*
* @throws SecurityException if the identity assertion fails.
*/
public Subject assertIdentity(Object oToken, Service service)
throws SecurityException
{
// The service is not needed so the service argument is being ignored.
// It could be used, for example, if there were different token types
// required per service.
if (oToken instanceof Object[])
{
String   sPassword        = System.getProperty(
"coherence.password", "secret-password");
Set      setPrincipalUser = new HashSet();
Object[] asName           = (Object[]) oToken;

// first name must be password
if (((String) asName[0]).equals(sPassword))
{
// prints the user name to server shell to ensure we are
// communicating with it and to ensure user is validated
System.out.println("Password validated for user: " + asName[1]);
for (int i = 1, len = asName.length; i < len; i++)
{
setPrincipalUser.add(new PofPrincipal((String)asName[i]));
}

return new Subject(true, setPrincipalUser, new HashSet(),
new HashSet());
}
}
throw new SecurityException("Access denied");
}
}

10.2.4 パスワード・ファイルの作成

キャッシュの参照の取得時にパスワードを必要とするJavaファイルを作成します。SecurityExampleHelper.login("BuckarooBanzai")を使用して、トークンを生成するSecurityExampleHelperファイルのloginメソッドをコールします。実行時に、ユーザー名がSecurityExampleHelperクラスで定義されたサブジェクトと関連付けられます。トークンは、PasswordIdentityTransformerクラスによってこのサブジェクトから生成され、PasswordIdentityAsserterクラスによって接続リクエストの一部として検証されます。検証が成功すると、プロキシへの接続およびキャッシュの参照の権限が付与されます。Subject.doasメソッドを使用して、セキュリティ・コンテキストでサブジェクトを利用できるようにします。

1. PasswordExampleという名前のSecurityプロジェクトに、mainメソッドを使用して新たなJavaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. キャッシュの参照を取得するmainメソッドを実装します。

3. SecurityExampleHelper.loginメソッドを使用して、ユーザーBuckarooBanzaiのサブジェクトを取得します。

4. doAsメソッドを実装して、Javaセキュリティ・コンテキストのサブジェクト・パートを作成します。このサブジェクトは、後続のいずれのコードでも利用できます。この例では、定義されたロールを基準にして、ユーザーがキャッシュにアクセスできるかどうかを検証するためにdoAsメソッドが実装されます。

例10-4は、考えられるPasswordExampleの実装を示しています。

例10-4 パスワード・サンプルを実行する実装例

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import java.io.IOException;

import java.security.PrivilegedExceptionAction;

import javax.security.auth.Subject;
import com.tangosol.net.Service;

/**
* This class shows how a Coherence Proxy can require a password to get a
* reference to a cache.
* <p>
* The PasswordIdentityTransformer will generate a security token that
* contains the password. The PasswordIdentityAsserter will validate the
* security token to enforce the password. The token generation and
* validation occurs automatically when a connection to the proxy is made.
*
*/
public class PasswordExample
{
// ----- static methods -------------------------------------------------

/**
* Get a reference to the cache. Password will be required.
*/
public static void main (String[] args){
getCache();
}
public static void getCache()
{
System.out.println("------password example begins------");

Subject subject = SecurityExampleHelper.login("BuckarooBanzai");

try
{
NamedCache cache = (NamedCache) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
throws Exception
{
NamedCache cache;

cache = CacheFactory.getCache(
SecurityExampleHelper.SECURITY_CACHE_NAME);
System.out.println("------password example succeeded------");
return cache;
}
});
}
catch (Exception e)
{
// get exception if the password is invalid
System.out.println("Unable to connect to proxy");
e.printStackTrace();
}
System.out.println("------password example completed------");
}

}

10.2.5 IDトランスフォーマおよびアサータの有効化

IDトランスフォーマ(Extendクライアント上でSubjectをトークンに変換するクラス)およびIDアサータ(クラスタ上でトークンを検証するクラス)を定義するクラスを識別する、オペレーション・オーバーライド・ファイル(tangosol-coherence-override.xml)を構成します。

1. 「Project Explorer」ウィンドウから、tangosol-coherence-override.xmlファイルを開きます。ファイルはSecurity/appClientModuleディレクトリの下位にあります。

2. security-configスタンザ内のidentity-transformer要素とidentity-asserter要素を使用して、PasswordIdentityTransformerとPasswordIdentityAsserterのそれぞれの実装クラスへのフルパスを識別します。subject-scopeパラメータをtrueに設定して、現在のセキュリティ・コンテキストのIDをキャッシュおよびクライアントに返されるリモート起動サービス参照に関連付けます。

例10-5は、考えられるtangosol-coherence-override.xmlファイルの実装を示しています。

例10-5 IDトランスフォーマとアサータの指定

<?xml version="1.0" encoding="UTF-8"?>

<coherence xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config http://xmlns.oracle.com/coherence/coherence-operational-config/1.2/coherence-operational-config.xsd">
<!--coherence-version:12.1.2-->
<security-config>
<identity-asserter>
<class-name>com.oracle.handson.PasswordIdentityAsserter</class-name>
</identity-asserter>
<identity-transformer>
<class-name>com.oracle.handson.PasswordIdentityTransformer</class-name>
</identity-transformer>
<subject-scope>true</subject-scope>
</security-config>
</coherence>

10.2.6 Extendクライアントのキャッシュ構成ファイルの作成

Extendクライアントのキャッシュ構成ファイルは、キャッシュ操作をクラスタ内の拡張プロキシにルーティングします。実行時に、キャッシュ操作はローカルで実行されるのではなく、拡張プロキシ・サービスに送信されます。

Extendクライアントのキャッシュ構成ファイルを作成するには:

1. 「Project explorer」ウィンドウから、coherence-cache-config.xmlファイルを開きます。ファイルはSecurity/appClientModuleディレクトリの下位にあります。

2. ファイルをclient-cache-config.xmlという名前で保存します。

3. Extendクライアント・キャッシュ構成を作成します。次のリストは、主な要素の一部を取り上げています。

- cache-name要素を使用して、キャッシュの名前としてsecurityを定義します。クラスタ側のキャッシュ構成でもsecurityという名前のキャッシュが定義されている必要があります。

- remote-cache-schemeタンザを使用して、リモート・キャッシュに関する詳細を定義します。

- tcp-initiatorスタンザのaddress要素とport要素を使用して、ポート9099でlocalhostアドレスのリスニングを行う拡張プロキシ・サービスを識別します。

- defaultsと値pofのserializerを使用して、カスタムPOF構成ファイルのシリアライザ(この章の後述部分で作成します)をコールします。

例10-6は、考えられるclient-cache-config.xmlファイルの実装を示しています。

例10-6 Extendクライアント・キャッシュ構成ファイルのサンプル

<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<defaults>
<serializer>pof</serializer>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>security</cache-name>
<scheme-name>examples-remote</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<remote-cache-scheme>
<scheme-name>examples-remote</scheme-name>
<service-name>ExtendTcpCacheService</service-name>
<initiator-config>
<tcp-initiator>
<remote-addresses>
<socket-address>
<address system-property="tangosol.coherence.proxy.address">localhost</address>
<port system-property="tangosol.coherence.proxy.port">9099</port>
</socket-address>
</remote-addresses>
</tcp-initiator>
</initiator-config>
</remote-cache-scheme>

<remote-invocation-scheme>
<scheme-name>remote-invocation-scheme</scheme-name>
<service-name>ExtendTcpInvocationService</service-name>
<initiator-config>
<connect-timeout>2s</connect-timeout>
<tcp-initiator>
<remote-addresses>
<socket-address>
<address system-property="tangosol.coherence.proxy.address">localhost</address>
<port system-property="tangosol.coherence.proxy.port">9099</port>
</socket-address>
</remote-addresses>
</tcp-initiator>
<outgoing-message-handler>
<request-timeout>5s</request-timeout>
</outgoing-message-handler>
</initiator-config>
</remote-invocation-scheme>
</caching-schemes>
</cache-config>

10.2.7 拡張プロキシのキャッシュ構成ファイルの作成

拡張プロキシ・サービスのキャッシュ構成ファイルを作成するには:

1. 「Project explorer」ウィンドウから、coherence-cache-config.xmlファイルを開きます。ファイルはSecurity/appClientModuleディレクトリの下位にあります。

2. ファイルをexamples-cache-config.xmlという名前で保存します。

3. 拡張プロキシ・キャッシュ構成ファイルを構成します。次のリストは、主な要素の一部を取り上げています。

- cache-name要素を使用して、キャッシュの名前としてsecurityを定義します。Extendクライアントのキャッシュ構成でもsecurityという名前のキャッシュが定義されている必要があります。

- acceptor-configスタンザのaddress要素とport要素を使用して、ポート9099でlocalhostアドレスのリスニングを行う拡張プロキシ・サービスを識別します。

- システム・プロパティtangosol.coherence.extend.enabledのautostart要素を使用して、キャッシュ・サーバーでのプロキシ・サービスの実行を防止します。

- defaultsと値pofのserializerを使用して、カスタムPOF構成ファイルのシリアライザ(この章の後述部分で作成します)をコールします。

例10-7は、考えられるexamples-cache-config.xmlファイルの実装を示しています。

例10-7 プロキシ・サーバーのキャッシュ構成ファイルのサンプル

<?xml version="1.0"?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<defaults>
<serializer>pof</serializer>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>security</cache-name>
<scheme-name>ExamplesPartitionedPofScheme</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<distributed-scheme>
<scheme-name>ExamplesPartitionedPofScheme</scheme-name>
<service-name>PartitionedPofCache</service-name>
<backing-map-scheme>
<local-scheme>
<!-- each node will be limited to 32MB -->
<high-units>32M</high-units>
<unit-calculator>binary</unit-calculator>
</local-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!--
Proxy Service scheme that allows remote clients to connect to the
cluster over TCP/IP.
-->
<proxy-scheme>
<scheme-name>secure-proxy</scheme-name>
<service-name>ProxyService</service-name>

<thread-count system-property="tangosol.coherence.extend.threads">2</thread-count>

<acceptor-config>
<tcp-acceptor>
<local-address>
<address system-property="tangosol.coherence.extend.address">localhost</address>
<port system-property="tangosol.coherence.extend.port">9099</port>
</local-address>
</tcp-acceptor>
</acceptor-config>

<autostart system-property="tangosol.coherence.extend.enabled">false</autostart>
</proxy-scheme>
</caching-schemes>
</cache-config>

10.2.8 キャッシュ・サーバーの起動構成の作成

キャッシュ・サーバー・クラスタ・ノードの起動構成を作成します。この構成には、プロキシ・サービスおよびクラスタ側のキャッシュ構成ファイルを指定するシステム・プロパティを含める必要があります。また、クラス・パス上のアプリケーション・クラス・ファイルおよびXML構成ファイルも含める必要があります。

キャッシュ・サーバーの起動ファイルを作成するには:

1. Eclipseで、起動構成を作成します。Securityプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Name」フィールドにSecurityCacheServerと入力します。

2. 「Main」タブの「Project」フィールドで「Browse」をクリックして「Security」プロジェクトを選択します。「Include system libraries when searching for a main class」を選択して、「Main class」フィールドの「Search」ボタンをクリックします。「Select Main Type」ダイアログ・ボックスの「Select type」フィールドにDefaultCacheServerを入力します。「DefaultCacheServer - com.tangosol.net」を選択して「OK」をクリックします。「Apply」をクリックします。

3. 「Coherence」タブに、クラスタ側のキャッシュ構成ファイルの名前と絶対パスを入力します(この例ではC:\home\oracle\workspace\Security\appClientModule\examples-cache-config.xml)。「Local storage」フィールドで、「Enabled (cache server)」を選択します。「Cluster port」フィールドに3155などの一意の値を入力します。「Apply」をクリックします。

4. 「Classpath」タブが図10-1のように表示されます。

図10-1 セキュリティ・キャッシュ・サーバーのクラスパス

5. 「Common」タブの「Shared file」フィールドで、「Browse」をクリックしてSecurityプロジェクトを選択します。「Apply」をクリックします。

10.2.9 キャッシュ・サーバーでのプロキシ・サービスの起動構成の作成

クラスタ内のキャッシュ・サーバー上で拡張プロキシサービスを起動する構成を作成します。Extendクライアントはこのサービスに接続します。この構成には、プロキシ・サービスおよびクラスタ側のキャッシュ構成ファイルを指定するシステム・プロパティを含める必要があります。また、クラス・パス上のアプリケーション・クラス・ファイルおよびXML構成ファイルも含める必要があります。

この例の場合、プロキシ・サービスの起動が構成されるキャッシュ・サーバーの構成は、キャッシュ・サーバーの起動構成と同じですが、拡張プロキシを有効にするシステム・プロパティが含まれます。

プロキシ・サービスを含むキャッシュ・サーバーの起動ファイルを作成するには:

1. Eclipseで、起動構成を作成します。Securityプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Name」フィールドにSecurityRunProxyと入力します。

2. 「Main」タブの「Project」フィールドで「Browse」をクリックして「Security」プロジェクトを選択します。「Include system libraries when searching for a main class」を選択して、「Main class」フィールドの「Search」ボタンをクリックします。「Select Main Type」ダイアログ・ボックスの「Select type」フィールドにDefaultCacheServerを入力します。「DefaultCacheServer - com.tangosol.net」を選択して「OK」をクリックします。「Apply」をクリックします。

3. 「Coherence」タブに、クラスタ側のキャッシュ構成ファイルの名前と絶対パスを入力します(この例ではC:\home\oracle\workspace\Security\appClientModule\examples-cache-config.xml)。「Local storage」フィールドで、「Enabled (cache server)」を選択します。「Cluster port」フィールドに3155などの一意の値を入力します。「Apply」をクリックします。

4. 「Arguments」タブで、システム・プロパティ-Dtangosol.coherence.extend.enabled=trueを入力して、「VM arguments」フィールドのプロキシ・サービスを指定します。

図10-2 セキュリティ・プロキシ・サーバーの「Arguments」タブ

5. 「Classpath」タブが図10-3のように表示されます。

図10-3 プロキシ・サーバーのクラスパス

6. 「Common」タブの「Shared file」フィールドで、「Browse」をクリックしてSecurityプロジェクトを選択します。「Apply」をクリックします。

10.2.10 パスワード・サンプルの実行

パスワード・サンプルを実行して、トークンの生成、検証、プロキシ・サービスへの引渡しを行います。

1. PasswordExample.javaファイルの実行構成を作成します。

1. 「Project Explorer」でPasswordExample.javaを右クリックして、「Run As」→「Run Configurations」を選択します。

2. 「New launch configuration」アイコンをクリックします。PasswordExampleが「Name」フィールドに、Securityが「Project」フィールドに、com.oracle.handson.PasswordExampleが「Main class」フィールドに表示されていることを確認します。「Apply」をクリックします。

3. 「Coherence」タブの「Cache configuration descriptor」フィールドにクライアント・キャッシュ構成ファイルへのパスC:\home\oracle\workspace\Security\appClientModule\client-cache-config.xmlを入力します「Local cache」フィールドで、「Disabled (cache client)」を選択します。「Cluster port」フィールドに3155などの一意の値を入力します。

4. 「Classpath」タブが図10-4のように表示されます。

図10-4 PasswordExampleプログラムの「Classpath」タブ

2. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

3. セキュリティ・プロキシ・サーバー、セキュリティ・キャッシュ・サーバー、続いてPasswordExample.javaプログラムを実行します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityRunProxy構成を実行します。

2. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityCacheServer構成を実行します。

3. 「Project Explorer」でPasswordExample.javaファイルを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスでPasswordExampleを選択し、「Run」をクリックします。

Eclipseコンソールに、PasswordExampleプログラムの出力が例10-8のように表示されます。これにはパスワード・サンプルの開始、プロキシ・サーバーへのソケットのオープンおよびこの例の完了が示されます。

例10-8 Eclipseコンソールでのパスワード・サンプルの出力

------password example begins------
2012-08-21 17:58:37.081/0.390 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-21 17:58:37.128/0.437 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-21 17:58:37.175/0.484 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Security/build/classes/tangosol-coherence-override.xml"
2012-08-21 17:58:37.175/0.484 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-21 17:58:37.191/0.500 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-21 17:58:37.191/0.500 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-21 17:58:37.425/0.734 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Security/appClientModule/client-cache-config.xml"
2012-08-21 17:58:37.769/1.078 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-21 17:58:37.878/1.187 Oracle Coherence GE 12.1.2.0 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.DefaultSerializer, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@10713de, RemoteAddresses=WrapperSocketAddressProvider{Providers=[[tpfaeffl-lap7/130.35.99.202:9099]]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}}
2012-08-21 17:58:37.894/1.203 Oracle Coherence GE 12.1.2.0 <D5> (thread=main, member=n/a): Connecting Socket to 130.35.99.202:9099
2012-08-21 17:58:37.894/1.203 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
------password example succeeded------
------password example completed------

プロキシ・サーバー・シェルの応答は、例10-9のように表示されます。これには、識別名からのCNおよびOUの値およびパスワードが検証されたかどうかがリスト表示されます。

例10-9 プロキシ・サービス・シェルを実行するキャッシュ・サーバーからの応答

2012-08-21 17:57:44.941/1.750 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-21 17:57:44.987/1.796 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-21 17:57:45.034/1.843 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Security/build/classes/tangosol-coherence-override.xml"
2012-08-21 17:57:45.034/1.843 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-21 17:57:45.050/1.859 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-21 17:57:45.050/1.859 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-21 17:57:45.534/2.343 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Security/appClientModule/examples-cache-config.xml"
2012-08-21 17:57:47.066/3.875 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-21 17:57:48.097/4.906 Oracle Coherence GE 12.1.2.0 <D4> (thread=main, member=n/a): TCMP bound to /130.35.99.202:8088 using SystemDatagramSocketProvider
2012-08-21 17:57:51.550/8.359 Oracle Coherence GE 12.1.2.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0x47DB" with Member(Id=1, Timestamp=2012-08-21 17:57:48.222, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:1500, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1)
2012-08-21 17:57:51.566/8.375 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0x47DB

Group{Address=224.12.1.0, Port=3155, TTL=4}

MasterMemberSet(
ThisMember=Member(Id=1, Timestamp=2012-08-21 17:57:48.222, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:1500, Role=CoherenceServer)
OldestMember=Member(Id=1, Timestamp=2012-08-21 17:57:48.222, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:1500, Role=CoherenceServer)
ActualMemberSet=MemberSet(Size=1
Member(Id=1, Timestamp=2012-08-21 17:57:48.222, Address=130.35.99.202:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:1500, Role=CoherenceServer)
)
MemberId|ServiceVersion|ServiceJoined|MemberState
1|12.1.2|2012-08-21 17:57:48.222|JOINED
RecycleMillis=1200000
RecycleSet=MemberSet(Size=0
)
)

TcpRing{Connections=[]}
IpMonitor{Addresses=0}

2012-08-21 17:57:51.706/8.515 Oracle Coherence GE 12.1.2.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-08-21 17:57:51.800/8.609 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1): Loaded Reporter configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/reports/report-group.xml"
2012-08-21 17:57:52.144/8.953 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Service PartitionedPofCache joined the cluster with senior service member 1
2012-08-21 17:57:52.378/9.187 Oracle Coherence GE 12.1.2.0 <Info> (thread=Proxy:ProxyService:TcpAcceptor, member=1): TcpAcceptor now listening for connections on 130.35.99.202:9099
2012-08-21 17:57:52.394/9.203 Oracle Coherence GE 12.1.2.0 <D5> (thread=Proxy:ProxyService:TcpAcceptor, member=1): Started: TcpAcceptor{Name=Proxy:ProxyService:TcpAcceptor, State=(SERVICE_STARTED), ThreadCount=2, HungThreshold=0, TaskTimeout=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.DefaultSerializer, PingInterval=0, PingTimeout=0, RequestTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@fe8610, LocalAddress=WrapperSocketAddressProvider{Providers=[[tpfaeffl-lap7/130.35.99.202:9099]]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}, ListenBacklog=0, BufferPoolIn=BufferPool(BufferSize=2KB, BufferType=DIRECT, Capacity=Unlimited), BufferPoolOut=BufferPool(BufferSize=2KB, BufferType=DIRECT, Capacity=Unlimited)}
2012-08-21 17:57:52.394/9.203 Oracle Coherence GE 12.1.2.0 <D5> (thread=Proxy:ProxyService, member=1): Service ProxyService joined the cluster with senior service member 1
2012-08-21 17:57:52.409/9.218 Oracle Coherence GE 12.1.2.0 <Info> (thread=NameService:TcpAcceptor, member=1): TcpAcceptor now listening for connections on 130.35.99.202:8088.3
2012-08-21 17:57:52.409/9.218 Oracle Coherence GE 12.1.2.0 <D5> (thread=NameService:TcpAcceptor, member=1): Started: TcpAcceptor{Name=NameService:TcpAcceptor, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.net.internal.NameServicePofContext, PingInterval=0, PingTimeout=0, RequestTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@fe8610, LocalAddress=WrapperSocketAddressProvider{Providers=[WrapperSocketAddressProvider{Providers=[Address=130.35.99.202:8088]}]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}, ListenBacklog=0, BufferPoolIn=BufferPool(BufferSize=2KB, BufferType=DIRECT, Capacity=Unlimited), BufferPoolOut=BufferPool(BufferSize=2KB, BufferType=DIRECT, Capacity=Unlimited)}
2012-08-21 17:57:52.409/9.218 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=1):
Services
(
ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=12.1.2, OldestMemberId=1}
InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=12.1.2, OldestMemberId=1}
PartitionedCache{Name=PartitionedPofCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
ProxyService{Name=ProxyService, State=(SERVICE_STARTED), Id=3, Version=12.1.2, OldestMemberId=1}
)

Started DefaultCacheServer...

2012-08-21 17:58:14.222/31.031 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-21 17:58:14.066, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:2212, Role=CoherenceServer) joined Cluster with senior member 1
2012-08-21 17:58:14.269/31.078 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-08-21 17:58:14.425/31.234 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service PartitionedPofCache with senior member 1
2012-08-21 17:58:14.534/31.343 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Transferring 0KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256} to member 2
2012-08-21 17:58:14.737/31.546 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Transferring primary PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127} to member 2 requesting 128
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne

10.3 クラスタに対するロールベース・アクセス制御の組込み

この項では、クラスタへのアクセスにロールベースのポリシーを使用するサンプルを作成する方法を説明します。このコードは、特定のロールに割り当てられたユーザーIDを使用して、ログインし、サブジェクトを取得します。そのサブジェクトのコンテキストで実行中のキャッシュ参照を取得して、様々なキャッシュ操作を試行します。ユーザーに付与されたロールに応じて、キャッシュ操作が許可または拒否されます。このサンプルのロールのマッピングおよびロールベースの認可は簡略化されており、実際のセキュリティ保護での使用は想定していません。

たとえば、ライター・ロールのユーザーは、putとgetのメソッドを使用できます。リーダー・ロールのユーザーは、getメソッドを使用できますが、putメソッドは使用できません。ライター・ロールのユーザーは、キャッシュを破棄できませんが、管理ロールのユーザーはできます。

サブジェクトのコンテキストでキャッシュ参照が作成されると、IDが永続的にその参照と関連付けられることに注意してください。キャッシュ参照の使用すべてがそのIDの代理として行われます。

この例では、前の項で作成したPasswordIdentityTransformerクラスとPasswordIdentityAsserterクラスを使用します。PasswordIdentityTransformerクラスは、パスワード、ユーザーIDおよびロールを格納するセキュリティ・トークンを生成します。PasswordIdentityAsserterクラス(プロキシで実行)は、セキュリティ・トークンを検証してパスワードを強制し、適切なユーザーIDとロールでサブジェクトを構成します。セキュリティ・トークンの生成とアサーションは自動的に実行されます。

サンプルを作成するには:

1. キャッシュ・メソッドへのアクセスの資格が付与されるユーザー・ロールの定義

2. キャッシュ・サービスへの資格の適用

3. アクセス制御のサンプル・プログラムの作成

4. クラスタ側のキャッシュ構成ファイルの編集

5. アクセス制御のサンプルの実行

10.3.1 キャッシュ・メソッドへのアクセスの資格が付与されるユーザー・ロールの定義

ユーザー・ロールを基準にして、キャッシュ・メソッドへのアクセスを可能にするJavaファイルを作成します。これを行うには、Coherence*Extendを使用し、クライアントから渡されたSubjectオブジェクトを使用して、ラップされたNamedCacheにアクセス権を適用できます。この実装では、指定されたロールのクライアントのみに、ラップされたNamedCacheへのアクセスが許可されます。

この項で作成するクラスは、com.tangosol.net.cache.WrapperNamedCacheクラスを拡張します。このクラスは、NamedCacheインタフェースのメソッドの保護を可能にする便利なファンクションです。

キャッシュ・メソッドへのアクセスが可能なユーザー・ロールを決定するため、キャッシュ・メソッドの実装のそれぞれにSecurityExampleHelper.checkAccessメソッドのコールをインクルードします。checkAccessに対する引数として、メソッドへのアクセスを許可するユーザー・ロールを指定します。superのコールによって実装を終了します。

たとえば、次のコードでは、adminロールのユーザーがキャッシュを破棄できることが指定されます。

public void destroy()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN);
super.destroy();
}

このサンプルでは、readerロールのユーザーにaggregateメソッドのコールが許可されます。

public Object aggregate(Filter filter, EntryAggregator agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.aggregate(filter, agent);
}

キャッシュ・メソッドをコールできるユーザーを決定するファイルを作成するには:

1. SecurityプロジェクトにEntitledNamedCacheという名前のJavaクラスを新規作成します。
詳細を確認する場合は、「Javaクラスの作成」を参照してください。

2. このクラスがWrapperNamedCacheをインポートして拡張することを確認します。

3. Filter、MapListener、ValueExtractor、Collection、Comparator、Map、ServiceおよびSetの各クラスをインポートします。WrapperNamedCache内のメソッド(および拡張によるEntitledNamedCache)ではこれらのデータ型の引数が使用されます。

4. 特定のロールのユーザーのみにメソッドのコールが許可されるようにして、EntitledNamedCacheにメソッドを実装します。

例10-10は、考えられるEntitledNamedCacheの実装を示しています。

例10-10 資格が付与される名前付きキャッシュ

package com.oracle.handson;

import com.tangosol.net.NamedCache;
import com.tangosol.net.security.SecurityHelper;

import com.tangosol.net.Service;
import com.tangosol.net.cache.WrapperNamedCache;

import com.tangosol.util.Filter;
import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;
import com.tangosol.util.ValueExtractor;

import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;

import javax.security.auth.Subject;

/**
* Example WrapperNamedCache that demonstrates how entitlements can be applied
* to a wrapped NamedCache using the Subject passed from the client through
* Coherence*Extend. This implementation only allows clients with a specified
* role to access the wrapped NamedCache.
*
*/
public class EntitledNamedCache
extends WrapperNamedCache
{
/**
* Create a new EntitledNamedCache.
*
* @param cache  the wrapped NamedCache
*/
public EntitledNamedCache(NamedCache cache)
{
super(cache, cache.getCacheName());
}

// ----- NamedCache interface -------------------------------------------

/**
* {@inheritDoc}
*/
public void release()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
super.release();
}

/**
* {@inheritDoc}
*/
public void destroy()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN);
super.destroy();
}

/**
* {@inheritDoc}
*/
public Object put(Object oKey, Object oValue, long cMillis)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.put(oKey, oValue, cMillis);
}

/**
* {@inheritDoc}
*/
public void addMapListener(MapListener listener)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
super.addMapListener(new EntitledMapListener(listener));
}

/**
* {@inheritDoc}
*/
public void removeMapListener(MapListener listener)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.removeMapListener(listener);
}

/**
* {@inheritDoc}
*/
public void addMapListener(MapListener listener, Object oKey, boolean fLite)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
super.addMapListener(new EntitledMapListener(listener), oKey, fLite);
}

/**
* {@inheritDoc}
*/
public void removeMapListener(MapListener listener, Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.removeMapListener(listener, oKey);
}

/**
* {@inheritDoc}
*/
public void addMapListener(MapListener listener, Filter filter, boolean fLite)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
super.addMapListener(new EntitledMapListener(listener), filter, fLite);
}

/**
* {@inheritDoc}
*/
public void removeMapListener(MapListener listener, Filter filter)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.removeMapListener(listener, filter);
}

/**
* {@inheritDoc}
*/
public int size()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.size();
}

/**
* {@inheritDoc}
*/
public void clear()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.clear();
}

/**
* {@inheritDoc}
*/
public boolean isEmpty()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.isEmpty();
}

/**
* {@inheritDoc}
*/
public boolean containsKey(Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.containsKey(oKey);
}

/**
* {@inheritDoc}
*/
public boolean containsValue(Object oValue)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.containsValue(oValue);
}

/**
* {@inheritDoc}
*/
public Collection values()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.values();
}

/**
* {@inheritDoc}
*/
public void putAll(Map map)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.putAll(map);
}

/**
* {@inheritDoc}
*/
public Set entrySet()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.entrySet();
}

/**
* {@inheritDoc}
*/
public Set keySet()
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.keySet();
}

/**
* {@inheritDoc}
*/
public Object get(Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.get(oKey);
}

/**
* {@inheritDoc}
*/
public Object remove(Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.remove(oKey);
}

/**
* {@inheritDoc}
*/
public Object put(Object oKey, Object oValue)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.put(oKey, oValue);
}

/**
* {@inheritDoc}
*/
public Map getAll(Collection colKeys)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.getAll(colKeys);
}

/**
* {@inheritDoc}
*/
public boolean lock(Object oKey, long cWait)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.lock(oKey, cWait);
}

/**
* {@inheritDoc}
*/
public boolean lock(Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.lock(oKey);
}

/**
* {@inheritDoc}
*/
public boolean unlock(Object oKey)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.unlock(oKey);
}

/**
* {@inheritDoc}
*/
public Set keySet(Filter filter)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.keySet(filter);
}

/**
* {@inheritDoc}
*/
public Set entrySet(Filter filter)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.entrySet(filter);
}

/**
* {@inheritDoc}
*/
public Set entrySet(Filter filter, Comparator comparator)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.entrySet(filter, comparator);
}

/**
* {@inheritDoc}
*/
public void addIndex(ValueExtractor extractor, boolean fOrdered, Comparator comparator)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.addIndex(extractor, fOrdered, comparator);
}

/**
* {@inheritDoc}
*/
public void removeIndex(ValueExtractor extractor)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.removeIndex(extractor);
}

/**
* {@inheritDoc}
*/
public Object invoke(Object oKey, EntryProcessor agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.invoke(oKey, agent);
}

/**
* {@inheritDoc}
*/
public Map invokeAll(Collection collKeys, EntryProcessor agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.invokeAll(collKeys, agent);
}

/**
* {@inheritDoc}
*/
public Map invokeAll(Filter filter, EntryProcessor agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.invokeAll(filter, agent);
}

/**
* {@inheritDoc}
*/
public Object aggregate(Collection collKeys, EntryAggregator agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.aggregate(collKeys, agent);
}

/**
* {@inheritDoc}
*/
public Object aggregate(Filter filter, EntryAggregator agent)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return super.aggregate(filter, agent);
}

// ----- inner class ----------------------------------------------------

/**
* Example MapListener that adds authorization to map events.
*/
public class EntitledMapListener
implements MapListener
{
// ----- constructors -------------------------------------------

/**
* Construct an EntitledMapListener with the current subject.
* The subject will not be available in the security context
* when events are received by the proxy at runtime.
*
* @param  listener  the MapListener
*/
public EntitledMapListener(MapListener listener)
{
m_listener = listener;
m_subject  = SecurityHelper.getCurrentSubject();
}

// ----- MapListener interface ----------------------------------

/**
* {@inheritDoc}
*/
public void entryInserted(MapEvent mapEvent)
{
try
{
SecurityExampleHelper.checkAccess(
SecurityExampleHelper.ROLE_WRITER, m_subject);

}
catch (SecurityException e)
{
System.out.println("Access denied for entryInserted");
return;
}
m_listener.entryInserted(mapEvent);
}

/**
* {@inheritDoc}
*/
public void entryUpdated(MapEvent mapEvent)
{
try
{
SecurityExampleHelper.checkAccess(
SecurityExampleHelper.ROLE_WRITER, m_subject);

}
catch (SecurityException e)
{
System.out.println("Access denied for entryUpdated");
return;
}
m_listener.entryUpdated(mapEvent);
}

/**
* {@inheritDoc}
*/
public void entryDeleted(MapEvent mapEvent)
{
try
{
SecurityExampleHelper.checkAccess(
SecurityExampleHelper.ROLE_WRITER, m_subject);

}
catch (SecurityException e)
{
System.out.println("Access denied for entryDeleted");
return;
}
m_listener.entryDeleted(mapEvent);
}

//  ----- data members ------------------------------------------

/**
* Subject from security context when the MapListener was registered
*/
private Subject m_subject;

/**
* Registered listener
*/
private MapListener m_listener;
}

// ----- helper methods -------------------------------------------------

/**
* Return the wrapped NamedCache.
*
* @return  the wrapped CacheService
*/
public NamedCache getNamedCache()
{
return (NamedCache) getMap();
}
}

10.3.2 キャッシュ・サービスへの資格の適用

Coherence*Extendを使用し、クライアントから渡されたSubjectを使用して、ラップされたCacheServiceにアクセス資格を適用する方法を示すファイルを作成します。この実装は、前の項で作成したEntitledNamedCacheにキャッシュ操作のアクセス制御を委譲します。

作成するクラスは、com.tangosol.net.WrapperCacheServiceクラスを拡張します。これは、CacheServiceのメソッドの保護を可能にする便利なファンクションです。また、プロキシ上のキャッシュ・サービスとクライアントのリクエスト間で委譲を行うメカニズムも提供します。

メソッドensureCache、releaseCacheおよびdestroyCacheを実装して、これらの使用が特定ロールのユーザーのみに許可されるように保証します。実装には、特定のユーザー・ロールを引数としてSecurityExampleHelper.checkAccessメソッドのコールをインクルードします。たとえば、次のコードでは、adminロールのユーザーのみにキャッシュの破棄が許可されることが保証されます。

public void destroyCache(NamedCache map)
{
if (map instanceof EntitledNamedCache)
{
EntitledNamedCache cache =  (EntitledNamedCache) map;
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN);
map = cache.getNamedCache();
}
super.destroyCache(map);
}

キャッシュ・サービスへのアクセスに資格を適用するファイルを作成するには:

1. SecurityプロジェクトにEntitledCacheServiceという名前のJavaクラスを新規作成します。

2. このクラスがWrapperCacheServiceクラスをインポートして拡張することを確認します。

3. ensureCache、releaseCacheおよびdestroyCacheのメソッドを実装して、これらの使用が特定ロールのユーザーのみに許可されるように保証します。

例10-11は、考えられるEntitledCacheServiceの実装を示しています。

例10-11 資格が付与されるキャッシュ・サービス

package com.oracle.handson;

import com.tangosol.net.CacheService;
import com.tangosol.net.NamedCache;
import com.tangosol.net.WrapperCacheService;

/**
* Example WrapperCacheService that demonstrates how entitlements can be
* applied to a wrapped CacheService using the Subject passed from the
* client through Coherence*Extend. This implementation delegates access control
* for cache operations to the EntitledNamedCache.
*
*/
public class EntitledCacheService
extends WrapperCacheService
{
/**
* Create a new EntitledCacheService.
*
* @param service     the wrapped CacheService
*/
public EntitledCacheService(CacheService service)
{
super(service);
}

// ----- CacheService interface -----------------------------------------

/**
* {@inheritDoc}
*/
public NamedCache ensureCache(String sName, ClassLoader loader)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
return new EntitledNamedCache(super.ensureCache(sName, loader));
}

/**
* {@inheritDoc}
*/
public void releaseCache(NamedCache map)
{
if (map instanceof EntitledNamedCache)
{
EntitledNamedCache cache =  (EntitledNamedCache) map;
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_READER);
map = cache.getNamedCache();
}
super.releaseCache(map);
}

/**
* {@inheritDoc}
*/
public void destroyCache(NamedCache map)
{
if (map instanceof EntitledNamedCache)
{
EntitledNamedCache cache =  (EntitledNamedCache) map;
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_ADMIN);
map = cache.getNamedCache();
}
super.destroyCache(map);
}
}

10.3.3 アクセス制御のサンプル・プログラムの作成

アクセス制御のサンプルを実行するファイルを作成します。ロール・ポリシーは、SecurityExampleHelperクラスで定義されます。EntitledCacheServiceクラスとEntitledNamedCacheクラスによってポリシーが強制されます。

このプログラムは、SecurityHelperFile.loginメソッドに対する引数として様々なユーザーを指定して、キャッシュの読取り、書込みおよび破棄の操作の実行を試行する必要があります。EntitledCacheServiceクラスとEntitledNamedCacheクラスで定義された資格ポリシーに従って、操作の成功、または失敗が決まります。

1. AccessControlExampleという名前のSecurityプロジェクトに、mainメソッドを使用して新たなJavaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. キャッシュにアクセスするmainメソッドを実装します。

3. SecurityExampleHelperファイルで定義されたユーザーをloginメソッドの引数として指定します。

4. ユーザーごとに、キャッシュに対する読取り(get)、書込み(put)および destroy操作を実行し、応答とする成功または失敗のメッセージを指定します。

例10-12は、考えられるAccessControlExample.javaクラスの実装を示しています。

例10-12 アクセス制御のサンプルを実行するサンプル・プログラム

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.InvocationService;
import com.tangosol.net.NamedCache;
import com.tangosol.net.Service;

import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;

import java.security.PrivilegedExceptionAction;

import javax.security.auth.Subject;

/**
* This class demonstrates simplified role based access control.
* <p>
* The role policies are defined in SecurityExampleHelper. Enforcmenent
* is done by EntitledCacheService and EntitledNamedCache.
*
*/
public class AccessControlExample
{
// ----- static methods -------------------------------------------------

public static void main (String[] args){
accessCache();
}
/**
* Demonstrate role based access to the cache.
*/
public static void accessCache()
{
System.out.println("------cache access control example begins------");

Subject subject = SecurityExampleHelper.login("JohnWhorfin");

// Someone with writer role can write and read
try
{
NamedCache cache = (NamedCache) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
throws Exception
{
return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME);
}
});
cache.put("myKey", "myValue");
cache.get("myKey");
System.out.println("    Success: read and write allowed");
}
catch (Exception e)
{
// get exception if not allowed to perform the operation
e.printStackTrace();
}

// Someone with reader role can read but not write
subject = SecurityExampleHelper.login("JohnBigboote");
try
{
NamedCache cache = (NamedCache) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
throws Exception
{
return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME);
}
});
cache.get("myKey");
System.out.println("    Success: read allowed");
cache.put("anotherKey", "anotherValue");
}
catch (Exception e)
{
// get exception if not allowed to perform the operation
System.out.println("    Success: Correctly cannot write");
}

// Someone with writer role cannot call destroy
subject = SecurityExampleHelper.login("JohnWhorfin");
try
{
NamedCache cache = (NamedCache) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
throws Exception
{
return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME);
}
});
cache.destroy();
}
catch (Exception e)
{
// get exception if not allowed to perform the operation
System.out.println("    Success: Correctly cannot " +
"destroy the cache");
}

// Someone with admin role can call destroy
subject = SecurityExampleHelper.login("BuckarooBanzai");
try
{
NamedCache cache = (NamedCache) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
throws Exception
{
return CacheFactory.getCache(SecurityExampleHelper.SECURITY_CACHE_NAME);
}
});
cache.destroy();
System.out.println("    Success: Correctly allowed to " +
"destroy the cache");
}
catch (Exception e)
{
// get exception if not allowed to perform the operation
e.printStackTrace();
}
System.out.println("------cache access control example completed------");
}
}

10.3.4 クラスタ側のキャッシュ構成ファイルの編集

クラスタ側のキャッシュ構成ファイルexamples-cache-config.xmlを編集します。cache-service-proxyスタンザのproxy-configで、キャッシュ・サービスのクラス名のフルパスを指定します。cache-service-proxyスタンザには、プロキシ・サービスによって管理されるキャッシュ・サービス・プロキシの構成情報が格納されます。

この例のキャッシュ・サービス・クラス名はcom.oracle.handson.EntitledCacheServiceプロキシで、param-typeは、com.tangosol.net.CacheServiceです。

例10-13は、構成に追加するXMLコードを示しています。

例10-13 クラスタ側のキャッシュ構成のキャッシュ・サービス・プロキシ構成

...
<proxy-config>
<cache-service-proxy>
<class-name>com.oracle.handson.EntitledCacheService</class-name>
<init-params>
<init-param>
<param-type>com.tangosol.net.CacheService</param-type>
<param-value>{service}</param-value>
</init-param>
</init-params>
</cache-service-proxy>
</proxy-config>
...

10.3.5 アクセス制御サンプルの実行

アクセス制御サンプルを実行し、ユーザーのロールを基準にしてキャッシュへのアクセスがどのように許可または拒否されるかを示します。

1. AccessControlExample.javaの実行構成を作成します。

1. 「Project Explorer」で、AccessControlExampleを右クリックします。「Run As」→「Run Configurations」を選択します。

2. 「Oracle Coherence」→「New launch configuration」アイコンを選択します。AccessControlExampleが「Name」フィールドに、Securityが「Project」フィールドに、com.oracle.handson.AccessControlExampleが「Main class」フィールドに表示されていることを確認します。「Apply」をクリックします。

3. 「Coherence」タブの「Cache configuration descriptor」フィールドにclient-cache-config.xmlファイルへのパスを入力します。「Local cache」フィールドで、「Disabled (cache client)」を選択します。「Cluster port」フィールドに3155と入力します。

4. 「Classpath」タブで、図10-5のように「User Entries」が表示されていることを確認します。「Apply」→「Close」をクリックします。

図10-5 AccessControlExampleプログラムの「Classpath」タブ

2. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

3. セキュリティ・プロキシ・サーバー、セキュリティ・キャッシュ・サーバー、続いてAccessControlExample.javaプログラムを実行します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityRunProxy構成を実行します。

2. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityCacheServer構成を実行します。

3. 「Project Explorer」でAccessControlExample.javaファイルを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、AccessControlExample構成を実行します。

Eclipseコンソールに、例10-14のような出力が表示されます。メッセージは、AccessControlExampleで指定され、キャッシュの読取り、書込みおよび破棄操作を実行する様々なユーザーに対応します。

- メッセージ「Success: read and write allowed」は、キャッシュの読取りおよび書込みを試行するロールwriterのユーザーに対応します。

- メッセージ「Success: read allowed」は、キャッシュの読取りを試行するロールreaderのユーザーに対応します。

- メッセージ「Success: Correctly cannot write」は、キャッシュへの書込みを試行するロールreaderのユーザーに対応します。

- メッセージ「Success: Correctly cannot destroy the cache」は、キャッシュの破棄を試行するロールwriterのユーザーに対応します。

- メッセージ「Success: Correctly allowed to destroy the cache」は、キャッシュの破棄を試行するロールadminのユーザーに対応します。

例10-14 Eclipseコンソールのアクセス制御サンプルの出力

------cache access control example begins------
2012-08-22 11:32:24.329/0.609 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2012-08-22 11:32:24.407/0.687 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-08-22 11:32:24.454/0.734 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "file:/C:/home/oracle/workspace/Security/build/classes/tangosol-coherence-override.xml"
2012-08-22 11:32:24.470/0.750 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-config.xml" is not specified
2012-08-22 11:32:24.470/0.750 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "cache-factory-builder-config.xml" is not specified
2012-08-22 11:32:24.470/0.750 Oracle Coherence 12.1.2.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

2012-08-22 11:32:24.688/0.968 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/workspace/Security/appClientModule/client-cache-config.xml"
2012-08-22 11:32:25.220/1.500 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Created cache factory com.tangosol.net.ExtensibleConfigurableCacheFactory
2012-08-22 11:32:26.001/2.281 Oracle Coherence GE 12.1.2.0 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.DefaultSerializer, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@1739f, RemoteAddresses=WrapperSocketAddressProvider{Providers=[[tpfaeffl-lap7/130.35.99.202:9099]]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}}
2012-08-22 11:32:26.141/2.421 Oracle Coherence GE 12.1.2.0 <D5> (thread=main, member=n/a): Connecting Socket to 130.35.99.202:9099
2012-08-22 11:32:26.173/2.453 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
Success: read and write allowed
2012-08-22 11:32:27.157/3.437 Oracle Coherence GE 12.1.2.0 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.DefaultSerializer, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@1739f, RemoteAddresses=WrapperSocketAddressProvider{Providers=[[tpfaeffl-lap7/130.35.99.202:9099]]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}}
2012-08-22 11:32:27.204/3.484 Oracle Coherence GE 12.1.2.0 <D5> (thread=main, member=n/a): Connecting Socket to 130.35.99.202:9099
2012-08-22 11:32:27.204/3.484 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
Success: read allowed
Success: Correctly cannot write
Success: Correctly cannot destroy the cache
2012-08-22 11:32:27.470/3.750 Oracle Coherence GE 12.1.2.0 <D5> (thread=ExtendTcpCacheService:TcpInitiator, member=n/a): Started: TcpInitiator{Name=ExtendTcpCacheService:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), Serializer=com.tangosol.io.DefaultSerializer, PingInterval=0, PingTimeout=0, RequestTimeout=0, ConnectTimeout=0, SocketProvider=com.oracle.common.internal.net.MultiplexedSocketProvider@1739f, RemoteAddresses=WrapperSocketAddressProvider{Providers=[[tpfaeffl-lap7/130.35.99.202:9099]]}, SocketOptions{LingerTimeout=0, KeepAliveEnabled=true, TcpDelayEnabled=false}}
2012-08-22 11:32:27.501/3.781 Oracle Coherence GE 12.1.2.0 <D5> (thread=main, member=n/a): Connecting Socket to 130.35.99.202:9099
2012-08-22 11:32:27.501/3.781 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
Success: Correctly allowed to destroy the cache
------cache access control example completed------

例10-15は、キャッシュ・サーバーでプロキシ・サービスが実行される場合のシェルの出力をリストしています。出力内のセキュリティの例外は、Eclipseコンソールのメッセージ「Success: Correctly cannot write」および「Success: Correctly cannot destroy the cache」に対応することに注意します。

例10-15 プロキシ・サービスを実行中のキャッシュ・サーバーの出力

Started DefaultCacheServer...

2012-08-22 11:32:02.985/93.234 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-22 11:32:02.837, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4180, Role=CoherenceServer) joined Cluster with senior member 1
2012-08-22 11:32:03.048/93.297 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-08-22 11:32:03.220/93.469 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member 2 joined Service PartitionedPofCache with senior member 1
2012-08-22 11:32:03.298/93.547 Oracle Coherence GE 12.1.2.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Transferring 0KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
...
...  123, 124, 125, 126, 127} to member 2 requesting 128
Password validated for user: role_writer
Password validated for user: role_writer
Password validated for user: role_writer
Password validated for user: role_reader
Password validated for user: role_reader
Password validated for user: role_reader
2012-08-22 11:32:27.235/117.484 Oracle Coherence GE 12.1.2.0 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:1, member=1): An exception occurred while processing a PutRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:105)
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:59)
at com.oracle.handson.EntitledNamedCache.put(EntitledNamedCache.java:68)
at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.put$Router(NamedCacheProxy.CDB:1)
at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.put(NamedCacheProxy.CDB:2)
at com.tangosol.coherence.component.net.extend.messageFactory.NamedCacheFactory$PutRequest.onRun(NamedCacheFactory.CDB:6)
at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4)
at com.tangosol.coherence.component.net.extend.proxy.NamedCacheProxy.onMessage(NamedCacheProxy.CDB:11)
at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:356)
at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:48)
at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9)
at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32)
at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:66)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

2012-08-22 11:32:27.391/117.640 Oracle Coherence GE 12.1.2.0 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:0, member=1): An exception occurred while processing a DestroyCacheRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:105)
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:59)
at com.oracle.handson.EntitledCacheService.destroyCache(EntitledCacheService.java:61)
at com.tangosol.coherence.component.net.extend.messageFactory.CacheServiceFactory$DestroyCacheRequest.onRun(CacheServiceFactory.CDB:6)
at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4)
at com.tangosol.coherence.component.net.extend.proxy.serviceProxy.CacheServiceProxy.onMessage(CacheServiceProxy.CDB:9)
at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:356)
at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:48)
at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9)
at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32)
at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:66)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne
Password validated for user: CN=BuckarooBanzai,OU=Yoyodyne

10.4 起動可能オブジェクトに対するロールベース・アクセス制御の組込み

起動サービス・クラスタ・サービスを使用すると、Extendクライアントによるクラスタ上の起動可能オブジェクトの実行が可能になります。このサンプルは、ロールベース・ポリシーを使用して起動可能オブジェクトの実行が可能なユーザーをどのように決定できるかを示しています。

たとえば、ライター・ロールのユーザーは、起動可能オブジェクトを実行できます。リーダー・ロールのユーザーはできません。

このサンプルでは、クライアント・プログラムからコールできる起動可能オブジェクトを作成します。起動可能オブジェクトはシリアライズ可能であるため、POF構成ファイルにこれをリストする必要もあります。また、ユーザーのロールを基準にして、特定のユーザーがサービス上のメソッドを実行できるかどうかをテストする起動サービス・プログラムも作成します。

前出のサンプルと同様、この例でもPasswordIdentityTransformerクラスを使用して、パスワード、ユーザーIDおよびロールが格納されるセキュリティ・トークンを使用します。パスワードを強制し、適正なユーザーIDとロールでサブジェクトを構成するセキュリティ・トークンの検証には、PasswordIdentityAsserter(プロキシで実行)が使用されます。セキュリティ・トークンの生成とアサーションは自動的に実行されます。

サンプルを作成するには:

1. 起動可能オブジェクトの作成

2. 資格が付与される起動サービスの作成

3. アクセス起動サービスのサンプル・プログラムの作成

4. クラスタ側のキャッシュ構成ファイルの編集

5. POF構成ファイルの作成

6. サーバーの実行構成の編集

7. アクセス起動サービス・サンプルの実行

10.4.1 起動可能オブジェクトの作成

資格が付与された起動サービスによって使用される簡略な起動可能オブジェクトの実装を作成します。たとえば、整数の増分および戻りを実行する起動可能オブジェクトを作成できます。

起動可能オブジェクトを作成するには:

1. SecurityプロジェクトにExampleInvocableという名前のJavaクラスを新規作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. InvocableインタフェースとInvocationServiceインタフェースをインポートします。このクラスはシリアライズ可能オブジェクトを処理するため、PortableObject、PofReaderおよびPofWriterのクラスをインポートします。

3. ExampleInvocableクラスがInvocableおよびPortableObjectを実装することを保証します。

4. ExampleInvocableクラスを実装して、整数を増分し、結果を返します。

5. PofReader.readExternalメソッドとPofWriter.writeExternalメソッドを実装します。

例10-16は、考えられるExampleInvocable.javaの実装を示しています。

例10-16 起動可能オブジェクトのサンプル

package com.oracle.handson;

import com.tangosol.io.pof.PortableObject;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;

import com.tangosol.net.Invocable;
import com.tangosol.net.InvocationService;

import java.io.IOException;

/**
* Invocable implementation that increments and returns a given integer.
*/
public class ExampleInvocable
implements Invocable, PortableObject
{
// ----- constructors ---------------------------------------------

/**   *    */     private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public ExampleInvocable()
{
}

// ----- Invocable interface --------------------------------------

/**
* {@inheritDoc}
*/
public void init(InvocationService service)
{
m_service = service;
}

/**
* {@inheritDoc}
*/
public void run()
{
if (m_service != null)
{
m_nValue++;
}
}

/**
* {@inheritDoc}
*/
public Object getResult()
{
return new Integer(m_nValue);
}

// ----- PortableObject interface ---------------------------------

/**
* {@inheritDoc}
*/
public void readExternal(PofReader in)
throws IOException
{
m_nValue = in.readInt(0);
}

/**
* {@inheritDoc}
*/
public void writeExternal(PofWriter out)
throws IOException
{
out.writeInt(0, m_nValue);
}

// ----- data members ---------------------------------------------

/**
* The integer value to increment.
*/
private int m_nValue;

/**
* The InvocationService that is executing this Invocable.
*/
private transient InvocationService m_service;
}

10.4.2 資格が付与される起動サービスの作成

この例は、アクセス制御が提供されるようにリモート起動サービスをラップする方法を示しています。Coherence*Extendを使用すると、クライアントから渡されるSubjectを使用して、ラップされるInvocationServiceにアクセス資格を適用できます。この実装では、ラップされた起動サービスへのアクセスが指定されたロールのクライアントのみに許可されます。

作成するクラスは、com.tangosol.net.WrapperInvocationServiceクラスを拡張します。これは、InvocationServiceのメソッドの保護を可能にする便利なファンクションです。また、プロキシ上の起動サービスとクライアントのリクエスト間で委譲を行うメカニズムも提供します。

資格が付与される起動サービスを作成するには:

1. SecurityプロジェクトにEntitledInvocationServiceという名前のJavaクラスを新規作成します。

2. Invocable、InvocationObserver、InvocationService、WrapperInvocationService、MapおよびSetのインタフェースをインポートします。EntitledInvocationServiceクラスがWrapperInvocationServiceクラスを拡張することを確認します。

3. queryメソッドとexecuteメソッドを実装します。指定されたユーザー・ロール(このサンプルではROLE_WRITER)がこれらの操作にアクセスできるかどうかを判別するため、この実装に、SecurityExampleHelper.checkAccessメソッドのコールをインクルードします。

例10-17は、考えられるEntitledInvocationService.javaの実装を示しています。

例10-17 資格が付与される起動サービスのサンプル

package com.oracle.handson;

import com.tangosol.net.Invocable;
import com.tangosol.net.InvocationObserver;
import com.tangosol.net.InvocationService;
import com.tangosol.net.WrapperInvocationService;

import java.util.Map;
import java.util.Set;

/**
* Example WrapperInvocationService that demonstrates how entitlements can be
* applied to a wrapped InvocationService using the Subject passed from the
* client through Coherence*Extend. This implementation only allows clients with a
* specified role to access the wrapped InvocationService.
*
*/
public class EntitledInvocationService
extends WrapperInvocationService
{
/**
* Create a new EntitledInvocationService.
*
* @param service  the wrapped InvocationService
*/
public EntitledInvocationService(InvocationService service)
{
super(service);
}

// ----- InvocationService interface ------------------------------------

/**
* {@inheritDoc}
*/
public void execute(Invocable task, Set setMembers, InvocationObserver observer)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
super.execute(task, setMembers, observer);
}

/**
* {@inheritDoc}
*/
public Map query(Invocable task, Set setMembers)
{
SecurityExampleHelper.checkAccess(SecurityExampleHelper.ROLE_WRITER);
return super.query(task, setMembers);
}
}

10.4.3 アクセス起動サービスのサンプル・プログラムの作成

アクセス起動サービス・サンプルを実行するプログラムを作成します。このプログラムの目的は、SecurityExampleHelperクラスで定義されている多様なユーザーが起動可能オブジェクトにアクセスして実行できるかどうかをテストすることです。ロールベース・ポリシーの強制は、EntitledInvocationServiceクラスによって指定されます。

アクセス起動サービスのサンプルを実行するプログラムを作成するには:

1. AccessInvocationServiceExample.javaという名前のSecurityプロジェクトに、mainメソッドを使用してJavaクラスを作成します。
詳細は、「Javaクラスの作成」を参照してください。

2. クラスの中から、ExampleInvocable、CacheFactoryおよびInvocationServiceをインポートします。

3. accessInvocationServiceメソッドを起動するmainメソッドを実装します。

4. accessInvocationServiceクラスを実装して、SecurityExampleHelperクラスで定義された様々なユーザーが、サービスへのログイン、およびExampleInvocableで定義されたオブジェクトの実行を試行できるようにします。SecurityExampleHelper.loginメソッドを使用して、起動可能サービスにそれぞれのユーザーがアクセスできるかどうかをテストします。

例10-18は、考えられるAccessInvocationServiceExample.javaの実装を示しています。

例10-18 アクセス起動サービス・サンプルを実行するサンプル・プログラム

package com.oracle.handson;

import com.oracle.handson.ExampleInvocable;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.InvocationService;

import java.security.PrivilegedExceptionAction;

import javax.security.auth.Subject;

/**
* This class demonstrates simplified role based access control for the
* invocation service.
* <p>
* The role policies are defined in SecurityExampleHelper. Enforcmenent
* is done by EntitledInvocationService.
*
*/
public class AccessInvocationServiceExample
{
/**
* Invoke the example
*
* @param asArg  command line arguments (ignored in this example)
*/
public static void main(String[] asArg)
{
accessInvocationService();
}

/**
* Access the invocation service
*/
public static void accessInvocationService()
{
System.out.println("------InvocationService access control example " +
"begins------");

// Someone with writer role can run invocables
Subject subject = SecurityExampleHelper.login("JohnWhorfin");

try
{
InvocationService service = (InvocationService) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
{
return CacheFactory.getService(
SecurityExampleHelper.INVOCATION_SERVICE_NAME);
}
});
service.query(new ExampleInvocable(), null);
System.out.println("    Success: Correctly allowed to " +
"use the invocation service");
}
catch (Exception e)
{
// get exception if not allowed to perform the operation
e.printStackTrace();
}

// Someone with reader role cannot cannot run invocables
subject = SecurityExampleHelper.login("JohnBigboote");
try
{
InvocationService service = (InvocationService) Subject.doAs(
subject, new PrivilegedExceptionAction()
{
public Object run()
{
return CacheFactory.getService(
SecurityExampleHelper.INVOCATION_SERVICE_NAME);
}
});
service.query(new ExampleInvocable(), null);
}
catch (Exception ee)
{
System.out.println("    Success: Correctly unable to " +
"use the invocation service");
}
System.out.println("------InvocationService access control example " +
"completed------");
}
}

10.4.4 クラスタ側のキャッシュ構成ファイルの編集

examples-cache-config.xmlファイルを編集して、起動サービスへのフルパスをinvocation-service-proxyスタンザのproxy-configに追加します。invocation-service-proxyスタンザには、プロキシ・サービスによって管理される起動サービス・プロキシの構成情報が格納されます。

このサンプルの起動サービス・クラス名はcom.oracle.handson.EntitledInvocationServiceで、そのparam-typeは、com.tangosol.net.InvocationServiceです。

例10-19 クラスタ側キャッシュの起動サービス・プロキシ構成

...
<proxy-config>
...
<invocation-service-proxy>
<class-name>com.oracle.handson.EntitledInvocationService</class-name>
<init-params>
<init-param>
<param-type>com.tangosol.net.InvocationService</param-type>
<param-value>{service}</param-value>
</init-param>
</init-params>
</invocation-service-proxy>
</proxy-config>
...

10.4.5 POF構成ファイルの作成

ユーザー定義型としてExampleInvocableを宣言するPOFファイルを作成します。

1. 「Project Explorer」で、Security\appClientModuleのpof-config.xmlファイルを探し、Eclipse IDEで開きます。

2. ユーザー定義型としてExampleInvocableを宣言するコードを入力して、ファイルを保存します。
このファイルの内容は、例10-20のようになります。このファイルは、C:\home\oracle\workspace\Security\appClientModuleフォルダに保存されます。

例10-20 ExampleInvocableユーザー定義型のPOF構成ファイル

<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config http://xmlns.oracle.com/coherence/coherence-pof-config/1.1/coherence-pof-config.xsd">
<user-type-list>
<!-- include all "standard" Coherence POF user types -->
<include>coherence-pof-config.xml</include>

<!-- com.tangosol.examples package -->
<user-type>
<type-id>1007</type-id>
<class-name>com.oracle.handson.ExampleInvocable</class-name>
</user-type>

</user-type-list>

<allow-interfaces>true</allow-interfaces>
<allow-subclasses>true</allow-subclasses>
</pof-config>

10.4.6 サーバーの実行構成の編集

クラスローダーは、coherence.jarファイル内での参照前に、カスタムPOF構成ファイルpof-config.xmlを検出する必要があります。このようにされないと、カスタムPOF構成ファイルが無視され、coherence.jarファイル内のデフォルト・ファイルが使用されることになります。

アプリケーションにC:\home\oracle\workspace\Security\appModuleのXML構成ファイルを使用させるには、サーバーのクラス・パスの「Bootstrap Entries」セクションにCoherence12.1.2ライブラリが表示されていないことを確認します。また、coherence.jarファイルをUser EntriesセクションのSecurityフォルダの後に配置します。

サーバーのクラスパスの「Bootstrap Entries」セクションにCoherence12.1.2ライブラリが表示されている場合は、次の手順に従ってそのライブラリを削除します。

1. 「Project Explorer」でプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。

2. SecurityRunProxyを選択します。「Classpath」タブで「Coherence12.1.2」が表示されている場合は、「Bootstrap Entries」のリストからそれを削除します。「Add External Jars」をクリックして、Oracle_Home\coherence\libフォルダからcoherence.jarファイルを選択します。「Apply」をクリックします。

3. SecurityCacheServerを選択します。「Classpath」タブで「Coherence12.1.2」が表示されている場合は、「Bootstrap Entries」のリストからそれを削除します。「Add External Jars」をクリックして、Oracle_Home\coherence\libフォルダからcoherence.jarファイルを選択します。「Apply」をクリックします。

注意:

クラス・パス上のcoherence.jarファイルの前に、XML構成ファイル(C:\home\oracle\workspace\SecurityおよびSecurity\build\classesフォルダ内)が表示されていることを確認します。クラスローダーは、coherence.jarファイル内での参照前に、カスタムPOF構成ファイルpof-config.xmlを検出する必要があります。

終了すると、SecurityRunProxyおよびSecurityCacheServerの「Classpath」タブが図10-6のように表示されます。

図10-6 キャッシュ・サーバーおよびプロキシ・サービスを実行するサーバーのクラスパス

10.4.7 アクセス起動サービス・サンプルの実行

アクセス起動サービス・サンプルを実行し、ユーザーのロールを基準にして起動可能オブジェクトへのアクセスがどのように許可または拒否されるかを示します。

1. AccessInvocationServiceExample.javaファイルの実行構成を作成します。

1. 「Project Explorer」でAccessInvocationServiceExample.javaを右クリックして、「Run As」→「Run Configurations」を選択します。

2. 「Oracle Coherence」→「New launch configuration」アイコンをクリックします。AccessInvocationServiceExampleが「Name」フィールドに、Securityが「Project」フィールドに、com.oracle.handson.AccessInvocationServiceExample.javaが「Main class」フィールドに表示されていることを確認します。「Apply」をクリックします。

3. 「Coherence」タブの「Cache configuration descriptor」フィールドにclient-cache-config.xmlファイルへのパスを入力します。「Local cache」フィールドで、「Disabled (cache client)」を選択します。

4. 「Classpath」タブで「Coherence12.1.2」が表示されている場合は、「Bootstrap Entries」リストからそれを削除します。「Add External Jars」をクリックして、coherence.jarファイルを「User Entries」に追加します。Securityフォルダを「User Entries」の先頭に移動して、coherence.jarファイルを移動します(表示されていない場合)。終了すると、「Classpath」タブが図10-7のように表示されます。「Apply」→「Close」をクリックします。

図10-7 AccessInvocationServiceExampleプログラムの「Classpath」タブ

2. 実行中のキャッシュ・サーバーがあれば停止します。詳細は、「キャッシュ・サーバーの停止」を参照してください。

3. セキュリティ・プロキシ・サーバー、セキュリティ・キャッシュ・サーバー、続いてAccessInvocationServiceExample.javaプログラムを実行します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityRunProxy構成を実行します。

2. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスから、SecurityCacheServer構成を実行します。

3. 「Project Explorer」でAccessInvocationServiceExample.javaファイルを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスでAccessControlExampleを選択し、「Run」をクリックします。

Eclipseコンソールに、例10-21のような出力が表示されます。このメッセージは、AccessInvocationServiceExampleクラスで指定され、起動可能オブジェクトExampleInvocableを実行しようとするユーザーに対応します。

- メッセージ「Success: Correctly allowed to use the invocation service」は、ExampleInvocableを実行しようとするロールwriterのユーザーに対応します。

- メッセージ「Success: Correctly unable to use the invocation service」は、ExampleInvocableを実行しようとするロールreaderのユーザーに対応します。

例10-21 Eclipseコンソールのクライアント・プログラムの応答

------InvocationService access control example begins------
2012-08-22 12:32:55.548/0.516 Oracle Coherence 12.1.2.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/Middleware/Oracle_Home/coherence/lib/coherence.jar!/tangosol-coherence.xml"
...
...
Oracle Coherence Version 12.1.2.0 Build 36845
Grid Edition: Development mode
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.

...
...
2012-08-22 12:32:56.501/1.469 Oracle Coherence GE 12.1.2.0 <D5> (thread=main, member=n/a): Connecting Socket to 130.35.99.202:9099
2012-08-22 12:32:56.501/1.469 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
Success: Correctly allowed to use the invocation service
...
...
2012-08-22 12:32:56.595/1.563 Oracle Coherence GE 12.1.2.0 <Info> (thread=main, member=n/a): Connected Socket to 130.35.99.202:9099
Success: Correctly unable to use the invocation service
------InvocationService access control example completed------

例10-22は、キャッシュ・サーバーでプロキシ・サービスが実行される場合のシェルの出力をリストしています。出力のセキュリティの例外は、ロールreaderのユーザーがExampleInvocableを実行しようとした場合のEclipseコンソールのメッセージ「Success: Correctly unable to use the invocation service」に対応することに注意します。

例10-22 Eclipseコンソールのプロキシ・サービスの応答

...
Started DefaultCacheServer...

2012-08-22 12:32:31.782/23.766 Oracle Coherence GE 12.1.2.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-08-22 12:32:31.595, Address=130.35.99.202:8090, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:4144, Role=CoherenceServer) joined Cluster with senior member 1
...
... 121, 122, 123, 124, 125, 126, 127} to member 2 requesting 128
Password validated for user: role_writer
Password validated for user: role_writer
Password validated for user: role_reader
Password validated for user: role_reader
2012-08-22 12:32:56.610/48.594 Oracle Coherence GE 12.1.2.0 <D5> (thread=Proxy:ProxyService:TcpAcceptorWorker:0, member=1): An exception occurred while processing a InvocationRequest for Service=Proxy:ProxyService:TcpAcceptor: java.lang.SecurityException: Access denied, insufficient privileges
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:105)
at com.oracle.handson.SecurityExampleHelper.checkAccess(SecurityExampleHelper.java:59)
at com.oracle.handson.EntitledInvocationService.query(EntitledInvocationService.java:50)
at com.tangosol.coherence.component.net.extend.messageFactory.InvocationServiceFactory$InvocationRequest.onRun(InvocationServiceFactory.CDB:12)
at com.tangosol.coherence.component.net.extend.message.Request.run(Request.CDB:4)
at com.tangosol.coherence.component.net.extend.proxy.serviceProxy.InvocationServiceProxy.onMessage(InvocationServiceProxy.CDB:9)
at com.tangosol.coherence.component.net.extend.Channel$MessageAction.run(Channel.CDB:13)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:356)
at com.tangosol.coherence.component.net.extend.Channel.execute(Channel.CDB:48)
at com.tangosol.coherence.component.net.extend.Channel.receive(Channel.CDB:26)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Peer$DaemonPool$WrapperTask.run(Peer.CDB:9)
at com.tangosol.coherence.component.util.DaemonPool$WrapperTask.run(DaemonPool.CDB:32)
at com.tangosol.coherence.component.util.DaemonPool$Daemon.onNotify(DaemonPool.CDB:66)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

11 ライブ・イベントの使用

この演習では、エントリとEntryProcessorイベントの使用方法、およびイベント・インターセプタを使用したイベントの通知方法を学習します。この演習では、プロジェクトを作成するための指示が提供され、このプロジェクトで、イベント・インターセプタと原因イベントを作成して、ライブ・イベント・フレームワークの機能を実行します。

ライブ・イベント・フレームワークの簡単な概要も示します。この章で説明するフレームワークおよびAPIの詳細は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のライブ・イベントに関する項およびOracle Fusion Middleware Oracle Coherence Java APIリファレンスを参照してください。

この章には次の項が含まれます:

- 概要

- イベント・インターセプタの作成、登録および実行

- イベント・インターセプタを使用したコミット前イベントおよびコミット後イベントの拒否

- イベント・インターセプタを使用したパーティション・アクティビティのロギング

11.1 概要

Coherenceは、データ・グリッドで実行された操作にアプリケーションで対応できるイベント・フレームワークを提供します。このフレームワークは、イベントがクラスタ操作の監視可能な発生を表すイベントベースのモデルを使用します。サポートされているイベントには、パーティション・サービス、キャッシュおよびアプリケーション・イベントがあります。これらのイベントは、プログラムで実行するか、またはキャッシュ構成を使用してイベント・インターセプタ(EventInterceptorを実装するクラス)を登録することで処理できます。

11.1.1 イベント・インターセプタについて

アプリケーションは、イベント・インターセプタ(EventInterceptor)を登録することによってライブ・イベントに対応できます。インターセプタは、どのイベントを受信するか、どのアクションを実行するのか(実行するアクションがある場合)を明示的に定義します。特定のキャッシュに対して、または特定のパーティション・サービスによって管理されるすべてのキャッシュに対して、任意の数のイベント・インターセプタを作成し、登録できます。同じイベント・タイプに対して登録されている複数のインターセプタは、自動的に連鎖され、1つのイベントのコンテキストで実行されます。

イベント・インターセプタは、EventInterceptorインタフェースを実装することによって作成されます。インタフェースは汎用を使用して定義され、インタフェースを使用すると、イベントの汎用タイプをタイプ・パラメータとして指定して、対象となるイベントをフィルタ処理できます。継承されたonEventメソッドは、イベントの受信時に必要な処理を実行する機能を提供します。EventInterceptor APIの詳細は、Oracle Fusion Middleware Oracle Coherence Java APIリファレンスを参照してください。

@Interceptor注釈は、イベントを特定のイベント・タイプに制限するために使用され、インターセプタの詳細構成も提供します。@Interceptor注釈には次の属性が含まれます。

- identifier—インターセプタの一意の識別子を指定します。この値は、キャッシュ構成ファイルでインターセプタ・クラスを登録するときにオーバーライドできます。

- entryEvents—インターセプタがサブスクライブするエントリ・イベント・タイプの配列を指定します。

- entryProcessorEvents—インターセプタがサブスクライブするエントリ・プロセッサ・イベント・タイプの配列を指定します。

- transferEvents—インターセプタがサブスクライブする転送イベント・タイプの配列を指定します。

- transactionEvents—インターセプタがサブスクライブするトランザクション・イベント・タイプの配列を指定します。

- order—このインターセプタを、インターセプタの連鎖の前に配置するかどうかを指定します。有効な値はHIGHとLOWです。HIGHの値は、そのインターセプタを、インターセプタの連鎖の前に配置することを示します。LOWの値は、順序付けの設定はないことを示します。デフォルト値はLOWです。この値は、キャッシュ構成ファイルでインターセプタ・クラスを登録するときにオーバーライドできます。

@Interceptor注釈の詳細は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のイベント・インターセプタの作成に関する項を参照してください。

11.1.2 キャッシュ・イベントについて

キャッシュ・イベントは、キャッシュ内の1つ以上のエントリに対して実行された一部の操作によって発生します。キャッシュ・イベントには、エントリ・イベントおよびエントリ・プロセッサ・イベントがあります。エントリ・イベント(EntryEvent)は、キャッシュ内のエントリに対して実行されるいくつかの操作(挿入、更新および削除)のいずれかを表すことができます。エントリ・イベントは、エントリに対する変更を許可するために操作の実行前に発生するコミット前イベント(INSERTING、UPDATINGおよびREMOVING)と、操作の完了後にイベントの発生順序と同じ順序で発生するコミット後イベント(INSERTED、UPDATEDおよびREMOVED)に分けることができます。

エントリ・プロセッサ(EntryProcessor)イベントは、キャッシュ内の一連のエントリに対するEntryProcessorの実行を表します。エントリ・プロセッサ・イベントは、エントリ・プロセッサ実装に対する変更を許可するためにエントリ・プロセッサの実行前に発生するコミット前イベント(EXECUTING)と、エントリ・プロセッサの実行後にイベントの発生順序と同じ順序で発生するコミット後イベント(EXECUTED)に分けることができます。

11.1.3 パーティション・サービス・イベントについて

パーティション・サービス(PartitionedService)イベントは、記憶域が有効なメンバー間のパーティション転送を表す転送イベントと、トランザクション・イベントで構成されます。転送イベントは、転送対象のパーティションのコンテキストでディスパッチされますが、パーティションに属するコンテンツは変更不可です。

11.1.4 イベント・インターセプタの登録について

イベント・インターセプタは、キャッシュ構成ファイルまたはプログラムのいずれかで登録します。イベント・インターセプタは、1つ以上のキャッシュまたは特定のパーティション・サービスのいずれかに対して登録されます。特定のキャッシュに対して登録されたイベント・インターセプタは、そのキャッシュに関連するイベントのみを受信します。特定のパーティション・サービスに対して登録されたイベント・インターセプタは、そのサービスによって管理されるキャッシュすべてのイベントを受信します。

キャッシュ構成ファイルで、イベント・インターセプタの完全クラス名は<interceptor>要素で指定され、この要素は<cache-mapping>スタンザの<cache-name>の下に表示されます。インターセプタは、<cache-name>要素で指定されるキャッシュと関連付けられます。イベント・インターセプタは、<caching-schemes>スタンザのパーティション・サービスに対しても登録できます。これを実行するには、任意の数の<interceptor>サブ要素を含む<interceptors>要素を<distributed-scheme>要素内に含めます。

キャッシュ構成ファイルを使用するかわりに、イベント・インターセプタをプログラムで登録できます。イベント・インターセプタを登録するためのキー・クラスおよびメソッドは、ConfigurableCacheFactoryインタフェースのgetInterceptorRegistryメソッド、およびInterceptorRegistryインタフェースのgetEventInterceptorメソッドとregisterEventInterceptorメソッドです。たとえば、次のコードではTimedTraceInterceptorが登録されますが、これは、この章で後述するEventInterceptorです。

ConfigurableCacheFactory ccf = CacheFactory.getConfigurableCacheFactory();
InterceptorRegistry reg = ccf.getInterceptorRegistry();

reg.registerEventInterceptor(new TimedTraceInterceptor(), RegistrationBehavior.FAIL);

プログラムによるイベント・インターセプタの登録の詳細説明および例は、このドキュメントの対象範囲ではありません。詳細は、『Oracle Fusion Middleware Oracle Coherenceでのアプリケーションの開発』のライブ・イベントの使用に関する項およびOracle Fusion Middleware Oracle Coherence Java APIリファレンスを参照してください。

11.2 イベント・インターセプタの作成、登録および実行

次の各項では、イベント・インターセプタを作成、登録および実行する方法を説明します。この演習では、コミット前イベントとコミット後イベントの間のタイミングを測定するイベント・インターセプタを使用します。

この演習を完了するには:

1. コミット前イベントとコミット後イベントの間の時間を測定するイベント・インターセプタの作成

2. イベントの処理を遅延するクラスの作成

3. イベント時間測定イベント・インターセプタの登録

4. 遅延プロセッサ・クラスのPOF構成ファイルの作成

5. イベント時間測定イベント・インターセプタを実行するクラスの作成

6. イベント時間測定サンプルのドライバ・ファイルの作成

7. キャッシュ・サーバー起動の構成の作成

8. イベント時間測定ドライバの起動構成の作成

9. イベント時間測定サンプルの実行

11.2.1 コミット前イベントとコミット後イベントの間の時間を測定するイベント・インターセプタの作成

イベントの各タイプに対して、コミット前イベントとコミット後イベント(INSERTING/INSERTED、UPDATING/UPDATEDおよびREMOVING/REMOVED)のタイミングを測定する、TimedTraceInterceptorというイベント・インターセプタを作成します。

TimedTraceInterceptorイベント・インターセプタ・クラスを作成するには:

1. Eclipseで、UEMEventsという新しいアプリケーション・クライアント・プロジェクトを作成します。開始ページの「Configuration」フィールドでCoherenceConfigが選択されていることと、「Application Client module」ページで「Create a default main」が選択されていないことを確認します。
詳細は、「Eclipse IDEでの新規プロジェクトの作成」を参照してください。

2. TimedTraceInterceptorという新しいJavaクラスを作成します。「Default Package」がcom.oracle.handsonであることを確認します。「Main Method」チェック・ボックスは選択しないでください。
詳細は、「Javaクラスの作成」を参照してください。

3. EventInterceptorインタフェースを実装するイベント・インターセプタを作成します。インターセプタは、イベントの各タイプ(挿入、更新、削除)に対するコミット前イベントとコミット後イベントの間のタイミング、およびエントリ・プロセッサを提供する必要があります。独自のインターセプタを作成するか、または例11-1で提供されているコードを使用できます。

例11-1は、イベント・インターセプタTimedTraceInterceptorを示しています。インターセプタは、EventInterceptorインタフェースを実装します。@Interceptor注釈は、identifier属性でインターセプタの一意名を示し、order属性で実行順序(Order.HIGH)を示します。

インターセプタには、保護されたEventTimer内部クラスも含まれています。このクラスでは、通知対象の各イベントの経過時間が測定されます。インターセプタは、各エントリに対するコミット前イベントとコミット後イベントの間の時間、およびそれぞれのイベント・タイプ(INSERT、UPDATE、REMOVE)を追跡します。タイミングは、サンプル統計と累積統計を表示するCoherenceログにまとめて送信されます。

汎用引数がcom.tangosol.net.events.partition.cache.Eventであるため、ユーザーは、フィルタリングを指定しなくても、そのイベントのコンシューマであるイベント(EntryEventおよびEntryProcessorEvent)のみを取得します。

例11-1 コミット前イベントとコミット後イベントの間のタイミングを提供するクラス

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.tangosol.net.events.EventInterceptor;
import com.tangosol.net.events.annotation.Interceptor;
import com.tangosol.net.events.annotation.Interceptor.Order;
import com.tangosol.net.events.partition.cache.EntryEvent;
import com.tangosol.net.events.partition.cache.EntryEvent.Type;
import com.tangosol.net.events.partition.cache.EntryProcessorEvent;
import com.tangosol.net.events.partition.cache.Event;

import com.tangosol.util.Binary;
import com.tangosol.util.BinaryEntry;

import java.util.HashMap;
import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
* TimedTraceInterceptor provides timings between pre- and postcommit events
* for each type of event i.e. inserts, updates, removes, and entry processor
* execution.
* <p>
* These timings are collected and averaged at a sample rate defined by
* parameter <tt>cSample</tt>. Additionally they are output to the log
* at the same time. This implementation does maintain a strong reference to
* the each binary key however this is removed upon receiving the postcommit event
* for the same key.
*
* @since Coherence 12.1.2
*/
@Interceptor(identifier = "trace", order = Order.HIGH)
public class TimedTraceInterceptor
implements EventInterceptor<Event<? extends Enum<?>>>
{

// ----- constructors ---------------------------------------------------

/**
* Default no-arg constructor.
*/
public TimedTraceInterceptor()
{
this(DEFAULT_SAMPLE_RATE);
}

/**
* Construct an TimedTraceInterceptor with specified {@link Event}
* types and chain position.
*
* @param cSample   sample size to calculate mean and output statistics
*/
public TimedTraceInterceptor(int cSample)
{
Map<Enum, EventTimer> mapTimedEvents = m_mapTimedEvents = new HashMap<Enum, EventTimer>(3);
EventTimer insertTimer = new EventTimer(Type.INSERTED, cSample);
EventTimer updateTimer = new EventTimer(Type.UPDATED, cSample);
EventTimer removeTimer = new EventTimer(Type.REMOVED, cSample);
EventTimer invocationTimer = new EventTimer(EntryProcessorEvent.Type.EXECUTED, cSample);

mapTimedEvents.put(Type.INSERTED,  insertTimer);
mapTimedEvents.put(Type.INSERTING, insertTimer);
mapTimedEvents.put(Type.UPDATED,   updateTimer);
mapTimedEvents.put(Type.UPDATING,  updateTimer);
mapTimedEvents.put(Type.REMOVED,   removeTimer);
mapTimedEvents.put(Type.REMOVING,  removeTimer);
mapTimedEvents.put(EntryProcessorEvent.Type.EXECUTED,  invocationTimer);
mapTimedEvents.put(EntryProcessorEvent.Type.EXECUTING, invocationTimer);
}

// ----- EventInterceptor methods ---------------------------------------

/**
* {@inheritDoc}
*/
public void onEvent(Event event)
{
if (event instanceof EntryEvent)
{
process((EntryEvent) event);
}
else if (event instanceof EntryProcessorEvent)
{
process((EntryProcessorEvent) event);
}
}

/**
* This method will be invoked upon execution of an entry processor and
* will time its execution from prior to post execution, including any
* backup requests that need to be made as a result.
*
* @param event  the {@link EntryProcessorEvent} that encompasses the
*               requested event
*/
protected void process(EntryProcessorEvent event)
{
EventTimer mapTimedEvents = m_mapTimedEvents.get(event.getType());

for (BinaryEntry binEntry : event.getEntrySet())
{
if (event.getType() == EntryProcessorEvent.Type.EXECUTING)
{
mapTimedEvents.starting(binEntry);
}
else if (event.getType() == EntryProcessorEvent.Type.EXECUTED)
{
mapTimedEvents.started(binEntry);
}
}
}

/**
* This method will be invoked upon execution of a data mutating request
* and will time its execution from prior to post execution, including
* any backup requests that need to be made as a result.
*
* @param event  the {@link EntryEvent} that encompasses the
*               requested event
*/
protected void process(EntryEvent event)
{
EventTimer mapTimedEvents = m_mapTimedEvents.get(event.getType());

switch ((Type) event.getType())
{
case INSERTING:
case UPDATING:
case REMOVING:
for (BinaryEntry binEntry : event.getEntrySet())
{
mapTimedEvents.starting(binEntry);
}
break;
case INSERTED:
case UPDATED:
case REMOVED:
for (BinaryEntry binEntry : event.getEntrySet())
{
mapTimedEvents.started(binEntry);
}
break;
}
}

// ----- inner class: EventTimer ----------------------------------------

/**
* The EventTimer times the elapsed time for each event it is notified
* of. It correlates the completion event based on equality comparisons
* of the Binary provided. Additionally it calculates the mean based on a
* sample set of <tt>cSample</tt> size. When reaching this sample set
* a log will be made of the current sample set mean and the cumulative
* mean.
*/
protected class EventTimer
{

// ----- constructors -----------------------------------------------

/**
* Construct an EventTimer with the event type provided.
*
* @param eventType  the type of event this timer will be timing
*/
protected EventTimer(Enum eventType, int cSample)
{
m_eventType = eventType;
m_cSampleSize = cSample;
}

/**
* Notifies the timer of the execution of the provided key will
* imminently commence.
*
* @param binEntry  the event will commence for this <tt>binEntry</tt>
*/
public void starting(BinaryEntry binEntry)
{
m_mapElapsedTimes.put(binEntry.getBinaryKey(), System.nanoTime());
}

/**
* Notifies the timer of the completion of the event for the provided
* key.
*
* @param binEntry  the event has completed for this <tt>binEntry</tt>
*/
public void started(BinaryEntry binEntry)
{
Long lStart = m_mapElapsedTimes.remove(binEntry.getBinaryKey());
if (lStart == null)
{
return;
}

add(System.nanoTime() - lStart);
}

/**
* Regardless of the specific data item add the elapsed time taken to
* process the data item. Upon reaching the sample set size of events
* calculate the mean, reset timings and continue.
*
* @param lElapsed  the number of nanos taken for a data item to
*                  process
*/
protected void add(long lElapsed)
{
AtomicInteger nEvents           = m_nEvents;
AtomicLong    lTotalElapsed     = m_lTotalElapsed;
int           nCurrEvents       = nEvents.incrementAndGet();
long          lCurrTotalElapsed = lTotalElapsed.addAndGet(lElapsed);

if (nCurrEvents % m_cSampleSize == 0)
{
nEvents.set(0);
lTotalElapsed.set(0L);
++m_cSamples;

long lMean   = lCurrTotalElapsed / nCurrEvents;
m_lMean = m_lMean == 0 ? lMean : lMean + m_lMean / 2;

String sStats = String.format("EventStats[name = %s, sampleMean = %fms, mean = %fms]",
m_eventType, (double) lMean / 1000000, (double) m_lMean / 1000000);

CacheFactory.log(sStats, CacheFactory.LOG_INFO);

NamedCache cacheResults = CacheFactory.getCache("events-results");
int        nMemberId    = CacheFactory.getCluster().getLocalMember().getId();

cacheResults.put(
String.format("%d-%s-%d", nMemberId, m_eventType.name(), m_cSamples),
sStats);
}
}

// ----- data members -----------------------------------------------

/**
* Sample size to calculate mean and output statistics.
*/
private int               m_cSampleSize;

/**
* The start times for a number of Binary keys.
*/
private Map<Binary, Long> m_mapElapsedTimes = new ConcurrentHashMap<Binary, Long>();

/**
* A counter of the total elapsed time.
*/
private AtomicLong        m_lTotalElapsed = new AtomicLong();

/**
* A counter of the number of events processed
*/
private AtomicInteger     m_nEvents = new AtomicInteger();

/**
* An average over time.
*/
private long              m_lMean;

/**
* The number of samples taken.
*/
private int               m_cSamples;

/**
* The type of event being timed.
*/
private Enum              m_eventType;
}

// ----- constants ------------------------------------------------------

/**
* The sample size for elapsed times.
*/
protected static final int DEFAULT_SAMPLE_RATE = 100;

// ----- data members ---------------------------------------------------

/**
* A map of event types to their timers.
*/
private Map<Enum, EventTimer> m_mapTimedEvents;
}

11.2.2 イベントの処理を遅延するクラスの作成

LazyProcessorというクラスを作成して、イベントの処理間の実体のない遅延を作成します。クラスでは、このプロセッサがイベントの処理間でスリープする必要があるミリ秒数を指定できる必要があります。このクラスは、EventsExamplesクラスのEventsTimingExampleサブクラスで使用されます。EventsExamplesクラスは後の手順で作成します。

LazyProcessorクラスが生成するデータはワイヤ経由で送信されるため、クラスでPOF (Portable Object Format)を使用する必要があります。POF構成ファイルへのLazyProcessorクラスの追加は後の手順で実行します。

LazyProcessorクラスを作成するには:

1. LazyProcessorという新しいJavaクラスを作成します。mainメソッドは含めないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. LazyProcessorクラスのコードを作成します。このクラスではデータのシリアライズにPortableObjectインタフェースを使用するため、LazyProcessorクラスはPortableObjectインタフェースを実装する必要があります。クラスは、AbstractProcessorクラスを拡張する必要もあります。Base、InvocableMap.Entry、AbstractProcessor、PortableObject、PofReaderおよびPofWriterのクラスとインタフェースをインポートします。LazyProcessorクラスの独自のコードを作成するか、または例11-2で提供されているコードを使用できます。

例11-2 イベントの処理を遅延するクラス

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;
import com.tangosol.util.Base;
import com.tangosol.util.InvocableMap.Entry;
import com.tangosol.util.processor.AbstractProcessor;

import java.io.IOException;

/**
* LazyProcessor will sleep for a specified period of time.
*
*
* @since 12.1.2
*/
public class LazyProcessor
extends AbstractProcessor
implements PortableObject
{
// ----- constructors ---------------------------------------------------

/**
*
*/
private static final long serialVersionUID = 1L;

/**
* Default no-arg constructor.
*/
public LazyProcessor()
{
}

/**
* Constructs a LazyProcessor with a specified time to sleep.
*
* @param lSleepTime  the number of milliseconds this processor should
*                    sleep
*/
public LazyProcessor(long lSleepTime)
{
m_lSleepTime = lSleepTime;
}

/**
* {@inheritDoc}
*/
public Object process(Entry entry)
{
try
{
Thread.sleep(m_lSleepTime);
}
catch (InterruptedException e)
{
throw Base.ensureRuntimeException(e);
}
return null;
}

// ----- PortableObject members -----------------------------------------

/**
* {@inheritDoc}
*/
public void readExternal(PofReader in) throws IOException
{
m_lSleepTime = in.readLong(0);
}

/**
* {@inheritDoc}
*/
public void writeExternal(PofWriter out) throws IOException
{
out.writeLong(0, m_lSleepTime);
}

// ----- data members ---------------------------------------------------

/**
* The number of milliseconds this processor should sleep.
*/
private long m_lSleepTime;
}

11.2.3 イベント時間測定イベント・インターセプタの登録

UEMEventsプロジェクトで、インターセプタはキャッシュ構成ファイルに登録されます。イベント・インターセプタの完全修飾名はinterceptor要素で指定され、この要素は<cache-mapping>スタンザの<cache-name>の下に表示されます。インターセプタは、<cache-name>要素で指定されるキャッシュと関連付けられます。この例で、TimedTraceInterceptorはeventsキャッシュ上のイベント・インターセプタです。

イベント・インターセプタを定義するキャッシュ構成ファイルを作成するには:

1. 「Project Explorer」ウィンドウから、coherence-cache-config.xmlファイルを開きます。ファイルはEvents/appClientModuleの下にあります。

2. ファイルをuem-cache-config.xmlという名前で保存します。

3. イベント・インターセプタをコールするキャッシュ構成を作成します。次のリストは、主な要素の一部を取り上げています。

- <cache-mapping>要素の下に、<interceptor>要素のcom.oracle.handson.TimedTraceInterceptorクラスから<cache-name>要素のeventsキャッシュへの参照があります。eventsキャッシュではevents-distributed-schemeが使用されます。このスキームでは、<distributed-schemes>の下にリストされているPartitionedPofCacheサービスが使用されます。

- events-resultsキャッシュとdist-events-resultsスキーム間のマッピングがあります。<distributed-scheme>セクションに、dist-events-resultsスキームとPartitionedEventsResultsサービスの間のアソシエーションがあります。

例11-3は、考えられるuem-cache-config.xmlファイルの実装を示しています。

例11-3 TimedTraceInterceptorを登録するキャッシュ構成ファイル

<?xml version="1.0"?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<defaults>
<serializer>pof</serializer>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>events</cache-name>
<scheme-name>events-distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.TimedTraceInterceptor</class-name>
<init-params>
<init-param>
<param-type>int</param-type>
<param-value>100</param-value>
</init-param>
</init-params>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
<cache-mapping>
<cache-name>events-results</cache-name>
<scheme-name>dist-events-results</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<distributed-scheme>
<scheme-name>events-distributed-scheme</scheme-name>
<service-name>PartitionedPofCache</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme>
<!-- each node will be limited to 32MB -->
<high-units>32M</high-units>
<unit-calculator>binary</unit-calculator>
</local-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!-- A PartitionedCache service used to store results for events examples
-->
<distributed-scheme>
<scheme-name>dist-events-results</scheme-name>
<service-name>PartitionedEventsResults</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme/>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!--
Invocation Service scheme.
-->
<invocation-scheme>
<scheme-name>examples-invocation</scheme-name>
<service-name>InvocationService</service-name>

<autostart system-property="tangosol.coherence.invocation.autostart">true</autostart>
</invocation-scheme>

</caching-schemes>
</cache-config>

11.2.4 遅延プロセッサ・クラスのPOF構成ファイルの作成

TimedTraceInterceptorクラスによって生成される情報はすべて、そのローカル・メンバー専用です。LazyProcessorとその状態は、記憶域が有効なメンバーに送信されて実行されるため、POF構成ファイルに追加される必要があります。Eclipseの「Project Explorer」で、pof-config.xmlファイルを右クリックし、名前をuem-pof-config.xmlに変更します。エディタでuem-pof-config.xmlファイルを開き、その内容を例11-4のコードに置換します。例は、このクラスを含むPOF構成ファイルを示しています。

例11-4 LazyProcessorクラスのPOF構成ファイル

<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config http://xmlns.oracle.com/coherence/coherence-pof-config/1.2/coherence-pof-config.xsd">
<user-type-list>
<!-- include all "standard" Coherence POF user types -->
<include>coherence-pof-config.xml</include>
<user-type>
<type-id>1008</type-id>
<class-name>com.oracle.handson.LazyProcessor</class-name>
</user-type>
</user-type-list>
</pof-config>

11.2.5 イベント時間測定イベント・インターセプタを実行するクラスの作成

TimedTraceInterceptorクラスによって実行されるアクションをトリガーするEventsExamplesというクラスを作成します。クラスは、結果キャッシュに挿入される、コミット前イベントとコミット後イベントの間の経過時間を測定できる方法を示す必要があります。結果キャッシュに挿入されたエントリは、このクラスを実行するプロセスによって標準出力に送信されます。

EventsExamplesクラスを作成するには:

1. EventsExamplesという新しいJavaクラスを作成します。mainメソッドは含めないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. EventsExamplesクラスのコードを作成します。LazyProcessor、CacheFactory、NamedCache、PartitionedService、MapEvent、MapListener、MultiplexListenerおよびCallableのクラスとインタフェースをインポートします。独自のコードを作成するか、または例11-5で提供されているコードを使用できます。

例11-5は、EventsExamplesクラスのサンプル実装を示しています。例には、EventsTimingExample内部クラスが含まれています。この内部クラスは、eventsおよびevent-resultsキャッシュにアクセスし、TimedTraceInterceptorクラスのログから、キャッシュ・クラスタ・メンバーの数、トリガーしているイベントの名前およびサンプル・サイズを取得します。処理対象のサンプルの時間、および処理対象の全サンプルの平均時間の計算が、TimedTraceInterceptorクラスによって提供されます。

EventsTimingExampleサブクラスでは、イベント処理の合計時間、およびイベントが実行できるスレッド数の値が提供されます。また、イベント処理の間の時間(スリープ時間)を計算するLazyProcessorクラスもコールされます。

例11-5 TimedTraceInterceptorイベント・インターセプタを実行するクラス

package com.oracle.handson;

import com.oracle.handson.LazyProcessor;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.net.PartitionedService;
import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;
import com.tangosol.util.MultiplexingMapListener;

import java.util.concurrent.Callable;

/**
* EventsExamples illustrates various features within the Live Events
* Model. This includes providing mean elapsed times split by event type.
*
* @since Coherence 12.1.2
*/
@SuppressWarnings("unchecked")
public class EventsExamples
{

// ----- inner-class: EventsTimingExample -------------------------------

/**
* The EventsTimingExample is a catalyst for action to be performed by
* {@link TimedTraceInterceptor}. This illustrates how the elapsed time
* between pre- and postcommit events can be measured which are inserted
* into a results cache. The entries inserted into the results cache are
* displayed via the stdout of the process executing this class.
*/
public static class EventsTimingExample
implements Callable<Boolean>
{
// ----- Callable methods -------------------------------------------

/**
* {@inheritDoc}
*/
public Boolean call() throws Exception
{
NamedCache cacheEvents  = CacheFactory.getCache("events");
NamedCache cacheResults = CacheFactory.getCache("events-results");
int        cFrequency   = ((PartitionedService) cacheEvents.getCacheService()).getOwnershipEnabledMembers().size();
int        cSet         = 110;

MapListener ml = new MultiplexingMapListener()
{
@Override
protected void onMapEvent(MapEvent evt)
{
String[] asKey = ((String) evt.getKey()).split("-");

System.out.printf("Received stats [memberId=%s, eventType=%s, sample=%s] = %s\n",
asKey[0], asKey[1], asKey[2], evt.getNewValue());
}
};

try
{
cacheResults.addMapListener(ml);

// execute inserts and updates
for (int i = cFrequency; i > 0; --i)
{
for (int j = 1, cMax = cSet * cFrequency; j <= cMax; ++j)
{
cacheEvents.put(j, "value " + j);
}
}

// execute processors
int nTotalTime = 3000;
int cThreads   = 5;
int nSleepTime = nTotalTime / (cThreads * cSet * cFrequency);
for (int i = 1, cMax = cSet * cFrequency; i <= cMax; ++i)
{
cacheEvents.invoke(i, new LazyProcessor(nSleepTime));
}
}
finally
{
cacheEvents.clear();
cacheResults.removeMapListener(ml);
cacheResults.clear();
}
return true;
}
}
}

11.2.6 イベント時間測定サンプルのドライバ・ファイルの作成

EventsExamplesクラスで定義したEventsTimingExampleサンプルを実行するドライバ・ファイルを作成します。

ドライバ・ファイルを作成するには:

1. UEMEventsプロジェクト内にDriverという新しいJavaクラスを作成します。mainメソッドを含むようにしてください。
詳細は、「Javaクラスの作成」を参照してください。

2. EventsExamplesクラスで定義したEventsTimingExampleサンプルを実行するコードを作成します。独自のドライバを作成するか、または例11-6で提供されているコードを使用できます。

例11-6 イベント時間測定サンプルのドライバ・ファイル

package com.oracle.handson;

import com.oracle.handson.EventsExamples.EventsTimingExample;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
* Driver executes all the Coherence Events examples.
* <p>
* <strong>Timed Events Example</strong> - In this example we time
* the elapsed time between pre- and postcommit events for each of the events
* that occur.
*
* @since Coherence 12.1.2
*/
public class Driver
{

// ----- static methods -------------------------------------------------

/**
* Execute Events examples.
*
* @param asArg  command line arguments
*/
public static void main(String[] asArg)
{
System.out.println("------ events examples begin ------");

// Run examples
for (Map.Entry<String, Callable<Boolean>> example : EVENTS_EXAMPLES.entrySet())
{
String sExample = example.getKey();

try
{
System.out.printf("------   %s begin\n\n", sExample);
boolean fSuccess = example.getValue().call();
System.out.printf("\n------   %s completed %ssuccessfully\n", sExample, fSuccess ? "" : "un");
}
catch(Exception e)
{
System.err.printf("----------%s completed unsuccessfully with the following exception:\n", sExample);
e.printStackTrace();
}
}

System.out.println("------ events examples completed------");
}

// ----- constants ------------------------------------------------------

/**
* All the examples to be executed in insertion order.
*/
protected static final Map<String, Callable<Boolean>> EVENTS_EXAMPLES = new LinkedHashMap<String, Callable<Boolean>>();

/**
* Default examples.
*/
static
{
EVENTS_EXAMPLES.put("timing interceptor", new EventsTimingExample());
}
}

11.2.7 キャッシュ・サーバー起動の構成の作成

UEMEventsプロジェクト用キャッシュ・サーバーを起動するための構成を作成します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで「Oracle Coherence」アイコンをダブルクリックして、新しい起動構成を作成します。

2. 「Main」タブで、「Name」フィールドにUEMEventsServerと入力します。「Project」フィールドの「Browse」をクリックし、「Project Selection」ダイアログ・ボックスでUEMEventsプロジェクトを選択します。「Include system libraries when searching for a main class」チェック・ボックスを選択し、「Search」をクリックします。「Select Type」フィールドにDefaultCacheServerと入力して、com.tangosol.net.DefaultCacheServerを選択します。「Apply」をクリックします。「Main」タブは図11-1のようになります。

図11-1 イベント・サーバー起動構成の「Main」タブ

3. 「Coherence」タブの「General」タブで、「Cache configuration descriptor」の下にあるキャッシュ構成ファイルへのパスを指定します。「Browse」ボタンをクリックして、キャッシュ構成ファイルの絶対ファイル・パスC:\home\oracle\workspace\UEMEvents\src\uem-cache-config.xmlに移動します。「Local storage」の下の「Enabled (cache server)」を選択します。「Cluster port」には3155などの一意の値を入力します。
「Other」タブで、tangosol.pof.configの項目をuem-pof-config.xmlに設定します。

4. 「Common」タブで、「Shared file」を選択して\UEMEventsプロジェクトを参照します。

5. 「Classpath」タブは例11-2のようになります。UEMEventsプロジェクトが「User Entries」の下に表示されます。JRE Entries LibraryとCoherence12.1.2ライブラリが「Bootstrap Entries」セクションに表示されます。

図11-2 イベント・サーバー起動構成の「Classpath」タブ

11.2.8 イベント時間測定ドライバの起動構成の作成

UEMEventsプロジェクト用クライアント・ドライバを起動するための構成を作成します。

1. プロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで「Oracle Coherence」アイコンをダブルクリックして、新しい起動構成を作成します。

2. 「Main」タブで、「Name」フィールドにUEMEventDriverと入力します。「Project」フィールドの「Browse」をクリックし、「Project Selection」ダイアログ・ボックスでUEMEventsプロジェクトを選択します。「Include system libraries when searching for a main class」チェック・ボックスを選択し、「Search」をクリックします。「Select Type」フィールドにDriverと入力し、com.oracle.handson.Driverを選択します。「Apply」をクリックします。「Main」タブは図11-0のようになります。

図11-3 イベント・クライアント起動構成の「Main」タブ

3. 「Coherence」タブの「General」タブで、「Cache configuration descriptor」の下にあるキャッシュ構成ファイルへのパスを指定します。「Browse」ボタンをクリックして、キャッシュ構成ファイルの絶対ファイル・パスC:\home\oracle\workspace\UEMEvents\src\uem-cache-config.xmlに移動します。「Local storage」で「Disabled (cache client)」を選択します。「Cluster port」には3155などの一意の値を入力します。
「Other」タブで、tangosol.pof.configの項目をuem-pof-config.xmlに設定します。

4. 「Common」タブで、「Shared file」を選択して\UEMEventsプロジェクトを参照します。

5. 「Classpath」タブは例11-4のようになります。UEMEventsプロジェクトが「User Entries」の下に表示されます。JRE Entries LibraryとCoherence12.1.2ライブラリが「Bootstrap Entries」セクションに表示されます。

図11-4 イベント・クライアント起動構成の「Classpath」タブ

11.2.9 イベント時間測定サンプルの実行

「Project Explorer」でUEMEventsプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、UEMEventsServer起動構成を選択し、「Run」をクリックしてキャッシュ・サーバーを起動します。キャッシュ・サーバーの起動後、UEMEventsServerを選択し、「Run」をもう一度、さらにもう一度クリックして、合計で3つのキャッシュ・サーバーを起動します。

3番目のキャッシュ・サーバーの起動後、UEMEventDriver構成を選択し、「Run」をクリックします。キャッシュ・クライアントからの出力は例11-7のようになります。

例11-7 キャッシュ・クライアントからの出力

------ events examples begin ------
------   timing interceptor begin
2013-03-07 15:53:49.958/0.406 Oracle Coherence 12.1.2.0.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2013-03-07 15:53:50.020/0.468 Oracle Coherence 12.1.2.0.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
...
...
2013-03-07 15:53:51.692/2.140 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=4): Service PartitionedPofCache joined the cluster with senior service member 1
2013-03-07 15:53:51.802/2.250 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:PartitionedEventsResults, member=4): Service PartitionedEventsResults joined the cluster with senior service member 1
Received stats [memberId=2, eventType=INSERTED, sample=1] = EventStats[name = INSERTED, sampleMean = 0.294040ms, mean = 0.294040ms]
Received stats [memberId=3, eventType=INSERTED, sample=1] = EventStats[name = INSERTED, sampleMean = 0.397855ms, mean = 0.397855ms]
Received stats [memberId=1, eventType=INSERTED, sample=1] = EventStats[name = INSERTED, sampleMean = 0.373270ms, mean = 0.373270ms]
Received stats [memberId=3, eventType=UPDATED, sample=1] = EventStats[name = UPDATED, sampleMean = 0.187132ms, mean = 0.187132ms]
Received stats [memberId=2, eventType=UPDATED, sample=1] = EventStats[name = UPDATED, sampleMean = 0.234314ms, mean = 0.234314ms]
Received stats [memberId=1, eventType=UPDATED, sample=1] = EventStats[name = UPDATED, sampleMean = 0.237622ms, mean = 0.237622ms]
Received stats [memberId=2, eventType=UPDATED, sample=2] = EventStats[name = UPDATED, sampleMean = 1.315323ms, mean = 1.432480ms]
Received stats [memberId=3, eventType=UPDATED, sample=2] = EventStats[name = UPDATED, sampleMean = 0.417201ms, mean = 0.510767ms]
Received stats [memberId=1, eventType=UPDATED, sample=2] = EventStats[name = UPDATED, sampleMean = 0.190555ms, mean = 0.309366ms]
Received stats [memberId=2, eventType=EXECUTED, sample=1] = EventStats[name = EXECUTED, sampleMean = 1.766313ms, mean = 1.766313ms]
Received stats [memberId=3, eventType=EXECUTED, sample=1] = EventStats[name = EXECUTED, sampleMean = 1.672603ms, mean = 1.672603ms]
Received stats [memberId=1, eventType=EXECUTED, sample=1] = EventStats[name = EXECUTED, sampleMean = 1.676003ms, mean = 1.676003ms]

------   timing interceptor completed successfully
------ events examples completed------

11.3 イベント・インターセプタを使用したコミット前イベントおよびコミット後イベントの拒否

この演習では、指定したキーに基づいてイベントを検出し、拒否するイベント・インターセプタを作成します。この演習を完了するには:

1. イベントを検出および拒否するイベント・インターセプタの作成

2. イベント拒否イベント・インターセプタの登録

3. イベント拒否イベント・インターセプタを実行するクラスの作成

4. イベント拒否サンプルのドライバ・ファイルの編集

5. イベント拒否サンプルの実行

11.3.1 イベントを検出および拒否するイベント・インターセプタの作成

イベントを受け入れるまたは拒否するライブ・イベントの機能を実行するには、CantankerousInterceptorというイベント・インターセプタを作成します。インターセプタは、指定したキーに対応するイベントに基づいて例外をスローします。

1. CantankerousInterceptorという新しいJavaクラスを作成します。「Default Package」がcom.oracle.handsonであることを確認します。「Main Method」チェック・ボックスは選択しないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. イベント・インターセプタのコードを作成します。Event、EventInterceptor、Interceptor、EntryEventおよびEntryEvent.Typeのクラスとインタフェースをインポートします。独自のインターセプタ・コードを作成するか、または例11-8で提供されているコードを使用できます。

例11-8は、挿入を試行しているキーに基づいて、コミット前イベントまたはコミット後イベント時に実行時例外をスローするイベント・インターセプタを示しています。例外がコミット前にスローされた場合は、ロールバックが発生し、例外がクライアントに伝播されます。例外がコミット後に発生した場合は、ログ・イベントが記録されます。例外に使用されるキーは、VETOおよびNON-VETOです。INSERTINGおよびUPDATINGは拒否できるイベントであるのに対して、INSERTEDおよびUPDATEDイベントは拒否できません。

例11-8 イベントを検出および拒否するクラス

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import com.tangosol.net.events.Event;
import com.tangosol.net.events.EventInterceptor;
import com.tangosol.net.events.annotation.Interceptor;
import com.tangosol.net.events.partition.cache.EntryEvent;
import com.tangosol.net.events.partition.cache.EntryEvent.Type;

import com.tangosol.util.BinaryEntry;

/**
* A CantankerousInterceptor is an {@link EventInterceptor} implementation
* that is argumentative in nature, hence the event of inserting certain keys
* will result in {@link RuntimeException}s at either pre- or postcommit
* phases. Throwing a {@link RuntimeException} during the precommit phase
* will result in a rollback and related exception being propagated to the
* client. A postcommit exception will result in a log event. A precommit
* event is considered an *ING event with a postcommit event being a
* *ED event.
* <p>
* This interceptor assumes it will be working against a cache with strings
* as keys with the following items that will be considered objectionable.
* <table>
*     <tr><td>Key</td><td>Exception Thrown During Event</td></tr>
*     <tr><td>{@value #VETO}</td><td>{@link Type#INSERTING} ||
*             {@link Type#UPDATING}</td></tr>
*     <tr><td>{@value #NON_VETO}</td><td>{@link Type#INSERTED} ||
*             {@link Type#UPDATED}</td></tr>
* </table>
*
*
* @since Coherence 12.1.2
*/
@Interceptor(identifier = "cantankerous",
entryEvents = {Type.INSERTING, Type.INSERTED, Type.UPDATING, Type.UPDATED})
public class CantankerousInterceptor
implements EventInterceptor<EntryEvent>
{
// ----- EventInterceptor methods ---------------------------------------

/**
* Throws {@link RuntimeException} iff the key used for this event is
* {@code #VETO} or {@code #NON_VETO}.
*
* @param event  the {@link Event} to be processed
*
* @throws RuntimeException iff {@code #VETO} || {@code #NON_VETO} are
*         keys of the event
*/
public void onEvent(EntryEvent event)
{
for (BinaryEntry binEntry : event.getEntrySet())
{
if (VETO.equals(binEntry.getKey()))
{
throw new RuntimeException("Objection! value = " + binEntry.getValue());
}
else if (NON_VETO.equals(binEntry.getKey())
&& (event.getType() == Type.INSERTED || event.getType() == Type.UPDATED))
{

NamedCache cacheResults = CacheFactory.getCache("events-results");
int        nMemberId    = CacheFactory.getCluster().getLocalMember().getId();
String     sMessage     = "Objection falls on deaf ears! value = " + binEntry.getValue();

cacheResults.put(
String.format("%d-NON_VETO-%d", nMemberId, ++m_cNonVetoableEvents),
sMessage);

throw new RuntimeException(sMessage);
}
}
}

// ----- constants ------------------------------------------------------

/**
* String used to determine whether the event should be VETO'd during the
* precommit phase.
*/
public static final String VETO     = "VETO";

/**
* String used to determine whether the event should be VETO'd during the
* postcommit phase.
*/
public static final String NON_VETO = "NON-VETO";

// ----- data members ---------------------------------------------------

/**
* A counter of the number of non-vetoable exceptions raised.
*/
private int m_cNonVetoableEvents;
}

11.3.2 イベント拒否イベント・インターセプタの登録

uem-cache-config.xmlキャッシュ構成ファイルを開き、CantankerousInterceptorイベント・インターセプタとそのキャッシュを登録するコードを追加します。参照するキャッシュであるvetod-eventsを<cache-name>要素にリストし、その関連スキームであるevents-distributed-schemeを<scheme-name>要素にリストします。CantankerousInterceptorクラスの完全修飾クラス名を、<interceptors>スタンザの<class-name>サブ要素にリストします。追加したコードは太字で示されています。

例11-9 CantankerousInterceptorクラスを登録するキャッシュ構成

<?xml version="1.0"?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<defaults>
<serializer>pof</serializer>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>events</cache-name>
<scheme-name>events-distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.TimedTraceInterceptor</class-name>
<init-params>
<init-param>
<param-type>int</param-type>
<param-value>100</param-value>
</init-param>
</init-params>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
<cache-mapping>
<cache-name>vetod-events</cache-name>
<scheme-name>events-distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.CantankerousInterceptor</class-name>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
<cache-mapping>
<cache-name>events-results</cache-name>
<scheme-name>dist-events-results</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<distributed-scheme>
<scheme-name>events-distributed-scheme</scheme-name>
<service-name>PartitionedPofCache</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme>
<!-- each node will be limited to 32MB -->
<high-units>32M</high-units>
<unit-calculator>binary</unit-calculator>
</local-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!-- A PartitionedCache service used to store results for events examples
-->
<distributed-scheme>
<scheme-name>dist-events-results</scheme-name>
<service-name>PartitionedEventsResults</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme/>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!--
Invocation Service scheme.
-->
<invocation-scheme>
<scheme-name>examples-invocation</scheme-name>
<service-name>InvocationService</service-name>

<autostart system-property="tangosol.coherence.invocation.autostart">true</autostart>
</invocation-scheme>

</caching-schemes>
</cache-config>

11.3.3 イベント拒否イベント・インターセプタを実行するクラスの作成

CantankerousInterceptorイベント・インターセプタを実行するクラスを作成します。クラス内に、サブクラスVetoedEventsExampleを作成します。VetoedEventsExampleサブクラスは、CantankerousInterceptorによって実行されるアクションを開始します。コードは、コミット前イベントおよびコミット後イベントにおける例外スローのセマンティクスを示しています。記録する必要がある例外のみが結果キャッシュに挿入されます。結果キャッシュに挿入されたエントリは、このクラスを実行するプロセスの標準出力を使用して表示されます。

例11-10 TimedTraceInterceptorイベント・インターセプタを実行するクラス

package com.oracle.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;
import com.tangosol.util.MultiplexingMapListener;

import java.util.concurrent.Callable;

/**
* VetoExample illustrates the different semantics in throwing exceptions in pre
*  events compared to post events.
*
* @since Coherence 12.1.2
*/
@SuppressWarnings("unchecked")
public class VetoExample
{

/**
* The VetoExample is a catalyst for action to be performed by
* {@link CantankerousInterceptor}. This illustrates the semantics of
* throwing exceptions in pre- and postcommit events. The exceptions that are
* expected to only be logged are inserted into a results cache. The
* entries inserted into the results cache are
* displayed via the stdout of the process executing this class.
*/
public static class VetoedEventsExample
implements Callable<Boolean>
{

// ----- Callable methods -------------------------------------------

/**
* {@inheritDoc}
*/
public Boolean call() throws Exception
{
// perform events to cause interceptors to veto said event
NamedCache  cacheVetoEvents = CacheFactory.getCache("vetod-events");
NamedCache  cacheResults    = CacheFactory.getCache("events-results");
MapListener ml              = new MultiplexingMapListener()
{
@Override
protected void onMapEvent(MapEvent evt)
{
String[] asKey = ((String) evt.getKey()).split("-");

System.out.printf("Received event [memberId=%s, eventType=%s, count=%s] = %s\n",
asKey[0], asKey[1], asKey[2], evt.getNewValue());
}
};
try
{
int cSet      = 110;
int cVetos    = 5;
int cNonVetos = 10;
int cVetod    = 0;

cacheResults.addMapListener(ml);

for (int i = 1; i <= cSet; ++i)
{
boolean fVetod = false;

if (i % (cSet / cVetos) == 0)
{
try
{
cacheVetoEvents.put(CantankerousInterceptor.VETO, "value: " + i);
}
catch(Throwable e)
{
fVetod = true;
++cVetod;
}
}
if (i % (cSet / cNonVetos) == 0)
{
cacheVetoEvents.put(CantankerousInterceptor.NON_VETO, "value: " + i);
fVetod = true;
}

if (!fVetod)
{
cacheVetoEvents.put(String.valueOf(i), "value: " + i);
}
}
System.out.printf("Number of veto'd events: %d\n", cVetod);
}
finally
{
cacheVetoEvents.clear();
cacheResults.removeMapListener(ml);
cacheResults.clear();
}
return true;
}
}
}

11.3.4 イベント拒否サンプルのドライバ・ファイルの編集

「イベント時間測定サンプルのドライバ・ファイルの作成」で作成したドライバ・ファイルを、VetoExampleクラスで定義したVetoedEventsExampleサンプルを実行するように編集します。

ドライバ・ファイルを編集するには:

1. イベント・タイミング・サンプルの次のインポート文を置換します。

import com.oracle.handson.EventsExamples.EventsTimingExample;

VetoedEventsExampleサブクラスの置換後のインポート文は、次のとおりです。

import com.oracle.handson.VetoExample.VetoedEventsExample;

2. イベント時間測定サンプルをコールする次のコマンドを置換します。

EVENTS_EXAMPLES.put("timing interceptor", new EventsTimingExample());

VetoExampleクラスで定義したVetoedEventsExampleサンプルを実行する置換後のコマンドは、次のとおりです。

EVENTS_EXAMPLES.put("veto interceptor", new VetoedEventsExample());

11.3.5 イベント拒否サンプルの実行

「Project Explorer」でUEMEventsプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「キャッシュ・サーバー起動の構成の作成」で作成したUEMEventsServer起動構成を選択します。「Run」をクリックして、キャッシュ・サーバーを起動します。キャッシュ・サーバーの起動後、UEMEventsServerを選択し、「Run」をもう一度、さらにもう一度クリックして、合計で3つのキャッシュ・サーバーを起動します。

3番目のキャッシュ・サーバーの起動後、UEMEventDriver起動構成を選択し、「Run」をクリックします。イベント拒否クライアントからの出力は例11-11のようになります。

例11-11 イベント拒否クライアントからの出力

------ events examples begin ------
------   veto interceptor begin
2013-03-08 12:00:57.718/1.843 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=4): Service Management joined the cluster with senior service member 1
...
2013-03-08 12:00:58.109/2.234 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:PartitionedEventsResults, member=4): Service PartitionedEventsResults joined the cluster with senior service member 1
Received event [memberId=3, eventType=NON_VETO, count=1] = Objection falls on deaf ears! value = value: 11
Received event [memberId=3, eventType=NON_VETO, count=2] = Objection falls on deaf ears! value = value: 22
Received event [memberId=3, eventType=NON_VETO, count=3] = Objection falls on deaf ears! value = value: 33
Received event [memberId=3, eventType=NON_VETO, count=4] = Objection falls on deaf ears! value = value: 44
Received event [memberId=3, eventType=NON_VETO, count=5] = Objection falls on deaf ears! value = value: 55
Received event [memberId=3, eventType=NON_VETO, count=6] = Objection falls on deaf ears! value = value: 66
Received event [memberId=3, eventType=NON_VETO, count=7] = Objection falls on deaf ears! value = value: 77
Received event [memberId=3, eventType=NON_VETO, count=8] = Objection falls on deaf ears! value = value: 88
Received event [memberId=3, eventType=NON_VETO, count=9] = Objection falls on deaf ears! value = value: 99
Number of veto'd events: 5
Received event [memberId=3, eventType=NON_VETO, count=10] = Objection falls on deaf ears! value = value: 110
------   veto interceptor completed successfully
------ events examples completed------

例11-12に示されている3番目のキャッシュ・サーバーからの出力に注意してください。出力には、拒否したイベントによって発生する例外が表示されます。

例11-12 キャッシュ・サーバーからの出力

Started DefaultCacheServer...

2013-03-08 12:00:52.921/12.968 Oracle Coherence GE 12.1.2.0.0 <D4> (thread=DistributedCache:PartitionedPofCache, member=3): Asking member 1 for primary ownership of PartitionSet{128..171}
...
2013-03-08 12:00:58.125/18.172 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=3): Member 4 joined Service PartitionedEventsResults with senior member 1
2013-03-08 12:00:58.265/18.312 Oracle Coherence GE 12.1.2.0.0 <Error> (thread=DistributedCache:PartitionedPofCache:EventDispatcher, member=3): Exception caught while dispatching to "<cantankerous, com.oracle.handson.CantankerousInterceptor>": Objection falls on deaf ears! value = value: 11
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:74)
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:1)
at com.tangosol.net.events.internal.NamedEventInterceptor.onEvent(NamedEventInterceptor.java:240)
at com.tangosol.net.events.internal.AbstractEvent.nextInterceptor(AbstractEvent.java:116)
at com.tangosol.net.events.internal.AbstractEvent.dispatch(AbstractEvent.java:154)
at com.tangosol.net.events.internal.AbstractEventDispatcher$1.proceed(AbstractEventDispatcher.java:254)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.PartitionedService$Continuations$Task.run(PartitionedService.CDB:6)
at com.tangosol.coherence.component.util.daemon.queueProcessor.Service$EventDispatcher.onNotify(Service.CDB:26)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

2013-03-08 12:00:52.953/13.000 Oracle Coherence GE 12.1.2.0.0 <Error> (thread=DistributedCache:PartitionedPofCache:EventDispatcher, member=3): Exception caught while dispatching to "<cantankerous, com.oracle.handson.CantankerousInterceptor>": Objection falls on deaf ears! value = value: 22
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:74)
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:1)
at com.tangosol.net.events.internal.NamedEventInterceptor.onEvent(NamedEventInterceptor.java:240)
at com.tangosol.net.events.internal.AbstractEvent.nextInterceptor(AbstractEvent.java:116)
at com.tangosol.net.events.internal.AbstractEvent.dispatch(AbstractEvent.java:154)
at com.tangosol.net.events.internal.AbstractEventDispatcher$1.proceed(AbstractEventDispatcher.java:254)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.PartitionedService$Continuations$Task.run(PartitionedService.CDB:6)
at com.tangosol.coherence.component.util.daemon.queueProcessor.Service$EventDispatcher.onNotify(Service.CDB:26)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

...

2013-03-08 12:00:58.640/18.687 Oracle Coherence GE 12.1.2.0.0 <Error> (thread=DistributedCache:PartitionedPofCache:EventDispatcher, member=3): Exception caught while dispatching to "<cantankerous, com.oracle.handson.CantankerousInterceptor>": Objection falls on deaf ears! value = value: 110
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:74)
at com.oracle.handson.CantankerousInterceptor.onEvent(CantankerousInterceptor.java:1)
at com.tangosol.net.events.internal.NamedEventInterceptor.onEvent(NamedEventInterceptor.java:240)
at com.tangosol.net.events.internal.AbstractEvent.nextInterceptor(AbstractEvent.java:116)
at com.tangosol.net.events.internal.AbstractEvent.dispatch(AbstractEvent.java:154)
at com.tangosol.net.events.internal.AbstractEventDispatcher$1.proceed(AbstractEventDispatcher.java:254)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.PartitionedService$Continuations$Task.run(PartitionedService.CDB:6)
at com.tangosol.coherence.component.util.daemon.queueProcessor.Service$EventDispatcher.onNotify(Service.CDB:26)
at com.tangosol.coherence.component.util.Daemon.run(Daemon.CDB:51)
at java.lang.Thread.run(Thread.java:722)

...
2013-03-08 12:00:58.734/18.781 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=3): MemberLeft notification for Member(Id=4, Timestamp=2013-03-08 12:00:58.718, Address=192.168.0.102:8094, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:5720, Role=OracleHandsonDriver) received from Member(Id=1, Timestamp=2013-03-08 12:00:08.343, Address=192.168.0.102:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3508, Role=CoherenceServer)

11.4 イベント・インターセプタを使用したパーティション・アクティビティのロギング

この演習では、パーティション・サービスのパーティション・イベントを記録するイベント・インターセプタを作成します。この演習を完了するには:

1. JVMの終了およびロギングの有効化と無効化を実行するクラスの作成

2. パーティション・アクティビティを記録するイベント・インターセプタの作成

3. パーティション・アクティビティ記録サンプルを実行するクラスの作成

4. パーティション・アクティビティ記録イベント・インターセプタの登録

5. POF構成ファイルの編集

6. パーティション・アクティビティ記録サンプルのドライバ・ファイルの編集

7. パーティション・アクティビティ記録サンプルの実行

11.4.1 JVMの終了およびロギングの有効化と無効化を実行するクラスの作成

クラスタの様々なメンバーで実行されるアクション可能な3つの状態を定義するRedistributionInvocableというクラスを作成します。この例では、状態を次のように定義します。

- DISABLE: RedistributionInterceptorイベント・インターセプタによって実行されるロギングを無効にします。

- ENABLE: RedistributionInterceptorイベント・インターセプタによって実行されるロギングを有効にします。

- KILL: この起動可能(RedistributionInvocable)が実行されるJVMを終了します。

RedistributionInterceptorイベント・インターセプタは後の手順で作成します。

ロギングが有効であるか無効であるかを判別する変数には、AtomicBooleanクラスを使用します。次に例を示します。

public static final AtomicBoolean ENABLED = new AtomicBoolean(false)

起動可能を終了するには、KILL状態で単にSystem.exitをコールできます。

クラスが生成するデータはワイヤ経由で送信されるため、クラスでPOF (Portable Object Format)を使用する必要があります。POF構成ファイルへのクラスの追加は後の手順で実行します。

RedistributionInvocableクラスを作成するには:

1. RedistributionInvocableという新しいJavaクラスを作成します。「Default Package」がcom.oracle.handsonであることを確認します。「Main Method」チェック・ボックスは選択しないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. インターセプタ・オブジェクトに割当て可能な3つの異なる状態を定義するクラスを作成します。AbstractInvocable、AtomicBoolean、PortableObject、PofReaderおよびPofWriterのクラスとインタフェースをインポートします。RedistributionInvocableクラスは、AbstractInvocableクラスを拡張し、PortableObjectインタフェースを実装する必要があります。独自のRedistributionInvocableクラスを作成するか、または例11-13で提供されているコードを使用します。

例11-13 JVMの終了およびロギングの有効化または無効化を実行するクラス

package com.oracle.handson;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import com.tangosol.net.AbstractInvocable;

import java.io.IOException;

import java.util.concurrent.atomic.AtomicBoolean;

/**
* RedistributionInvocable has three states in which appropriate action is
* taken:
* <ol>
*     <li><strong>{@link State#DISABLE}</strong> - Disables the logging
*     performed by {@link com.oracle.handson.RedistributionInterceptor}.</li>
*     <li><strong>{@link State#ENABLE}</strong> - Enables the logging
*     performed by {@link com.oracle.handson.RedistributionInterceptor}.</li>
*     <li><strong>{@link State#KILL}</strong> - Kills the JVM this invocable
*     is executed on.</li>
* </ol>
*
*
* @since 12.1.2
*/
public class RedistributionInvocable
extends AbstractInvocable
implements PortableObject
{
// ----- constructors ---------------------------------------------------

/**
*
*/
private static final long serialVersionUID = 1L;

/**
* Default no-arg constructor.
*/
public RedistributionInvocable()
{
this(State.DISABLE);
}

/**
* Constructs a RedistributionInvocable with the specified state.
*
* @param state  the state indicating the action to be performed
*/
public RedistributionInvocable(State state)
{
m_state = state;
}

// ----- Invocable methods ----------------------------------------------

/**
* {@inheritDoc}
*/
public void run()
{
switch (m_state)
{
case DISABLE:
ENABLED.set(false);
break;
case ENABLE:
ENABLED.set(true);
break;
case KILL:
System.exit(1);
}
}

// ----- PortableObject methods -----------------------------------------

/**
* {@inheritDoc}
*/
public void readExternal(PofReader in) throws IOException
{
m_state = State.values()[in.readInt(0)];
}

/**
* {@inheritDoc}
*/
public void writeExternal(PofWriter out) throws IOException
{
out.writeInt(0, m_state.ordinal());
}

// ----- inner class: State ---------------------------------------------

/**
* Representation of the action to be performed when
* {@link RedistributionInvocable#run()}.
*/
public enum State
{
/**
* Disables the logging performed by
* {@link com.oracle.handson.RedistributionInterceptor}
*/
DISABLE,
/**
* Enables the logging performed by
* {@link com.oracle.handson.RedistributionInterceptor}
*/
ENABLE,
/**
* Terminates the JVM process in which the
* {@link RedistributionInvocable} is executed.
*/
KILL
}

// ----- constants ------------------------------------------------------

/**
* Flag used to determine whether to log partition events.
*/
public static final AtomicBoolean ENABLED = new AtomicBoolean(false);

// ----- data members ---------------------------------------------------

/**
* The state used to determine which action to perform.
*/
private State m_state;
}

11.4.2 パーティション・アクティビティを記録するイベント・インターセプタの作成

パーティション・サービスのパーティション・イベントを記録するRedistributionInterceptorというイベント・インターセプタを作成します。

RedistributionInterceptorイベント・インターセプタ・クラスを作成するには:

1. RedistributionInterceptorという新しいJavaクラスを作成します。「Default Package」がcom.oracle.handsonであることを確認します。「Main Method」チェック・ボックスは選択しないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. パーティション・イベントを記録するRedistributionInterceptorクラスを作成します。RedistributionInvocable、CacheFactory、EventInterceptor、Interceptor、TransferEventのクラスとインタフェースをインポートします。RedistributionInterceptorクラスはEventInterceptor<TransferEvent>インタフェースを実装する必要があります。パーティション・イベントを記録する独自のクラスを作成するか、または例11-14で提供されるコードを使用します。

例11-14は、パーティション・イベントを記録するイベント・インターセプタを示しています。@Interceptor注釈にあるオプションのidentifier属性を使用して、インターセプタに名前を割り当てることができます。イベント・インターセプタでは、RedistributionInvocable.ENABLED定数の値を参照して、パーティション・イベントを記録するかどうかを決定します。

例11-14 パーティション・イベントを記録するクラス

package com.oracle.handson;

import com.oracle.handson.RedistributionInvocable;

import com.tangosol.net.CacheFactory;

import com.tangosol.net.events.EventInterceptor;
import com.tangosol.net.events.annotation.Interceptor;
import com.tangosol.net.events.partition.TransferEvent;

/**
* RedistributionInterceptor is an {@link
* com.tangosol.net.events.EventInterceptor}
* that logs partition activity when enabled. Logging can be enabled via
* setting the {@link RedistributionInvocable#ENABLED} constant.
*
* @since Coherence 12.1.2
*/
@Interceptor(identifier = "redist")
public class RedistributionInterceptor
implements EventInterceptor<TransferEvent>
{

// ----- EventInterceptor methods ---------------------------------------

/**
* {@inheritDoc}
*/
public void onEvent(TransferEvent event)
{
if (RedistributionInvocable.ENABLED.get())
{
CacheFactory.log(String.format("Discovered event %s for partition-id %d from remote member %s\n",
event.getType(), event.getPartitionId(), event.getRemoteMember()),
CacheFactory.LOG_INFO);
}
}
}

11.4.3 パーティション・アクティビティ記録サンプルを実行するクラスの作成

RedistributionInterceptorクラスによって実行されるアクションをトリガーするLogExampleというクラスを作成します。

LogExampleクラスを作成するには:

1. LogExampleという新しいJavaクラスを作成します。mainメソッドは含めないでください。
詳細は、「Javaクラスの作成」を参照してください。

2. LogExampleクラスのコードを作成します。RedistributionInvocable、RedistributionInvocable.State、CacheFactory、InvocationService、Member、ArrayList、Collection、Random、SetおよびCallableのクラスとインタフェースをインポートします。独自のコードを作成するか、または例11-15で提供されているコードを使用できます。

例11-15は、LogExampleクラスのサンプル実装を示しています。例には、RedistributionInterceptorクラスによって実行されるアクションをトリガーするサブクラスであるRedistributionEventsExampleサブクラスが含まれています。サブクラスは、パーティション再配布イベントの記録方法を示しています。このサンプルを実行するには、少なくとも2つのクラスタ・メンバーを実行している必要があります。

例11-15 パーティション・アクティビティ記録サンプルを実行するサンプル・クラス

package com.oracle.handson;

import com.oracle.handson.RedistributionInvocable;
import com.oracle.handson.RedistributionInvocable.State;
import com.tangosol.net.CacheFactory;
import com.tangosol.net.InvocationService;
import com.tangosol.net.Member;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Callable;

/**
* LogExample illustrates logging of partition movement when enabled.
*
* @since Coherence 12.1.2
*/
@SuppressWarnings("unchecked")
public class LogExample
{

/**
* The RedistributionEventsExample is a catalyst for action to be
* performed by {@link RedistributionInterceptor}. This illustrates how
* partition redistribution events can be logged.
*/
public static class RedistributionEventsExample
implements Callable<Boolean>
{

// ----- Callable methods -------------------------------------------

/**
* {@inheritDoc}
*/
public Boolean call() throws Exception
{
// transfer events
try
{
InvocationService is       = (InvocationService) CacheFactory.getService("InvocationService");
Random            rnd      = new Random();
int               cMembers = is.getInfo().getServiceMembers().size();

if (cMembers < 3)
{
System.err.println("<Error> At least two members must exist for the RedistributionEvent example");
return false;
}

// enable the logging of transfer event
is.query(new RedistributionInvocable(State.ENABLE), null);

Set<Member> isMembers = is.getInfo().getServiceMembers();
isMembers.remove(is.getCluster().getLocalMember());

Member memChosen = new ArrayList<Member>(isMembers).get(rnd.nextInt(isMembers.size()));

System.out.printf("Choosing to kill member %s\n", memChosen);
is.query(new RedistributionInvocable(State.KILL), Collections.singleton(memChosen));
}
finally
{
}

return true;
}
}
}

11.4.4 パーティション・アクティビティ記録イベント・インターセプタの登録

イベント・インターセプタは、プログラムで、またはキャッシュ構成ファイルにそれらに対する参照を含めることによって登録できます。

UEMEventsプロジェクトで、インターセプタはキャッシュ構成ファイルに登録されます。イベント・インターセプタの完全修飾クラス名は、<interceptor>要素で指定されます。インターセプタは、<cache-name>要素で指定されるキャッシュと関連付けられます。

パーティション記録イベント・サンプルの場合、イベント・インターセプタRedistributionInterceptorは、<distributed-scheme>要素の下のパーティション・キャッシュ・サービスに登録されます。

RedistributionInterceptorイベント・インターセプタを定義するキャッシュ構成ファイルを編集するには:

1. 「Project Explorer」ウィンドウから、uem-cache-config.xmlファイルを開きます。ファイルはEvents/appClientModuleの下にあります。

2. イベント・インターセプタをコールするキャッシュ構成を作成します。<distributed-scheme>要素の下で、<interceptor>要素に完全修飾RedistributionInterceptorクラスへの参照があることを確認してください。

例11-16は、考えられるuem-cache-config.xmlファイルの実装を示しています。RedistributionInterceptorイベント・インターセプタの構成は、太字で示されています。

例11-16 イベント・インターセプタを含むキャッシュ構成ファイル

<?xml version="1.0"?>

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
<defaults>
<serializer>pof</serializer>
</defaults>

<caching-scheme-mapping>
<cache-mapping>
<cache-name>events</cache-name>
<scheme-name>events-distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.TimedTraceInterceptor</class-name>
<init-params>
<init-param>
<param-type>int</param-type>
<param-value>100</param-value>
</init-param>
</init-params>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
<cache-mapping>
<cache-name>vetod-events</cache-name>
<scheme-name>events-distributed-scheme</scheme-name>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.CantankerousInterceptor</class-name>
</instance>
</interceptor>
</interceptors>
</cache-mapping>
<cache-mapping>
<cache-name>events-results</cache-name>
<scheme-name>dist-events-results</scheme-name>
</cache-mapping>
</caching-scheme-mapping>

<caching-schemes>
<distributed-scheme>
<scheme-name>events-distributed-scheme</scheme-name>
<service-name>PartitionedPofCache</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme>
<!-- each node will be limited to 32MB -->
<high-units>32M</high-units>
<unit-calculator>binary</unit-calculator>
</local-scheme>
</backing-map-scheme>
<autostart>true</autostart>
<interceptors>
<interceptor>
<instance>
<class-name>com.oracle.handson.RedistributionInterceptor</class-name>
</instance>
</interceptor>
</interceptors>
</distributed-scheme>

<!-- A PartitionedCache service used to store results for events examples
-->
<distributed-scheme>
<scheme-name>dist-events-results</scheme-name>
<service-name>PartitionedEventsResults</service-name>
<thread-count>5</thread-count>
<backing-map-scheme>
<local-scheme/>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>

<!--
Invocation Service scheme.
-->
<invocation-scheme>
<scheme-name>examples-invocation</scheme-name>
<service-name>InvocationService</service-name>

<autostart system-property="tangosol.coherence.invocation.autostart">true</autostart>
</invocation-scheme>

</caching-schemes>
</cache-config>

11.4.5 POF構成ファイルの編集

RedistributionInvocableクラスを除いて、パーティション・アクティビティ記録演習のクラスによって生成された情報はすべて、その固有のクラスタ・メンバー上に保持されます。ただし、RedistributionInvocableクラスによって生成された情報は、ワイヤ経由で他のクラスタ・メンバーに送信されます。したがって、POF構成ファイルに追加する必要があります。

RedistributionInvocableデータ型用のPOF構成ファイルを編集するには:

1. uem-pof-config.xmlファイルを開きます。ファイルはUEMEvents/appClientModule/META-INFの下にあります。

2. com.oracle.handson.RedistributionInvocableクラスに対する<user-type>要素を定義し、タイプID 1009を割り当てます。このファイルには、Coherenceデータ型の最初の1000個のIDを予約するcoherence-pof-config.xmlファイルが含まれている必要があります。

例11-17は、uem-pof-config.xmlファイルのサンプルを示しています。RedistributionInvocableクラスの構成は、太字で示されています。

例11-17 パーティション記録イベント・サンプルのPOF構成ファイル

<?xml version="1.0"?>
<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config http://xmlns.oracle.com/coherence/coherence-pof-config/1.2/coherence-pof-config.xsd">
<user-type-list>
<!-- include all "standard" Coherence POF user types -->
<include>coherence-pof-config.xml</include>
<user-type>
<type-id>1008</type-id>
<class-name>com.oracle.handson.LazyProcessor</class-name>
</user-type>
<user-type>
<type-id>1009</type-id>
<class-name>com.oracle.handson.RedistributionInvocable</class-name>
</user-type>
</user-type-list>
</pof-config>

11.4.6 パーティション・アクティビティ記録サンプルのドライバ・ファイルの編集

「イベント時間測定サンプルのドライバ・ファイルの作成」で作成したドライバ・ファイルを、LogExampleクラスで定義したRedistributionEventsExampleサンプルを実行するように編集します。

ドライバ・ファイルを編集するには:

1. イベント拒否サンプルの次のインポート文を置換します。

import com.oracle.handson.VetoExample.VetoedEventsExample;

LogExampleクラスのRedistributionEventsExampleサブクラスの置換後のインポート文は、次のとおりです。

import com.oracle.handson.LogExample.RedistributionEventsExample;

2. イベント拒否サンプルをコールする次のコマンドを置換します。

EVENTS_EXAMPLES.put("veto interceptor", new VetoedEventsExample());

LogExampleクラスで定義したRedistributionEventsExampleサンプルを実行する置換後のコマンドは、次のとおりです。

EVENTS_EXAMPLES.put("redistribution interceptor", new RedistributionEventsExample());

11.4.7 パーティション・アクティビティ記録サンプルの実行

「Project Explorer」でUEMEventsプロジェクトを右クリックして、「Run As」→「Run Configurations」を選択します。「Run Configurations」ダイアログ・ボックスで、「キャッシュ・サーバー起動の構成の作成」で作成したUEMEventsServer起動構成を選択します。「Run」をクリックして、キャッシュ・サーバーを起動します。キャッシュ・サーバーの起動後、UEMEventsServerを選択し、「Run」をもう一度、さらにもう一度クリックして、合計で3つのキャッシュ・サーバーを起動します。

3番目のキャッシュ・サーバーの起動後、UEMEventDriver構成を選択し、「Run」をクリックします。キャッシュ・クライアントからの出力は例11-18のようになります。

例11-18 キャッシュ・クライアントからの出力

------ events examples begin ------
------   redistribution interceptor begin
2013-03-08 12:35:38.640/2.062  Oracle Coherence 12.1.2.0.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/Oracle7/coherence/lib/coherence.jar!/tangosol-coherence.xml"

...

2013-03-08 12:35:38.640/2.062 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:InvocationService, member=4): Service InvocationService joined the cluster with senior service member 1
Choosing to kill member Member(Id=1, Timestamp=2013-03-08 12:34:41.218, Address=192.168.0.102:8088, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3476, Role=CoherenceServer)
------   redistribution interceptor completed successfully
------ events examples completed------
2013-03-08 12:35:38.703/2.125 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Invocation:Management, member=4): Member 1 left service Management with senior member 1

...

例11-19は、終了したキャッシュ・サーバーからの出力を示しています。出力は、クラスタに参加しているクライアント(Member 4)および現在のキャッシュ・サーバーの停止を示しています。

例11-19 最初のキャッシュ・サーバーからの出力

...

2013-03-08 12:43:41.750/2.438 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Transferring primary PartitionSet{128..171} to member Member(Id=3, Timestamp=2012-12-24 12:19:36.983, Address=10.159.166.164:8092, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:1692, Role=CoherenceServer) requesting 44
2013-03-08 12:44:14.109/34.797 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-12-24 12:19:53.952, Address=10.159.166.164:8094, MachineId=18578, Location=site:,machine:tpfaeffl-lap7,process:3360, Role=OracleHandsonDriver) joined Cluster with senior member 1
2013-03-08 12:44:14.375/35.063 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
22013-03-08 12:44:14.640/35.328 Oracle Coherence GE 12.1.2.0.0 <D5> (thread=Cluster, member=1): Member 4 joined Service InvocationService with senior member 1
2013-03-08 12:44:14.656/35.344 Oracle Coherence GE 12.1.2.0.0 <D4> (thread=ShutdownHook, member=1): ShutdownHook: stopping cluster node

12 管理対象WebLogic Serverを使用したセッションのキャッシュ

この演習では、WebLogic Serverインスタンス間でデプロイされたWebアプリケーション・インスタンスのセッション情報をキャッシュする方法を説明します。ここでは、Coherenceデータ・キャッシュを使用し、セッション管理のためのCoherence*Webをシームレスに組み込むことができる管理対象サーバーの使用について取り上げます。

最新のWebLogic Serverリリースをまだ導入していない場合は、次のURLで入手できます。

http://www.oracle.com/technology/software/products/middleware/index.html

この章の内容は、次のとおりです。

- 概要

- Webアプリケーション・インスタンスのセッション情報のキャッシュ

- カスタム・セッション・キャッシュ構成ファイルの使用

12.1 概要

WebLogic Serverには、デプロイされたアプリケーションでCoherenceデータ・キャッシュを使用し、セッション管理のためのCoherence*Webおよびオブジェクト・ツー・リレーショナル永続フレームワークのためのTopLink Gridをシームレスに統合する機能が組み込まれています。これらの機能はまとめてCoherenceコンテナと呼ばれます。

Coherenceコンテナについて

Coherenceコンテナは、WebLogic Serverで実行されるアプリケーションによって利用され、Coherenceデータ・クラスタ内のすべてのサーバーでアプリケーションのデータを利用できるようにするレプリケーション・キャッシュ・サービスと分散キャッシュ・サービスを提供します。アプリケーションでは、リソース・インジェクション、またはコンポーネントベースのJNDIルックアップを介して、データ・キャッシュへの直接アクセスを取得できます。WebLogic Server管理コンソールおよびWLSTを使用して、Coherenceクラスタを表示、モニター、作成および構成できます。

WebLogic ServerインスタンスでCoherenceコンテナを使用すると、アプリケーション・データのキャッシュとレプリケートされたセッション状態の格納専用のデータ層を作成できます。これは、WebLogic Serverインスタンスがアプリケーションの実行専用に使用するアプリケーション層とは分離されます。

Coherence*WebをCoherenceコンテナとともに使用することによって、アプリケーションにCoherenceベースのHTTPセッション状態の永続性を提供できます。Coherence*Webは、異なる複数のWebアプリケーション、ドメインおよび異機種のアプリケーション・サーバー間におけるHTTPセッション共有および管理を実現します。セッション・データは、アプリケーション・サーバー外のデータ・キャッシュに格納できるため、アプリケーション・サーバーのヒープ・スペースを解放し、セッション・データを消失させずにサーバーを再起動できます。

CoherenceおよびCoherence*Webは、WebLogic Serverのデフォルト・インストールに含まれています。CoherenceおよびCoherence*Webライブラリ(coherence.jarおよびcoherence-web.jar)は、WebLogic Serverのシステム・クラスパスに含まれます。これらのライブラリは、適切なクラスローダーを使用してアプリケーション・クラスをWebLogic Serverにロードします。つまり、coherence.jarまたはcoherence-web.jarファイルをWebアプリケーションのクラスパスに含める必要はありません。

Oracle WebLogic Server、CoherenceおよびCoherence*Webの統合の詳細は、『Oracle Fusion Middleware Oracle Coherence*WebでのHTTPセッション・マネージメントの管理』を参照してください。Coherenceコンテナの詳細は、『Oracle Fusion Middleware Oracle WebLogic Server Oracle Coherenceアプリケーションの開発』を参照してください。

Coherenceクラスタについて

Coherenceクラスタは、WebLogic Serverクラスタとは異なります。これらは、異なるクラスタ・プロトコルを使用して、別々に構成されます。複数のWebLogic Serverクラスタを1つのCoherenceクラスタに関連付けることができ、WebLogic Serverドメインには1つのCoherenceクラスタのみを含めることができます。Coherenceクラスタ・メンバーとして構成される管理対象サーバーは、管理対象Coherenceサーバーとして参照されます。管理対象Coherenceサーバーは、1つのCoherenceクラスタに明示的に関連付けたり、Coherenceクラスタに関連付けられている1つのWebLogic Serverクラスタに関連付けることができます。管理対象Coherenceサーバーは通常、それぞれのタイプに基づいてデータを格納するデータ層、アプリケーションをホストするアプリケーション層および外部クライアントへのアクセスを許可するプロキシ層の各層に設定されます。

WebLogicサーバー環境のCoherenceクラスタの詳細は、Oracle WebLogic Serverのクラスタの管理のCoherenceクラスタの構成および管理に関する項を参照してください。

12.2 Webアプリケーション・インスタンスのセッション情報のキャッシュ

次の例は、WebLogic Serverインスタンス間にデプロイされるWebアプリケーション・インスタンスのセッション情報をCoherenceコンテナおよびCoherence*Webがキャッシュする方法を示しています。これを行うには、Webアプリケーションを作成して、Coherenceクラスタに属する2つのWebLogic Serverインスタンスにデプロイします。このアプリケーションは、現在のカウントをセッション属性として格納する簡単なカウンタです。Coherence*Webによって、両方のサーバー・インスタンス間の属性のシリアライズとレプリケートが自動実行されます。各アプリケーション・インスタンスへのアクセスにはブラウザが使用され、インスタンス間で同じセッション属性が使用されていることが示されます。

1. WebLogic Serverの構成および起動

2. WebLogic Serverの作成

3. Coherenceクラスタ構成の作成

4. Coherence*Webローカル記憶域に対するサーバーの有効化

5. カウンタWebアプリケーションの作成

6. WebLogic Serverの起動

7. アプリケーションのデプロイ

8. サンプルの検証

12.2.1 WebLogic Serverの構成および起動

次の手順では、WebLogic Serverがデフォルトの場所であるC:\Oracle\Middleware\Oracle_Homeにインストールされていることを想定しています。

WebLogic Serverを構成および起動するには:

1. Oracle WebLogic構成ウィザードを実行して、新しいWebLogic Serverドメインを作成します。

2. 「ドメインの作成」ページで、「新規拡張ドメインの作成(E)」オプションを選択します。「ドメインの場所」フィールドに、ドメイン名および場所としてC:\Oracle\Middleware\Oracle_Home\user_projects\domains\test_domainと入力します。

3. 「テンプレート」ページで、デフォルトの基本のWebLogic Serverドメインが選択されていることを確認します。

4. 「管理者アカウント」ページで、ドメインのパスワードを入力します。

5. 「ドメイン・モードおよびJDK」および「オプションの構成」ページで、各デフォルトを受け入れます。

6. 「構成サマリー」 ページで、「作成」をクリックします。

7. 最後の「構成に成功しました」ページで、「管理サーバーの起動」チェック・ボックスを選択して「完了」をクリックします。構成ウィザードによって、管理サーバーが自動的に起動します。

8. WebLogic Server 管理コンソールを起動します。
ブラウザから、次のURLを使用して、Oracle WebLogic Server管理コンソールにログインします: http://hostname:7001/console。コンソールが起動し、ドメインのホーム・ページが表示されます。

12.2.2 マシンの作成

WebLogic Serverインスタンスをホストするマシンを作成するには:

「ドメイン構造」ウィンドウから、「環境」→「マシン」を選択します。「新規」をクリックします。「新しいマシンの作成」ページが表示されます。マシンの名前(この例ではTest)を入力して、「次」をクリックします。次のページで「終了」をクリックします。図12-1は、「新しいマシンの作成」ページを示しています。

図12-1 新しいマシンの作成

「マシンのサマリー」ページは、図12-2のようになります。

図12-2 マシンのサマリー

12.2.3 WebLogic Serverの作成

マシンに関連付ける2つのWebLogic Serverインスタンスを作成します。1つは、Coherence*Web記憶域を有効にし、もう1つはCoherence*Web記憶域を無効にします。これらのサーバーには後の手順でアプリケーションがデプロイされます。

サーバー・インスタンスを作成するには:

1. 「マシンのサマリー」ページで、マシンの名前をクリックし、「マシンの設定」ページを開きます。「サーバー」タブ→「追加」をクリックして、サーバーを作成します。

2. 「マシンにサーバーを追加」ページで「新しいサーバーを作成してこのマシンに関連付けます。」を選択し、「次」をクリックします。

3. 「新しいサーバーの作成」ページでサーバーの詳細を指定します。
「サーバー名」にServerAを、「サーバー・リスニング・ポート」に8081を入力します。図12-3に示すように、「いいえ、これはスタンドアロン・サーバーです。」が選択されていることを確認します。「終了」をクリックします。

図12-3 マシンへのサーバーの追加

4. 「マシンの設定」ページに戻ったら、「追加」をクリックして、前述の手順を繰り返し、2番目のサーバーを作成します。
「サーバー名」にServerBを、「サーバー・リスニング・ポート」に8082を入力します。「いいえ、これはスタンドアロン・サーバーです。」が選択されていることを確認します。「終了」をクリックします。

「サーバーのサマリー」ページは、図12-4のようになります。

図12-4 「サーバーのサマリー」ページ

12.2.4 Coherenceクラスタ構成の作成

1つのCoherenceクラスタは、通信を可能にするグループ・アドレスを共有するCoherenceノードのグループです。Coherenceクラスタは、アプリケーション、モジュール、またはアプリケーション・サーバー(WebLogic Serverインスタンスまたはキャッシュ・サーバー)によって形成されるノードで構成されます。この手順では、Coherenceクラスタを作成して2つのWebLogic Serverインスタンスに割り当てます。

Coherenceクラスタを作成するには:

1. ドメインの「構造ウィンドウ」で「環境」をクリックして、「Coherenceクラスタ」をクリックします。「Coherenceクラスタのサマリー」ページで、「新規」をクリックします。「Coherenceクラスタ構成の作成」ウィザードの「Coherenceクラスタのプロパティ」ページで、「名前」フィールドにCoherenceClusterを入力して、「次」をクリックします。
図12-5は、「Coherenceクラスタ構成の作成」ページを示しています。

図12-5 Coherenceクラスタの作成

2. 「ユニキャスト・リスニング・ポート」フィールドに、8085などの値を入力します。他の値は変更しないで、「次」をクリックします。

図12-6 Coherenceクラスタのユニキャスト・リスニング・ポートの指定

3. 「Coherenceクラスタ構成の作成」ウィザードの「Coherenceクラスタ・ターゲット」ページで、ターゲットとしてServerAとServerBを選択します。「終了」をクリックします。

図12-7 Coherenceクラスタ・ターゲットの選択

「Coherenceクラスタのサマリー」ページは、図12-8のようになります。

図12-8 Coherenceクラスタのサマリー

12.2.5 Coherence*Webローカル記憶域に対するサーバーの有効化

WebLogic Serverの1つをCoherence*Webローカル記憶域に対して有効にする必要があります。この手順では、ServerBをCoherence*Web記憶域に対して有効にします。

1. 「ドメイン構造」ツリーで「サーバー」をクリックし、「サーバーのサマリー」を開きます。

2. 「ServerB」をクリックします。

3. 「ServerBの設定」で、「構成」タブをクリックし、次に「Coherence」タブをクリックします。

4. 図12-9に示すように、Coherence*Webローカル記憶域有効チェック・ボックスを選択します。

5. 「保存」をクリックします。

図12-9 Coherence*Webローカル記憶域に対するサーバーの有効化

12.2.6 カウンタWebアプリケーションの作成

カウンタWebアプリケーションは、JSPとして実装される簡単なカウンタです。このカウンタはHTTPセッション属性として格納され、ページへのアクセスごとにカウントが増えます。

カウンタWebアプリケーションを作成するには:

1. 次の手順で標準のWebアプリケーション・フォルダを作成します。

/
/WEB-INF

2. 次のコードをテキスト・ファイルにコピーして、/WEB-INFフォルダにweb.xmlと名前を付けて保存します。

<?xml version = '1.0' encoding = 'windows-1252'?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<description>Empty web.xml file for Web Application</description>
</web-app>

3. /WEB-INFフォルダにweblogic.xmlファイルを作成します。

- セッション・ディスクリプタの永続ストア・タイプとしてcoherence-webを参照します。

- coherence-cluster-refスタンザでCoherenceクラスタを参照します。

例12-1は、サンプルのweblogic.xmlファイルを示しています。

例12-1 サンプルweblogic.xmlファイル

<weblogic-web-app>
<session-descriptor>
<persistent-store-type>coherence-web</persistent-store-type>
</session-descriptor>
<coherence-cluster-ref>
<coherence-cluster-name>CoherenceCluster</coherence-cluster-name>
</coherence-cluster-ref>
</weblogic-web-app>

4. WEB-INFフォルダにlibサブフォルダを作成します。空白のままにします。

5. counter JSPの次のコードをテキスト・ファイルにコピーして、Webアプリケーション・フォルダのルートにcounter.jspと名前を付けて保存します。

<html>
<body>
<h3>
Counter :
<%
Integer counter = new Integer(1);
HttpSession httpsession = request.getSession(true);
if (httpsession.isNew()) {
httpsession.setAttribute("count", counter);
out.println(counter);
} else {
int count = ((Integer) httpsession.getAttribute("count")).intValue();
httpsession.setAttribute("count", new Integer(++count));
out.println(count);
}
%>
</h3>
</body>
</html>

6. META-INFフォルダにMANIFEST.MFファイルを作成します。例12-2は、MANIFEST.MFファイルのサンプルを示しています。

例12-2 サンプルMANIFEST.MFファイル

Manifest-Version: 1.0
Created-By: 1.7.0_03 (Oracle Corporation)

7. Webアプリケーション・フォルダの構成は、次のように表示されます。

/
/counter.jsp
/META-INF/MANIFEST.MF
/WEB-INF/lib/
/WEB-INF/web.xml
/WEB-INF/weblogic.xml

8. Webアプリケーション・フォルダにZIPまたはJAR処理を行い、counter.warと名前を付けてファイルを保存します。

12.2.7 WebLogic Serverの起動

管理対象WebLogic ServerのServerAとServerBを起動します。WebLogicとCoherenceは緊密に統合されているため、管理対象サーバーとともにキャッシュ・サーバーが起動します。管理対象サーバーは、コマンド行またはWebLogic Server管理コンソールから起動できます。

- コマンド行からWebLogic Serverを起動するには

- WebLogic Server管理コンソールからWebLogic Serverを起動するには

12.2.7.1 コマンド行からWebLogic Serverを起動するには

次に、コマンド行からサーバーを起動する手順を示します。

1. ドメインのbinフォルダからコマンド・プロンプトを開きます。この例では、binフォルダがc:\Oracle\user_projects\domains\base_domain\binに配置されていることを想定しています。

2. 次のコマンドを入力して、ServerAを起動します。

startManagedWebLogic.cmd ServerA

プロンプトが表示されたら、サーバーのユーザー名およびパスワードを入力します。

3. ドメインのbinフォルダから2番目のコマンド・プロンプトを開きます。

4. 次のコマンドを入力して、ServerBを起動します。

startManagedWebLogic.cmd ServerB

プロンプトが表示されたら、サーバーのユーザー名およびパスワードを入力します。

サーバーが実行中の場合は、WebLogic Server管理コンソールの「サーバーのサマリー」ページに図12-10に類似した応答が表示されます。

図12-10 管理対象WebLogic Serverの起動

12.2.7.2 WebLogic Server管理コンソールからWebLogic Serverを起動するには

ノード・マネージャを起動し、その後WebLogic Server管理コンソールからWebLogic Serverインスタンスを起動します。ノード・マネージャは、Oracle WebLogic Serverとは別のプロセスとして稼働するJavaユーティリティで、管理サーバーを基準とした場所に関係なく、管理対象サーバーに対する共通操作の実行を可能にします。

1. ノード・マネージャを起動するには、「スタート」→「すべてのプログラム」→「Oracle」→「WebLogic Server 12c」→「ツール」→「ノード・マネージャ」の順に移動します。

2. WebLogic Server管理コンソールのドメインの「構造ウィンドウ」で、「環境」→「サーバー」をクリックします。WebLogic Server管理コンソールの「サーバーのサマリー」ページから、「制御」タブをクリックして、ServerAおよびServerBを起動します。

サーバーが実行中の場合は、WebLogic Server管理コンソールの「サーバーのサマリー」ページに図12-10に類似した応答が表示されます。

12.2.8 アプリケーションのデプロイ

実行中の管理対象サーバーにcounter.warアプリケーションをデプロイします。

counter.warアプリケーションをデプロイするには:

1. Oracle WebLogic Server管理コンソールの「ドメイン構造」メニューで、「デプロイメント」をクリックして「デプロイメントのサマリー」ページを開きます。

2. 「インストール」をクリックします。「アプリケーション・インストール・アシスタント」ウィザードが開きます。

3. 図12-11に示すように、counter.warファイルの場所に移動します。「次」をクリックします。

図12-11 デプロイ可能なアプリケーションの選択

4. 図12-12に示すように、「このデプロイメントをアプリケーションとしてインストールする」を選択します。「次」をクリックします。

図12-12 デプロイメントのアプリケーションとしてのインストール

5. 図12-13に示すように、デプロイメントのターゲットをServerAおよびServerBに指定します。

図12-13 デプロイメントのターゲット指定

6. 図12-14に示すように、「オプション設定」ページで、デフォルトを受け入れます。「終了」をクリックします。

図12-14 インストール・アシスタントの「オプション設定」ページ

「デプロイメントのサマリー」ページの表内にcounter.warファイルが表示されます。図12-15に示すように、この表は、アプリケーションがServerAおよびServerBでアクティブかつ実行中(サーバーが実行中のため)であることを示しています。

図12-15 デプロイされたアプリケーションが表示された「デプロイメント」ウィンドウ

12.2.9 サンプルの検証

サンプルを検証するには:

1. ブラウザを開き、次のURLを使用してServerAのカウンタ・インスタンスにアクセスします。
http://host:8081/counter/counter.jsp

図12-16に示されるように、カウンタ・ページが表示され、カウンタが1に設定されています。

図12-16 カウンタが1に設定されたカウンタ・ページ

2. 新しいブラウザ(または新しいブラウザのタブ)で、次のURLを使用してServerBのカウンタ・インスタンスにアクセスします。
http://host:8082/counter/counter.jsp

図12-17に示すように、カウンタ・ページが表示され、セッション・データに基づいてカウンタが2に増えています。

図12-17 カウンタが2に設定されたカウンタ・ページ

3. ページをリフレッシュすると、カウンタが3に増えます。元のブラウザ(またはブラウザ・タブ)に戻り、インスタンスをリフレッシュすると、カウンタに4が表示されます。

12.3 カスタム・セッション・キャッシュ構成ファイルの使用

カスタム・セッション・キャッシュ構成ファイルを使用する場合は、使用しているアプリケーションでパッケージ化する必要があります。また、グリッド・アーカイブ(GAR)ファイルに格納して、記憶域が有効なCoherenceクラスタ・メンバーとして機能するWebLogic ServerクラスタにGARファイルをデプロイする必要があります。カスタム・セッション・キャッシュ構成ファイルの使用の詳細な説明はこのドキュメントの対象範囲ではありません。カスタム・セッション・キャッシュ構成ファイルの作成およびデプロイの詳細は、『Oracle Fusion Middleware Oracle Coherence*WebでのHTTPセッション・マネージメントの管理』のカスタム・セッション・キャッシュ構成ファイルの使用に関する項を参照してください。

オラクル社の法律上の注意点について

コピーライトについて

Copyright © 1994-2014, Oracle and/or its affiliates.All rights reserved.

商標と登録商標について

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

制限付権利

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション（人的傷害を発生させる可能性があるアプリケーションを含む）への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性（redundancy）、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

ドラフトのアルファ版およびベータ版ドキュメントについて

このドキュメントが試作版の場合:

このドキュメントは試作版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。オラクル社およびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。