Pool
Commons Poolは、どんなオブジェクトでもプールできるすばらしいフレームワークです。JDBC接続、スレッド、業務用オブジェクト、JNDI接続のプールにも十分に役立つはずです。
サンプルアプリケーションではJNDI接続プールを利用します。このサンプルの実行にはJNDI互換のディレクトリサーバーが必要になります。また、このサンプルではActive Directory Application Mode(ADAM)を使用しますが、ADAMはこちらからダウンロードできます。それでは、このサンプルがCommons Poolを使ってどのようにJNDI接続をプールするのかを見ていきましょう。
リスト16は、JNDIの操作を行うメソッドを公開するインターフェイスです。
public interface IJNDIConnection { /** * Execute the given query against the directory server. * * @param query JNDI query of the form ((objectclass=user)(cn=john)) * @return Search result * @throws NamingException Directory server error */ NamingEnumeration executeQuery(String query) throws NamingException; /** * Fetch the attributed of a given DN of an object. * * @param dn Distinguished name of the object * @return Attributes of an object * @throws NamingException Directory server error */ Attributes getAttributes(String dn) throws NamingException; }
このin.co.narayanan.commons.pool.JNDIConnectionクラスは、さきほどのインターフェイスを実装しており、javax.naming.directory.DirContextクラスを使って、要求されるJNDI操作を実行します。リスト17のコードは、プールされた接続をどのように取得して利用するかを示すテストケースクラスTestPoolの一部です。
String host = "localhost"; String port = "389"; String binDN = "CN=guest,CN=Users,DC=narayanan,DC=co,DC=in"; String password = "guest"; String baseDN = "DC=narayanan,DC=co,DC=in"; JNDIConnectionManager manager = JNDIConnectionManager.getJNDIConnectionManager( host, port, binDN, password, baseDN); IJNDIConnection connection = manager.getConnection(); String query = "(objectclass=container)"; NamingEnumeration users = connection.executeQuery(query); while (users.hasMoreElements()) { System.out.println(users.next()); }
このコードは、JNDIConnectionManagerを使って接続プールからIJNDIConnectionへの参照を取得したうえで、簡単な検索クエリを実行します。Commons Poolの利用では、org.apache.commons.pool.PoolableObjectFactoryインターフェイスの各メソッドを実装して、その参照をorg.apache.commons.pool.impl.GenericObjectPoolインターフェイスの実装に渡す、というのが基本的な手順です。ほとんどの場合は、org.apache.commons.pool.impl.GenericObjectPoolクラス ― ObjectPoolのデフォルト実装 ― で十分に間に合います。リスト18のコードは、Commons Poolによる新たなオブジェクトの要求時にJNDI接続を作成するJNDIConnectionFactoryの一部です。
public class JNDIConnectionFactory implements PoolableObjectFactory { private JNDIConnectionInfo connInfo; public JNDIConnectionFactory(String host, String port, String bindDN, String password, String baseDN) { connInfo = new JNDIConnectionInfo( host, port, bindDN, password, baseDN); } public Object makeObject() throws Exception { Hashtable dirProps = connInfo.getJNDIConnectionProps(); DirContext dirContext = new InitialDirContext(dirProps); return dirContext; } public void destroyObject(Object context) throws Exception { DirContext dirContext = (DirContext)context; dirContext.close(); } // remaining methods // inner class JNDIConnectionInfo }
太字の行は、Commons Poolからの要求に応じてDirContextの生成と破棄をどのように行うかを示しています。このObjectPoolを実装したクラスはmakeObjectメソッドとdestroyObjectメソッドを適切に呼び出します。リスト19は、JNDIConnectionManagerクラスの一部です。
public class JNDIConnectionManager { // remaining declarations private GenericObjectPool pool; private PoolableObjectFactory factory; private JNDIConnectionManager( String host, String port, String bindDN, String password, String baseDN) { factory = new JNDIConnectionFactory( host, port, bindDN, password, baseDN); pool = new GenericObjectPool(factory); } // remaining code public IJNDIConnection getConnection() { try { return new JNDIConnection((DirContext)pool.borrowObject()); } catch (Exception e) { return null; } } public void returnConnection(IJNDIConnection connection) { try { pool.returnObject( ((JNDIConnection)connection).getContext()); } catch (Exception e) { System.out.println("Unable return the object back to pool"); } } }
このコードでは、JNDIConnectionFactoryの参照をGenericObjectPoolに渡すことでJNDI接続を作成しています。強調表示された行は、プールとの間でこの接続の取得と返却をどのように行うかを示しています。
Commons PoolはすべてのJavaアプリケーションで間違いなく役に立ちます。Javaアプリケーションではリソースのプールが共通の要件になっているためです。また、ニーズに合わせてGenericObjectPoolクラスをカスタマイズすることも可能です(詳細については、このクラスのjavadocを参照)。
まとめ
Jakarta Commonsを紹介するシリーズの最終回では、次の内容を取り上げました。
- Commonsのさまざまなコンポーネントが提供する豊富な機能
- ユーティリティクラスの特定のコンポーネントやメソッドの具体的な用途
- さまざまなAPIのパッケージとクラスの概要
これからJavaアプリケーションをデザインしたり開発したりするときには、有用なクラスを選んで適切に使用できることでしょう。
