LoginSignup
34
35

More than 5 years have passed since last update.

jBatch のお試し実装

Last updated at Posted at 2013-08-26

jBatch(Batch Application for the java Platform) のお試し実装メモ。

環境

OS

Windows7 64bit

Java EE 環境

GlassFish OpenSource Edition 4.0

実装

Chunk の実装

Chunk を実装する場合は、 ItemReaderItemProcessorItemWriter の3つのインターフェースを実装したクラスを用意する。

ItemReader の実装

MyItemReader
package jbatch.chunk;

import java.io.Serializable;

import javax.batch.api.chunk.ItemReader;

public class MyItemReader implements ItemReader {

    @Override
    public void open(Serializable checkPoint) throws Exception {
        System.out.println("[Reader] open");
    }

    private int counter;

    @Override
    public Object readItem() throws Exception {
        String item;

        if (counter < 22) {
            item = String.format("item-%03d", ++counter);
        } else {
            item = null;
        }

        System.out.println("[Reader] readItem. item = " + item);

        return item;
    }

    @Override
    public void close() throws Exception {
        System.out.println("[Reader] close");
    }

    @Override
    public Serializable checkpointInfo() throws Exception {
        System.out.println("[Reader] checkpointInfo");
        return null;
    }
}

ItemProcessor の実装

MyItemProcessor
package jbatch.chunk;

import javax.batch.api.chunk.ItemProcessor;

public class MyItemProcessor implements ItemProcessor {

    @Override
    public Object processItem(Object item) throws Exception {
        System.out.println("[Processor] item = " + item);
        return ((String)item).toUpperCase();
    }
}

ItemWriter の実装

MyItemWriter
package jbatch.chunk;

import java.io.Serializable;
import java.util.List;

import javax.batch.api.chunk.ItemWriter;

public class MyItemWriter implements ItemWriter {

    @Override
    public void open(Serializable checkPoint) throws Exception {
        System.out.println("[Writer] open");
    }

    @Override
    public void writeItems(List<Object> items) throws Exception {
        System.out.println("[Writer] writeItems. items = " + items);
    }

    @Override
    public void close() throws Exception {
        System.out.println("[Writer] close");
    }

    @Override
    public Serializable checkpointInfo() throws Exception {
        System.out.println("[Writer] checkpointInfo");
        return null;
    }
}

Batchlet の実装

Batchlet を実装する場合は、 Batchlet インターフェースを実装したクラスを用意する。

MyBatchlet
package jbatch.batchlet;

import javax.batch.api.Batchlet;

public class MyBatchlet implements Batchlet {

    @Override
    public String process() throws Exception {
        System.out.println("[Batchlet] process");
        return null;
    }

    @Override
    public void stop() throws Exception {
        System.out.println("[Batchlet] stop");
    }
}

ジョブXMLの作成

ジョブの内容を定義した XML ファイルを作成して、 WEB-INF/classes/META-INF/batch-jobs の下に配置する。

sample-job.xml
<?xml version="1.0" encoding="UTF-8"?>
<job id="sample-job"
     xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
     version="1.0">

  <step id="sample-chunk" next="sample-batchlet">
    <chunk>
      <reader    ref="jbatch.chunk.MyItemReader"    />
      <processor ref="jbatch.chunk.MyItemProcessor" />
      <writer    ref="jbatch.chunk.MyItemWriter"    />
    </chunk>
  </step>

  <step id="sample-batchlet">
    <batchlet ref="jbatch.batchlet.MyBatchlet" />
  </step>

</job>

エントリポイント用の JAX-RS サービスを実装

jBatch のジョブを実行するためのエントリポイントとして、 JAX-RS のサービスを実装する。

MyApplication
package jbatch.rest;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest")
public class MyApplication extends Application {
}
JBatchResource
package jbatch.rest;

import javax.batch.operations.JobOperator;
import javax.batch.runtime.BatchRuntime;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("sample")
public class JBatchResource {

    @GET
    public String start() {
        JobOperator job = BatchRuntime.getJobOperator();

        System.out.println("[REST] バッチ呼び出し前");
        long id = job.start("sample-job", null);
        System.out.println("[REST] バッチ呼び出し後");

        return "jBatch Start. id = " + id;
    }
}

Eclipse プロジェクトの様子

Eclipseプロジェクトの様子

実行結果

Web ブラウザで http://localhost:8080/jbatch/rest/sample にアクセスすると、以下のようにコンソールに出力される。

※ホスト名(localhost)、ポート(8080)、コンテキストパス(jbatch)は適宜読み替え。

