本チュートリアルでは、Eclipseのみを利用した開発環境を前提としたバッチアプリケーションの開発手順を紹介します。
本チュートリアルでは、下記環境を前提に説明を行います。
Eclipse IDE for Java Developers (92 MB) http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/galileosr2 (2010/6/30 現在)
java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07) Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)
Eclipseの利用方法やトラブルに関するお問合せには対応できない点をご注意ください。
発注レポート生成ジョブのサンプルは下記のようなバッチ処理を想定して作成します。
| テーブル名 | カラム定義 | |
|---|---|---|
| 商品マスタテーブル | SYOHIN_MST | SYOHIN_ID VARCHAR(10), SYOHIN_NAME VARCHAR(50), PRICE INTEGER |
| 店舗マスタテーブル | TENPO_MST | TENPO_ID VARCHAR(10), TENPO_NAME VARCHAR(50) |
| 店舗毎の 発注明細テーブル |
HATTYU_TENPO00001 | SYOHIN_ID VARCHAR(10), HATTYU_COUNT INTEGER, HATTYU_DATE DATE |
| HATTYU_TENPO00002 | ||
| HATTYU_TENPO00003 | ||
| HATTYU_TENPO00004 | ||
| HATTYU_TENPO00005 |

発注明細テーブルでは、発注の取り消しを行った場合に、 レコードの削除をせずに負の値の個数のレコードが入力されており、そのレコードもそのままCSVファイルに出力します。
例えば、下記のようなCSVを出力することになります。... 商品1, 30 商品2, 20 商品1, -30 商品1, 100 ...
*************************************** 発注レポート: 2010/06/30 商品 : syohin0003 発注内訳 :- サンプル店舗1 (ID:tenpo00001) 50 個 サンプル店舗2 (ID:tenpo00002) 20 個 サンプル店舗3 (ID:tenpo00003) 30 個 サンプル店舗4 (ID:tenpo00004) 90 個 サンプル店舗5 (ID:tenpo00005) 30 個 発注総数 : 220 個 **************************************
このバッチ処理の要件を満たす単位ジョブを設計します。
発注レポート処理で共通的に利用する1件の発注データを表現するHattyuクラスを下記のように定義します。

