JNDIの概要、パート3:高度なJNDI

今月は多くの地面をカバーする必要があるので、綿毛を省き、箇条書きに切り詰めます。まず、Java Naming and Directory Interfaceは、いくつかのJavaテクノロジで重要な役割を果たします。Java全体像におけるJNDIの戦略的位置をよりよく理解するために、この役割を見ていきます。次に、動作するJNDIサービスが必要であることを認識して、無料で利用できるポータブルLDAP実装を紹介し、JNDIサービスプロバイダーに接続して使用する方法を説明します。最後に、オブジェクトをJNDIのエントリにバインドする方法について詳しく説明します。

テキストボックス:

TEXTBOX_HEAD:JNDIの概要:シリーズ全体を読んでください!

  • パート1。ネーミングサービスの概要

  • パート2.JNDIディレクトリサービスを使用して、分散アプリケーションをより適切に管理します

  • パート3。JNDIを使用して分散アプリケーションのオブジェクトを格納します

  • パート4.JNDI対応アプリケーションで学んだことをまとめる

:END_TEXTBOX

私が始める前に、少し二重思考が必要です。過去2か月間、ネーミングサービスとディレクトリサービスは、図書館にあるカードカタログとほぼ電子的に同等であることを納得させようとしました。JNDIの高度な機能のツアーを開始するとき、このアナロジーを完全に忘れてください。これは、JNDIのパワーを大幅に過小評価しています。

JNDIが他のJavaテクノロジーでどのように表示されるかを見てみましょう。

どこでもJNDI

JNDIは、多くのJavaテクノロジーで役割を果たします。それらのうちの3つを考えてみましょう:JDBC(Java Database Connectivityパッケージ)、JMS(Java Messaging Service)、およびEJB(Enterprise JavaBeans)。

JDBCは、リレーショナルデータベース用のJavaテクノロジです。JNDIは、DataSourceインターフェースと組み合わせてJDBC 2.0オプションパッケージ(「参考文献」を参照)に最初に登場しました。DataSource多くの場合、データベースではなく、常にから-その名が示すように、インスタンスは、データのソースを表します。DataSource例えば、その名前、負荷および使用ドライバ、その場所など- -データ・ソースについてのインスタンス情報が格納され、アプリケーションが下層の詳細に関係なく、データソースへの接続を得ることができます。JDBC仕様では、JNDIを使用してDataSourceオブジェクトを格納することを推奨しています。

JMSは、メッセージング用のJavaテクノロジです。JMS仕様では、管理対象オブジェクト(JMS構成情報を含み、JMSクライアントが特定のメッセージキューおよびトピックを見つけるために使用するオブジェクト)について説明しています。JDBCの場合と同様に、仕様ではJNDIを介してJMS管理対象オブジェクトを検索することを推奨しています。

最後に、EnterpriseJavaBeansについて考えてみましょう。すべてのエンタープライズBeanは、JNDIを介してホームインターフェース(クライアントが特定のエンタープライズBeanを見つけるための単一の場所)を公開します。

JNDIは、それを非常に高く評価する原因となるものを何にもたらしますか?

まず、JNDIは、一元管理された情報ソースの概念を推進します。これは、エンタープライズアプリケーションの重要な要件です。一元管理された情報ソースは、情報ソースの分散コレクションよりも管理が簡単です。また、クライアントが1つの場所を探すだけでよい場合は、必要な情報を簡単に見つけることができます。

次に、後で説明するように、Javaオブジェクトを直接格納するJNDIの機能により、Javaアプリケーションにほぼ透過的に統合できます。

プロバイダーのポイント

JNDIを使用するには、ネーミングおよびディレクトリサービスとJNDIサービスプロバイダーが必要です。Sunは、一般的なネーミングおよびディレクトリサービス(COSネーミング、NIS、RMIレジストリ、LDAPなど)のプロバイダーをいくつか提供しています。LDAPに落ち着きました。

