続・Wicket + Guice + warp-persist + JPA を試す

 先日のエントリのやり方では Tomcat 上では動いても Glassfish では動かないことがわかりましたので、訂正します。

 インジェクタの初期化を Wicket つまり、フィルタ(Wicket はフィルタとして動作している)で行ってはいけないようなので、リスナで初期化を行います。

package com.example.listener;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.servlet.GuiceServletContextListener;
import com.wideplay.warp.persist.PersistenceService;
import com.wideplay.warp.persist.UnitOfWork;
import com.wideplay.warp.persist.jpa.JpaUnit;

public class MyServletContextListener extends GuiceServletContextListener {

    @Override
    protected Injector getInjector() {
        // warp-persist の Guice モジュール生成
        Module warpModule = PersistenceService.usingJpa().across(UnitOfWork.REQUEST).buildModule();

        // Guice Injector を生成
        return Guice.createInjector(warpModule, buildWebModule());
    }

    private Module buildWebModule() {
        return new AbstractModule() {
            @Override
            public void configure() {
                // JPA の persistence.xml に記述している persistence-unit name を指定
                bindConstant().annotatedWith(JpaUnit.class).to("persistence-unit name");
            }
        };
    }
}

web.xml にリスナを追加します。

    <listener>
        <listener-class>com.example.listener.MyServletContextListener</listener-class>
    </listener>

WicketApplication クラスの init メソッドは以下のようにします。

    @Override
    protected void init() {
        super.init();

        // サーブレットコンテキストからインジェクタを取得
        Injector injector = (Injector) getServletContext().getAttribute("com.google.inject.Injector");

        // Wicket にインジェクタを登録
        addComponentInstantiationListener(new GuiceComponentInjector(this, injector));
    }

Wicket + Guice + warp-persist + JPA を試す

 WicketActiveObjects の組み合わせが良いよ!という記事をかなり前に書きました。ところが、その「良さ」を発揮するための Databinder というプロダクトがなかなか Wicket 1.4.x に対応してくれない! んじゃあ、自分でやるぜ! と思って Databinder のソースを見てみたのですが、ちょっと厳しいところがありまして(Wicket 1.4 のジェネリクス対応のせい)Databinder の開発チームも同じところで悩んでいることがあとでわかりました。

 ということで、WicketActiveObjects の組み合わせが流行っているなんて言われる割に Databinder なしでみんなどうやってるんだろ? なんて思っていたところです。もしかして、DTO 的なものをわざわざ作っているのでしょうか? それとも Proxy を使ってる? 何にしてもいまいちスマートにならないんですよね、私の頭では。

 となってくると、O/R マッパの再選考だ! となるわけです。そこで、今試しているのが JPA。半分食わず嫌いだったのですが、いままでよくつかってきた S2JDBC のエンティティがそのまま使えるし、この際やってみよう! となりました。S2JDBC を使わないのは、dicon の組み立てでハマりまくった経験が多く、さすがに疲れてきたからです。

 で、そのまま JPA を使うのはおもしろくないので、warp-persist を使ってみました。バージョンは 2.0-20090214 です。これは何をするものかというと、

するものです。

 使い方ですが、まず、WicketApplication クラスの init メソッドの例です。

    @Override
    protected void init() {
        super.init();

        // warp-persist の Guice モジュール生成
        Module warpModule = PersistenceService.usingJpa().across(UnitOfWork.REQUEST).buildModule();

        // Guice Injector を生成
        Injector injector = Guice.createInjector(warpModule, buildWebModule());

        // Wicket に登録
        addComponentInstantiationListener(new GuiceComponentInjector(this, injector));
    }

    protected Module buildWebModule() {
        return new AbstractModule() {
            public void configure() {
                // JPA の persistence.xml に記述している persistence-unit name を指定
                bindConstant().annotatedWith(JpaUnit.class).to("persistence-unit name");
            }
        };
    }

次に DAO (S2JDBC 風にいえば Service)の作り方の例です。

package com.example.dao;

import com.example.dao.impl.SomeEntityDaoImpl;
import com.example.entity.SomeEntity;
import com.google.inject.ImplementedBy;

@ImplementedBy(SomeEntityDaoImpl.class)
public interface SomeEntityDao {
    void someMethod(SomeEntity someEntity);
}
package com.example.dao.impl;

import javax.persistence.EntityManager;

import com.example.dao.SomeEntityDao;
import com.example.entity.SomeEntity;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.wideplay.warp.persist.Transactional;

@Transactional
public class SomeEntityDaoImpl implements SomeEntityDao {
    @Inject
    private Provider<EntityManager> entityManagerProvider;

    @Override
    public void someMethod(SomeEntity someEntity) {
        EntityManager em = entityManagerProvicer.get();

        // 処理
    }
}

最後に web.xml に以下の filter を追加

    <filter>
        <filter-name>warpPersistFilter</filter-name>
        <filter-class>com.wideplay.warp.persist.PersistenceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>warpPersistFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