図5.1.2.1-1
createHattyuDataジョブは、DB上のデータをCSVファイルに出力する 単純なDB→Fileパターンのジョブです。
SELECT h.SYOHIN_ID, smst.SYOHIN_NAME, h.HATTYU_COUNT,
'パラメータで指定した店舗ID', tmst.TENPO_NAME
FROM hattyu_パラメータで指定した店舗ID h, tenpo_mst tmst, syohin_mst smst
WHERE tmst.TENPO_ID='パラメータで指定した店舗ID'
AND smst.SYOHIN_ID=h.SYOHIN_ID
発注元の店舗ID, 発注元の店舗名, 商品ID, 商品名, 個数
外部プロパティhattyu.csv.dirに指定されたディレクトリの下に店舗ID.csvという名前で出力します。
ジョブパラメータtarget.tenpo.idをキーとして店舗IDを指定します。
hattyuReportジョブはcreateHattyuDataジョブで生成された店舗毎の発注データから
商品毎の発注レポートを作成します。
複数のジョブステップとフローによって商品毎のデータ抽出とレポートの生成を実現します。
|
|
外部プロパティhattyu.csv.dirで指定されたディレクトリ内の全てのCSVファイルを読み込み、 発注データの商品IDがtarget.syohin.idに一致するものだけを外部プロパティtemporary.out.dir で指定したディレクトリ下に商品ID.csvとして出力します。
商品ID.csvの中には、一つの店舗IDに対して複数のレコードが含まれる可能性があります。 このステップでは、商品ID.csvの中でこのようなデータを店舗毎にマージ・集計してメモリ内のListに出力します。
発注レポートの出力は、FlatFileItemWriterの ヘッダ、フッタ出力機能を組合せて実現します。
*************************************** 発注レポート: 実行時の日付をフォーマット 商品 : target.syohin.idの値 発注内訳 :-
1件の発注データを下記文字列に整形して出力
店舗名 (ID:店舗ID) 個数 個
発注総数 : ボディ出力時にデータを集計 個 **************************************
本チュートリアルで利用するサンプルアプリケーションの構成について説明します。
| ${BS_HOME}/sample/application/ | サンプルアプリケーション格納ディレクトリ | ||||||
| +-- apps/ | ドメインへの配備イメージディレクトリ | ||||||
| +-- hattyu | hattyu バッチアプリケーショングループの内容 | ||||||
| +-- lib/ | |||||||
| +-- hattyuApg.jar | hattyuバッチアプリケーショングループ共通のライブラリ | ||||||
| +-- createHattyuDataStep.jar | createHattyuDataステップの定義 | ||||||
| +-- hattyuReportSyohinListup.jar | hattyuReportSyohinListupステップの定義 | ||||||
| +-- hattyuReportStep.jar | hattyuReportステップの定義 | ||||||
| +-- report/ | report バッチアプリケーション | ||||||
| +-- report.xml | report バッチアプリケーションのジョブ定義ファイル | ||||||
| +-- classes/ | |||||||
| +-- createHattyuData.xml | createHattyuDataジョブの定義ファイル | ||||||
| +-- hattyuReport.xml | hattyuReportジョブの定義ファイル | ||||||
| +-- hattyu.jar | hattyu バッチアプリケーショングループアーカイブ | ||||||
| +-- src/ | ソースファイル格納ディレクトリ | ||||||
| +-- tutorial/ | |||||||
| +-- 0_HattyuApg/ | hattyuバッチアプリケーショングループ | ||||||
| +-- 1_HattyuReportApp/ | reportバッチアプリケーション | ||||||
| +-- 2_HattyuDataFileJob/ | createHattyuDataジョブ | ||||||
| +-- 3_HattyuDataFileStep/ | createHattyuDataFileジョブステップ | ||||||
| +-- 4_HattyuReportJob/ | hattyuReportジョブ | ||||||
| +-- 5_HattyuReporSyohinListupStep/ | |||||||
| +-- 6_HattyuReportStep/ | |||||||
Batch Serverに配備可能な構成に配置したappsディレクトリと、Eclipse上にインポートするためのsrcディレクトリから構成されます。
開発環境のセットアップ手順を紹介します。
JDK、Eclipseはすでにインストールされているものとして説明します。
チュートリアルで利用するサンプルのソースコードは全てUTF-8の文字コードを利用しています。
Window - Preferences を開き、General - Workspace の Text file encodingをUTF-8に変更しておいてください。
以下、記載されている順序に従って作業を進めてください。
ジョブを開発・テストするために必要なライブラリをEclipseにとりこみます。
※Batch Serverが提供するライブラリにはオープンソースソフトウェアのライブラリが含まれます
各ソフトウェア・ライブラリのライセンスは ライセンスについて、
または、BS_HOME/notice.htmlを参照してください。
バッチアプリケーショングループ、バッチアプリケーション、
ジョブ、ジョブステップ毎にJavaプロジェクトを作成します。
サンプルのソースコードをEclipse上に取り込む手順例を紹介します。
|
|||||||||||||||||
|
|||||||||||||||||
|
|
|||||||||||||||||
|
|||||||||||||||||
全てのジョブで共通で利用する部品をバッチアプリケーショングループ プロジェクトで開発します。
Hattyuクラスのように、発注業務全体で利用するようなクラスを、
バッチアプリケーショングループ用のライブラリとして開発します。
それぞれ、下記クラスとして定義しています。
次に、バッチアプリケーショングループ内の全てのジョブステップで共通で実施したい処理や、 処理のテンプレートなどをバッチアプリケーショングループとして開発することもできます。 例えば、
する方法を紹介します。
下記の内容を0_HattyuApg/src/main/sample/common/common.xmlに記載し共通の設定を定義します。
ItemReaderを指定するだけで、ジョブ実行ログに読込んだItemのtoString()の結果を出力できるように、 あらかじめ、"commonStep"という名前で定義しておきます。
<b:step id="commonStep" abstract="true">
<b:tasklet>
<b:chunk processor="pathThroughProcessor" writer="logWriter" commit-interval="10"/>
</b:tasklet>
</b:step>
<bean id="pathThroughProcessor"
class="org.springframework.batch.item.support.PassThroughItemProcessor"/>
<bean id="logWriter"
class="org.springframework.batch.item.adapter.ItemWriterAdapter">
<property name="targetObject">
<bean class="com.nec.webotx.batch.util.BSJobExecutionLogUtil"/>
</property>
<property name="targetMethod" value="info"/>
</bean>
この定義をしておくことで、
実際のジョブステップを定義する際に
<b:step id="step" parent="commonStep">
<b:tasklet>
<b:chunk reader="fileReader"/>
</b:tasklet>
</b:step>
と記載するだけで、定義を引き継ぐことができます。
まず、ジョブ実行ログにログを出力するためには、BSJobExecutionLogUtil#getLogger()メソッドを利用して
Apache Commons LoggingのLogインスタンスを取得します。
次に、ジョブの開始・終了をハンドリングするStepExecutionListenerを実装し、メソッドの引数として渡される
StepExecutionから必要な情報を取り出してログに書き込みます。
private static Log log = BSJobExecutionLogUtil.getLogger();
@Override
public void beforeStep(StepExecution stepExecution) {
String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
log.info("Start Step:" + stepExecution.getStepName()+" in Job:" + jobName);
}
こうして実装したListenerを先ほどのcommonStepに追加します。
<b:step id="commonStep" abstract="true">
<b:tasklet>
<b:chunk processor="pathThroughProcessor" writer="logWriter" commit-interval="10"/>
<b:listeners>
<b:listener ref="commonListener"/>
</b:listeners>
</b:tasklet>
</b:step>
<bean id="commonListener" class="sample.common.CommonStepExecutionListener"/>
このように、親のステップにListenerを定義した場合、そのListenerの設定を引き継ぐステップの定義では、 下記のようにlistenersの属性にmerge="true"を設定する必要があります。
<b:step id="step" parent="commonStep">
<b:tasklet>
<b:chunk reader="fileReader"/>
<b:listeners merge="true">
<b:listener ref="someListener"/>
</b:listeners>
</b:tasklet>
</b:step>
merge属性を省略した場合や、merge="false"を設定した場合、 listenersの設定は引き継がれずに、その場で指定したListenerのみが適用されます。
Batch Serverでは、ジョブの強制停止処理機能を提供しています。
この強制停止機能を有効にするには、各ジョブステップのListenerにBatch Serverが提供する強制停止処理用の
Listenerを埋め込む必要があります。
そこで、前節で紹介したジョブステップのデフォルトの設定として、この強制停止処理用のListenerを組み込みます。
前節と同様の方法で、 0_HattyuApg/src/main/sample/common/common.xmlに強制停止処理用のListenerであるBSForceStopListenerを組み込みます。
<b:step id="commonStep" abstract="true">
<b:tasklet>
<b:chunk processor="pathThroughProcessor" writer="logWriter" commit-interval="10"/>
<b:listeners>
<b:listener ref="commonListener"/>
<b:listener ref="bsForceStopListener"/>
</b:listeners>
</b:tasklet>
</b:step>
<bean id="commonListener" class="sample.common.CommonStepExecutionListener"/>
<bean id="bsForceStopListener" class="com.nec.webotx.batch.util.BSForceStopListener"/>
発注データ生成ステップは、店舗IDを指定した単純なDB→Fileパターンの処理です。 ここでは、主に以下の点を検討する必要があります。
以下それぞれの実装について説明します。
SELECT h.SYOHIN_ID, smst.SYOHIN_NAME, h.HATTYU_COUNT,
'#{jobParameters['target.tenpo.id']}', tmst.TENPO_NAME
FROM hattyu_#{jobParameters['target.tenpo.id']} h, tenpo_mst tmst, syohin_mst smst
WHERE tmst.TENPO_ID='#{jobParameters['target.tenpo.id']}'
AND smst.SYOHIN_ID=h.SYOHIN_ID
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Hattyu hattyu = new Hattyu();
hattyu.getSyohin().setId(rs.getString(1)); // 商品ID
hattyu.getSyohin().setName(rs.getString(2)); // 商品名
hattyu.setCount(rs.getInt(3)); // 個数
hattyu.getHattyuMoto().setId(rs.getString(4)); // 店舗ID
hattyu.getHattyuMoto().setName(rs.getString(5)); // 店舗名
return hattyu;
}
このRowMapperをorg.springframework.batch.item.database.JdbcCursorItemReaderのrowMapperに設定します。
発注元の店舗ID, 発注元の店舗名, 商品ID, 商品名, 個数の順に整列させます。
<property name="names" value="hattyuMoto.id,hattyuMoto.name,syohin.id,syohin.name,count"/>例えば、"hattyuMoto.id" は、HattyuオブジェクトのgetHattyuMoto().getId()の実行結果と等しくなります。
このように、ジョブステップの開発においては、Spring FrameworkやSpring Batchが提供する部品群の組合せや、 独自にカスタマイズしたクラスを実装しながら処理を実現します。
Eclipse上でジョブステップの単体テストを実行する方法を紹介します。
Batch Serverがインストールされていない開発端末上でジョブステップの
動作を確認するには、Batch Serverが提供する各種の設定を独自に指定する必要があります。
本サンプルでは、このような設定類をバッチアプリケーショングループのテスト用ソースファイルとして、
まとめて定義しています。
| testLauncher.xml | この定義ファイルには、Spring Batchのジョブを実行するために最低限必要な
|
| testDataSource.xml | この定義ファイルにはテスト用のデータソースに接続するための設定が定義されます。 |
| log4j.xml | この定義ファイルはテスト実行時のログ出力の設定が定義されます。 |
これらは、各ジョブステップのBuild Pathに設定することでテスト時に参照可能にしています。
下記手順によって発注データ生成ステップの動作をテストします。
src/testの下にsample.step.createHattyuDataStepTest.xmlを作成します。
createHattyuDataStep.xmlはジョブステップの定義のみを行っているため、
その定義単独ではジョブとして動作させることはできません。
そこで、テスト時にのみ利用するジョブの定義を作成して単体のジョブステップの動作をテストします。
<import resource="classpath:testLauncher.xml"/>
<import resource="classpath:testDataSource.xml"/>
<import resource="classpath:sample/common/common.xml"/>
<import resource="classpath:sample/step/createHattyuDataStep.xml"/>
<b:job id="createHattyuDataStepTest1">
<b:step id="testStep1" parent="createHattyuData"/>
</b:job>
----- Main タブ ------------------------------------------------- Project : 3_HattyuDataFileStep Main class : org.springframework.batch.core.launch.support.CommandLineJobRunner ----- Arguments タブ -------------------------------------------- Program arguments: sample/step/createHattyuDataStepTest.xml createHattyuDataStepTest1 target.tenpo.id=tenpo00001 -----------------------------------------------------------------Runを実行し、 3_HattyuDataFileStep/test/data/inputディレクトリにtenpo00001.csvファイルが出力されることを確認してください。
サンプルには、ジョブステップ、ジョブ、バッチアプリケーションの単位で
それぞれテストを実行するためのテスト用xxxxTest.xmlを用意しています。
上記手順と同様の方法で、それぞれをテストすることができます。
HatyuDataFileStepをHattyuDataFileJobに組み込み、さらに、reportバッチアプリケーションに登録します。
2_HattyuDataFileJobのsrc/main/hattyuDataFileJob.xmlに下記の定義を行います。
<import resource="classpath:sample/step/createHattyuDataStep.xml"/>
<b:job id="job1">
<b:step id="job1_step1" parent="createHattyuData"/>
</b:job>
ジョブステップの定義をクラスパス上から確実にロードさせるため、importするリソースの指定時には "classpath:"を必ず指定するようにします。
次に、1_HattyuReportAppのsrc/main/report.xmlに下記定義を追加して、上記のジョブを登録しておきます。
<import resource="classpath:hattyuDataFileJob.xml"/>
本チュートリアルでは、バッチアプリケーション、ジョブ、ジョブステップの定義を個別に分割していますが、 開発の規模や体制等に応じて適切な粒度で分割・統合することが可能です。
ジョブステップの開発・テストは省略し、商品ID一覧を取得するステップのポイントのみを紹介します。
商品ID毎の発注レポート出力処理は、以下のジョブステップに分割しこれらを全商品ID分順次繰り返し実行することで実現します。
hattyu.csv.dir/*.csvファイルを全て読み込み、対象の商品IDに一致するレコードのみを中間ファイルに出力します。
このステップの実行前に、前段のステップで読込んだ商品ID一覧の中から、商品IDを順に決定し、
JobExecutionContextのtarget.syohin.idに設定します。
複数ファイルからの順次読み込みはorg.springframework.batch.item.file.MultiResourceItemReaderにて行います。
sample.job2.report.HattyuSyohinIdFilterを
org.springframework.batch.item.validator.ValidatingItemProcessorのvalidatorに設定することで、
対象の商品IDと異なる発注データをフィルタします。
中間ファイルに出力したデータを店舗毎にマージし、内部のListに保存します。
sample.job2.report.MergedHattyuListItemWriterItemReaderを実装し、ItemWriter#write()に渡された、
各発注データがすでに内部のListに登録されていれば、発注データの個数を合計していきます。
保存されたListの発注データをソートし、発注レポートのフォーマットに従って出力します。
sample.job2.report.MergedHattyuListItemWriterItemReaderは、ItemWriterで書込みを行ったListを
発注元の店舗IDでソートして1件ずつ返却するItemReaderです。
このステップは、同一のステップを何度も実行する必要があるため、ItemStream#open(),ItemStrem#close()
のタイミングで、次回のフローで同一のインスタンスが再利用できるように初期化しています。
ここまでで定義したジョブステップの実行順序と、処理フローを定義します。
あらかじめ6_HattyuReportStepには、
org.springframework.batch.core.job.flow.JobExecutionDeciderを実装し、
reportStep.xmlにsyohinLoopControllerとしてBeanを定義しておきます。
このsyohinLoopControllerは、現在設定されている対象の商品IDが商品ID一覧のListの
末尾の要素でなければ"CONTINUE"というステータスを返却します。
このJobExecutionDeciderをフローの定義に利用し、
<b:decision id="syohinLoopDecision" decider="syohinLoopController">
<b:next on="CONTINUE" to="job2_step2" />
<b:end on="COMPLETED"/>
</b:decision>
と定義することで、"CONTINUE"の場合は、もう一度"job2_step2"の処理に戻るよう定義します。
このとき、一度完了したステップを何度も実行できるように
allow-start-if-complete="true"をtaskletの属性に指定しています。
完全なフローの定義は下記のようになります。
この定義を4_HattyuReportJobのsrc/main/hattyuReportJob.xmlとして定義します。
<import resource="classpath:sample/common/common.xml"/>
<import resource="classpath:sample/job2/syohinlistup/syohinListupStep.xml"/>
<import resource="classpath:sample/job2/report/reportStep.xml"/>
<b:job id="job2">
<b:step id="job2_step1" parent="syohinIdListup" next="job2_step2"/>
<b:step id="job2_step2" parent="classificationStep" next="job2_step3">
<b:tasklet>
<b:listeners merge="true">
<b:listener ref="syohinLoopController"/>
</b:listeners>
</b:tasklet>
</b:step>
<b:step id="job2_step3" parent="hattyuMergeStep" next="job2_step4"/>
<b:step id="job2_step4" parent="reportStep" next="syohinLoopDecision"/>
<b:decision id="syohinLoopDecision" decider="syohinLoopController">
<b:next on="CONTINUE" to="job2_step2" />
<b:end on="COMPLETED"/>
</b:decision>
</b:job>
このジョブ定義を 単位ジョブの作成、バッチアプリケーションへの登録と同様、 1_HattyuReportAppのsrc/main/reprot.xmlに下記定義を追加します。
<import resource="classpath:hattyuDataFileJob.xml"/> <import resource="classpath:hattyuReportJob.xml"/>
以上、createHattyuDataジョブと、hattyuReportジョブの定義は完了です。
発注レポート出力ジョブでは複数の商品毎の発注レポートを生成します。 本節では、一部の商品の発注レポートに問題がある場合 (ここでは、発注数の合計が負の値になっている場合を想定します)に、 WebSAM JobCenterが提供する変数継承機能を使って 後続のジョブでその情報を利用できるようにするための方法を紹介します。
また、全ての発注レポートが正常であれば、後続のジョブでリカバリする必要はないかもしれません。
このような場合、ジョブの実行結果をコマンドの終了コードに反映させ、
その終了コードをもとにジョブネットにおける以降のフローを決定するのが一般的です。
WebSAM JobCenter が提供する変数継承機能とは、 ジョブ実行コマンドの標準出力に下記のように出力することで、後続のジョブが"AAAA=BBBB"の値を入力として受け取る機能です。
... EXPORTVAR AAAA=BBBB EXPORTVAR ...
この機能を利用して、下記変数を全ての商品ID分出力し、後続のジョブが利用できるようにします。
商品ID.total=発注数の合計
はじめに、reportSummaryPropsという名前でreportStep.xmlにPropertiesオブジェクトを定義しておきます。
<bean id="reportSummaryProps" class="java.util.Properties"/>
次に、各商品ID分のレポートを出力した際に、各商品の発注数合計をreportSummaryPropsに セットするように FlatFileHattyuReportLayout を修正します。
public void writeFooter(Writer writer) throws IOException {
...
this.reportSummary.setProperty(
this.syohinId + SUMMARY_TOTAL_PREFIX, String.valueOf(total));
}
最後に、ジョブの終了時にreportSummaryPropsの内容を変数継承機能に渡すようにhattyuReportJob.xmlに設定します
<b:listeners>
<b:listener ref="exportVarListener"/>
</b:listeners>
</b:job>
<bean id="exportVarListener" class="com.nec.webotx.batch.util.ExportVariableJobExecutionListener">
<property name="properties" ref="reportSummaryProps"/>
</bean>
</beans>
ジョブ実行コマンドの終了コードを変更するには、ジョブのExitCodeを変更し、 そのExitCodeに対応する終了コードを設定します。
まず、ExitCodeの判定を行うために、 FlatFileHattyuReportLayoutによって修正された、reportSummaryPropsの内容を、 商品ID毎の処理フローの最後にチェックを行うためTargetSyohinDeciderのdecide()メソッドの中に、 下記のような実装を行います。
if( 商品ID一覧の最後に達した ) {
for(String syohinId : syohinIdList) {
String value = reportSummary.getProperty(syohinId + ".total");
if( value が不正 ) {
return CONTAINS_ILLEGAL;
}
}
return COMPLETED;
} else { // 商品ID一覧の途中なのでフローを継続
return CONTINUE;
}
上記実装により、商品の中に一つでも発注数の合計が不正だった場合に"CONTAINS_ILLEGAL"が 返却されます。この結果を用いて、hattyuReportJob.xmlのフロー制御部分を以下のように修正します。
<b:decision id="syohinLoopDecision" decider="syohinLoopController">
<b:next on="CONTINUE" to="job2_step2" />
<b:end on="COMPLETED" />
<b:end on="CONTAINS_ILLEGAL" exit-code="CONTAINS_ILLEGAL"/>
<b:fail on="*"/>
</b:decision>
<b:end>はexit-codeを指定して、TargetSyohinDeciderが返却するFlowExecutionStatus
が"CONTAINS_ILLEGAL"の場合のExitCodeを"CONTAINS_ILLEGAL"とします。
<b:end>はexit-codeを省略するとCOMPLETEDで終了します。
Batch Serverでは、
ExitCode "CONTAINS_ILLEGAL" で終了したジョブに対するコマンドの終了コードを
DOMAIN_HOME/config/batch/exitcode/mapping.properties で指定します。
下記1行をmapping.propertiesに追加します。
webotx.batch.exit.status.CONTAINS_ILLEGAL=終了コード
この設定を行わずに ExitCode "CONTAINS_ILLEGAL" で終了すると、
あらかじめ設定されている webotx.batch.exit.default の値(既定値は255)で
ジョブ実行コマンドが終了します。
設定の詳細は
定義ファイルリファレンス
を参照してください。
次に、Eclipse上で開発・テストを実施してきたバッチアプリケーションを、 Batch Serverへ配備可能な構成(DOMAIN_HOME/sample/application/appsのフォルダ構成をjarで圧縮した形式)にまとめる必要があります。
本サンプルでは下記のような方針で配置先を決定しています。
共通のクラスや、各ジョブステップは、個別の開発者によって開発・テストされ、 最終的にバッチアプリケーションとして結合、ジョブネットからの総合テストを実施することを想定し、 本構成をとっています。
このような構成にまとめるためのAntスクリプト等を準備しておくと便利です。
参考までに、0_HattyuApg/build.xmlに上記構成の物件を一度に作成するAntスクリプトを提供しています。
Eclipse上でAntスクリプトを実行するには、