LDAP(Lightweight Directory Access Protocol)には、広く実装されている(商用形式と無料形式の両方)という2つの利点と、適度に使いやすいという2つの利点があります。その機能は、SunのLDAPサービスプロバイダーとJNDIによっても十分にサポートされています。

LDAPサーバーの取得と構成は実際にはJavaの主題ではないため、正しい方向に進んでインターネットリソースへの参照を提供するだけです。

多数のLDAP実装が利用可能です。多くは、Netscape DirectoryServerやIBMのSecureWayDirectoryなどの商用製品です。一部はより大きな製品の一部としてパッケージ化されています(MicrosoftのActiveDirectoryはWindows2000の一部です)。このような実装にアクセスできる場合は、このセクションのほとんどをスキップできます。それ以外の場合は、OpenLDAP(ミシガン大学のリファレンス実装に基づいて無料で利用できるLDAPの実装)とそのインストールおよび構成について説明します。

OpenLDAPは、OpenLDAP Foundationから入手できます(「参考文献」を参照)。そのライセンスはPerlの「アーティスティックライセンス」に基づいています。つまり、OpenLDAPは無料(またはオープンソース)のソフトウェアです。あらかじめパッケージ化されたバイナリは、さまざまな種類のLinux(Debian、Red Hat)およびBSDUnixで利用できます。WindowsNTへの移植作業が進行中です。

OpenLDAPをインストールする場合は、SLAPDおよびSLURPD管理者ガイドをお読みください(slapdはLDAPサーバーの実行可能ファイルの名前、slurpdはLDAPレプリケーションサーバーの名前です。場所については「参考文献」を参照してください)。

I have one final suggestion to make your entire experience more pleasing: no matter which LDAP implementation you use, turn schema checking off. An LDAP schema, like a database schema, defines constraints on the stored information. In normal use, schema checking helps ensure that entries (think of address book entries) conform to the correct format. However, since you'll probably be playing rather than building something of lasting significance, schema checking will just get in the way. Take my word for it.

Connecting to a JNDI context

In previous articles, I tried to avoid explaining in detail how to interact with a JNDI service provider such as the LDAP service provider. I mentioned that you need an initial context to do JNDI operations, but I didn't spend much time telling you how to get one. Let me fill in the gaps. (For more on initial contexts, see the first two articles in this series.)

Before you can do anything with JNDI, you need an initial context. All operations are performed relative to the context or one of its subcontexts.

Obtaining an initial context requires three steps:

  1. First, select a service provider. If you're going to use OpenLDAP or some other LDAP implementation, Sun supplies a reference LDAP service provider (see Resources). Add the name of the service provider to the set of environment properties (stored in a Hashtable instance):

     Hashtable hashtableEnvironment = new Hashtable(); hashtableEnvironment.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" ); 
  2. Add any extra information the service provider requires. For LDAP, that includes the URL that identifies the service, the root context, and the name and password to connect with:

     // the service: ldap://localhost:389/ // the root context: dc=etcee,dc=com hashtableEnvironment.put( Context.PROVIDER_URL, "ldap://localhost:389/dc=etcee,dc=com" ); hashtableEnvironment.put( Context.SECURITY_PRINCIPAL, "name" ); hashtableEnvironment.put( Context.SECURITY_CREDENTIALS, "password" ); 
  3. Finally, get the initial context. If you just intend to perform naming operations, you'll only need a Context instance. If you intend to perform a directory operation as well, you'll need a DirContext instance instead. Not all providers supply both:

     Context context = new InitialContext(hashtableEnvironment); 

    Or:

     DirContext dircontext = new InitialDirContext(hashtableEnvironment); 

That's all there is to it. Now let's look at how applications store objects to and retrieve objects from JNDI.

Work with objects

The ability to store Java objects is useful: object storage provides persistence and allows objects to be shared between applications or between different executions of the same application.

From the standpoint of the code involved, object storage is surprisingly easy:

 context.bind("name", object) 

