| <!DOCTYPE html> |
| <!-- |
| 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 |
| |
| https://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 lang="en"> |
| <head> |
| <link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> |
| <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 Apache 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 <em>setter</em> methods and <em>add</em> |
| methods. |
| </p> |
| <p> |
| After the class has been written, it is added to the ant system by |
| using <code><typedef></code>. |
| </p> |
| <h3 id="customconditions">Custom Conditions</h3> |
| <p> |
| Custom conditions are datatypes that |
| implement <code class="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> |
| <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); |
| } |
| }</pre> |
| <p> |
| Adding the condition to the system is achieved as follows: |
| </p> |
| <pre> |
| <typedef |
| name="alluppercase" |
| classname="com.mydomain.AllUpperCaseCondition" |
| classpath="${mydomain.classes}"/></pre> |
| <p> |
| This condition can now be used wherever a Core Ant condition is used. |
| </p> |
| <pre> |
| <condition property="allupper"> |
| <alluppercase value="THIS IS ALL UPPER CASE"/> |
| </condition></pre> |
| <h3 id="customselectors">Custom Selectors</h3> |
| <p> |
| Custom selectors are datatypes that |
| implement <code class="code">org.apache.tools.ant.types.selectors.FileSelector</code>. |
| </p> |
| <p> |
| There is only one method required, <code class="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 <samp>.java</samp> would be: |
| </p> |
| <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) { |
| return filename.toLowerCase().endsWith(".java"); |
| } |
| }</pre> |
| <p> |
| Adding the selector to the system is achieved as follows: |
| </p> |
| <pre> |
| <typedef |
| name="javaselector" |
| classname="com.mydomain.JavaSelector" |
| classpath="${mydomain.classes}"/></pre> |
| <p> |
| This selector can now be used wherever a Core Ant selector is used, for example: |
| </p> |
| <pre> |
| <copy todir="to"> |
| <fileset dir="src"> |
| <javaselector/> |
| </fileset> |
| </copy></pre> |
| <p> |
| One may use <code class="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 class="code">setError(String errmsg)</code> and the class |
| will know that there is a problem. Then, at the top of |
| your <code class="code">isSelected()</code> method call <code class="code">validate()</code> |
| and a <code>BuildException</code> will be thrown with the contents of your error |
| message. The <code class="code">validate()</code> method also gives you a last chance to check |
| your settings for consistency because it |
| calls <code class="code">verifySettings()</code>. Override this method and |
| call <code class="code">setError()</code> within it if you detect any problems in how your |
| selector is set up. |
| </p> |
| <p> |
| To write custom selector containers one should |
| extend <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>. |
| Implement the <code class="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 class="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> |
| <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> |
| <p> |
| To define and use this selector one could do: |
| </p> |
| <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> |
| <p> |
| <em>The custom selector</em> |
| </p> |
| <p> |
| The custom selector was the pre Ant 1.6 way of defining custom selectors. This method is |
| still supported for backward compatibility. |
| </p> |
| <p> |
| You can write your own selectors and use them within the selector containers by specifying |
| them within the <code><custom></code> tag. |
| </p> |
| <p> |
| To create a new Custom Selector, you have to create a class that |
| implements <code class="code">org.apache.tools.ant.types.selectors.ExtendFileSelector</code>. |
| The easiest way to do that is through the convenience base |
| class <code 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 class="code">isSelected()</code> method, and optionally |
| the <code class="code">verifySettings()</code> method. If your custom selector requires |
| parameters to be set, you can also override the <code class="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 class="attr"> |
| <tr> |
| <th scope="col">Attribute</th> |
| <th scope="col">Description</th> |
| <th scope="col">Required</th> |
| </tr> |
| <tr> |
| <td>classname</td> |
| <td> |
| The name of your class that |
| implements <code class="code">org.apache.tools.ant.types.selectors.FileSelector</code>. |
| </td> |
| <td>Yes</td> |
| </tr> |
| <tr> |
| <td>classpath</td> |
| <td> |
| 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> |
| <td>No</td> |
| </tr> |
| <tr> |
| <td>classpathref</td> |
| <td> |
| 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> |
| <td>No</td> |
| </tr> |
| </table> |
| |
| <p> |
| Here is how you use <code><custom></code> to use your class as a selector: |
| </p> |
| <pre> |
| <fileset dir="${mydir}" includes="**/*"> |
| <custom classname="com.mydomain.MySelector"> |
| <param name="myattribute" value="myvalue"/> |
| </custom> |
| </fileset></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 |
| classname <code class="code">org.apache.tools.ant.types.selectors.ContainsSelector</code></li> |
| <li><a href="selectors.html#dateselect">Date Selector</a> with |
| classname <code class="code">org.apache.tools.ant.types.selectors.DateSelector</code></li> |
| <li><a href="selectors.html#depthselect">Depth Selector</a> with |
| classname <code class="code">org.apache.tools.ant.types.selectors.DepthSelector</code></li> |
| <li><a href="selectors.html#filenameselect">Filename Selector</a> with |
| classname <code class="code">org.apache.tools.ant.types.selectors.FilenameSelector</code></li> |
| <li><a href="selectors.html#sizeselect">Size Selector</a> with |
| classname <code class="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> |
| <pre> |
| <fileset dir="${doc.path}" includes="**/*"> |
| <custom classname="org.apache.tools.ant.types.selectors.DepthSelector"> |
| <param name="max" value="1"/> |
| </custom> |
| </fileset></pre> |
| <p>Selects all files in the base directory and one directory below that.</p> |
| |
| <h3 id="filterreaders">Custom Filter Readers</h3> |
| <p> |
| Custom filter readers selectors are datatypes that |
| implement <code class="code">org.apache.tools.ant.types.filters.ChainableReader</code>. |
| </p> |
| <p> |
| There is only one method required, <code class="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> |
| <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> |
| <p> |
| For line oriented filters it may be easier to |
| extend <code class="code">ChainableFilterReader</code> an inner class |
| of <code class="code">org.apache.tools.ant.filters.TokenFilter</code>. |
| </p> |
| <p> |
| For example a filter that appends the line number could be |
| </p> |
| <pre> |
| public class AddLineNumber extends ChainableReaderFilter { |
| private void lineNumber = 0; |
| public String filter(String string) { |
| lineNumber++; |
| return "" + lineNumber + "\t" + string; |
| } |
| }</pre> |
| |
| </body> |
| </html> |