もし標準リソースファクトリに要件を満たすものがなければ、
独自のファクトリを実装し Tomcat 5 に組み込み、conf/server.xml
設定ファイルでそのファクトリの利用方法を設定できます。
以下の例においては、前述の 汎用
JavaBean リソースの例から、com.mycompany.MyBean Bean
の作り方だけを知っているファクトリを作成します。
1. リソースファクトリクラスの実装
JNDI サービスプロバイダである javax.naming.spi.ObjectFactory
インタフェースを実装するクラスを作成しなければいけません。
Web アプリケーションがこのファクトリと紐づいたコンテキストエントリへの
lookup() を呼出すたびに、以下の引数で
getObjectInstance() メソッドが呼出されます。
- Object obj - オブジェクト作成時に使われる、
場所および参照の情報を含むオブジェクト (null の可能性あり)。
Tomcat では、これは常に
javax.naming.Reference
型のオブジェクトで、このファクトリクラスのクラス名や、
返値のオブジェクトを作成するのに使う (conf/server.xml
からの) 設定プロパティが含まれています。
- Name name - このファクトリが紐づく名前で、
nameCtx をベースとします。
名前を指定しないときは null。
- Context nameCtx - 指定された
name
パラメータのベースとなるコンテキスト。name
がデフォルトの初期コンテキストをベースとする場合は
null。
- Hashtable environment -
このオブジェクトを作成するのに使われる環境 (null の可能性あり)。
Tomcat オブジェクトファクトリでは通常は無視される。
MyBean インスタンスの生成方法を知るリソースファクトリを作成するには、
以下のようなクラスを作ればいいでしょう。
 |  |  |
 |
package com.mycompany;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
public class MyBeanFactory implements ObjectFactory {
public Object getObjectInstance(Object obj,
Name name, Context nameCtx, Hashtable environment)
throws NamingException {
// 指定の bean クラスのインスタンスを取得
MyBean bean = new MyBean();
// 属性にしたがい bean のプロパティをカスタマイズ
Reference ref = (Reference) obj;
Enumeration addrs = ref.getAll();
while (addrs.hasMoreElements()) {
RefAddr addr = (RefAddr) addrs.nextElement();
String name = addr.getType();
String value = (String) addr.getContent();
if (name.equals("foo")) {
bean.setFoo(value);
} else if (name.equals("bar")) {
try {
bean.setBar(Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new NamingException("Invalid 'bar' value " + value);
}
}
}
// カスタマイズしたインスタンスを返す
return (bean);
}
}
|  |
 |  |  |
この例では、無条件に com.mycompany.MyBean
クラスの新しいインスタンスを作成し、このファクトリを設定する
<ResourceParams> 要素 (以下を参照)
に含まれているパラメータに基づいてプロパティに設定を行います。
factory という名前のパラメータはすべてスキップされることに注意して下さい。
このパラメータは、bean に設定されるパラメータではなく、
ファクトリクラスそのものの名前 (この場合は
com.mycompany.MyBeanFactory) を指定するのに使います。
ObjectFactory に関するより詳しい情報は、
JNDI 1.2 Service
Provider Interface (SPI) 仕様 を参照してください。
このクラスをコンパイルするには、クラスパスに $CATALINA_HOME/common/lib
と $CATALINA_HOME/server/lib ディレクトリ内のすべての JAR
ファイルが含まれている必要があります。それが完了している場合は、
ファクトリクラス (と対応する bean クラス) を展開した状態で
$CATALINA_HOME/common/classes 以下に置くか、もしくは JAR
ファイルとして $CATALINA_HOME/common/lib 内に置いてください。
こうすれば、必要なクラスファイルが Catalina 内部リソースと Web
アプリケーションの両方から見えるようになります。
2. リソースに必要なものを定義
次に、この bean の新しいインスタンスをリクエストする JNDI 名を定義するために
Web アプリケーション配備記述子 (/WEB-INF/web.xml) を修正します。
一番簡単なのは以下のように <resource-env-ref>
要素を使う方法です。
 |  |  |
 |
<resource-env-ref>
<description>
MyBean インスタンスのためのオブジェクトファクトリ。
</description>
<resource-env-ref-name>
bean/MyBeanFactory
</resource-env-ref-name>
<resource-env-ref-type>
com.mycompany.MyBean
</resource-env-ref-type>
<resource-env-ref>
|  |
 |  |  |
警告 - 要素の順序が Web アプリケーション配備記述子の DTD
で要求されたとおりであることを確認してください! 詳細は、
Servlet
仕様 を参照してください。
3. このリソースを使うコードをアプリケーションに記述
このリソース環境参照の典型的な使い方は、以下のようになるでしょう。
 |  |  |
 |
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
writer.println("foo = " + bean.getFoo() + ", bar = " +
bean.getBar());
|  |
 |  |  |
4. Tomcat でのリソースファクトリの定義
Tomcat のリソースファクトリを設定するには、この Web アプリケーションの
Context 要素内で入れ子になった
(あるいは <Host> または <Engine>
要素内の DefaultContext 要素内で入れ子になった)、
以下のような要素を $CATALINA_HOME/conf/server.xml
ファイルに追加します。
 |  |  |
 |
<Context ...>
...
<Resource name="bean/MyBeanFactory" auth="Container"
type="com.mycompany.MyBean"/>
<ResourceParams name="bean/MyBeanFactory">
<parameter>
<name>factory</name>
<value>com.mycompany.MyBeanFactory</value>
</parameter>
<parameter>
<name>bar</name>
<value>23</value>
</parameter>
</ResourceParams>
...
</Context>
|  |
 |  |  |
リソース名 (ここでは bean/MyBeanFactory) が Web
アプリケーション配備記述子で指定した値と一致していなければならないことに注意してください。
また、bar プロパティの値の初期化も行っており、それにより
新しい bean が返される前に setBar(23) が呼び出されます。
foo プロパティは (初期化可能でしたが) 初期化していないので、
bean ではコンストラクタでセットアップする何らかのデフォルト値が入ることでしょう。
また、アプリケーション開発者としての観点で言えば、リソース環境参照の定義や、
新しいインスタンスを要求するのに使われているプログラミングは、
汎用 JavaBean リソース の例で使われている方法と同じであることにも注意して下さい。
これは、機能性をカプセル化するために JNDI リソースを使う利点の一つを具体的に示しています。
つまり 互換性のある API を維持している限り、
リソースを使ってアプリケーションを修正しなくても、
内部の実装を変更できます。