URLをResource経由で取得
最近は何かとSOAP通信が要求される。
これが単一のサーバ相手だったりするといいのだけど、当然テストと本番が分かれている。
とうぜん手元もテストと本番で分かれているわけだから、テスト機で通信するのか、本番機で通信するのか、はたまたローカルマシンで通信するのかで、接続先を変える必要がある。
普通のプログラマならば「なら設定ファイルで持っておけばいいじゃない」と発想してJavaならpropertiesファイルに接続先を突っ込むのだそうだ。
# と、言われたのだが、本当だろうか。俄かには信じがたい。
しかし待ってくれ。
その設定ファイル、テストのwarと本番のwarの両方に入らなきゃならないわけだけど、テストから本番に持っていくときに書き換えるのかい?
それはありえないだろ。
JavaのAPサーバなら、大抵そういう「リソース」を管理する仕組みがあるんだから、それに一丁頼ってみるのが、この場合よさそうじゃないか。
そこで、java.net.URLをtomcatのserver.xmlにResourceで登録してうまく動かないものかやってみた。
流れを読んでみる
まずResourceエレメントはどのように解釈されるのだろう。
Resourceエレメントが指定されると、tomcatではcatalinaエンジンがjavax.naming.Referenceのオブジェクトを作成する(ここが本当にCatalinaなのかは追いきれて居ない。ん〜)
そして、ResourceParams のオブジェクトをEnumerationとして、Referenceの中に入れる。(っぽい)
ResourceParams で factory があったら、値をクラス名としてインスタンスをリフレクションで作成し、ObjectFactoryにキャストする。
で、getObjectInstanceを呼んで帰ってきたオブジェクトを渡す…。
とまぁ、こんな流れっぽい。
ということは、適切なObjectoFactoryを使用すれば良さそうだ。
Bean標準でなんとかしてみる
そこで、java.net.URLに適合するFactoryを探してみた。
そのまま直に対応しているものはなかったのだが、次点ということでorg.apache.naming.factory.BeanFactory が目に付いた。
これはBeanInfoを受け取ってオブジェクトを作成する物。
保持するオブジェクトのクラスが、BeanInfoインターフェースを実装している事を期待している。
となると、java.net.URLのサブクラスを作り、BeanInfoインターフェースを適合すればよいということになる。
まずはスケルトンとばかりに、早速作ってみた。
C:\>copy con A.java import java.net.URL; class A extends URL { } ^Z 1 個のファイルをコピーしました。 C:\>c:\Develop\Language\j2sdk1.4.2_08\bin\javac.exe A.java
A「なぁ兄弟。いまどきJava1.4のプロジェクトってどう思う?」
B「そりゃとびっきりのジョークだ!」
そう、ジョークだったらよかったと思うよ…兄弟。
A.java:2: final java.net.URL からは継承できません。 class A extends URL { ^ A.java:2: シンボルを解決できません。 シンボル: コンストラクタ URL () 場所 : java.net.URL の クラス class A extends URL { ^ エラー 2 個 C:\>
まぁ、なんですか。
分かりやすく言うとURLクラスはfinalなので継承できないってことですね。
この方向はあえなく失敗。
Bean標準でなんとかしてみる
BeanInfoを実装する方向ではなくするとなると、ObjectFactoryを実装するしかない。
そっちからなら単純にできるのだけど、キット汎用性は無いよなぁ…。
というわけで、org.apache.naming.SendMailFactoryを参考にして書いてみる。
import java.net.URL; import java.util.Hashtable; import javax.naming.Context; import javax.naming.Name; import javax.naming.RefAddr; import javax.naming.Reference; import javax.naming.spi.ObjectFactory; public class URLFactory implements ObjectFactory { public Object getObjectInstance(Object refObj, Name name, Context context, Hashtable env) throws Exception { Reference ref = (Reference) refObj; if (!ref.getClassName().equals("java.net.URL")) { return null; } RefAddr attr = ref.get("url"); if (attr == null) { return null; } return new URL((String) attr.getContent()); } }
これをjarにして $CATALINA_HOME/common/lib につっこみ、server.xmlに対象リソースを記述。
<Server port="8005" shutdown="SHUTDOWN"> <Service name="Catalina"> <Connector port="8080" /> <Engine name="Catalina" defaultHost="localhost"> <Host name="localhost"> <Context path="/" docBase="foobar" reloadable="true"> <Resource auth="Container" name="url" scope="Shareable" type="java.net.URL"/> <ResourceParams name="url"> <parameter> <name>factory</name> <value>URLFactory</value> </parameter> <parameter> <name>url</name> <value>http://example.com</value> </parameter> </ResourceParams> </Context> </Host> </Engine> </Service> </Server>
で、立ち上げるとJNDIリソースが出来上がっているはず。
確認のため、これをServletから呼び出してみる。
public class TestServlet extends HttpServlet { protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { try { Context context = new InitialContext(); URL url = (URL) context.lookup("java:comp/env/url"); System.out.println(url); } catch (NamingException e) { e.printStackTrace(); } } }
web.xmlも作成してwarにしてdeployする(ここは省略させてくだしあ)。
いや、warにしなくてもいいのですけど…。
実際にアクセスしてみる
準備が全て整ったところでアクセス。
対象のtomcatは5.0.28。なんでそんなバージョンかって?
キカナイデクレ。
2008/10/28 00:35:54 org.apache.coyote.http11.Http11Protocol init 情報: Coyote HTTP/1.1をポートhttp-8080で初期化します 2008/10/28 00:35:54 org.apache.catalina.startup.Catalina load 情報: Initialization processed in 0 ms 2008/10/28 00:35:54 org.apache.catalina.core.StandardService start 情報: サービス Catalina を起動します 2008/10/28 00:35:54 org.apache.catalina.core.StandardEngine start 情報: Starting Servlet Engine: Apache Tomcat/5.0.28 2008/10/28 00:35:54 org.apache.catalina.core.StandardHost start 2008/10/28 00:36:02 org.apache.catalina.core.StandardHost getDeployer 情報: Create Host deployer for direct deployment ( non-jmx ) 2008/10/28 00:36:02 org.apache.coyote.http11.Http11Protocol start 情報: Coyote HTTP/1.1をポート http-8080 で起動します 2008/10/28 00:36:02 org.apache.catalina.startup.Catalina start 情報: Server startup in 0 ms http://example.com
ということで、無事、リソースの取得に成功した。