The bind() operation binds a name to a Java object. The syntax of the command is reminiscent of RMI, but the semantics are not as clearly defined. It's permissible for the bind() operation to store either a snapshot of the object or a reference to a "live" object, for example.

Be aware that the bind() operation throws a NamingException if an exception occurs during the execution of the operation.

Now let's take a look at the bind() operation's complement -- lookup():

 Object object = context.lookup("name") 

The lookup() operation retrieves the object bound to the specified name. Once again, the syntax is reminiscent of RMI, but the method's semantics are not as clearly defined.

Just as with bind(), the lookup() operation throws a NamingException if an exception occurs during the execution of the operation.

Object storage

What does it mean to store an object in a JNDI naming and directory service? We've already mentioned that the exact semantics of the bind() and lookup() operations aren't tightly defined; it's up to the JNDI service provider to define their semantics.

According to the JNDI specification, service providers are encouraged (but not required) to support object storage in one of the following formats:

  • Serialized data
  • Reference
  • Attributes in a directory context

If all JNDI service providers support these standard mechanisms, Java programmers are free to develop generic solutions that work even when the underlying service provider layer changes.

Each of the methods above has advantages and disadvantages. The best method will depend on the requirements of the application under development.

Let's consider each in turn.

As serialized data

The most obvious approach to storing an object in a directory is to store the serialized representation of an object. The only requirement is that the object's class implement the Serializable interface.

When an object is serialized, its state becomes transformed into a stream of bytes. The service provider takes the stream of bytes and stores it in the directory. When a client looks up the object, the service provider reconstructs it from the stored data.

The following code demonstrates how to bind a LinkedList to an entry in an JNDI service:

 // create linked list LinkedList linkedlist = new LinkedList(); . . . // bind context.bind("cn=foo", linkedlist); . . . // lookup linkedlist = (LinkedList)context.lookup("cn=foo"); 

It's that easy!

Unfortunately, the other two methods are more complicated. I will describe them briefly but reserve a detailed discussion for a later date.

As a reference

Sometimes it's not appropriate (or possible) to serialize an object. If the object provides a service on a network, for example, it doesn't make sense to store the state of the object itself. We're interested in the information necessary to find and communicate with the object.

An example is a connection to an external resource (one outside the scope of the Java Virtual Machine) such as a database or file. It clearly doesn't make sense to try to store the database or the file itself in the JNDI service. Instead, we want to store the information necessary to reconstruct the connection.

In this case the programmer should either bind a Reference instance that corresponds to the object or have the object's class implement the Referenceable interface (in which the object generates and provides a Reference instance when requested by the service provider).

The Reference instance contains enough information to recreate the reference. If a reference to a file was stored, the reference contains enough information to create a File object that points to the correct file.

As attributes

If you're using a service provider that provides directory functionality instead of only naming functionality, you can also store an object as a collection of attributes on a DirContext object (a DirContext instance differs from a Context instance in that it may have attributes).

To use this method, you must create objects that implement the DirContext interface and contain the code necessary to write their internal state as an Attributes object. You must also create an object factory to reconstitute the object.

This approach is useful when the object must be accessible by non-Java applications.

Conclusion

If you've read the series, you should understand and appreciate the power and importance of JNDI -- you don't hear much about it, but it's there under the covers.

来月は、JNDIベースのアプリケーションを見ていきます。それまでの間、LDAPサーバーでJNDIを起動して実行するようにしてください。

このトピックの詳細

  • JDBC2.0オプションパッケージ

    //java.sun.com/products/jdbc/articles/package2.html

  • OpenLDAP Foundationにアクセスして、OpenLDAPをダウンロードします

    //www.openldap.org/

  • SLAPDおよびSLURPD管理者ガイドをダウンロードするには、次のURLにアクセスしてください。

    //www.umich.edu/~dirsvcs/ldap/doc/guides/

  • JNDI情報、サービスプロバイダーなど

    //java.sun.com/products/jndi/

このストーリー「JNDIの概要、パート3:高度なJNDI」は、もともとJavaWorldによって公開されました。