2009年12月22日火曜日

MultiDeviceFilter(mobylet + T2 + Velocity on GAE/J)

スズキです。

GAE/J上で"/index.html"などの同じURLで、PCからのアクセスと携帯からのアクセスで
表示内容を変えたいなーと思い、mobylet(携帯専用フレームワーク)、T2、Velocity、
そして独自フィルターを用いて実現してみました。(それぞれのサイトは下記となります)

▼mobylet
http://mobylet.seasar.org/
▼T2
http://code.google.com/p/t-2/
▼Velocity(VelocityView)
http://velocity.apache.org/tools/devel/view.html
▼独自フィルター
http://code.google.com/p/suz-lab-gae/source/browse/?r=40#svn/trunk/suz-lab-gae/src/suz/lab/gae/filter

"web.xml"は以下のようになりました。

最初に"mobylet"フィルター、次が独自フィルター、
そして、"T2"フィルター、"Velocity"サーブレットと続いています。

--------【web.xml】--------
...
<context-param>
  <param-name>t2.encoding</param-name>
  <param-value>UTF-8</param-value>
</context-param>

<filter>
  <filter-name>mobylet</filter-name>
  <filter-class>org.mobylet.core.http.MobyletFilter</filter-class>
  <init-param>
    <param-name>mobylet.config.dir</param-name>
    <param-value>WEB-INF/mobylet/</param-value>
  </init-param>
</filter>

<filter>
  <filter-name>multi</filter-name>
  <filter-class>suz.lab.gae.filter.MultiDeviceFilter</filter-class>
</filter>

<filter>
  <filter-name>t2</filter-name>
  <filter-class>org.t2framework.t2.filter.T2Filter</filter-class>
  <init-param>
    <param-name>t2.rootpackage</param-name>
    <param-value>abokyu.apps.page</param-value>
  </init-param>
  <init-param>
    <param-name>t2.container.adapter</param-name>
    <param-value>org.t2framework.t2.adapter.SimpleContainerAdapter</param-value>
  </init-param>
  <init-param>
    <param-name>t2.exclude-resources</param-name>
    <param-value>txt, css, js, ico</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>mobylet</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
  <filter-name>multi</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
  <filter-name>t2</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
  <servlet-name>velocity</servlet-name>
  <servlet-class>org.apache.velocity.tools.view.servlet.VelocityLayoutServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>velocity</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>
...
--------

"mobylet"に関してですが、携帯端末以外は変換処理がかからないように、
"WEB-INF/mobylet/mobylet.xml"を下記のようにしています。

--------【mobylet.xml】--------
...
<through>
  <carrier>OTHER</carrier>
</through>
...
--------

そして、独自フィルターです。コードは下記のようになっていて、
まず、"response.setCharacterEncoding("UTF-8")"をしています。
これは、"mobylet"フィルターをかけると"ISO-8859-1"が設定されてしまい、
Velocity変換時に文字化けしてしまうからです。

--------【MultiDeviceFilter】--------
...
@Override
public void doFilter(
    ServletRequest request,
    ServletResponse response,
    FilterChain chain
) throws IOException, ServletException {
  response.setCharacterEncoding("UTF-8");
  chain.doFilter(new MultiDeviceHttpServletRequest(
    (HttpServletRequest)request), response
  );
}
...
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-gae/src/suz/lab/gae/filter/MultiDeviceFilter.java?r=40

次に以下の"MultiDeviceHttpServletRequest"を使って、
デバイス(mobile/other)ごとに"RequestURI"と"ServletPath"を調整しています。

--------【MultiDeviceFilter】--------
...
public class MultiDeviceHttpServletRequest extends HttpServletRequestWrapper {
  private String device;

  public MultiDeviceHttpServletRequest(HttpServletRequest request)
      throws UnsupportedEncodingException {
    super(request);
    Carrier carrier = MobyletFactory.getInstance().getCarrier();
    if(carrier == Carrier.OTHER) {
      this.device = "other";
    } else {
      this.device = "mobile";
    }
  }

  @Override
  public String getRequestURI() {
    if(super.getRequestURI().startsWith("/" + this.device)) {
      return super.getRequestURI();
    } else {
      return "/" + this.device + super.getRequestURI();
    }
  }

  @Override
  public String getServletPath() {
    if(super.getServletPath().startsWith("/" + this.device)) {
      return super.getServletPath();
    } else {
      return "/" + this.device + super.getServletPath();
    }
  }
}
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-gae/src/suz/lab/gae/filter/MultiDeviceHttpServletRequest.java?r=40

こうすることで、"/index.html"にアクセスした場合、
PCだと、"page.other.IndexPage.java(T2)"が実行され、
テンプレートは"vm/page/other/index.html(Velocity)"が利用され、
携帯だと、"page.mobile.IndexPage.java(T2)"が実行され、
テンプレートは"vm/page/mobile/index.html(Velocity)"が利用され、
さらに、"mobylet"のフィルター効果もききます。

ってダラダラ書いてしまいましたが、ブランクプロジェクト作れって話ですね。
実際に動いてるものと、そのソースも公開したい…

--------
http://www.suz-lab.com

0 コメント: