Servlet 3.0でよりよい無設定T2Framework

前回T2Frameworkを無設定で行えるようにした。

ただ、無設定といいつつパッケージが完全固定されているのが致命的にダメだった。

所詮サーブレット 3.0のfragmentの解説用なのであのままでは実用にならないとはいいつつもやはり使いにくいままではいかんなと。


というわけで、実用品質に変えていく。つまり、無設定ならばデフォルトのパッケージを見に行くように、設定があればそちらを優先するように。


web-fragment.xmlを以下のように書き換える。

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">
  <context-param>
    <param-name>t2.rootpackage</param-name>
    <param-value>t2.defaultroot</param-value>
  </context-param>
  <filter>
    <filter-name>t2</filter-name>
    <filter-class>org.t2framework.t2.filter.T2Filter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>t2</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
  <session-config>
    <session-timeout>
            30
        </session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>/</welcome-file>
  </welcome-file-list>
</web-fragment>

つまり、フィルタのパラメータを削除している。


jarの中にソースファイルをひとつ追加。リスナで動的にフィルタパラメータの生成をしている。

package t2;

import java.util.Map.Entry;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;


@WebListener
public class T2ConfigListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext context = sce.getServletContext();

        String root = context.getInitParameter("t2.rootpackage");


        System.out.println("★t2.rootpackage:" + root);
        for (Entry<String, ? extends FilterRegistration> e : context.getFilterRegistrations().entrySet()) {
            FilterRegistration reg = e.getValue();

            if (reg.getClassName().equals("org.t2framework.t2.filter.T2Filter")) {
                reg.setInitParameter("t2.rootpackage", root);
                System.out.println("★パラメータのセット");
            }
        }
    }

    public void contextDestroyed(ServletContextEvent sce) {
    }
}


実行したときのログを表示してみる。

情報: ★t2.rootpackage:t2.defaultroot
情報: ★パラメータのセット
情報: Loading application T2 at /T2
情報: T2 was successfully deployed in 1,062 milliseconds.
情報: ★t2.rootpackage:hogeroot
情報: ★パラメータのセット
情報: Loading application T2 at /T2
情報: T2 was successfully deployed in 563 milliseconds.

1回目の実行時はweb.xmlファイルが存在しないとき。2回目の実行が「context-param」のみを設定したweb.xmlを配置したとき。

ちゃんと動的にパッケージルートがかわっているのがわかると思う。


ちなみに2回目の動作が速いのはGlassfishのリロードのみで済んでるので。NetBeansのデフォルト設定だとCTRL+Sで保存時にコンパイル、再配備される。セッションも維持されてるのでセッションに入れる値の書式が変わっていない限りテストにしても最初のログイン画面から実行していくとかいうこともない(再配備時のセッション維持するかどうかはNetBeansの機能ではなくGlassfishの機能ね)。

NetBeansGlassfish V3の場合logbackとの相性が悪いようなのでsl4jの設定を変えたほうが良いかと。上は相性が悪い状態の起動なのでものすごく遅い。


見てわかるようにT2Framework側のソースは一切いじっていない。Servlet 3.0ではかなり柔軟に設定できるのがわかるだろうか。動的にフィルタやサーブレットを設定する場合、クラス名やクラスを渡すほかにインスタンスそのものも渡せるようになっている。これはおそらくCDI対応のためだろう。つまり、動的に設定できるような仕組みを独自にするのではなく、web.xmlやweb-fragment.xmlからたどれるようにしておくとJavaEE 6時代のフレームワークとしてJavaEE 5世代とは別物の快適さになるだろう。

なんにせよ動的に柔軟に設定できるのは面白い。Java EE 6では基本となるServlet APIにほんの少し手を加えるだけでStrutsくらいの基盤はすぐに作れるということだ。