自定义Condition
编写自定义的condition,可以实现自定义的条件判断逻辑,需要实现org.apache.tools.ant.taskdefs.condition.Condition接口,只有一个必须实现的方法就是eval,用于返回条件判断结果。
比如:实现一个用于判断一个字符串是否全部大写的Condition。
步骤:
1.新建Java工程
2.引入ant库
ant相关的jar就在apache-ant-1.9.4\lib目录下。在Java工程中新建一个libs目录,把jar包都拷贝到libs下,选中所有jar,右键Build Path——Add To Build Path,就完成了ant库的引入。
3.自定义Condition条件判断类
package linchaolong.ant.condition;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.condition.Condition;
// 用于判断字符串是否全部是大写
public class UppoerCondition implements Condition{
private String value;
// 定义一个setter方法,用于设置value的值
public void setValue(String value){
this.value = value;
}
//Is this condition true?,条件是否成立的判定方法
@Override
public boolean eval() throws BuildException {
// 如果未设置value属性,抛出异常
if (value == null) {
throw new BuildException("value attribute is not set");
}
// 判断字符串是否大写
return value.toUpperCase().equals(value);
}
}
4.使用自定义类
<project name="test" default="run">
<target name="run">
<!-- 自定义类型 -->
<typedef
name="isupper"
classname="linchaolong.ant.condition.UppoerCondition"
classpath="./../bin"/><!-- 我这里把工程bin目录添加到类路径 -->
<!-- 在condition中使用自定义标签 -->
<condition property="isUpper">
<isupper value="THIS IS ALL UPPER CASE"/> <!-- 如果条件成立,则定义isUpper属性,而值为true -->
</condition>
<!-- 打印属性值 -->
<echo>result : ${isUpper}</echo>
<antcall target="result" />
</target>
<target name="result" if="${isUpper}">
<echo>is all uppper</echo>
</target>
</project>
打印结果:
自定义选择器
FilenameSelector
通过自定义选择器可以实现自定义的文件过滤规则。需要继承org.apache.tools.ant.types.selectors.FilenameSelector,并重写isSelected方法。
示例:
package linchaolong.ant.selector;
import java.io.File;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.selectors.FilenameSelector;
// 用于过滤出所有指定后缀的文件的Selector
public class EndWithSelector extends FilenameSelector {
private String endWith;
// setter
public void setEndWith(String endWith) {
this.endWith = endWith;
}
@Override
public boolean isSelected(File dir, String filename, File file) {
// 如果未设置endWith属性则抛出异常
if (endWith == null) {
throw new BuildException("endWith is not set.");
}
return filename.toLowerCase().endsWith(endWith.toLowerCase().trim());
}
}
使用示例:
<project name="test" default="run">
<target name="run">
<!-- 自定义类型 -->
<typedef
name="endwithSelector"
classname="linchaolong.ant.selector.EndWithSelector"
classpath="./../bin"/><!-- 我这里把工程bin目录添加到类路径 -->
<!-- 把上层目录下所有.class文件拷贝到to目录下 -->
<copy todir="to">
<fileset dir="./../">
<endwithSelector endWith=".class"/>
</fileset>
</copy>
</target>
</project>
BaseSelectorContainer
BaseSelectorContainer是一个选择器容器,在过滤文件的时候可能需要多个判断条件,这时就需要用到选择器容器了。
BaseSelectorContainereva中有一个vlidate方法,当调用vlidate方法时会调用verifySettings方法,主要用于检查配置是否正确。可以通过定义verifySettings方法检查配置。
示例代码
package linchaolong.ant.selector;
import java.io.File;
import java.util.Enumeration;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.selectors.BaseSelectorContainer;
import org.apache.tools.ant.types.selectors.FileSelector;
// 用于过滤出满足指定数量条件的文件的选择器容器
public class MatchCountSelectors extends BaseSelectorContainer {
private int count = -1;
private String when;
public static final String MORE = "more";
public static final String LESS = "less";
public static final String EQUAL = "equal";
// setter
public void setCount(int count) {
this.count = count;
}
// setter
public void setWhen(String when){
this.when = when;
}
// 校验配置是否正确
public void verifySettings() {
if (count < 0) {
// 如果配置不正确抛出异常
throw new BuildException("count attribute should be set");
}
if(when == null){
throw new BuildException("when attribute should be set");
}
}
// 从选择的文件中选择指定数量的文件
public boolean isSelected(File baseDir, String filename, File file) {
// 调用validate方法检查配置是否正确
validate();
// 迭代所有容器的选择器列表,计算当前文件满足的条件个数
int countSelected = 0;
for (Enumeration e = selectorElements(); e.hasMoreElements();) {
FileSelector s = (FileSelector) e.nextElement();
if (s.isSelected(baseDir, filename, file)) {
countSelected++;
}
}
// 判断是否满足指定数量的条件
if(MORE.equalsIgnoreCase(when)){
return countSelected > count;
}else if(EQUAL.equalsIgnoreCase(when)){
return countSelected == count;
}
else if(LESS.equalsIgnoreCase(when)){
return countSelected < count;
}else{
throw new BuildException("when value is not defined");
}
}
}
使用示例
<project name="test" default="run">
<target name="run">
<!-- 自定义类型 -->
<typedef
name="matchCountSelectors"
classname="linchaolong.ant.selector.MatchCountSelectors"
classpath="./../bin"/><!-- 我这里把工程bin目录添加到类路径 -->
<copy todir="to">
<!-- 找出在上层目录下满足以下条件其中2个的所有文件 -->
<fileset dir="./../">
<matchCountSelectors count="2" when="more">
<!-- 文件中包含selector的文件,忽略大小写 -->
<contains text="selector" casesensitive="no"/>
<!-- 小于4KB -->
<size value="4" units="Ki" when="less"/>
<!-- 类型为文件,dir表示目录 -->
<type type="file"/>
<!-- 可读 -->
<readable />
<!-- 在2001年1月1日12点后创建的文件 -->
<date datetime="01/01/2001 12:00 AM" when="after"/>
</matchCountSelectors>
</fileset>
</copy>
</target>
</project>
自定义Task
有时ant提供的功能可能不足以满足需求时,我们可以通过继承org.apache.tools.ant.Task编写自己需要的功能,实现public void execute()方法,在execute()方法编写需要执行代码。
在java中通过定义addXXX方法,获取子标签。
示例代码:
package linchaolong.ant.task;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Resource;
// 统计文件个数并把值赋给指定的property
public class TotalFile extends Task {
private List<FileSet> files = new ArrayList<FileSet>();
private String name;
// setter,设置属性名
public void setName(String name){
this.name = name;
}
// 在java中通过addXXX方法获取子标签
public void add(FileSet fs) {
files.add(fs);
}
// 检查配置
public void validitySetting(){
if (name == null || name.isEmpty()) {
throw new BuildException("attribute name is empty");
}
}
@Override
public void execute() throws BuildException {
super.execute();
// 检查配置
validitySetting();
int total = 0;
// 统计文件个数
for (FileSet fs : files) {
Iterator<Resource> it = fs.iterator();
while(it.hasNext()){
it.next();
++total;
}
}
// 设置属性值
getProject().setProperty(name, Integer.toString(total));
}
}
使用示例:
<project name="test" default="run">
<target name="run">
<!-- 自定义类型 -->
<typedef name="totalFile" classname="linchaolong.ant.task.TotalFile"
classpath="./../bin" /><!-- 我这里把工程bin目录添加到类路径 -->
<!-- 统计文件个数 -->
<totalFile name="total" >
<fileset dir="./">
<!-- 文件中包含selector的文件,忽略大小写 -->
<contains text="selector" casesensitive="no" />
<!-- 小于4KB -->
<size value="4" units="Ki" when="less" />
</fileset>
<fileset dir="./../libs">
<!-- 类型为文件,dir表示目录 -->
<type type="file" />
<!-- 可读 -->
<readable />
<!-- 在2001年1月1日12点后创建的文件 -->
<date datetime="01/01/2001 12:00 AM" when="after" />
</fileset>
</totalFile>
<!-- 打印结果 -->
<echo>total = ${total}</echo>
</target>
</project>
运行结果:
导出和使用自定义库
一般我们都会把所有class文件打成一个jar,供外部调用。
1.配置关联
比如这里在工程根目录新建了一个tags.cfg文件,内容如下:
#key为tag的名称,value为类的全路径名
#判断字符串是否全部大写
isupper = linchaolong.ant.condition.UpperCondition
#过滤出满足指定条件数量的文件
matchCountSelectors = linchaolong.ant.selector.MatchCountSelectors
#过滤出指定后缀的文件
endwithSelector = linchaolong.ant.selector.EndWithSelector
#统计文件数量
totalFile = linchaolong.ant.task.TotalFile
2.导出jar
选中项目,右键——export——Java——JAR file,选中src目录和配置文件tags.cfg,设置好导出路径,点击finish就ok了。
3.使用自定义库
一般在文件开头的地方先加载扩展库。
<!-- 使用自定义库 -->
<typedef resource="tags.cfg"> <!-- 解析tags.cfg并建立关联 -->
<classpath>
<pathelement location="./linchaolong_ant.jar" /> <!-- jar文件路径 -->
</classpath>
</typedef>
项目地址:https://coding.net/u/linchaolong/p/AntCustomLibrary/git
相关文档
http://ant.apache.org/manual/Types/custom-programming.html
http://ant.apache.org/manual/develop.html#writingowntask
打开apache-ant-1.9.4/manual/index.html可以查看ant文档,点击左边的Ant API查看API文档。