ant/manual/Types/custom-programming.html

369 lines
13 KiB
HTML
Raw Normal View History

<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<meta http-equiv="Content-Language" content="en-us">
2018-02-28 07:58:59 +01:00
<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
<title>Custom Components</title>
</head>
<body>
<h2>Custom Components</h2>
<h3>Overview</h3>
<p>
2018-02-28 07:58:59 +01:00
Custom components are conditions, selectors, filters and other objects
that are defined outside Apache Ant core.
</p>
<p>
2018-02-28 07:58:59 +01:00
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
2018-02-28 07:58:59 +01:00
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
2018-02-28 07:58:59 +01:00
interface or extends a particular class, or has been adapted to the
interface or class.
</p>
<p>
2018-02-28 07:58:59 +01:00
It is exactly like writing
a <a href="../develop.html#writingowntask">custom task</a>. One
defines attributes and nested elements by writing <em>setter</em>
methods and <em>add</em> methods.
</p>
<p>
2018-02-28 07:58:59 +01:00
After the class has been written, it is added to the ant system by
using <code>&lt;typedef&gt;</code>.
</p>
<h3 id="customconditions">Custom Conditions</h3>
<p>
2018-02-28 07:58:59 +01:00
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>
2018-02-09 06:54:03 +01:00
<pre>
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);
2018-02-28 07:58:59 +01:00
}
}</pre>
<p>
2018-02-28 07:58:59 +01:00
Adding the condition to the system is achieved as follows:
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;typedef
name="alluppercase"
classname="com.mydomain.AllUpperCaseCondition"
2018-02-28 07:58:59 +01:00
classpath="${mydomain.classes}"/&gt;</pre>
<p>
2018-02-28 07:58:59 +01:00
This condition can now be used wherever a Core Ant condition is used.
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;condition property="allupper"&gt;
2018-02-28 07:58:59 +01:00
&lt;alluppercase value="THIS IS ALL UPPER CASE"/&gt;
&lt;/condition&gt;</pre>
<h3 id="customselectors">Custom Selectors</h3>
<p>
2018-02-28 07:58:59 +01:00
Custom selectors are datatypes that
implement <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
</p>
2018-02-28 07:58:59 +01:00
<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
2018-02-28 07:58:59 +01:00
in <samp>.java</samp> would be:
</p>
2018-02-09 06:54:03 +01:00
<pre>
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) {
2018-02-28 07:58:59 +01:00
return filename.toLowerCase().endsWith(".java");
}
2018-02-28 07:58:59 +01:00
}</pre>
<p>
Adding the selector to the system is achieved as follows:
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;typedef
name="javaselector"
classname="com.mydomain.JavaSelector"
2018-02-28 07:58:59 +01:00
classpath="${mydomain.classes}"/&gt;</pre>
2018-02-09 06:54:03 +01:00
<p>
2018-02-28 07:58:59 +01:00
This selector can now be used wherever a Core Ant selector is used,
for example:
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;copy todir="to"&gt;
2018-02-28 07:58:59 +01:00
&lt;fileset dir="src"&gt;
&lt;javaselector/&gt;
&lt;/fileset&gt;
&lt;/copy&gt;</pre>
2018-02-09 06:54:03 +01:00
<p>
2018-02-28 07:58:59 +01:00
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 <code>setError(String errmsg)</code> 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>
2018-02-28 07:58:59 +01:00
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>
2018-02-28 07:58:59 +01:00
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>
2018-02-09 06:54:03 +01:00
<pre>
public class MatchNumberSelectors extends BaseSelectorContainer {
private int number = -1;
public void setNumber(int number) {
this.number = number;
}
public void verifySettings() {
if (number &lt; 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;
}
2018-02-28 07:58:59 +01:00
}</pre>
<p>
To define and use this selector one could do:
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;typedef name="numberselected"
classname="com.mydomain.MatchNumberSelectors"/&gt;
...
&lt;fileset dir="${src.path}"&gt;
2018-02-28 07:58:59 +01:00
&lt;numberselected number="2"&gt;
&lt;contains text="script" casesensitive="no"/&gt;
&lt;size value="4" units="Ki" when="more"/&gt;
&lt;javaselector/&gt;
&lt;/numberselected&gt;
&lt;/fileset&gt;</pre>
<p>
2018-02-28 07:58:59 +01:00
<em>The custom selector</em>
</p>
<p>
2018-02-28 07:58:59 +01:00
The custom selector was the pre Ant 1.6 way of defining custom
selectors. This method is still supported for backward compatibility.
</p>
2018-02-28 07:58:59 +01:00
<p>
You can write your own selectors and use them within the selector
containers by specifying them within the <code>&lt;custom&gt;</code>
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>&lt;param&gt;</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>&lt;custom&gt;</code> tag.
</p>
2018-02-28 07:58:59 +01:00
<table class="attr">
<tr>
2018-02-28 07:58:59 +01:00
<th>Attribute</th>
<th>Description</th>
<th>Required</th>
</tr>
<tr>
2018-02-28 07:58:59 +01:00
<td>classname</td>
<td>
2018-03-01 06:44:53 +01:00
The name of your class that
implements <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
</td>
2018-02-28 07:58:59 +01:00
<td>Yes</td>
</tr>
<tr>
2018-02-28 07:58:59 +01:00
<td>classpath</td>
<td>
2018-03-01 06:44:53 +01:00
The classpath to use in order to load the custom selector class. If
neither <var>classpath</var> nor <var>classpathref</var> are specified, the class will be
loaded from the classpath that Ant uses.
</td>
2018-02-28 07:58:59 +01:00
<td>No</td>
</tr>
<tr>
2018-02-28 07:58:59 +01:00
<td>classpathref</td>
<td>
2018-03-01 06:44:53 +01:00
A reference to a classpath previously defined. If neither <var>classpathref</var>
nor <var>classpath</var> above are specified, the class will be loaded from the classpath
that Ant uses.
</td>
2018-02-28 07:58:59 +01:00
<td>No</td>
</tr>
</table>
2018-02-28 07:58:59 +01:00
<p>
Here is how you use <code>&lt;custom&gt;</code> to use your class as a
selector:
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;fileset dir="${mydir}" includes="**/*"&gt;
&lt;custom classname="com.mydomain.MySelector"&gt;
&lt;param name="myattribute" value="myvalue"/&gt;
&lt;/custom&gt;
2018-02-28 07:58:59 +01:00
&lt;/fileset&gt;</pre>
<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
2018-02-28 07:58:59 +01:00
classname <code>org.apache.tools.ant.types.selectors.ContainsSelector</code></li>
<li><a href="selectors.html#dateselect">Date Selector</a> with
2018-02-28 07:58:59 +01:00
classname <code>org.apache.tools.ant.types.selectors.DateSelector</code></li>
<li><a href="selectors.html#depthselect">Depth Selector</a> with
2018-02-28 07:58:59 +01:00
classname <code>org.apache.tools.ant.types.selectors.DepthSelector</code></li>
<li><a href="selectors.html#filenameselect">Filename Selector</a> with
2018-02-28 07:58:59 +01:00
classname <code>org.apache.tools.ant.types.selectors.FilenameSelector</code></li>
<li><a href="selectors.html#sizeselect">Size Selector</a> with
2018-02-28 07:58:59 +01:00
classname <code>org.apache.tools.ant.types.selectors.SizeSelector</code></li>
</ul>
2018-02-28 07:58:59 +01:00
<p>
Here is the example from the Depth Selector section rewritten to use
the selector through <code>&lt;custom&gt;</code>.
</p>
2018-02-09 06:54:03 +01:00
<pre>
&lt;fileset dir="${doc.path}" includes="**/*"&gt;
&lt;custom classname="org.apache.tools.ant.types.selectors.DepthSelector"&gt;
&lt;param name="max" value="1"/&gt;
&lt;/custom&gt;
2018-02-28 07:58:59 +01:00
&lt;/fileset&gt;</pre>
<p>Selects all files in the base directory and one directory below that.</p>
<h3 id="filterreaders">Custom Filter Readers</h3>
<p>
2018-02-28 07:58:59 +01:00
Custom filter readers selectors are datatypes that
implement <code>org.apache.tools.ant.types.filters.ChainableReader</code>.
</p>
2018-02-28 07:58:59 +01:00
<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>
2018-02-28 07:58:59 +01:00
For example a filterreader that removes every second character could
be:
</p>
2018-02-09 06:54:03 +01:00
<pre>
public class RemoveOddCharacters implements ChainableReader {
2018-02-28 07:58:59 +01:00
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;
}
}
2018-02-28 07:58:59 +01:00
}
}
}
}</pre>
<p>
2018-02-28 07:58:59 +01:00
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>
2018-02-09 06:54:03 +01:00
<pre>
public class AddLineNumber extends ChainableReaderFilter {
2018-02-28 07:58:59 +01:00
private void lineNumber = 0;
public String filter(String string) {
lineNumber++;
return "" + lineNumber + "\t" + string;
}
}</pre>
</body>
</html>