パスワードを忘れた? アカウント作成
457565 journal

quabbinの日記: [Java] URLをResource経由で取得 5

日記 by quabbin

最近は何かとSOAP通信が要求される。
これが単一のサーバ相手だったりするといいのだけど、当然テストと本番が分かれている。
とうぜん手元もテストと本番で分かれているわけだから、テスト機で通信するのか、本番機で通信するのか、はたまたローカルマシンで通信するのかで、接続先を変える必要がある。

普通のプログラマならば「なら設定ファイルで持っておけばいいじゃない」と発想してJavaならpropertiesファイルに接続先を突っ込むのだそうだ。
# と、言われたのだが、本当だろうか。俄かには信じがたい。

しかし待ってくれ。
その設定ファイル、テストのwarと本番のwarの両方に入らなきゃならないわけだけど、テストから本番に持っていくときに書き換えるのかい?
それはありえないだろ。
JavaのAPサーバなら、大抵そういう「リソース」を管理する仕組みがあるんだから、それに一丁頼ってみるのが、この場合よさそうじゃないか。
そこで、java.net.URLをtomcatのserver.xmlにResourceで登録してうまく動かないものかやってみた。

流れを読んでみる
対象はtomcatなので、tomcatの流れを追ってみる。

まず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:\>
</eocde>
まぁ、なんですか。
分かりやすく言うとURLクラスはfinalなので継承できないってことですね。
この方向はあえなく失敗。
 
<b>Bean標準でなんとかしてみる</b>
BeanInfoを実装する方向ではなくするとなると、ObjectFactoryを実装するしかない。
そっちからなら単純にできるのだけど、キット汎用性は無いよなぁ…。
というわけで、org.apache.naming.SendMailFactoryを参考にして書いてみる。
<ecode>
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

ということで、無事、リソースの取得に成功した。

しかし
tomcatはいろいろと探ってみて標準ではURLの管理ができないらしく、このようにクラスを追加作成する必要があると結論付けた。
しかし、他はどうなのだろう。
JBossやGeronimo、その他商用APサーバは、標準でURLの管理が可能なのだろうか。
# JBossは可能そうな気がするけど、試したことがないから今後の課題。

ぱっと検索したところ、WebSphereはURLの管理ができそうな感じ。
さすがは商用ですね。

…ん~。何か見逃している気がするんだよなぁ…。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • 私が作ったWebアプリの場合、DataSource以外の環境依存の情報もすべてPropertyファイルに入れてしまっています。その上で、antのビルドの際に環境毎にPropertyを書き換えるようにしてきました。というより、それ以外に思い浮かばなかったので。

    環境毎にバイナリ(warファイル)が異なってしまいますが、ビルドプロセスがきちんとテストされていれば実質的に問題はないでしょう。

    ですが、環境依存情報はすべてサーバに持たせるというquabbinさんの方が正しい気がします。テストと環境構築がすこし面倒になる気はしますけど。
  • by Anonymous Coward on 2008年10月28日 10時02分 (#1445523)
    init-paramとかcontext-paramをつかえば良いのに!

    #非商用ではJettyという選択も悪くないと思うけど、日本語資料が少ないなあ
    • init-paramとかcontext-paramって、web.xml内に書くものだと思ったのですが…。
      web.xmlって、テストと本番で書き換えるものなのですか?
      それとも、別の場所に書けるのでしょうか。

      どうもこのあたり、私が何かを見落としている気がしてならんのです。
      親コメント
      • by Anonymous Coward
        すいません><

        少なくともこの件については、アントワネット的に「似たようなもんだろ!」と突っ込んでいただければ。
        propatiesファイルの位置をweb.xmlに書くか、値そのものを書くかはケースバイケースですが
        本番でそれをコンソールから触らせていますが、propatiesファイルより運用寄りというだけですね。
        それにしても、うちも1.4の案件でですね・・・一般的とはとてもいえな(ry

        #WebSphereといえばCommunity EditionのベースはGeronimo [nikkeibp.co.jp]なんですね。
typodupeerror

※ただしPHPを除く -- あるAdmin

読み込み中...