| <!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>Programming Selectors in Apache Ant</title> |
| </head> |
| |
| <body> |
| <h2>Programming your own Selectors</h2> |
| |
| <h3>Selector Programming API</h3> |
| |
| <p>Want to define your own selectors? It's easy!</p> |
| |
| <p>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.</p> |
| |
| <ol> |
| <li>Custom Selectors |
| |
| <p>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 <code><custom></code> element and specify the class name of your selector |
| within it. See the <a href="selectors.html#customselect">Custom Selectors</a> section of |
| the Selector page for details. The <code><custom></code> element can be used |
| anywhere the core selectors can be used. It can be contained |
| within <a href="selectors.html#selectcontainers">Selector Containers</a>, for |
| example.</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> |
| |
| <li>Core Selectors |
| |
| <p>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.</p> |
| |
| <ul> |
| <li><p>First, create a class that |
| implements <code class="code">org.apache.tools.ant.types.selectors.FileSelector</code>. |
| You can either choose to implement all methods yourself from scratch, or you can |
| extend <code class="code">org.apache.tools.ant.types.selectors.BaseSelector</code> |
| instead, a convenience class that provides reasonable default behaviour for many |
| methods.</p> |
| |
| <p>There is only one method required. <code class="code">public boolean isSelected(File |
| basedir, String filename, File file)</code> is the real purpose of the whole |
| exercise. It returns <q>true</q> or <q>false</q> depending on whether the given file |
| should be selected from the list or not.</p> |
| |
| <p>If you are |
| using <code class="code">org.apache.tools.ant.types.selectors.BaseSelector</code> 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 <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>You may also want to override <code class="code">toString()</code>.</p></li> |
| |
| <li>Put an <code class="code">add()</code> method for your selector |
| in <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code>. |
| This is an interface, so you will also have to add an implementation for the method in |
| the classes which implement it, |
| namely <code class="code">org.apache.tools.ant.types.AbstractFileSet</code>, <code class="code">org.apache.tools.ant.taskdefs.MatchingTask</code> |
| and <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>. |
| Once it is in there, it will be available everywhere that core selectors are |
| appropriate.</li> |
| </ul> |
| |
| <li>Selector Containers |
| <p>Got an idea for a new Selector Container? Creating a new one is no problem:</p> |
| <ul> |
| <li>Create a new class that |
| implements <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code>. |
| 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 <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.</li> |
| <li>Implement the <code class="code">public boolean isSelected(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.</li> |
| <li>Again, put an <code class="code">add()</code> method for your container |
| in <code class="code">org.apache.tools.ant.types.selectors.SelectorContainer</code> and |
| its implementations <code class="code">org.apache.tools.ant.types.AbstractFileSet</code> |
| and <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.</li> |
| </ul> |
| </ol> |
| |
| <h3>Testing Selectors</h3> |
| |
| <p>For a robust component (and selectors are (Project)Components) tests are necessary. For |
| testing Tasks we use JUnit Tests and Rules—more |
| specific <code class="code">org.apache.tools.ant.BuildFileRule extends |
| org.junit.rules.ExternalResource</code>. 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 <code class="code">BaseExtendSelector</code> its features have to be tested also |
| (e.g. <code class="code">setError()</code>).</p> |
| |
| <p>That's why we have a test rule for doing our selector |
| tests: <code class="code">org.apache.tools.ant.types.selectors.BaseSelectorRule</code>.</p> |
| |
| <p>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 <samp>src/etc/testcases/types/selectors.xml</samp>. BaseSelectorRule then gives us |
| helper methods for handling multiple selections.</p> |
| |
| <p>Because the term "testcase" or "testenvironment" are so often used, this special |
| testenvironment got a new name: <em>bed</em>. The setup and cleanup of the bed is all |
| handled by the BaseSelectorRule so any test only has to handle the actual test scenarios</p> |
| |
| <p>A usual test scenario is:</p> |
| <ol> |
| <li>instantiate the selector</li> |
| <li>configure the selector</li> |
| <li>let the selector do some work</li> |
| <li>verify the work</li> |
| </ol> |
| |
| <p>An example test would be:</p> |
| <pre> |
| 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)); |
| } |
| }</pre> |
| <p>As an example of an error JUnit could log</p> |
| <pre> |
| [junit] FAILED |
| [junit] Error for files: <span style="color:blue">.;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz</span> |
| [junit] expected:<<span style="color:blue">FTTTFTTTF...</span>> 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)</pre> |
| |
| <p>Described above the test class should provide a <code class="code">getInstance()</code> |
| method. But that isn't used here. The used <code class="code">getSelector()</code> 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 |
| (<code class="code">getProject()</code>), for example for logging.</p> |
| |
| <h3>Logging</h3> |
| |
| <p>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 <code class="code">DataType</code> and therefore |
| a <code class="code">ProjectComponent</code>.<br/> That means that you have access to the |
| project object and its logging capability. <code class="code">ProjectComponent</code> itself |
| provides <code class="code">log()</code> methods which will do the access to the project |
| instance. Logging is therefore done simply with:</p> |
| <pre>log("message");</pre> |
| <p>or</p> |
| <pre>log("message", loglevel);</pre> |
| <p>where the <code>loglevel</code> is one of the values</p> |
| <ul> |
| <li><code class="code">org.apache.tools.ant.Project.MSG_ERR</code></li> |
| <li><code class="code">org.apache.tools.ant.Project.MSG_WARN</code></li> |
| <li><code class="code">org.apache.tools.ant.Project.MSG_INFO</code> (default)</li> |
| <li><code class="code">org.apache.tools.ant.Project.MSG_VERBOSE</code></li> |
| <li><code class="code">org.apache.tools.ant.Project.MSG_DEBUG</code></li> |
| </ul> |
| |
| </body> |
| </html> |