実行結果
[REST] バッチ呼び出し前
[REST] バッチ呼び出し後
[Reader] open
[Writer] open
[Reader] readItem. item = item-001
[Processor] item = item-001
[Reader] readItem. item = item-002
[Processor] item = item-002
[Reader] readItem. item = item-003
[Processor] item = item-003
[Reader] readItem. item = item-004
[Processor] item = item-004
[Reader] readItem. item = item-005
[Processor] item = item-005
[Reader] readItem. item = item-006
[Processor] item = item-006
[Reader] readItem. item = item-007
[Processor] item = item-007
[Reader] readItem. item = item-008
[Processor] item = item-008
[Reader] readItem. item = item-009
[Processor] item = item-009
[Reader] readItem. item = item-010
[Processor] item = item-010
[Writer] writeItems. items = [ITEM-001, ITEM-002, ITEM-003, ITEM-004, ITEM-005, ITEM-006, ITEM-007, ITEM-008, ITEM-009, ITEM-010]
[Reader] checkpointInfo
[Writer] checkpointInfo
[Reader] readItem. item = item-011
[Processor] item = item-011
[Reader] readItem. item = item-012
[Processor] item = item-012
[Reader] readItem. item = item-013
[Processor] item = item-013
[Reader] readItem. item = item-014
[Processor] item = item-014
[Reader] readItem. item = item-015
[Processor] item = item-015
[Reader] readItem. item = item-016
[Processor] item = item-016
[Reader] readItem. item = item-017
[Processor] item = item-017
[Reader] readItem. item = item-018
[Processor] item = item-018
[Reader] readItem. item = item-019
[Processor] item = item-019
[Reader] readItem. item = item-020
[Processor] item = item-020
[Writer] writeItems. items = [ITEM-011, ITEM-012, ITEM-013, ITEM-014, ITEM-015, ITEM-016, ITEM-017, ITEM-018, ITEM-019, ITEM-020]
[Reader] checkpointInfo
[Writer] checkpointInfo
[Reader] readItem. item = item-021
[Processor] item = item-021
[Reader] readItem. item = item-022
[Processor] item = item-022
[Reader] readItem. item = null
[Writer] writeItems. items = [ITEM-021, ITEM-022]
[Reader] checkpointInfo
[Writer] checkpointInfo
[Reader] close
[Writer] close
[Batchlet] process

JobOperator#start(String, Properties) の呼び出し後は非同期でジョブが実行されている。

ジョブXML について

ファイルは WEB-INF/classes/META-INF/batch-jobs の下に配置する

前述したとおり、ジョブXML は WEB-INF/classes/META-INF/batch-jobs の下に配置する。

job タグの id 属性

sample-job.xml
<?xml version="1.0" encoding="UTF-8"?>
<job id="sample-job"
     ...>
</job>
  • ジョブXML のファイル名は、job タグの id 属性と一致させなければならない。

(2016/03/06 追記)
上記間違ってました。すみません。。。
ジョブ XML のファイル名と <job> タグの id 属性は、一致させる必要はないみたいです。

<job> タグの id 属性は任意の値で良いようです。
JSR-352 によると、

Specifies the logical name of the job and is used for identification purposes. It must be a valid XML string value. This is a required attribute.

(意訳)
ジョブの論理名を指定し、識別のために使用される。
この値は、 XML の文字列値として有効な値でなければならない。
これは必須の属性です。

ということで、論理名なのでファイル名と一致させる必要はないようです。

step タグについて

<step id="sample-chunk" next="sample-batchlet">
  ...
</step>

<step id="sample-batchlet">
  ...
</step>
  • ジョブXML では、 step タグを使ってジョブの具体的な実行内容(順序)を記述する。
  • step タグは id 属性が 必須
  • next 属性に他の step タグの id 属性を指定することで step の実行順序を制御できる。

ref 属性には CDI の Named で設定した名前も指定できる

前述の例では、 ref 属性には FQCN を指定していたが、下記のように Named アノテーションで設定した名前も指定できる。

Namedで名前付け
import javax.enterprise.context.Dependent;
import javax.inject.Named;

@Dependent
@Named("myItemWriter")
public class MyItemWriter implements ItemWriter {
    ...
}
Namedで設定した名前を指定
<step id="sample-chunk" next="sample-batchlet">
  <chunk>
    ...
    <processor ref="myItemProcessor" />
    ...
  </chunk>
</step>

なお、 javax.enterprise.context.Dependent アノテーションは beans.xml がなくても CDI が有効になるようにするために付与している。(詳しくはJava EE環境におけるCDIのデフォルト化 - 別に危なくないプログラミング日記を参照)。

ジョブの起動方法

JobOperator job = BatchRuntime.getJobOperator();
job.start("sample-job", null);

BatchRuntime#getJobOperator() メソッドで JobOperator のインスタンスを取得する。
次に、 start(String, Properties) メソッドでジョブを実行する。このとき、第一引数で実行するジョブ ID を指定する。ジョブ ID とは、ジョブXML の job タグで指定した id 属性の値のこと。

ジョブID
<?xml version="1.0" encoding="UTF-8"?>
<job id="sample-job"
     ...>
  ...
</job>

(2016/03/06 追記)
第一引数に指定するのは、拡張子を除いたジョブXMLのファイル名でした。すみません。。。

以下、 Javadoc の JobOperator#start(String, Properties) を訳しました。

Note the Job XML describing the job is first searched for by name according to a means prescribed by the batch runtime implementation. This may vary by implementation. If the Job XML is not found by that means, then the batch runtime must search for the specified Job XML as a resource from the META-INF/batch-jobs directory based on the current class loader. Job XML files under META-INF/batch-jobs directory follow a naming convention of "name".xml where "name" is the value of the jobXMLName parameter (see below).

(意訳)
注意点として、 名前を使った Job XML の最初の検索は、バッチ実行環境の実装が指定します。これは、実装によって異なるかもしれません。
もし最初の検索で Job XML が見つからない場合、バッチ実行環境は現在のクラスローダを使って META-INF/batch-jobs ディレクトリからリソースとして Job XML を検索しなければなりません。
META-INF/batch-jobs ディレクトリ以下の Job XML ファイルは、 "name".xml という名前で定義します("name" は、第一引数の jobXMLName で指定する値です)。

参考

34
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
35