以上です。JPA 自体の説明は今回は割愛します。

 JPA のエンティティは、POJO なので Wicket でも扱い易くていいですね。

続・JInputでキーボードの状態を拾うプログラムをUbuntu上で動かしたら動かない

 昨日のエントリのやり方では Ubuntu を再起動するともとにもどってしまうので、udev の設定をいじらないとダメだということが判明しました。

 まず、デフォルトの設定ファイルを /etc にコピーします。

sudo cp 50-udev-default.rules /etc/udev/rules.d/

つぎのこの設定ファイルを修正します。

sudo vi /etc/udev/rules.d/50-udev-default.rules 

24行目のあたりが以下のようになっていると思います。これは、デバイスパーミッションを設定しているところで、なぜか所有者と所有グループ以外は読むことができなくなっています。

# input
KERNEL=="mouse*|mice|event*",   MODE="0640"
KERNEL=="ts[0-9]*|uinput",      MODE="0640"
KERNEL=="js[0-9]*",             MODE="0644"

これを↓こんな塩梅に修正します。

# input
KERNEL=="mouse*|mice|event*",   MODE="0644"
KERNEL=="ts[0-9]*|uinput",      MODE="0644"
KERNEL=="js[0-9]*",             MODE="0644"

これで再起動すれば今渡こそ解決。

JInputでキーボードの状態を拾うプログラムをUbuntu上で動かしたら動かない

 なんでか調べてみたら、JInput が読み込もうとしている /dev/input/* が所有者(つまり root)しか読めないパーミッションになっていたからでした。

chmod go+r /dev/input/*

これで解決。

教育を通してわかった「Wicketの良さ」

 ここのところJavaによるWebアプリケーションの経験が皆無な人にいろいろ教育してみてわかったのですが、教育の観点からするとWicketはとてもいいですね。

 つまり、学習コストが低い。

 故あってWicketとともにSlim3も学習対象にしているので、Slim3のような「薄い」フレームワークとの対比となるのですが、以下のような学習コストの低減にあたっての利点がありました。

  • HTTP そのものの知識がほぼ不要。
  • テンプレート(View層)の作成には HTML の知識だけでほぼことたりる。
    • JSPJSTLのようにJava以外のものを身につける必要がない。
  • ページ間の値の引渡しについて特別に設計、考慮の必要がない。

ただし、Wicketはリソース食いな上にデフォルトのパスがカッコ悪いので、BtoCのWebサービスにはあまり向かないでしょう。逆に従来のC/S型の社内システムをWebベースでリプレースしたいときなどには威力を発揮すると思います。

Scala 用 IDE はどれがいい?

 現在いろいろ試しているところです。

Scala IDE for Eclipse

 JavaIDE として高いシェアを誇る Eclipse。私も一番慣れているのがこれ。ScalaEclipse で扱えたら嬉しい。ということで使ってみた。

  • ソースコードのフォーマッタが稼働しない。私は整形はフォーマッタまかせなので、これが使えないと使う気が失せる。
  • 補完はかなり賢いらしい(これを検証する前にフォーマッタが効かないからやる気が失せるのでほんとうのところはよく分からない)
  • Maven とからませるとちょいと面倒。M2Eclipse ではどうしようもなくて、MavenEclipse プラグインでなんとかしなきゃイケないらしい。ただ、MavenScala のクイックスタートアーキテクトを使って生成させた pom.xml では上手くいかなかった(Scala プロジェクトとして認識しない)。

Scala Plugin for NetBeans

 Eclipse がダメなら NetBeans でしょ。ということで使ってみた。

  • 私のメインマシンが Ubuntu だったときは気がつかなかったが、Scala エディタがプロジェクトの文字コード設定を無視しているっぽい。つまり、Windows 環境ならかならず「Windows-31J」として読み込みにいってしまう。
  • 私のメインマシンが Ubuntu だったときは割と使っていたが、コード補完がアホだった気がする。
  • プラグインのインストール、設定方法が若干わかりづらかった。

Scala Plugin for IntelliJ IDEA

 最近 Community Edition もリリースされて、大手を振って使えるようになった IDEGoogle の人も使ってるらしいので、使ってみた。

  • IntelliJ IDEA 自体が英語。日本語のメッセージリソースを持っていないっぽい。
  • 前出の2つに比べて Scala IDE としての完成度が高い。
  • JDK のクラスライブラリをスタティックインポートして使うと「このインポートは使っていないから消せ」的な警告が出る。Scala で作ったものからは出ない。
  • 入力補完の性能はまあまあ。インポートされていないクラスは入力補完できないっぽい(設定か?)
  • キーバインドを「Eclipse 風」にしてもやっぱり細かく違う(実行とか)。

ということで使い物になるのは今のところ IDEA だけなんだけど、いかんせん英語が……。
Eclipse プラグインは次バージョンでだいぶ良くなると聞くけど、ほんとかなぁ。