Timer and Work Manager API (CommonJ) プログラマーズ ガイド

     前  次    新しいウィンドウで目次を開く     
ここから内容の開始

Timer and Work Manager API

この節では、Timer and Work Manager API の概要を説明し、これらをアプリケーション内に実装する方法を示します。

 


Timer and Work Manager API とは

Timer and Work Manager API は、BEA Systems と IBM が共同作成した仕様で定義されています。この API を使用すると、Java EE アプリケーション内に EJB とサーブレットを同時にプログラミングできます。この API はしばしば CommonJ と呼ばれます。

CommonJ API には、次のコンポーネントが含まれます。

commonj.timer と commonj.work は同じ API の一部ですが、それぞれ別の機能を提供します。どちらの API を実装するかは、アプリケーション固有のニーズによって決定します。CommonJ Timer API は、作業を特定の間隔でスケジューリングする場合に理想的です。たとえば、あるジョブを特定の時刻に実行する必要がある場合などです。CommonJ Work Manager API は、作業を優先順位に基づいて処理する場合に理想的です。たとえば、特定のジョブの発生時期をはっきりと予測できないが、発生した場合には高い (または低い) 優先順位を与える場合などです。

以下の節では、CommonJ API を詳細に説明します。

 


Timer API の概要

Timer API は次の 3 つのインタフェースで構成されています。

タイマー マネージャは、管理対象の環境においてタイマーを作成および使用するためのフレームワークを提供します。タイマー リスナは、タイマー通知を受信します。TimerManager.schedule() メソッドを使用して、TimerListener を特定の時刻または間隔において実行するようにスケジューリングします。

タイマーの実装方法の詳細については、「Timer API の使用」を参照してください。

TimerManager インタフェース

TimerManager インタフェースは、アプリケーション内の全般的なスケジューリング フレームワークを提供します。管理対象の環境では、複数の TimerManager インスタンスをサポートできます。1 つのアプリケーション内に複数の TimerManager インスタンスを設定できます。

タイマー マネージャを作成およびコンフィグレーションする

TimerManager は、デプロイ中にデプロイメント記述子でコンフィグレーションされます。TimerManager の定義には、実装固有の付加的なコンフィグレーション情報が含まれることもあります。

デプロイメント記述子に TimerManager が定義されると、そのインスタンスはローカル Java 環境で JNDI ルックアップを使用してアクセスできるようになります。JNDI lookup() で TimerManager を呼び出すたびに、TimerManager の新しい論理インスタンスが返されます。

TimerManager インタフェースはスレッドセーフです。

JNDI の使用方法の詳細については、『WebLogic JNDI プログラマーズ ガイド』を参照してください。

TimerManager を中断する

TimerManager は、suspend() メソッドおよび resume() メソッドを使用して中断および再開できます。TimerManager を中断すると、未処理のタイマーはすべて TimerManager が再開されるまで保留されます。

TimerManager を停止する

TimerManager は、stop() メソッドを使用すると停止できます。stop() が呼び出されると、アクティブなタイマーはすべて停止され、TimerManager インスタンスはすべての TimerListener インスタンスのモニタを停止します。

TimerListener インタフェース

commonj.timers パッケージを使用するすべてのアプリケーションは、TimerListener インタフェースを実装する必要があります。

Timer インタフェース

Timer インタフェースのインスタンスは、TimerManager を介してタイマーがスケジューリングされたときに返されます。

 


Timer API の使用

この節では、アプリケーション内で Timer API を使用するために必要な手順を簡単に示します。

アプリケーションをデプロイする前に、タイマー マネージャへのリソース参照を含むデプロイメント記述子が作成済みであることを確認してください。

これにより、TimerManager が JNDI を介してアクセス可能になります。JNDI ルックアップの詳細については、『WebLogic JNDI プログラマーズ ガイド』を参照してください。

以下の手順で、Timer API の実装方法を説明します。

  1. commonj.timers.* パッケージをインポートします。
  2. InitialContext を作成します。これにより TimerManager が JNDI でルックアップ可能になります。
  3. IntialContext inctxt = new InitialContext();

    JNDI ルックアップの詳細については、『WebLogic JNDI プログラマーズ ガイド』を参照してください。

  4. TimerManager の JNDI ルックアップに基づいて新しい TimerManager を作成します。
  5. TimerManager mgr = (TimerManager)ctx.lookup(`java:comp/env/timer/MyTimer');

    この文では JNDI ルックアップの結果が TimerManager にキャストされています。

  6. タイマー通知を受信するために TimerListener を実装します。
  7. TimerListener listener = new StockQuoteTimerListener(`abc', `example');
  8. TimerManager.schedule() を呼び出します。
  9. mgr.schedule(listener, 0, 1000*60)

    schedule() メソッドは Timer オブジェクトを返します。

  10. timerExpired() メソッドを実装します。
  11. public void timerExpired(Timer timer) {
         //このメソッド内で
         //ビジネス ロジックが実行される
    }

