カスタムコンポーネント

概要

カスタムコンポーネントは、Apache Antコアの外で定義される条件、セレクタ、フィルタ、およびその他のオブジェクトです。

Ant 1.6では、カスタム条件、セレクタ、フィルタが改良されました。

Antコアコンポーネントのように動作するカスタム条件、セレクタ、フィルタを定義できるようになりました。これは、ビルドスクリプトで定義されたデータ型が、データ型のクラスが互換性がある場合、またはアダプタクラスによって適応されている場合、カスタムコンポーネントとして使用できるようにすることで実現されます。

カスタムコンポーネントを定義する従来の方法も引き続きサポートされています。

定義と使用方法

カスタムコンポーネントは、特定のインターフェースを実装するか、特定のクラスを拡張するか、またはインターフェースまたはクラスに適応された通常のJavaクラスです。

カスタムタスクを作成する場合と全く同じです。属性とネストされた要素は、setterメソッドとaddメソッドを記述することで定義します。

クラスを記述した後、<typedef>を使用してAntシステムに追加します。

カスタム条件

カスタム条件は、org.apache.tools.ant.taskdefs.condition.Conditionを実装するデータ型です。たとえば、文字列がすべて大文字の場合にtrueを返すカスタム条件は、次のように記述できます。

package com.mydomain;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.condition.Condition;

public class AllUpperCaseCondition implements Condition {
    private String value;

    // The setter for the "value" attribute
    public void setValue(String value) {
        this.value = value;
    }

    // This method evaluates the condition
    public boolean eval() {
        if (value == null) {
            throw new BuildException("value attribute is not set");
        }
        return value.toUpperCase().equals(value);
    }
}

条件をシステムに追加する方法は次のとおりです。

<typedef
    name="alluppercase"
    classname="com.mydomain.AllUpperCaseCondition"
    classpath="${mydomain.classes}"/>

この条件は、コアAnt条件が使用されている場所であればどこでも使用できるようになりました。

<condition property="allupper">
    <alluppercase value="THIS IS ALL UPPER CASE"/>
</condition>

カスタムセレクタ

カスタムセレクタは、org.apache.tools.ant.types.selectors.FileSelectorを実装するデータ型です。

必要なメソッドはpublic boolean isSelected(File basedir, String filename, File file)のみです。これは、指定されたファイルを選択するかどうかによってtrueまたはfalseを返します。

ファイル名が.javaで終わるファイルを選択するカスタム選択の例を以下に示します。

package com.mydomain;
import java.io.File;
import org.apache.tools.ant.types.selectors.FileSelector;
public class JavaSelector implements FileSelector {
    public boolean isSelected(File b, String filename, File f) {
        return filename.toLowerCase().endsWith(".java");
    }
}

セレクタをシステムに追加する方法は次のとおりです。

<typedef
    name="javaselector"
    classname="com.mydomain.JavaSelector"
    classpath="${mydomain.classes}"/>

このセレクタは、コアAntセレクタが使用されている場所であればどこでも使用できます。たとえば、次のようになります。

<copy todir="to">
    <fileset dir="src">
        <javaselector/>
    </fileset>
</copy>

org.apache.tools.ant.types.selectors.BaseSelectorは、妥当なデフォルトの動作を提供する便利なクラスです。利用できるいくつかの事前定義された動作があります。属性の設定またはタグの追加時に問題が発生した場合は、setError(String errmsg)を呼び出すことができ、クラスは問題があることを認識します。その後、isSelected()メソッドの先頭でvalidate()を呼び出すと、エラーメッセージの内容を含むBuildExceptionがスローされます。validate()メソッドは、verifySettings()を呼び出すため、設定の一貫性をチェックするための最後の機会も提供します。このメソッドをオーバーライドし、セレクタの設定方法に問題を検出した場合はその中でsetError()を呼び出してください。

カスタムセレクタコンテナを作成するには、org.apache.tools.ant.types.selectors.BaseSelectorContainerを拡張する必要があります。public boolean isSelected(File baseDir, String filename, File file)メソッドを実装して適切な処理を行います。おそらく、自分の下のセレクタを反復処理したいと思うでしょう。そのためには、selectorElements()を使用してそれを行うイテレータを取得します。

たとえば、特定の数の含まれるセレクタが選択した場合にファイルを選択するセレクタコンテナを作成するには、次のようにセレクタを作成できます。

