|
この章では、SPI 実装の作成について説明します。節の内容は以下のとおりです。
VCR は、アプリケーション リポジトリのコンフィグレーションのセットから特定のリポジトリにアクセスする必要がある時、VCR SPI リポジトリ インタフェースを実装するコンフィグレーションした SPI 実装のクラスのインスタンスをロードし、作成します。VCR は、他の VCR SPI インタフェースを実装する [Ticket] などのオブジェクトを取得するためにリポジトリ実装のメソッドを呼び出します。
VCR は、SPI 実装の機能についてクエリを送信するために [Repository] および [Ticket] 実装のメソッドを呼び出します。(機能とは、実装がサポートする操作のことです。) VCR はメソッドを呼び出して、SPI をエクスポーズする NodeOpsV1 などの操作インタフェースを取得します。最後に、VCR は操作インタフェースのメソッドを呼び出します。
Repository クラスは VCR で直接にインスタンス化されます。このクラスは匿名リポジトリ アクセスを提供します。たとえば、SPI 実装は、そのバージョンおよび基本的な情報を報告できます。もっとも重要なのは、これは Ticket を取得するために SPI 実装認可のエントリ ポイントです。認可済みのユーザのみが Ticket を取得できます。Ticket を使用して重要なリポジトリ操作にアクセスできます。
Ticket は認可されたリポジトリ アクセスを提供し、NodeOpsV1 などの認可されている操作のインタフェースにアクセスすることもできます。認可済みのユーザのみが Ticket を取得することができ、Ticket を使用して重要なリポジトリ操作にアクセスにできます。このクラスは Repository.connect(…) によってインスタンス化されます。
Repository は、getAllInterfaces() および getInterface() を実装して NodeOpsV1、SearchOpsV1 などの追加の認可された Ticket 操作インタフェースを必要に応じてエクスポーズできます。
SPI 実装を作成する場合、以下のデザインのガイドラインを使用してください。
上記に対する複数の理由は以下の通りです。第一に、クラスタ シナリオまたは複数のエンタープライズ アプリケーションが同一サーバ上に存在するため、変更はすぐに外部システムに伝播される必要があります。データをどのサーバおよびエンタープライズ アプリケーションからアクセスするかにかかわらず、データが 「本稼動」として表示されます。
Nodes、Properties、Values、ObjectClasses、PropertyDefinitions および PropertyChoices)。VCR およびクライアント コードはこれらのオブジェクトを所有しており、変更することができます。たとえば、VCR は、ノードをクライアントへ戻る前に、ノード パスを変更する場合があります。
安全な方法は、オブジェクトをキャッシュして、SPI 実装が参照しないこれらのオブジェクトのクローンを返すことです。
データ オブジェクト タイプは、SPI 実装、VCR およびクライアント コード間共有されるので、これらのデータ オブジェクトのすべての方法は各タイプのコーラーのために適切ではありません。(詳細については、「WebLogic Portal Javadoc」を参照してください。)たとえば、「Node」を作成する場合、VCR から SPI 実装へ「Properties」などの新しいオブジェクト データを渡しますが、「PropertyID」の UUID はありません。これは、UUID が SPI 実装により割り当てられ、新しいオブジェクトがSPI 実装によりまだ持続していないことにより起こります。UUID は SPI によって取り出されるか返されるデータ オブジェクトのために存在します。
connect()」メソッドを呼び出す前に「Repository.setName()」および「Repository.setProperties()」メソッドを呼び出します。
各リポジトリ インスタンスは、単一のエンタープライズ アプリケーションおよび単一のユーザが使用できるように単一のリポジトリ コンフィグレーションに対応します。実行時に、VCR は、現在の多数 WebLogic Portal ユーザが使用できるようにリポジトリの多くのインスタンスを作成できます。何百ものオブジェクトが存在する場合があるので、比較的に軽量なオブジェクトである必要があります。
エンタープライズ アプリケーションでは、特定の SPI 実装用の複数アクティブ リポジトリ コンフィグレーションがある場合があります。たとえば、VCR が管理するアプリケーションに対して 3 つのリポジトリ コンフィグレーションが存在する場合があり、各リポジトリには独自のコンフィグレーション データおよび実行的に作成される独自のリポジトリ インスタンスがあります。
RepositoryException を送出する必要があります。RepositoryException の複数のサブクラスを定義し、一致する場合、使用する必要があります。たとえば、SPI 実装が操作をサポートしない場合、UnsupportedRepositoryOperationException を送出する必要があります。Ticket オブジェクトをキャッシュと再利用します。通常、それは同時上の理由で、ステートレスである必要があります。VCR は Ticket と HTTPSession のユーザを関連します。同じリポジトリに対して HTTPSession に複数のリクエストを受信した場合、同じ Ticket オブジェクト上で複数の操作が同時に実行される可能性があります。ステートレスの設計によって、このような状態での問題が回避されます。 - ノードのプロパティ (および価値) をロードする場合、パフォーマンスを向上させるために、バイナリ プロパティ inputstream を null として返すことができます。
com.bea.content.spi.flexspi.Repository インタフェースを実装する Java クラスを作成します。
このクラスは、実装する必要なインタフェースです。これは WebLogic Portal に組み込まれています。
setProperties() を実装します。ローカル変数に保存します。setName() を実装します。ローカル変数に保存します。getProperties() および getName() を実装します。 getDescription() を実装します。
これは、SPIDescriptionKeys にある定義したキーを持つ Properties バケットです。これには、ベンダ、バージョンなどがあります。
getRepositoryDefinedCapabilities() を実装します。
基本的な SPI 実装のために、Collections.emptySet() を返します。
ticket を除いて) 操作のインタフェースを返すには、getAllInterfaces() を実装します。
これは、リポジトリが実装できる RepositoryConfigOpsV1 などのオプション インタフェースです。
ベアボーン SPI 実装の場合、空の HashMap を返します。
getAllInterfaces()と一致できるように、getInterface( String interfaceName ) を実装します。 getCapabilitySupport( Set<ICapabilityDefinition> ) を実装します。
オプション リポジトリ操作インタフェース全体でリポジトリがサポートするメソッド機能も報告します。
connect( Credentials ) および Connect( String username, String password ) を実装します。
ユーザ名とパスワードが使用可能な場合、connect( username, password ) を呼び出します (通常、リポジトリ コンフィグレーション データから)。
ユーザ名とパスワードが使用可能でない場合、connect( credentials ) を呼び出します。資格にコーラーの暗黙の ID を含みます。
基本的な SPI 実装の場合、新しい Ticket インスタンスを作成して返します。より高度な実装は資格を認証する場合があり、成功すると Ticket インスタンスのみが返されます。
RepositoryConfigOpsV1 などの省略可能な Repository 操作インタフェースを実装します。
Repository.getAllInterfaces() が返されたリポジトリ操作インタフェースの場合、
実装されていないメソッドの場合、UnsupportedRepositoryOperationException が送出され、getCapabilitySupport() メソッドは、このメソッドはサポートされていることを報告する必要はありません。
Repository.getAllInterfaces() および getInterface() を変更します。Repository.getCapabilitySupport() を変更します。 com.bea.content.spi.flexspi.Ticket インタフェース (WebLogic Portal と共に提供される) を実装する Java クラスを作成します。getAllInterfaces() を実装します。これらは、Ticket が実装できる NodeOpsV1 などのオプション インタフェースです。基本的な SPI 実装の場合、空の HashMap を戻ります。getAllInterfaces() と一致するよに getInterface( String interfaceName ) を実装します。基本的な SPI 実装の場合、null のみを返します。getCapabilitySupport( Set<ICapabilityDefinition> ) を実装します。NodeOpsV1 などのオプション Ticket 操作インスタンスを実装します。
Ticket.getAllInterfaces() が返される Ticket 操作インスタンスの場合、
実装されいないメソッドの場合、UnsupportedRepositoryOperationException が送出され、getCapabilitySupport() メソッドは、このメソッドはサポートされていることを報告する必要はありません。
Ticket.getAllInterfaces() および getInterface() を変更します。Ticket.getCapabilitySupport() を変更します。
コード リスト 4-1 は、以下の制限があるリポジトリの簡単な SPI リポジトリ コードの例を示します。
RepositoryConfigOpsV1 などのオプション リポジトリ操作インタフェースはサポートされていないので、メソッドの機能はサポートされていません。 import com.bea.content.spi.flexspi.Repository;
import com.bea.content.spi.flexspi.Ticket;
import com.bea.content.spi.flexspi.common.capability.ICapabilityDefinition;
import com.bea.content.spi.flexspi.common.capability.CapabilityLevel;
import com.bea.content.spi.flexspi.common.capability.FeatureCapabilityDefinition;
import com.bea.content.spi.flexspi.common.ISPIMarker;
import com.bea.content.spi.flexspi.common.SPIRepositoryInterfaces;
import com.bea.content.spi.flexspi.common.SPIDescriptionKeys;
import com.bea.content.capability.NodeFeatureCapability;
import com.bea.content.*;
import java.util.*;
public class FlexRepositoryImpl implements Repository
{
// VCRは connect()を呼ぶ前にこれをコンフィグレーションする
private String repositoryName;
private Properties props;
// キー・値の詳細
private Map<String, String> descMap = new HashMap<String, String>();
public FlexRepositoryImpl()
{
// SPI 実装にはデフォルトのパブリック コンストラクタを持つ必要がある。
//標準キー
descMap.put(SPIDescriptionKeys.VENDOR_KEY,
"Some third party vendor");
descMap.put(SPIDescriptionKeys. VERSION_KEY, "0.1.1");
descMap.put(SPIDescriptionKeys. DESCRIPTION_KEY, "Simple SPI");
//カスタムキーを追加することができます
descMap.put("InternalVersion", "Build 31141");
}
public Ticket connect(Credentials credentials)
throws AuthenticationException, RepositoryException
{
// この SPI は認証を実行しません
return new FlexTicketImpl(this);
}
public Ticket connect(String username, String password)
throws AuthenticationException, RepositoryException
{
// この SPI は認証を実行しません
return new FlexTicketImpl(this);
}
public String getName() {
return repositoryName;
}
public void setName(String name) {
repositoryName = name;
}
public Properties getProperties() {
return props;
}
public void setProperties(Properties properties) {
props = properties;
}
public Set<ICapabilityDefinition> getRepositoryDefinedCapabilities() {
return Collections.emptySet();
}
public Map<String, String> getDescription() {
return descMap;
}
public Map<String, ISPIMarker> getAllInterfaces() {
// リポジトリ操作インタフェースはありません
return new HashMap<String,ISPIMarker>();
}
public ISPIMarker getInterface(String interfaceName) {
// リポジトリ操作インタフェースはありません
return null;
}
public Map<ICapabilityDefinition, CapabilityLevel>
getCapabilitySupport(Set<ICapabilityDefinition> capabilities)
{
HashMap<ICapabilityDefinition, CapabilityLevel> capMap
=new HashMap<ICapabilityDefinition, CapabilityLevel>();
// サポートされていないすべての項目から開始し、
// サポートされる個々の機能をマークします。
for (ICapabilityDefinition capDef : capabilities) {
capMap.put(capDef, CapabilityLevel.NotSupported);
}
// 以前サポートされていない機能はサポートする場合、
// サポートされなかった値がオーバーライドされます
// すべてはサポートされていません
return capMap;
}
}
コード リスト 4-2 は、Ticket はNodeOpsV1 および SearchOpsV1 などのオプション Ticket 操作インタフェースをサポートしないので、1 つのメソッド機能はサポートしない SPI Ticket コードの例を示します。
import com.bea.content.spi.flexspi.Ticket;
import com.bea.content.spi.flexspi.Repository;
import com.bea.content.spi.flexspi.common.ISPIMarker;
import com.bea.content.spi.flexspi.common.SPITicketInterfaces;
import com.bea.content.spi.flexspi.common.capability.ICapabilityDefinition;
import com.bea.content.spi.flexspi.common.capability.CapabilityLevel;
import com.bea.content.spi.flexspi.common.capability.MethodCapabilityDefinition;
import java.util.*;
public class FlexTicketImpl implements Ticket
{
Repository repository; // この Ticket の作成に使用したリポジトリ
//1=flex インタフェース名、2=flex インタフェース オブジェクト
private Map<String, ISPIMarker> advertisedInterfaces;
public FlexTicketImpl(Repository repository) {
this.repository = repository;advertisedInterfaces= new HashMap<String,ISPIMarker>();
// まだインタフェースはない
}
public Map<String, ISPIMarker> getAllInterfaces() {
return advertisedInterfaces;
} public ISPIMarker getInterface(String interfaceName) {
return advertisedInterfaces.get(interfaceName);
}public Map<ICapabilityDefinition, CapabilityLevel>
getCapabilitySupport(Set<ICapabilityDefinition> capabilities)
{
// インタフェース、メソッド、機能すべてはサポートされていません
HashMap<ICapabilityDefinition, CapabilityLevel> capMap
=new HashMap<ICapabilityDefinition, CapabilityLevel>();
// サポートされていないすべての項目から開始し、
// サポートされる個々の機能をマークします。
for (ICapabilityDefinition capDef : capabilities) {
capMap.put(capDef, CapabilityLevel.NotSupported);
}
// 以前サポートされていない機能はサポートする場合、
// サポートされなかった値がオーバーライドされます
// すべてはサポートされていません
return capMap;
}
}
VCR にノードとタイプをエクスポーズするために、省略可能な SPI インタフェースを使用します。一般的に、クライアントコードはコードに対して実行されるリポジトリの機能について特定な仮定があります (たとえば、ノードへの読み取り専用アクセス)。VCR はノードとタイプをリポジトリに委託するので、クライアント コードは特定の VCR メソッドが適切に動作することを前提とします。
NodeOpsV1 などの省略可能な SPI インタフェースをエクスポーズするには、
たとえば、MyNodeOps は NodeOpsV1 を実装します。一般に、多数のオブジェクトが作成される場合があるので、軽量のクラスを作成する必要があります。
| 注意 : | 実装されていないのメソッドの場合、UnsupportedRepositoryOperationException が送出されます。また、Ticket.getCapabilitySupport() メソッドは、このメソッドはサポートされていることを報告する必要があります。 |
Ticket.getAllInterfaces() および getInterface() を変更します。
オブジェクトの作成を減らすには、Ticket の作成時にインタフェースを作成して保持し、getAllInterfaces() および getInterface() に返します。次に例を示します。
private Map<String,ISPIMarker> ifaces;
public FlexTicketImpl( Repository repository ) {
this.repository= repository;
//init インタフェース
ifaces= new HashMap<String,ISPIMarker>();
ifaces.put(SPITicketInterfaces.NODE_OPS_V1,
new MyNodeOps(…);
. . .
}
public Map<String, ISPIMarker> getAllInterfaces() {
return ifaces;
}
public ISPIMarker getInterface( String ifaceName ) {
return ifaces.get( ifaceName );
}Ticket.getCapabilitySupport() を変更します。次に例を示します。public Map<ICapabilityDefinition, CapabilityLevel>
getCapabilitySupport(Set<ICapabilityDefinition> capabilities)
{
Map<ICapabilityDefinition, CapabilityLevel> capMap
=new HashMap<ICapabilityDefinition, CapabilityLevel>();
// サポートされていないすべての項目から開始し、
// サポートされる個々の機能をマークします。
for (ICapabilityDefinition capDef : capabilities) {
capMap.put(capDef, CapabilityLevel.NotSupported);
}
// 必要に応じてサポートされていない値をオーバーライドします
final String[] supportedNodeOpsMethodNames = new String[] {
NodeOpsV1.MethodName.getNodeChildren.toString(),
NodeOpsV1.MethodName.getNodeChildrenAsNodeIds.toString(),
NodeOpsV1.MethodName.getNodesWithIds.toString(),
NodeOpsV1.MethodName.getNodeWithId.toString(),
NodeOpsV1.MethodName.getNodeWithPath.toString(),
};
for (String methodName : supportedNodeOpsMethodNames) {
ICapabilityDefinition capDef
= new MethodCapabilityDefinition(
SPITicketInterfaces.NODE_OPS, methodName
);
if (capabilities.contains(capDef)) {
capMap.put(capDef, CapabilityLevel.FullySupported);
}
}return capMap;
}
オプションで、SPI 実装では結果をソートおよびフィルタするの機能を含むことができます。SPI が返された項目の集合を QueryResult オブジェクト (結果の順序付きリストを含む) および返された集合のソートとフィルタの方法を (処理を行う場合) 記述する QueryCriteria オブジェクトに返します。たとえば、QueryResult<Node> には、ソートおよびフィルタしたノードの集合を含む場合があります。
結果の集合を返す多数のメソッドは QueryCriteria パラメータを使用します。このパラメタでコーラーは結果のソートまたはフィルタ方法 (可能であれは両方も) を設定できます。たとえば、コーラーは結果が名前によってソートされるよう要求する場合があります。現在、コーラーは 1 つのソート条件および 1 つのフィルタ条件のみを指定できます。
SortCriteriaには、名前昇順 などのプロパティ (条件) および昇順または降順フラグがあります。
FilterCriteria には、プロパティ (条件) とフィルターなし、等しい、等しくない、含む、含まない、で始まる、で終わる、より大きい、より小さいおよび値などの FilterMethod オペランドがあります。たとえば、name contains 'foo'
プロパティのソートおよびフィルタ条件のセットは使用しているデータ オブジェクトの JavaBean プロパティに関連付けられます。たとえば、Node には getName() メソッドがあるので name および getCreatedDate() メソッドがあるので createdDate のために JavaBean プロパティを含みます。
ネイティブのソート、フィルタ処理はうまく機能します。また、SPI 実装がソートまたはフィルタの要求を処理できない場合、VCR はメモリ内にソーティングとフィルタリングを行うためにメカニズムをサポートします。クライアント コード (と VCR) は、SPI がネイティブにソートおよびフィルタできるプロパティを確認できます。
SPI 実装は NodeOpsV1.getNativeSortableProperties() および NodeOpsV1.getNativeFilterableProperties() などのメソッドを実装して、インタフェースのオブジェクトのために VCR にそのソーティングおよびフィルタリング機能 (ソートおよびフィルタできるプロパティ) を報告します。たとえば、SPI はノードが name および createDate プロパティでソートできることを報告します。
ソーティングおよびフィルタリング機能の報告は実際にインタフェース精度で行っています。つまり、NodeOpsV1 などの特定のインタフェースには主なデータ オブジェクトがあります。主なデータ オブジェクト、たとえば、Node は、インタフェースでの結果の集合メソッド全体でソート、フィルタ処理の機能を報告します。
| ヒント : | SPI がネイティブのソートまたはフィルタ処理をサポートしていない場合、null ではなく、Collections.emptySet() などの空セットを返す必要があります。 |
SPI 実装は、サポートするソーティングとフィルタリング機能よりも高度な機能を要求する QueryCriteria パラメタを受信する場合があります。この場合に、SPI 実装は例外を送出しないことを確認します。代わりに、SPI 実装は結果をソートおよびフィルタする現在の方法を報告する必要があります。たとえば、SPI 実装は、未ソートと未フィルタ QueryResult を作成して、ソートとフィルタできなかった項目を表します。SPI 実装が 1 つの要求を実行できる場合、要求を実行して適切に結果を報告する必要があります。たとえば、ソートすることができる場合、SPI 実装は結果を [ソート済みが未フィルタ] として報告する必要があります。
必要に応じて、VCR はクライアントの要求によってソートまたはフィルタ処理を行っているかを確認するために、メモリ内でクエリ結果をソートまたはフィルタする場合があります。
ソートおよびフィルタ処理を行うために以下のオブジェクトを使用します。
QueryCriteria – 一部のメソッドは、結果のソートおよびフィルタ処理を要求するためにコーラーが使用する QueryCriteria オブジェクトを渡します。これらのメソッドは SortCriteria および FilterCriteria オブジェクトを含みます。現在、1 つの SortCriteria または FilterCriteria のみを指定できます。マルチ条件ソーティングとフィルタリングはサポートされていません。SortCriteria – 特定のプロパティ (条件)で昇順または降順ソートできる機能を提供します。sortResults フラグは結果がソートされているかを示します。SortCriteria はデータ オブジェクトの JavaBean プロパティの 1 つである property も含みます。FilterCriteria – 特定のプロパティ (条件)でフィルタできる機能を提供します。filterResults フラグは結果がフィルタされているかを示します。FilterCriteria は、データ オブジェクトの JavaBean プロパティの 1 つである property を含み、等しい、より大きい、未フィルターなどのフィルタ操作を示す filterMethod を含みます。QueryResult – SPI 実装が返された結果のセットを表します。QueryResult には、結果のソートおよびフィルタ方法 (または両方もない) を記述する QueryCriteria オブジェクトとデータ オブジェクトの順序リストを含みます。
|