jBatch(Batch Application for the java Platform) のお試し実装メモ。
#環境
##OS
Windows7 64bit
##Java EE 環境
GlassFish OpenSource Edition 4.0
#実装
##Chunk の実装
Chunk を実装する場合は、 ItemReader
、 ItemProcessor
、 ItemWriter
の3つのインターフェースを実装したクラスを用意する。
###ItemReader の実装
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 の実装
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 の実装
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
インターフェースを実装したクラスを用意する。
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
の下に配置する。
<?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 のサービスを実装する。
package jbatch.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("rest")
public class MyApplication extends Application {
}
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;
}
}
#実行結果
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 属性
<?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
アノテーションで設定した名前も指定できる。
import javax.enterprise.context.Dependent;
import javax.inject.Named;
@Dependent
@Named("myItemWriter")
public class MyItemWriter implements ItemWriter {
...
}
<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
属性の値のこと。
<?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
で指定する値です)。
#参考