Antタスク作成

2008年03月10日

タスククラスの実装

Ant は標準だけでもかなり豊富なタスクが用意されていますが、フレームワークの作業 や cron などのバッチとして使用する場合などのためにローカル環境に合わせた独自の タスクが実装したくなります。Ant のタスクは TaskJava™ API リファレンス クラスと対応付けられており、このサブクラスを実装することで Ant タスクを自由に 作成することが出来ます。

単純なタスク

タスクの処理はオーバーライドされた execute() メソッドによって行われます。 以下のタスクは hostname プロパティに実行環境のホスト名を設定しています。

Java
package biz.moyo.lab.sample;
import java.net.*;
import org.apache.tools.ant.*;

public class HostnameTask extends Task{
    /** タスクの実行 */
    @Override
    public void execute() {
        try{
            InetAddress local = InetAddress.getLocalHost();
            getProject().setProperty("hostname", local.getHostName());
        } catch(UnknownHostException ex){
            throw new BuildException("ホスト名不明", ex);
        }
        return;
    }
}

ビルドファイル内で <taskdef> タグを使用して Task クラスをタグ名 にマッピングします。

build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>

    <!-- タスクの定義 -->
    <taskdef name="hostname"
        classname="biz.moyo.lab.sample.HostnameTask"
        classpath="sample.jar" />

    <target name="test">
        <hostname />    <!-- タスクを実行 -->
        <echo message="${hostname}" />
    </target>

</project>

この実行結果は以下のようになります。

実行結果
Buildfile: C:\…\build.xml
test:
     [echo] amber
BUILD SUCCESSFUL
Total time: 310 milliseconds

属性付きのタスク

Task サブクラスに setter を定義することでタスクタグの属性値を受け取る ことが出来ます。以下の例は property 属性に指定したプロパティ名にホスト 名を設定します。

Java
package biz.moyo.lab.sample;
import java.net.*;
import org.apache.tools.ant.*;

public class HostnameTask extends Task{
    private String property = "hostname";

    /** ホスト名を設定するプロパティの名前
     * @param property プロパティ名
    */
    public void setProperty(String property){
        this.property = property;
        return;
    }

    /** タスクの実行 */
    @Override
    public void execute() {
        try{
            InetAddress local = InetAddress.getLocalHost();
            getProject().setProperty(property, local.getHostName());
        } catch(UnknownHostException ex){
            throw new BuildException("ホスト名不明", ex);
        }
        return;
    }
}

setter の型には String の他に int などのプリミティブ型や File などを使用することが 出来ます。

build.xml
<target name="test">
    <hostname property="local" />
    <echo message="${local}" />
</target>

実行結果は前述と同じです。

内包テキストの取得

タスククラスに public void addText(String) というメソッドを実装すること でタグが内包するテキストを受け取ることが出来ます。これはスーパークラスのメソッド ではなくリフレクションによって呼び出されます。

以下のタスクは Scripting API を使用して内部に記述された JavaScript を実行します (Ant には既に <script> タスクが用意されていますが)。

Java
package biz.moyo.lab.sample;
import javax.script.*;
import org.apache.tools.ant.*;

public class ScriptTask extends Task{
    private String type = "text/javascript";
    private StringBuilder content = new StringBuilder();

    /** スクリプトタイプの設定
     * @param type スクリプトの MIME-Type
    */
    public void setType(String type){
        this.type = type;
        return;
    }

    /** 内包テキストの取得
     * @param text 内包テキスト
     */
    public void addText(String text){
        this.content.append(text);
        return;
    }

    /** タスクの実行 */
    @Override
    public void execute() {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByMimeType(type);
        try{
            engine.eval(content.toString());
        } catch(ScriptException ex){
            throw new BuildException("実行に失敗", ex);
        }
        return;
    }
}

内部のテキストには CDATA セクションを使用すると XML エスケープを省略できます。

build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
    <taskdef name="jscript"
        classname="biz.moyo.lab.sample.ScriptTask"
        classpath="sample.jar" />
    <target name="test">
        <jscript type="text/javascript">
        <![CDATA[
            println(1 + 1);
        ]]>
        </jscript>
    </target>
</project>

実行結果
Buildfile: C:\…\batch.xml
test:
   [jscript] 2
BUILD SUCCESSFUL
Total time: 300 milliseconds

下位要素の使用

タスクタグの下層に独自の要素を使用する事ができます。

まず下位要素の属性や内包テキストを保持するクラス (例: MyChild) を 用意します。このクラスにはタスクの場合と同にように setter や addText() を 実装します。

タスククラスには以下のいずれかを実装することで下位要素の情報を受け取る ことが出来ます。

  1. public void addMychild(MyChild) - 引数の型に基づいたインスタンスが Ant によって構築され、タスクに渡されます。この時 MyChild クラスには デフォルトコンストラクタか 1 つの Project を引数に取るコンストラクタ が必要です。
  2. public void addConfiguredMychild(MyChild) - 引数の型に基づいた インスタンスが Ant によって構築され、タスクに渡されます。属性や内包 テキストが設定された後に呼び出される以外は上記と同じです。
  3. public MyChild createMychild() - タスククラス内でどのオブジェクトを 使用するかを選択する場合に使用します。

下線の部分に注意してください。要素名とのバインディングはネーミングルールと リフレクションによって解決しています。上記の例は <mychild> 要素を受け取る事ができます。

Java
package biz.moyo.lab.sample;
import java.text.*;
import java.util.*;
import org.apache.tools.ant.*;

public class DateTask extends Task{
    private final List<Date> date = new ArrayList<Date>();

    /** 日時の追加
     * @param date 追加する日時
     */
    public void addDate(Date date){
        this.date.add(date);
        return;
    }

    /** タスクの実行 */
    @Override
    public void execute() {
        DateFormat df = DateFormat.getDateInstance();
        for(Date d: date){
            log(df.format(d));
        }
        return;
    }
}
build.xml
<target name="test">
    <taskdef name="xdate"
        classname="biz.moyo.lab.sample.DateTask"
        classpath="sample-task.jar" />
    <xdate>
        <date year="100" month="0" date="1" />
        <date year="101" month="1" date="3" />
    </xdate>
</target>

実行結果
Buildfile: C:\...\build.xml
test:
    [xdate] 2000/01/01
    [xdate] 2001/02/03
BUILD SUCCESSFUL
Total time: 271 milliseconds

標準で用意されている FileSet クラスなどを使用することで <zip> タスクのようにファイル集合を受け取るタスクを作成することが出来ます。

CVS 2008/03/10