「ASP.NET/定期的にTaskを実行する」の内容を、QuizMLに試験的に実装し、ASP.NETで非同期実行ができることがわかりました。じゃぁ、J2EEではどうなんだ? ということで、やってみました。
java.util.TimerをServletで使う †
- まず、java.util.TimerTaskクラスを継承、runメソッドを実装したクラスを作成し、runメソッド内に実行したいタスクを記述します。
- Servlet内でTimerインスタンスを生成し、上で作成したTaskを登録するだけです。
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new Task01(config.getServletContext()), firstTime, peroid);
- サンプルサーブレット TimerTestServlet01.java
- ※1 開始時刻として過去の時刻を設定すると、その時刻から現在時刻までの実行されたはずの回数分が、スケジュール登録時に一気に実行されてしまいます。開始時刻は、未来時刻になるようにするのが好いでしょうね。
問題点 †
- J2EEでjava.util.Timerを利用することは、問題があるようです。
- J2EE 1.4仕様では、サーブレットのサービス・メソッド(service(), doPost(), doGet()等)から新たに別のスレッドを生成し、その新スレッドでJTA(Java Transaction API)を利用したトランザクションを開始することを禁じている
- J2EE 1.4仕様の「J2EE.4.2.3 Transactions and Threads」の節を参照
- EJB 2.1仕様では、Enterprise Beanが開始、終了、中断、再開を含むスレッドの管理を行うことを禁じている。スレッドの管理はEJBコンテナの役割なのです。
- EJB 2.1仕様の「25.1.2 Programming Restrictions」の節を参照
- 開発者がクラスThreadのインスタンスを生成して新たなスレッドを開始した場合には、その新たなスレッドにJava EEコンテキストを渡すことができないため、そのスレッドは認証済みユーザーとは別のSecurity Identityを持つものとして稼働する可能性がある。また、トランザクションの開始や終了といった制御が行えない可能性がある。
- その解決策が、BEAとIBMが共同策定した「JSR 236:Timer for Application Servers」と「JSR 237:Work Manager for Application Servers」であり、その実行が「commonj」というプロジェクトらしい。
必要なパーツをうまく抽出できません ...orz
Tomcat5.5を用い、<Context>(server.xml)およびweb.xmlで<Resource>設定をし、TimerManagerインスタンスの取得はできているようなのですが、java.lang.IllegalMonitorStateException が出まくります ...orz