Want to define your own selectors? It's easy!
First, pick the type of selector that you want to define. There are three types, and a recipe for each one follows. Chances are you'll want to work with the first one, Custom Selectors.
This is the category that Apache Ant provides specifically for you to define your own
Selectors. Anywhere you want to use your selector you use
the <custom>
element and specify the class name of your selector
within it. See the Custom Selectors section of
the Selector page for details. The <custom>
element can be used
anywhere the core selectors can be used. It can be contained
within Selector Containers, for
example.
To create a new Custom Selector, you have to create a class that
implements org.apache.tools.ant.types.selectors.ExtendFileSelector
.
The easiest way to do that is through the convenience base
class org.apache.tools.ant.types.selectors.BaseExtendSelector
,
which provides all of the methods for supporting <param>
tags. First,
override the isSelected()
method, and optionally
the verifySettings()
method. If your custom selector requires
parameters to be set, you can also override the setParameters()
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.
These are the selectors used by Ant itself. To implement one of these, you will have to alter some of the classes contained within Ant.
First, create a class that
implements org.apache.tools.ant.types.selectors.FileSelector
.
You can either choose to implement all methods yourself from scratch, or you can
extend org.apache.tools.ant.types.selectors.BaseSelector
instead, a convenience class that provides reasonable default behaviour for many
methods.
There is only one method required. public boolean isSelected(File
basedir, String filename, File file)
is the real purpose of the whole
exercise. It returns true
or false
depending on whether the given file
should be selected from the list or not.
If you are
using org.apache.tools.ant.types.selectors.BaseSelector
there
are also 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 isSelected()
method call validate()
and a BuildException
will
be thrown with the contents of your error
message. The validate()
method also gives you a last chance to
check your settings for consistency because it
calls verifySettings()
. Override this method and
call setError()
within it if you detect any problems in how
your selector is set up.
You may also want to override toString()
.
add()
method for your selector
in org.apache.tools.ant.types.selectors.SelectorContainer
.
This is an interface, so you will also have to add an implementation for the method in
the classes which implement it,
namely org.apache.tools.ant.types.AbstractFileSet
, org.apache.tools.ant.taskdefs.MatchingTask
and org.apache.tools.ant.types.selectors.BaseSelectorContainer
.
Once it is in there, it will be available everywhere that core selectors are
appropriate.Got an idea for a new Selector Container? Creating a new one is no problem:
org.apache.tools.ant.types.selectors.SelectorContainer
.
This will ensure that your new Container can access any new selectors that come
along. Again, there is a convenience class available for you
called org.apache.tools.ant.types.selectors.BaseSelectorContainer
.public boolean isSelected(String filename, File
file)
method to do the right thing. Chances are you'll want to iterate over the
selectors under you, so use selectorElements()
to get an
iterator that will do that.add()
method for your container
in org.apache.tools.ant.types.selectors.SelectorContainer
and
its implementations org.apache.tools.ant.types.AbstractFileSet
and org.apache.tools.ant.types.selectors.BaseSelectorContainer
.For a robust component (and selectors are (Project)Components) tests are necessary. For
testing Tasks we use JUnit Tests and Rules—more
specific org.apache.tools.ant.BuildFileRule extends
org.junit.rules.ExternalResource
. Some of its features like configure the (test) project
by reading its buildfile and execute targets we need for selector tests also. Therefore we use
that BuildFileRule. But testing selectors requires some more work: having a set of files,
instantiate and configure the selector, check the selection work and more. Because we usually
extend BaseExtendSelector
its features have to be tested also
(e.g. setError()
).
That's why we have a test rule for doing our selector
tests: org.apache.tools.ant.types.selectors.BaseSelectorRule
.
This class extends ExternalResource and therefore can included in the set of Ant's unit tests. It holds an instance of preconfigured BuildFileRule. Configuration is done by parsing the src/etc/testcases/types/selectors.xml. BaseSelectorRule then gives us helper methods for handling multiple selections.
Because the term "testcase" or "testenvironment" are so often used, this special testenvironment got a new name: bed. The setup and cleanup of the bed is all handled by the BaseSelectorRule so any test only has to handle the actual test scenarios
A usual test scenario is:
An example test would be:
package org.apache.tools.ant.types.selectors; public class MySelectorTest { @Rule public final BaseSelectorRule selectorRule = new BaseSelectorRule(); @Test public void testCase1() { // Configure the selector MySelector s = new MySelector(); s.addParam("key1", "value1"); s.addParam("key2", "value2"); s.setXX(true); s.setYY("a value"); // do the tests assertEquals("FTTTTTTTT", selectorRule.selectionString(s)); } }
As an example of an error JUnit could log
[junit] FAILED [junit] Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz [junit] expected:<FTTTFTTTF...> but was:<TTTTTTTTT...> [junit] junit.framework.ComparisonFailure: Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz [junit] expected:<FTTTFTTTF...> but was:<TTTTTTTTT...> [junit] at junit.framework.Assert.assertEquals(Assert.java:81) [junit] at org.apache.tools.ant.types.selectors.BaseSelectorTest.performTest(BaseSelectorTest.java:194)
Described above the test class should provide a getInstance()
method. But that isn't used here. The used getSelector()
method is
implemented in the base class and gives an instance of an Ant Project to the selector. This is
usually done inside normal build file runs, but not inside this special environment, so this
method gives the selector the ability to use its own Project object
(getProject()
), for example for logging.
During development and maybe later you sometimes need the output of information. Therefore
Logging is needed. Because the selector extends BaseExtendSelector or directly BaseSelector it
is an Ant DataType
and therefore
a ProjectComponent
.
That means that you have access to the
project object and its logging capability. ProjectComponent
itself
provides log()
methods which will do the access to the project
instance. Logging is therefore done simply with:
log("message");
or
log("message", loglevel);
where the loglevel
is one of the values
org.apache.tools.ant.Project.MSG_ERR
org.apache.tools.ant.Project.MSG_WARN
org.apache.tools.ant.Project.MSG_INFO
(default)org.apache.tools.ant.Project.MSG_VERBOSE
org.apache.tools.ant.Project.MSG_DEBUG