目次 | 前へ | 次へ |
JNDI には、Context
と DirContext
という 2 つのコアインタフェースがあります。このうち、DirContext
は、Context
の基本ネーミング操作を拡張してディレクトリサービス操作を追加したものです。これらは、モジュール性の点と、「使用する分だけを考慮する」という JNDI の目標に従って、個別のインタフェースに分離されました。
ネーミングは、ファイルシステム、スプレッドシート、カレンダサービス、ディレクトリサービスなどの、多くのコンピューティングサービスにある基本コンポーネントです。ネーミング操作のためのベースとなる Context
インタフェースを、ディレクトリサービスだけでなく、これらのその他のすべてのサービスで使用できるようにしています。
DirContext
は、Context
を拡張して、基本的なディレクトリサービス操作を提供します。これには、指定されたオブジェクトに関連付けられた属性の操作、属性に基づいた検索、およびこれらの属性や指定されたオブジェクトのスキーマ関連の操作が含まれます。
JNDI は、4 つのクライアントパッケージ (javax.naming
、javax.naming.directory
、javax.naming.event
、javax.naming.ldap
) と 1 つのサービスプロバイダパッケージ (javax.naming.spi
) に分離されています。これは、各パッケージには特定のカテゴリのアプリケーションに必要なインタフェースとクラスが含まれるという、これも「使用する分だけを考慮する」という目標に従った考え方から来ています。たとえば、名前のルックアップだけを実行するアプリケーションは、javax.naming
パッケージしか使用する必要がありません。あるオブジェクトに関連付けられた属性を検査または変更するアプリケーションは、javax.naming
および javax.naming.directory
パッケージを使用します。LDAP 固有のコントロールまたは拡張操作を使用する必要のあるアプリケーションは、javax.naming.ldap
パッケージを使用します。理解および使用しなければならないクラスおよびインタフェースは、アプリケーションの開発カテゴリによって異なります。
JNDI では、サービスプロバイダ関連のインタフェースおよびクラスから、クライアントアプリケーションで使用されるインタフェースおよびクラスが分割され、いくつかのパッケージが作成されています。たとえば、クライアントが javax.naming
のインタフェースとクラスを使用するのに対して、ネームサービスに接続しているサービスプロバイダは javax.naming
と javax.naming.spi
の両方を使用します。パッケージを分割すると、アプリケーション開発者の混乱が少なくなり、プログラムを作成するときに調査が必要なパッケージが明確になります。
コンテキストを一覧表示するアプリケーションには、次の 2 つの一般的な種類があります。1 つはブラウザ型のアプリケーションで、もう 1 つはコンテキスト内のすべてのオブジェクトに対して操作を実行するアプリケーションです。ブラウザ型のアプリケーションの場合は通常、コンテキストの内容の名前が表示されます。多くのブラウザでは、名前以外に、名前にバインドされたオブジェクトの型情報が必要です。型情報に応じて、オブジェクトの画像表現が適切に表示されます。このブラウザは通常、対話型です。ブラウザを使用してコンテキストの内容が表示されたときに、表示されたエントリからいくつかのエントリを選択すると、そのエントリの詳細情報が表示されます。
一部のアプリケーションは、コンテキスト内のオブジェクトに対して、まとめて操作を実行する必要があります。たとえば、バックアッププログラムは、ファイルディレクトリ内のすべてのオブジェクトに対して「file stats」操作を実行する場合があります。また、プリンタ管理プログラムでは、1 つの建物内にあるすべてのプリンタを再起動します。これらの操作を実行するには、プログラムでは、コンテキストにバインドされているすべてのオブジェクトを取得する必要があります。
これらの 2 つの一般的な種類の使用法を念頭におき、Context
インタフェースには、list()
と listBindings()
という 2 種類のリストメソッドがあります。list()
が名前/クラス名のペアのリストを返すのに対して、listBindings()
は名前/クラス名/オブジェクトのタプルのリストを返します。list()
は、ほとんどの場合、コンテキスト内でバインドされているオブジェクトの名前と型だけが必要なブラウザ型のアプリケーション向けに設計されています。listBindings()
は、コンテキスト内のすべてのオブジェクトのほか、それらの名前と型を取得する可能性のあるアプリケーション用です。listBindings()
は、Binding
の列挙を返します。listBindings()
操作自体と、Binding
クラスでのメソッド (getObject()
など) の呼び出しはどちらも、遅れて、またはすぐに実装されます。listBindings()
を使用する場合は、呼び出し側がコンテキスト内のすべてまたはほとんどのオブジェクトを取得することを前提として、実装がコンテキストに対して最適化されます。list()
を使用する場合は、呼び出し元が必ずしもコンテキスト内のすべてのオブジェクトを取得しないことを前提として、実装がコンテキストに対して最適化されます。
代わりに、リスト操作を 1 つにして、Binding
の実装の一部として遅延動作または即時動作を行うようにする方法があります。この方法の利点は、理解が必要なリスト操作が 1 つだけになることです。ただし、リストから返される情報を呼び出し側から指定できなくなり、プログラムの目的の動作に応じて実装が最適化されなくなります。
連合は、JNDI における重要な概念です。クライアントインタフェースでは、これは、1 つ以上の名前空間にまたがる可能性のある名前を指定するための Name
インタフェースの使用によってサポートされます。クライアントインタフェースのメソッドの呼び出し側では、連合の情報は必要ありません。複数のシステムにまたがる名前は SPI によって解決されるため、呼び出し側の介入は発生しません。
連合は重要な概念ですが、すべての呼び出し側およびサービスプロバイダがこれを使用する必要があるわけではありません。アプリケーションまたはサービスが連合を利用しない場合は、Name
が常に複数の名前空間にまたがる必要はありません。Name
は 1 つの名前空間内のオブジェクトに名前を付けることができるだけであり、SPI は (複数の名前空間のサポートの一部として) 1 つの名前空間内の名前解決も処理できます。
DirContext
で Context
を拡張する代わりに、Context
をまったく拡張せずに、ディレクトリ関連のすべてのメソッドをカプセル化する、DirObject
と呼ばれる別のインタフェースを使用する方法があります。その場合、あるオブジェクトがネーミング操作とディレクトリ操作の両方をサポートしていれば、そのオブジェクトは Context
と DirObject
の両方を実装できます。別のオブジェクトでは、DirObject
だけを実装することもできます。
DirContext
を排除した場合の問題として、DirContext
には、ネーミングとディレクトリの両方を含むいくつかのハイブリッド操作 (引数として属性を受け入れる bind()
、createSubcontext()
メソッド) が含まれている点があります。これらの操作を保持しながら、同時に DirObject
を使用するには、これらのハイブリッド操作だけを含む (おそらく DirContext
と呼ばれる) 3 番目のインタフェースが必要になります。
さらに、DirObject
の代わりに DirContext
を使用する方が、一部の操作を 2 つのステップではなく 1 つのステップで実行できるという点で便利です。たとえば、DirContext.getAttributes()
を使用した場合は、指定されたオブジェクトに関連付けられた属性を取得できるのに対して、DirObject
では、まずオブジェクト (Context.lookup()
) に解決してから、DirObject.getAttributes()
を使用してその属性を取得する必要があります。
DirContext
インタフェースには、スキーマのサポートが含まれています。たとえば、DirContext
オブジェクトから、この特定の DirContext
インスタンスのスキーマが定義されているディレクトリ空間を指す、そのスキーマオブジェクトを取得できます。DirContext
オブジェクトからは、また、そのスキーマクラス定義 (つまり、これがディレクトリ内で表すオブジェクトの型に関する情報) も取得できます。Attribute
クラスには、スキーマに対するそれ以上のサポートが存在します。これには、属性の構文情報 (つまり、属性の値の型) や属性の定義 (複数値かどうか、構文、その構文に関する制約など) を取得するためのメソッドが含まれます。このスキーマ情報に動的にアクセスできる (ライブディレクトリ空間を指している) 必要はありません。このスキーマ情報のサポートは、サービスプロバイダによって静的に生成される場合もあります。たとえば、特定のディレクトリサービスでは、文字列の属性値以外はサポートされていないことがあります。この場合は、属性を返すときに属性の構文が強制的に適用されます。ディレクトリによっては、静的スキーマ (スキーマ内の情報を変更できない) 以外はサポートされていないことがあります。また、動的スキーマがすべてサポートされているディレクトリもあります。DirContext
内のインタフェースとクラスには十分な柔軟性があるため、スキーマに対するこれらのさまざまなレベルのサポートが可能になります。
Name
引数を受け入れる Context
および DirContext
インタフェース内の各メソッドには、名前を指定するための String
引数を受け入れる対応するオーバーロードされた形式があります。
String
ベースのメソッドは、エンドユーザーから文字列名を受け入れ、その文字列名で指定されたオブジェクトに対してコンテキストメソッドを実行するアプリケーションが多数存在する場合に使用します。これらのアプリケーションの場合は、アプリケーションがまず、文字列名を使用して Name
オブジェクトを構築する必要があるようにするのではなく、コンテキストメソッドが名前の文字列を直接受け入れるようにすることが有効です。
Name
ベースのメソッドは、名前を操作するアプリケーションが多く、名前の作成および変更を行うときに名前の文字列の構文への対応を省略する場合に使用します。これらのアプリケーションでは、構文解析された名前が処理されるので、文字列の名前より Name
オブジェクトが処理に適しています。これらのアプリケーションには、コンテキストインタフェースで Name
ベースのメソッドを提供しています。これらのメソッドを使用しない場合は、JNDI の上位で開発されたアプリケーションで使用されている形式の名前を操作するために、Name
形式のインタフェースやクラスが必要以上に生成されることになります。
アプリケーションやサービスがディレクトリを使用してオブジェクトを検索する場合は、さまざまな方法があります。JNDI は汎用性が高いので、さまざまなモデルに対応できます。たとえば、ディレクトリ内のオブジェクトが、オブジェクト自体にバインドされることがあります。アプリケーションがアクティブなときに動的ディレクトリが構築され、アプリケーションが終了するとそのディレクトリが削除されることもあります。名前空間内でオブジェクトを検索するための属性として、URL を格納することもあります。システムによっては、ディレクトリ内の一部の参照情報がバインドされ、実際のオブジェクトの検索またはアクセスを行うときにその情報が使用されることもあります。インストール済みのベースに実装されているサービスを Java アプリケーションで使用するときに、この最後の例がよく使用されます。このディレクトリ内の参照は、実際のオブジェクトへの「ポインタ」として機能します。
JNDI では、参照情報を表す統一された方法を提供するために、Reference
クラスが定義されます。Reference
には、オブジェクトへのアクセス方法に関する情報が含まれています。この情報は、アドレスのリスト、およびこの参照が表現するオブジェクトのクラス情報で構成されます。つまり、ディレクトリ内で参照として表現されるオブジェクトに名前をバインドしたときは、オブジェクトの参照の展開およびバインドが行われることになります。この動作を許可するには、オブジェクトのクラスが、getReference()
メソッドを含む Referenceable
インタフェースを実装する必要があります。
Serializable
インタフェースと Referenceable
インタフェースは類似しているため、「なぜ、Serializable
だけを使用しないのか」という自然な疑問がわきます。直列化されたオブジェクトが、実際にはオブジェクトの凍結されたバージョンであるのに対して、参照にはオブジェクトの構築に必要な情報だけが含まれているというのがその答えです。また、直列化されたオブジェクトには、ディレクトリへの格納に適していない状態が多く含まれている可能性があります。
ディレクトリ内で Reference
としてバインドされているオブジェクトの場合、JNDI SPI フレームワークは、その参照で識別されるオブジェクトを自動的に作成してインスタンス化します。これにより、プログラムは lookup()
の結果を目的のクラスのオブジェクトに変換するための別の操作を呼び出す代わりに、lookup()
の結果を目的のクラスに単純にナロー変換できます。
たとえば、プリンタオブジェクトを検索している場合は、ルックアップが成功すると、直接使用できるプリンタオブジェクトが返されます。
Printer prt = (Printer) ctx.lookup(somePrinterName); prt.print(someFileName);
これが予測される一般的な使用法のパターンであるため、明示的な変換ステップを必要とすることなく、JNDI はこれを自動的に実行します。Reference
クラスと、Reference
を Reference
で識別されるオブジェクトに変換するための共通のメカニズムを備えているため、JNDI では、さまざまなアプリケーションおよびシステムプロバイダが個別のメカニズムを独自に開発するのではなく、このメカニズムを利用することを推奨しています。