2006年03月26日

EJB (JBoss)でスレッド

 EJBの最悪さを知らない人々は幸福である。幸福な人々には大変恐縮だが、暗澹たる事実のひとつをお知らせしよう。
  EJBコンテナ内では、普通の方法でスレッドを作ってはいけない。
  今度はEJB 3.0だそうだが、そもそも最初から作り直せと言いたい。MSの.NETがよくできている(後発だから当然だが)のを見るにつけ、「貧乏人はJavaをやれ」と言われている気分だ。
  普通の方法でスレッドを作ってはいけないが、普通でない方法ならある。JCA 1.5で導入された javax.resource.spi.work.WorkManager を使う方法だ。具体的にどんなコードになるのか、ちょっと調べれば出てくるだろう――しかしこの期待はあっさりと裏切られた。
  この記事が典型例だ。WorkManagerインスタンスをJNDIで取ってくる、と書いてあるだけで、具体的にどこでどうやってインスタンスを生成し、JNDIにバインドするのかは書いていない。この問題について書いた記事は、どこをどう探しても、出てこない。そして、WorkManagerについて書いてある記事は、ひとつの例外もなく、どこか知らないところで生成・バインドされたインスタンスを取ってきているのだ。これらの記事を書いた連中は、実際に動くコードを自分の手元に持っていたのだろうか。どれかがオリジナルで、ほかの記事はオリジナルをコピペしたのではないだろうか。
  私が書くのは記事ではなくソフトウェアなので、実際に動くコードが必要だ。JNDIで取ってくるのは正しい方法なのかもしれないが、私は違う方法をとった。
  以下に実際のコードを示す。まず、Runnable相当のクラスから。

import javax.resource.spi.work.Work;

public class MyWork implements Work {
    public void release() {
        System.out.println("MyWork#release");
    }

    public void run() {
        System.out.println("MyWork#run");
    }
}

 そしてEJB。

import java.util.Set;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.management.Exception;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.resource.spi.work.WorkManager;

/**
 * @ejb.bean
 *     name="My"
 *     type="Stateless"
 *     view-type="remote"
 *     transaction-type="Bean"
 * @ejb.transaction type="Required"
 */
public abstract class MyBean implements SessionBean {
    /**
     * 
     * @ejb.interface-method view-type="remote"
     * @throws EJBException
     */
    public void calltest() throws EJBException {
        try {
            ObjectName name = new ObjectName("jboss.jca:service=WorkManager");
            ObjectInstance wmo = mbserver.getObjectInstance(name);
            WorkManager wm = (WorkManager) mbserver.invoke(wmo.getObjectName(), "getInstance",
                    new Object[] {}, new String[] {});
            wm.scheduleWork(new MyWork());
            System.out.println("MyWork scheduled");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 これが私の結論だ。
  ちなみに私はEJBのトランザクション管理をまったく使っていないので、ここからトランザクション管理をしようとすると、なにが起こるかわからない。あしからず。

Posted by hajime at 2006年03月26日 02:04
Comments