|
@@ -0,0 +1,391 @@ |
|
|
|
|
|
<html> |
|
|
|
|
|
<head> |
|
|
|
|
|
<meta http-equiv="Content-Language" content="en-us"></meta> |
|
|
|
|
|
<title>Custom Components</title> |
|
|
|
|
|
</head> |
|
|
|
|
|
|
|
|
|
|
|
<body> |
|
|
|
|
|
<h2>Custom Components</h2> |
|
|
|
|
|
<h3>Overview</h3> |
|
|
|
|
|
<p> |
|
|
|
|
|
Custom components are conditions, selectors, filters and other |
|
|
|
|
|
objects that are defined outside ant core. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
In Ant 1.6 custom conditions, selectors and filters has |
|
|
|
|
|
been overhauled. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
It is now possible to define custom conditions, selectors and filters |
|
|
|
|
|
that behave like Ant Core components. |
|
|
|
|
|
This is achieved by allowing datatypes defined in build scripts |
|
|
|
|
|
to be used as custom components if the class of the datatype |
|
|
|
|
|
is compatible, or has been adapted by an adapter class. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
The old methods of defining custom components are still supported. |
|
|
|
|
|
</p> |
|
|
|
|
|
<h3>Definition and use</h3> |
|
|
|
|
|
<p> |
|
|
|
|
|
A custom component is a normal Java class that implements a particular |
|
|
|
|
|
interface or extends a particular class, or has been adapted to the |
|
|
|
|
|
interface or class. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
It is exactly like writing a |
|
|
|
|
|
<a href="../develop.html#writingowntask">custom task</a>. |
|
|
|
|
|
One defines attributes and nested elements by writing <i>setter</i> |
|
|
|
|
|
methods and <i>add</i> methods. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
After the class has been written, it is added to the ant system |
|
|
|
|
|
by using <code><typedef></code>. |
|
|
|
|
|
</p> |
|
|
|
|
|
<h3><a name="customconditions">Custom Conditions</a></h3> |
|
|
|
|
|
<p> |
|
|
|
|
|
Custom conditions are datatypes that implement |
|
|
|
|
|
<code>org.apache.tools.ant.taskdefs.condition.Condition</code>. |
|
|
|
|
|
For example a custom condition that returns true if a |
|
|
|
|
|
string is all upper case could be written as: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
package com.mydomain; |
|
|
|
|
|
|
|
|
|
|
|
import org.apache.tools.ant.BuildException; |
|
|
|
|
|
import org.apache.tools.ant.taskdefs.condition.Condition; |
|
|
|
|
|
|
|
|
|
|
|
public class AllUpperCaseCondition extends 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); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
|
|
|
|
|
|
<p> |
|
|
|
|
|
Adding the condition to the system is achieved as follows: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
<typedef |
|
|
|
|
|
name="alluppercase" |
|
|
|
|
|
classname="com.mydomain.AllUpperCaseCondition" |
|
|
|
|
|
classpath="${mydomain.classes"/> |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
This condition can now be used wherever a Core Ant condition |
|
|
|
|
|
is used. |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
<condition property="allupper"> |
|
|
|
|
|
<alluppercase value="THIS IS ALL UPPER CASE"/> |
|
|
|
|
|
</condition> |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<h3><a name="customselectors">Custom Selectors</a></h3> |
|
|
|
|
|
<p> |
|
|
|
|
|
Custom selectors are datatypes that implement |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.FileSelector</code>. |
|
|
|
|
|
<p>There is only one method required. |
|
|
|
|
|
<code>public boolean isSelected(File basedir, String filename, |
|
|
|
|
|
File file)</code>. |
|
|
|
|
|
It returns true |
|
|
|
|
|
or false depending on whether the given file should be |
|
|
|
|
|
selected or not. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
An example of a custom selection that selects filenames ending |
|
|
|
|
|
in ".java" would be: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
package com.mydomain; |
|
|
|
|
|
import org.apache.tools.ant.types.selectors.FileSelector; |
|
|
|
|
|
public class JavaSelector { |
|
|
|
|
|
public boolean isSelected(File b, String filename, File f) { |
|
|
|
|
|
return filename.toLowerCase().endsWith(".java"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
Adding the selector to the system is achieved as follows: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
<typedef |
|
|
|
|
|
name="javaselector" |
|
|
|
|
|
classname="com.mydomain.JavaSelector" |
|
|
|
|
|
classpath="${mydomain.classes"/> |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
This selector can now be used wherever a Core Ant selector |
|
|
|
|
|
is used. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
One may use |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.BaseSelector</code>, |
|
|
|
|
|
a convenience class that provides reasonable default |
|
|
|
|
|
behaviour. |
|
|
|
|
|
It has some predefined behaviours you can take advantage |
|
|
|
|
|
of. Any time you encounter a problem when setting attributes or |
|
|
|
|
|
adding tags, you can call setError(String errmsg) and the class |
|
|
|
|
|
will know that there is a problem. Then, at the top of your |
|
|
|
|
|
<code>isSelected()</code> method call <code>validate()</code> and |
|
|
|
|
|
a BuildException will be thrown with the contents of your error |
|
|
|
|
|
message. The <code>validate()</code> method also gives you a |
|
|
|
|
|
last chance to check your settings for consistency because it |
|
|
|
|
|
calls <code>verifySettings()</code>. Override this method and |
|
|
|
|
|
call <code>setError()</code> within it if you detect any |
|
|
|
|
|
problems in how your selector is set up.</p> |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
To write custom selector containers one should extend |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>. |
|
|
|
|
|
Implement the |
|
|
|
|
|
<code>public boolean isSelected(File baseDir, String filename, File file)</code> |
|
|
|
|
|
method to do the right thing. Chances are you'll want to iterate |
|
|
|
|
|
over the selectors under you, so use |
|
|
|
|
|
<code>selectorElements()</code> to get an iterator that will do |
|
|
|
|
|
that. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
For example to create a selector container that will select files |
|
|
|
|
|
if a certain number of contained selectors select, one could write |
|
|
|
|
|
a selector as follows: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
To define and use this selector one could do: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
<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> |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
<i>The custom selector</i> |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
The custom selector was the pre ant 1.6 way of defining custom selectors. |
|
|
|
|
|
This method is still supported for backward compatiblity. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p>You can write your own selectors and use them within the selector |
|
|
|
|
|
containers by specifying them within the <custom> tag.</p> |
|
|
|
|
|
|
|
|
|
|
|
<p>To create a new Custom Selector, you have to create a class that |
|
|
|
|
|
implements |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.ExtendFileSelector</code>. |
|
|
|
|
|
The easiest way to do that is through the convenience base class |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.BaseExtendSelector</code>, |
|
|
|
|
|
which provides all of the methods for supporting |
|
|
|
|
|
<code><param></code> tags. First, override the |
|
|
|
|
|
<code>isSelected()</code> method, and optionally the |
|
|
|
|
|
<code>verifySettings()</code> method. If your custom |
|
|
|
|
|
selector requires parameters to be set, you can also override |
|
|
|
|
|
the <code>setParameters()</code> method and interpret the |
|
|
|
|
|
parameters that are passed in any way you like. Several of the |
|
|
|
|
|
core selectors demonstrate how to do that because they can |
|
|
|
|
|
also be used as custom selectors.</p> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p>Once that is written, you include it in your build file by using |
|
|
|
|
|
the <code><custom></code> tag. |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<table border="1" cellpadding="2" cellspacing="0"> |
|
|
|
|
|
<tr> |
|
|
|
|
|
<td valign="top"><b>Attribute</b></td> |
|
|
|
|
|
<td valign="top"><b>Description</b></td> |
|
|
|
|
|
<td align="center" valign="top"><b>Required</b></td> |
|
|
|
|
|
</tr> |
|
|
|
|
|
<tr> |
|
|
|
|
|
<td valign="top">classname</td> |
|
|
|
|
|
<td valign="top">The name of your class that implements |
|
|
|
|
|
<code>org.apache.tools.ant.types.selectors.FileSelector</code>. |
|
|
|
|
|
</td> |
|
|
|
|
|
<td valign="top" align="center">Yes</td> |
|
|
|
|
|
</tr> |
|
|
|
|
|
<tr> |
|
|
|
|
|
<td valign="top">classpath</td> |
|
|
|
|
|
<td valign="top">The classpath to use in order to load the |
|
|
|
|
|
custom selector class. If neither this classpath nor the |
|
|
|
|
|
classpathref are specified, the class will be |
|
|
|
|
|
loaded from the classpath that Ant uses. |
|
|
|
|
|
</td> |
|
|
|
|
|
<td valign="top" align="center">No</td> |
|
|
|
|
|
</tr> |
|
|
|
|
|
<tr> |
|
|
|
|
|
<td valign="top">classpathref</td> |
|
|
|
|
|
<td valign="top">A reference to a classpath previously |
|
|
|
|
|
defined. If neither this reference nor the |
|
|
|
|
|
classpath above are specified, the class will be |
|
|
|
|
|
loaded from the classpath that Ant uses. |
|
|
|
|
|
</td> |
|
|
|
|
|
<td valign="top" align="center">No</td> |
|
|
|
|
|
</tr> |
|
|
|
|
|
</table> |
|
|
|
|
|
|
|
|
|
|
|
<p>Here is how you use <code><custom></code> to |
|
|
|
|
|
use your class as a selector: |
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
<blockquote><pre> |
|
|
|
|
|
<fileset dir="${mydir}" includes="**/*"> |
|
|
|
|
|
<custom classname="com.mydomain.MySelector"> |
|
|
|
|
|
<param name="myattribute" value="myvalue"/> |
|
|
|
|
|
</custom> |
|
|
|
|
|
</fileset> |
|
|
|
|
|
</pre></blockquote> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<p>The core selectors that can also be used as custom selectors |
|
|
|
|
|
are</p> |
|
|
|
|
|
|
|
|
|
|
|
<ul> |
|
|
|
|
|
<li><a href="selectors.html#containsselect">Contains Selector</a> with |
|
|
|
|
|
classname <code>org.apache.tools.ant.types.selectors.ContainsSelector</code> |
|
|
|
|
|
</li> |
|
|
|
|
|
<li><a href="selectors.html#dateselect">Date Selector</a> with |
|
|
|
|
|
classname <code>org.apache.tools.ant.types.selectors.DateSelector</code> |
|
|
|
|
|
</li> |
|
|
|
|
|
<li><a href="selectors.html#depthselect">Depth Selector</a> with |
|
|
|
|
|
classname <code>org.apache.tools.ant.types.selectors.DepthSelector</code> |
|
|
|
|
|
</li> |
|
|
|
|
|
<li><a href="selectors.html#filenameselect">Filename Selector</a> with |
|
|
|
|
|
classname <code>org.apache.tools.ant.types.selectors.FilenameSelector</code> |
|
|
|
|
|
</li> |
|
|
|
|
|
<li><a href="selectors.html#sizeselect">Size Selector</a> with |
|
|
|
|
|
classname <code>org.apache.tools.ant.types.selectors.SizeSelector</code> |
|
|
|
|
|
</li> |
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
|
|
|
|
<p>Here is the example from the Depth Selector section rewritten |
|
|
|
|
|
to use the selector through <code><custom></code>.</p> |
|
|
|
|
|
|
|
|
|
|
|
<blockquote><pre> |
|
|
|
|
|
<fileset dir="${doc.path}" includes="**/*"> |
|
|
|
|
|
<custom classname="org.apache.tools.ant.types.selectors.DepthSelector"> |
|
|
|
|
|
<param name="max" value="1"/> |
|
|
|
|
|
</custom> |
|
|
|
|
|
</fileset> |
|
|
|
|
|
</pre></blockquote> |
|
|
|
|
|
|
|
|
|
|
|
<p>Selects all files in the base directory and one directory below |
|
|
|
|
|
that.</p> |
|
|
|
|
|
|
|
|
|
|
|
<h3><a name="filterreaders">Custom Filter Readers</a></h3> |
|
|
|
|
|
<p> |
|
|
|
|
|
Custom filter readers selectors are datatypes that implement |
|
|
|
|
|
<code>org.apache.tools.ant.types.filters.ChainableReader</code>. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p>There is only one method required. |
|
|
|
|
|
<code>Reader chain(Reader reader)</code>. |
|
|
|
|
|
This returns a reader that filters input from the specified |
|
|
|
|
|
reader. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
For example a filterreader that removes every second character |
|
|
|
|
|
could be: |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
<p> |
|
|
|
|
|
For line oriented filters it may be easier to extend |
|
|
|
|
|
<code>ChainableFilterReader</code> an inner class of |
|
|
|
|
|
<code>org.apache.tools.ant.filters.TokenFilter</code>. |
|
|
|
|
|
</p> |
|
|
|
|
|
<p> |
|
|
|
|
|
For example a filter that appends the line number could be |
|
|
|
|
|
</p> |
|
|
|
|
|
<blockquote> |
|
|
|
|
|
<pre> |
|
|
|
|
|
public class AddLineNumber extends ChainableReaderFilter { |
|
|
|
|
|
private void lineNumber = 0; |
|
|
|
|
|
public String filter(String string) { |
|
|
|
|
|
lineNumber++; |
|
|
|
|
|
return "" + lineNumber + "\t" + string; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
</pre> |
|
|
|
|
|
</blockquote> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<hr></hr> |
|
|
|
|
|
<p align="center">Copyright © 2003 Apache Software Foundation. All rights |
|
|
|
|
|
Reserved.</p> |
|
|
|
|
|
</body> |
|
|
|
|
|
</html> |
|
|
|
|
|
|