タイマー マネージャのサンプル

package examples.servlets;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import commonj.timers.*;

/**
* TimerServlet は commonj タイマーの簡単な使用法を示す
*/
public class TimerServlet extends HttpServlet {

/**
* commonj タイマーをスケジューリングするサービス メソッドの
* とても単純な実装
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
try {
InitialContext ic = new InitialContext();
TimerManager tm = (TimerManager)ic.lookup
("java:comp/env/tm/default");
// すぐに開始する 10 秒ごとのタイマーを実行
tm.schedule (new MyTimerListener(), 0, 10*1000);
out.println("<h4>Timer scheduled!</h4>");
} catch (NamingException ne) {
ne.printStackTrace();
out.println("<h4>Timer schedule failed!</h4>");
}
}

private static class MyTimerListener implements TimerListener {
public void timerExpired(Timer timer) {
System.out.println("timer expired called on " + timer);
// ここに有用な処理を記述
// タイマーはキャンセルすること
System.out.println("cancelling timer ...");
timer.cancel();
}
}
}

 


ジョブ スケジューラの使用

この節では、ジョブ スケジューラ機能の使用方法について説明します。ジョブ スケジューラを使用すると、クラスタ化環境内に commonj.timer API を実装できます。

ジョブ スケジューラは、基本的には commonj.timer API パッケージの実装であり、クラスタ内で使用できます。ここではジョブは commonj.timers.TimerListener インスタンスとして定義され、ジョブ スケジューラに送信されて実行されます。

この節では、以下のトピックを取り上げます。

タイマーのライフ サイクル

アプリケーション内に commonj.timer API を実装する場合、タイマーにコンフィグレーションできるライフ サイクルには 2 種類あります。

各タイマーにはそれぞれメリットとデメリットがあります。ローカル タイマーでは、複数のジョブをより短い時間間隔で処理できます。ジョブ スケジューラでは、クラスタ内の永続性要件のために同様の精度ではジョブを処理できません。一方で、初めにタスクを作成したサーバが失敗した場合にもそのタスクを実行する必要がある場合には、ジョブ スケジューラの方が適しています。

ジョブ スケジューラの実装とコンフィグレーション

この節では、アプリケーション内にジョブ スケジューラを実装し、それを利用するように WebLogic Server 環境をコンフィグレーションするための基本的な手順を簡単に示します。

データベースをコンフィグレーションする

永続性を保持し、タイマーがクラスタを認識できるようにするため、ジョブ スケジューラにはデータベース接続が必要です。ジョブ スケジューラ機能では、サーバの移行でサポートされるのと同じデータベース ベンダおよびバージョンがサポートされます。

便宜上、セッション永続性、サーバの移行などに使用されているのと同じデータベースを使用できます。

データベースには、以下のスキーマで WEBLOGIC_TIMERS というテーブルを作成する必要があります。

CREATE TABLE WEBLOGIC_TIMERS (
  TIMER_ID VARCHAR2(100) NOT NULL,
  LISTENER BLOB NOT NULL,
  START_TIME NUMBER NOT NULL,
  INTERVAL NUMBER NOT NULL,
  TIMER_MANAGER_NAME VARCHAR2(100) NOT NULL,
  DOMAIN_NAME VARCHAR2(100) NOT NULL,
  CLUSTER_NAME VARCHAR2(100) NOT NULL,
  CONSTRAINT SYS_C00323062 PRIMARY KEY(TIMER_ID, CLUSTER_NAME, DOMAIN_NAME)
)

データ ソースをコンフィグレーションする

必要なスキーマでテーブルを作成した後には、クラスタ コンフィグレーション内で参照されるデータ ソースを定義する必要があります。ジョブ スケジューラ機能は、クラスタ MBean の DataSourceForJobScheduler 属性に有効なデータ ソースが定義されている場合にのみ利用できます。これは、WebLogic Server Administration Console でコンフィグレーション可能です。

この定義の仕方について、以下の config.xml からの抜粋に示します。

<domain>
...
<cluster>
<name>Cluster-0</name>
<multicast-address>239.192.0.0</multicast-address>
<multicast-port>7466</multicast-port>
<data-source-for-job-scheduler>JDBC Data Source-0</data-source-for-job-scheduler>
</cluster>
...
<jdbc-system-resource>
<name>JDBC Data Source-0</name>
<target>myserver,server-0</target>
<descriptor-file-name>jdbc/JDBC_Data_Source-0-3407-jdbc.xml</descriptor- file-name>
</jdbc-system-resource>
</domain>

ジョブ スケジューラ内で JNDI アクセスする

クラスタ化されたタイマー内で JNDI ルックアップを実行する手順は、一般的な commonj.timer API における手順とは異なります。JNDI ルックアップを TimerManager にキャストする方法を以下の抜粋コードに示します。

InitialContext ic = new InitialContext(); 
commonj.timers.TimerManager jobScheduler =(common.timers.TimerManager)ic.lookup
("weblogic.JobScheduler");
commonj.timers.TimerListener timerListener = new MySerializableTimerListener();
jobScheduler.schedule(timerListener, 0, 30*1000);
// 30 秒ごとにこのジョブを実行

サポートされていないメソッドおよびインタフェース

commonj.timer API のメソッドおよびインタフェースの中には、ジョブ スケジューラ環境でサポートされていないものもあります。以下のメソッドおよびインタフェースはサポートの対象外です。

 


Work Manager API とは

Work Manager (commonj.work) API は、アプリケーションがコンテナ内で複数の作業項目を同時に実行できるようにするインタフェースを提供します。

基本的に、この API は java.lang.Thread API のコンテナ管理の代替機能を提供します。java.lang.Thread API は、管理対象の Java EE 環境でホストされるアプリケーション内では使用しないようにする必要があります。Work Manager API を使用するとコンテナが実行中のすべてのスレッドを認識および制御できるので、そうした環境では代わりに Work Manager API を使用するようお勧めします。

注意 : Work Manager API では、フェイルオーバや永続性メカニズムは提供されません。管理対象サーバ環境が失敗または停止した場合、現在の作業はすべて失われます。

ワーク マネージャのインタフェース

この節では、Work Manager API に定義されているインタフェースの全般的な概要を説明します。これらのインタフェースの詳細な使用方法については、commonj.work パッケージの javadoc を参照してください。

Work Manager API には以下のインタフェースがあります。

ワーク マネージャのデプロイメント

ワーク マネージャは、サーバレベルで、適切なデプロイメント記述子の resource-ref を使用して定義します。さまざまな記述子がありますが、特に web.xml または ejb-jar.xml が定義場所になります。

以下のデプロイメント記述子からの抜粋に、WorkManager のコンフィグレーション方法を示します。


<resource-ref>
<res-ref-name>wm/MyWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
...
注意 : WorkManager オブジェクトの JNDI ネームスペースに推奨されるプレフィックスは java:comp/env/wm です。

 


ワーク マネージャのサンプル

この節には、HTTP サーブレット内で CommonJ ワーク マネージャを使用する作業コードのサンプルを示します。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import weblogic.work.ExecuteThread;
import commonj.work.WorkManager;
import commonj.work.Work;
import commonj.work.WorkException;

public class HelloWorldServlet extends HttpServlet {
   public void service(HttpServletRequest req, HttpServletResponse res)
      throws IOException
   {
      res.setContentType("text/html");
      PrintWriter out = res.getWriter();


      try {
         InitialContext ic = new InitialContext();
         System.out.println("## [servlet] executing in: " +
            ((ExecuteThread)Thread.currentThread()).getWorkManager()
            .getName());
         WorkManager wm = (WorkManager)ic.lookup
            ("java:comp/env/foo-servlet");
         System.out.println("## got Java EE work manager !!!!");
         wm.schedule(new Work(){
         public void run() {
         ExecuteThread th = (ExecuteThread) Thread.currentThread();
         System.out.println("## [servlet] self-tuning workmanager: " +
           th.getWorkManager().getName());
         }
         public void release() {}
         public boolean isDaemon() {return false;}
});
}
catch (NamingException ne) {
ne.printStackTrace();}

catch (WorkException e) {
e.printStackTrace();
}

out.println("<h4>Hello World!</h4>");
// 出力ストリームを閉じないこと - 出力ストリームはサーブレット エンジンが閉じられるようにする
// これはパフォーマンス向上のため
System.out.println("finished execution");}
}

ページの先頭       前  次