public class MatchNumberSelectors extends BaseSelectorContainer {
    private int number = -1;
    public void setNumber(int number) {
        this.number = number;
    }
    public void verifySettings() {
        if (number < 0) {
           throw new BuildException("Number attribute should be set");
        }
    }
    public boolean isSelected(File baseDir, String filename, File file) {
        validate();
        int numberSelected = 0;
        for (Enumeration e = selectorElements(); e.hasNextElement();) {
            FileSelector s = (FileSelector) e.nextElement();
            if (s.isSelected(baseDir, filename, file)) {
                numberSelected++;
            }
        }
        return numberSelected == number;
    }
}

このセレクタを定義して使用するには、次のことができます。

<typedef name="numberselected"
         classname="com.mydomain.MatchNumberSelectors"/>
...
<fileset dir="${src.path}">
    <numberselected number="2">
        <contains text="script" casesensitive="no"/>
        <size value="4" units="Ki" when="more"/>
        <javaselector/>
    </numberselected>
</fileset>

カスタムセレクタ

カスタムセレクタは、Ant 1.6以前のカスタムセレクタの定義方法でした。この方法は、下位互換性のために引き続きサポートされています。

独自のセレクタを作成し、<custom>タグ内で指定することで、セレクタコンテナ内でそれらを使用できます。

新しいカスタムセレクタを作成するには、org.apache.tools.ant.types.selectors.ExtendFileSelectorを実装するクラスを作成する必要があります。最も簡単な方法は、<param>タグのサポートに必要なすべてのメソッドを提供する便利な基本クラスorg.apache.tools.ant.types.selectors.BaseExtendSelectorを使用することです。まず、isSelected()メソッドをオーバーライドし、必要に応じてverifySettings()メソッドをオーバーライドします。カスタムセレクタでパラメータの設定が必要な場合は、setParameters()メソッドをオーバーライドし、渡されたパラメータを好きなように解釈することもできます。コアセレクタのいくつかは、カスタムセレクタとしても使用できるため、その方法を示しています。

記述したら、<custom>タグを使用してビルドファイルに含めます。

属性 説明 必須
classname org.apache.tools.ant.types.selectors.FileSelectorを実装するクラスの名前。 はい
classpath カスタムセレクタクラスをロードするために使用するクラスパス。 classpathclasspathrefのどちらも指定されていない場合、クラスはAntが使用するクラスパスからロードされます。 いいえ
classpathref 以前に定義されたクラスパスへの参照。上記のclasspathrefclasspathのどちらも指定されていない場合、クラスはAntが使用するクラスパスからロードされます。 いいえ

クラスをセレクタとして使用するのに<custom>を使用する方法は次のとおりです。

<fileset dir="${mydir}" includes="**/*">
    <custom classname="com.mydomain.MySelector">
        <param name="myattribute" value="myvalue"/>
    </custom>
</fileset>

カスタムセレクタとしても使用できるコアセレクタは次のとおりです。

Depth Selectorセクションの例を<custom>を使用してセレクタを使用するように書き直したものを次に示します。

<fileset dir="${doc.path}" includes="**/*">
    <custom classname="org.apache.tools.ant.types.selectors.DepthSelector">
        <param name="max" value="1"/>
    </custom>
</fileset>

ベースディレクトリとその下の1つのディレクトリ内のすべてのファイルを選択します。

カスタムフィルタリーダー

カスタムフィルタリーダーセレクタは、org.apache.tools.ant.types.filters.ChainableReaderを実装するデータ型です。

必要なメソッドはReader chain(Reader reader)のみです。これは、指定されたリーダーからの入力をフィルタリングするリーダーを返します。

たとえば、2番目の文字を削除するfilterreaderは次のようになります。

public class RemoveOddCharacters implements ChainableReader {
    public Reader chain(Reader reader) {
        return new BaseFilterReader(reader) {
            int count = 0;
            public int read() throws IOException {
                while (true) {
                    int c = in.read();
                    if (c == -1) {
                        return c;
                    }
                    count++;
                    if ((count % 2) == 1) {
                        return c;
                    }
                }
            }
        }
    }
}

行指向のフィルタの場合、org.apache.tools.ant.filters.TokenFilterの内部クラスであるChainableFilterReaderを拡張する方が簡単かもしれません。

たとえば、行番号を追加するフィルタは次のようになります。

public class AddLineNumber extends ChainableReaderFilter {
    private void lineNumber = 0;
    public String filter(String string) {
        lineNumber++;
        return "" + lineNumber + "\t" + string;
    }
}