Bugzilla Report 20474 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275236 13f79535-47bb-0310-9956-ffa450edef68master
@@ -597,6 +597,9 @@ Other changes: | |||||
* additional shortcuts for ant options (-d --> -debug, -e --> -emacs, | * additional shortcuts for ant options (-d --> -debug, -e --> -emacs, | ||||
-h --> -help, -p --> -projecthelp, -s --> -find). | -h --> -help, -p --> -projecthelp, -s --> -find). | ||||
* new selector <modified>. "cache" was renamed to "modified". | |||||
Bugzilla Report 20474. | |||||
Changes from Ant 1.5.3 to Ant 1.5.4 | Changes from Ant 1.5.3 to Ant 1.5.4 | ||||
=================================== | =================================== | ||||
@@ -18,7 +18,7 @@ | |||||
<ol> | <ol> | ||||
<li>Custom Selectors | <li>Custom Selectors | ||||
<p>This is the category that Ant provides specifically for youto | |||||
<p>This is the category that Ant provides specifically for you to | |||||
define your own Selectors. Anywhere you want to use your selector | define your own Selectors. Anywhere you want to use your selector | ||||
you use the <code><custom></code> element and specify | you use the <code><custom></code> element and specify | ||||
the class name of your selector within it. See the | the class name of your selector within it. See the | ||||
@@ -86,7 +86,8 @@ | |||||
<code>org.apache.tools.ant.types.selectors.SelectorContainer</code>. | <code>org.apache.tools.ant.types.selectors.SelectorContainer</code>. | ||||
This is an interface, so you will also have to add an implementation | This is an interface, so you will also have to add an implementation | ||||
for the method in the classes which implement it, namely | for the method in the classes which implement it, namely | ||||
<code>org.apache.tools.ant.types.AbstractFileSet</code> and | |||||
<code>org.apache.tools.ant.types.AbstractFileSet</code>, | |||||
<code>org.apache.tools.ant.taskdefs.MatchingTask</code> and | |||||
<code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>. | <code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>. | ||||
Once it is in there, it will be available everywhere that core | Once it is in there, it will be available everywhere that core | ||||
selectors are appropriate.</p> | selectors are appropriate.</p> | ||||
@@ -118,10 +119,131 @@ | |||||
</ul> | </ul> | ||||
</ol> | </ol> | ||||
<h3>Testing Selectors</h3> | |||||
<p>For a robust component (and selectors are (Project)Component´s) tests are | |||||
necessary. For testing Tasks we use JUnit TestCases - more specific | |||||
<tt>org.apache.tools.ant.BuildFileTest extends junit.framework.TestCase</tt>. | |||||
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 BuildFileTest. | |||||
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 <tt>BaseExtendSelector</tt> its features have to be tested also (e.g. setError()). | |||||
</p> | |||||
<p>That´s why we have a base class for doing our selector tests: | |||||
<tt>org.apache.tools.ant.types.selectors.BaseSelectorTest</tt>.</p> | |||||
<p>This class extends TestCase and therefore can included in the set of Ant´s | |||||
unit tests. It holds an instance of preconfigured BuildFileTest. Configuration | |||||
is done by parsing the src/etc/testcases/types/selectors.xml. BaseSelectorTest | |||||
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: <i>bed</i>. Like you initialize the | |||||
test environment by calling setUp() and cleaning by calling tearDown() (<i>or like | |||||
to make your bed before go sleeping</i>) you have to do that work with your | |||||
<i>bed</i> by calling <tt>makeBed()</tt> respecitive <tt>cleanupBed()</tt>.</p> | |||||
<p>A usual test scenario is<ol> | |||||
<li>make the bed</li> | |||||
<li>instantiate the selector</li> | |||||
<li>configure the selector</li> | |||||
<li>let the selector do some work</li> | |||||
<li>verify the work</li> | |||||
<li>clean the bed</li> | |||||
</ol> | |||||
</p> | |||||
<p>For common way of instantiation you have to override the <tt>getInstance()</tt> | |||||
simply by returning a new object of your selector. For easier "selection and verification work" | |||||
BaseSelectorTest provides the method <tt>performTests()</tt> which | |||||
iterates over all files (and directories) in the String array <tt>filenames</tt> | |||||
and checks whether the given selector returns the expected result. If an error | |||||
occured (especially the selector does not return the expected result) the test | |||||
fails and the failing filenames are logged.</p> | |||||
<p>An example test would be:<pre> | |||||
package org.apache.tools.ant.types.selectors; | |||||
public class MySelectorTest extends BaseSelectorTest { | |||||
public MySelectorTest(String name) { | |||||
super(name); | |||||
} | |||||
public BaseSelector getInstance() { | |||||
return new MySelector(); | |||||
} | |||||
public void testCase1() { | |||||
try { | |||||
// initialize test environment 'bed' | |||||
makeBed(); | |||||
// Configure the selector | |||||
MySelector s = (MySelector)getSelector(); | |||||
s.addParam("key1", "value1"); | |||||
s.addParam("key2", "value2"); | |||||
s.setXX(true); | |||||
s.setYY("a value"); | |||||
// do the tests | |||||
performTests(s, "FTTTTTTTTTTT"); // First is not selected - rest is | |||||
} finally { | |||||
// cleanup the environment | |||||
cleanupBed(); | |||||
} | |||||
} | |||||
} | |||||
</pre> | |||||
As an example of an error JUnit could log<pre> | |||||
[junit] FAILED | |||||
[junit] Error for files: <font color=blue>.;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz</font> | |||||
[junit] expected:<<font color=blue>FTTTFTTTF...</font>> 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> | |||||
<p>Described above the test class should provide a <tt>getInstance()</tt> | |||||
method. But that isn´t used here. The used <tt>getSelector()</tt> 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 (<tt>getProject()</tt>), 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 <tt>DataType</tt> and therefore a <tt>ProjectComponent</tt>. <br> | |||||
That means that you have access to the project object and its logging capability. | |||||
<tt>ProjectComponent</tt> itself provides <i>log</i> methods which will do the | |||||
access to the project instance. Logging is therefore done simply with: | |||||
<pre> | |||||
log( "message" ); | |||||
</pre> | |||||
or | |||||
<pre> | |||||
log( "message" , loglevel ); | |||||
</pre> | |||||
where the <tt>loglevel</tt> is one of the values <ul> | |||||
<li> org.apache.tools.ant.Project.MSG_ERR </li> | |||||
<li> org.apache.tools.ant.Project.MSG_WARN </li> | |||||
<li> org.apache.tools.ant.Project.MSG_INFO (= default) </li> | |||||
<li> org.apache.tools.ant.Project.MSG_VERBOSE </li> | |||||
<li> org.apache.tools.ant.Project.MSG_DEBUG </li> | |||||
</ul> | |||||
</p> | |||||
<hr> | <hr> | ||||
<p align="center">Copyright © 2002 Apache Software | |||||
<p align="center">Copyright © 2002-2003 Apache Software | |||||
Foundation. All rights Reserved.</p> | Foundation. All rights Reserved.</p> | ||||
</body> | </body> | ||||
</html> | |||||
</html> |
@@ -40,28 +40,31 @@ | |||||
<ul> | <ul> | ||||
<li><a href="#containsselect"><contains></a> - Select | <li><a href="#containsselect"><contains></a> - Select | ||||
files that contain a particular text string | |||||
files that contain a particular text string</li> | |||||
<li><a href="#dateselect"><date></a> - Select files | <li><a href="#dateselect"><date></a> - Select files | ||||
that have been modified either before or after a particular date | that have been modified either before or after a particular date | ||||
and time | |||||
and time</li> | |||||
<li><a href="#dependselect"><depend></a> - Select files | <li><a href="#dependselect"><depend></a> - Select files | ||||
that have been modified more recently than equivalent files | that have been modified more recently than equivalent files | ||||
elsewhere | |||||
elsewhere</li> | |||||
<li><a href="#depthselect"><depth></a> - Select files | <li><a href="#depthselect"><depth></a> - Select files | ||||
that appear so many directories down in a directory tree | |||||
that appear so many directories down in a directory tree</li> | |||||
<li><a href="#differentselect"><different></a> - Select files | <li><a href="#differentselect"><different></a> - Select files | ||||
that are different from those elsewhere | |||||
that are different from those elsewhere</li> | |||||
<li><a href="#filenameselect"><filename></a> - Select | <li><a href="#filenameselect"><filename></a> - Select | ||||
files whose name matches a particular pattern. Equivalent to | files whose name matches a particular pattern. Equivalent to | ||||
the include and exclude elements of a patternset. | |||||
the include and exclude elements of a patternset.</li> | |||||
<li><a href="#presentselect"><present></a> - Select | <li><a href="#presentselect"><present></a> - Select | ||||
files that either do or do not exist in some other location | |||||
files that either do or do not exist in some other location</li> | |||||
<li><a href="#regexpselect"><containsregexp></a> - Select | <li><a href="#regexpselect"><containsregexp></a> - Select | ||||
files that match a regular expression | |||||
files that match a regular expression</li> | |||||
<li><a href="#sizeselect"><size></a> - Select files | <li><a href="#sizeselect"><size></a> - Select files | ||||
that are larger or smaller than a particular number of bytes. | |||||
that are larger or smaller than a particular number of bytes.</li> | |||||
<li><a href="#typeselect"><type></a> - Select files | <li><a href="#typeselect"><type></a> - Select files | ||||
that are either regular files or directories. | |||||
that are either regular files or directories.</li> | |||||
<li><a href="#modified"><modified></a> - Select files if | |||||
the return value of the configured algorithm is different from that | |||||
stored in a cache.</li> | |||||
</ul> | </ul> | ||||
<a name="containsselect"></a> | <a name="containsselect"></a> | ||||
@@ -465,7 +468,7 @@ | |||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td valign="top">expression</td> | <td valign="top">expression</td> | ||||
<td valign="top">Specifies the regular expression that must | |||||
<td valign="top">Specifies the regular expression that must | |||||
match true in every file</td> | match true in every file</td> | ||||
<td valign="top" align="center">Yes</td> | <td valign="top" align="center">Yes</td> | ||||
</tr> | </tr> | ||||
@@ -479,10 +482,10 @@ | |||||
</fileset> | </fileset> | ||||
</pre></blockquote> | </pre></blockquote> | ||||
<p>Selects all the text files that match the regular expression | |||||
<p>Selects all the text files that match the regular expression | |||||
(have a 4,5 or 6 followed by a period and a number from 0 to 9). | (have a 4,5 or 6 followed by a period and a number from 0 to 9). | ||||
<a name="sizeselect"></a> | <a name="sizeselect"></a> | ||||
<h4>Size Selector</h4> | <h4>Size Selector</h4> | ||||
@@ -592,6 +595,193 @@ | |||||
</pre></blockquote> | </pre></blockquote> | ||||
<a name="modified"></a> | |||||
<h4>Modified Selector</h4> | |||||
<p>The <modified> computes a value for a file, compares that | |||||
to the value stored in a cache and select the file, if these two values | |||||
differ.</p> | |||||
<p>Because this selector is highly configurable the order in which the selection is done | |||||
is: <ol> | |||||
<li> get the absolute path for the file </li> | |||||
<li> get the cached value from the configured cache (absolute path as key) </li> | |||||
<li> get the new value from the configured algorithm </li> | |||||
<li> compare these two values with the configured comparator </li> | |||||
<li> update the cache if needed and wished </li> | |||||
<li> do the selection according to the comparison result </li> | |||||
</ol> | |||||
The comparison, computing of the hashvalue and the store is done by implementation | |||||
of special interfaces. Therefore they may provide additional parameters.</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"> algorithm </td> | |||||
<td valign="top"> The type of algorithm should be used. | |||||
Acceptable values are (further information see later): | |||||
<ul> | |||||
<li> hashvalue - HashvalueAlgorithm </li> | |||||
<li> digest - DigestAlgorithm </li> | |||||
</ul> | |||||
</td> | |||||
<td valign="top" align="center"> No, defaults to <i>digest</i> </td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> cache </td> | |||||
<td valign="top"> The type of cache should be used. | |||||
Acceptable values are (further information see later): | |||||
<ul> | |||||
<li> propertyfile - PropertyfileCache </li> | |||||
</ul> | |||||
</td> | |||||
<td valign="top" align="center"> No, defaults to <i>propertyfile</i> </td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> comparator </td> | |||||
<td valign="top"> The type of comparator should be used. | |||||
Acceptable values are (further information see later): | |||||
<ul> | |||||
<li> equal - EqualComparator </li> | |||||
<li> rule - java.text.RuleBasedCollator </li> | |||||
</ul> | |||||
</td> | |||||
<td valign="top" align="center"> No, defaults to <i>equal</i> </td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> update </td> | |||||
<td valign="top"> Should the cache be updated when values differ? (boolean) </td> | |||||
<td valign="top" align="center"> No, defaults to <i>true</i> </td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> seldirs </td> | |||||
<td valign="top"> Should directories be selected? (boolean) </td> | |||||
<td valign="top" align="center"> No, defaults to <i>true</i> </td> | |||||
</tr> | |||||
</table> | |||||
<p>These attributes can be set with nested <param/> tags. With <param/> | |||||
tags you can set other values too - as long as they are named according to | |||||
the following rules: <ul> | |||||
<li> <b> algorithm </b>: same as attribute algorithm </li> | |||||
<li> <b> cache </b>: same as attribute cache </li> | |||||
<li> <b> comparator </b>: same as attribute cache </li> | |||||
<li> <b> update </b>: same as attribute comparator </li> | |||||
<li> <b> seldirs </b>: same as attribute seldirs </li> | |||||
<li> <b> algorithm.* </b>: Value is transfered to the algorithm via its | |||||
<i>set</i>XX-methods </li> | |||||
<li> <b> cache.* </b>: Value is transfered to the cache via its | |||||
<i>set</i>XX-methods </li> | |||||
<li> <b> comparator.* </b>: Value is transfered to the comparator via its | |||||
<i>set</i>XX-methods </li> | |||||
</ul></p> | |||||
<table border="1" cellpadding="2" cellspacing="0"> | |||||
<tr><td colspan="2"><font size="+1"><b> Algorithm´s </b></font></td></tr> | |||||
<tr> | |||||
<td valign="top"><b>Name</b></td> | |||||
<td valign="top"><b>Description</b></td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> hashvalue </td> | |||||
<td valign="top"> Reads the content of a file into a java.lang.String | |||||
and use thats hashValue(). No additional configuration required. | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td valign="top"> digest </td> | |||||
<td valign="top"> Uses java.security.MessageDigest. This Algorithm supports | |||||
the following attributes: | |||||
<ul> | |||||
<li><i>algorithm.algorithm</i> (optional): Name of the Digest algorithm | |||||
(e.g. 'MD5' or 'SHA', default = <i>MD5</i>) </li> | |||||
<li><i>algorithm.provider</i> (optional): Name of the Digest provider | |||||
(default = <i>null</i>) </li> | |||||
</ul> | |||||
</td> | |||||
</tr> | |||||
<tr><td colspan="2"><font size="+1"><b> Cache´s </b></font></td></tr> | |||||
<tr> | |||||
<td valign="top"> propertyfile </td> | |||||
<td valign="top"> Use the java.util.Properties class and its possibility | |||||
to load and store to file. | |||||
This Cache implementation supports the following attributes: | |||||
<ul> | |||||
<li><i>cache.cachefile</i> (optional): Name of the properties-file | |||||
(default = <i>cache.properties</i>) </li> | |||||
</ul> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
<p>Here are some examples of how to use the Modified Selector:</p> | |||||
<blockquote><pre> | |||||
<copy todir="dest"> | |||||
<filelist dir="src"> | |||||
<modified/> | |||||
</filelist> | |||||
</copy | |||||
</pre></blockquote> | |||||
<p>This will copy all files from <i>src</i> to <i>dest</i> which content has changed. | |||||
Using an updating PropertyfileCache with cache.properties and | |||||
MD5-DigestAlgorithm.</p> | |||||
<blockquote><pre> | |||||
<copy todir="dest"> | |||||
<filelist dir="src"> | |||||
<modified update="true" | |||||
seldirs="true" | |||||
cache="propertyfile" | |||||
algorithm="digest" | |||||
comparator="equal"> | |||||
<param name="cache.cachefile" value="cache.properties"/> | |||||
<param name="algorithm.algorithm" value="MD5"/> | |||||
</modified> | |||||
</filelist> | |||||
</copy> | |||||
</pre></blockquote> | |||||
<p>This is the same example rewritten as CoreSelector with setting the all the values | |||||
(same as defaults are).</p> | |||||
<blockquote><pre> | |||||
<copy todir="dest"> | |||||
<filelist dir="src"> | |||||
<custom class="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"> | |||||
<param name="update" value="true"/> | |||||
<param name="seldirs" value="true"/> | |||||
<param name="cache" value="propertyfile"/> | |||||
<param name="algorithm" value="digest"/> | |||||
<param name="comparator" value="equal"/> | |||||
<param name="cache.cachefile" value="cache.properties"/> | |||||
<param name="algorithm.algorithm" value="MD5"/> | |||||
</custom> | |||||
</filelist> | |||||
</copy> | |||||
</pre></blockquote> | |||||
<p>And this is the same rewritten as CustomSelector.</p> | |||||
<blockquote><pre> | |||||
<target name="generate-and-upload-site"> | |||||
<echo> generate the site using forrest </echo> | |||||
<antcall target="site"/> | |||||
<echo> upload the changed file </echo> | |||||
<ftp server="${ftp.server}" userid="${ftp.user}" password="${ftp.pwd}"> | |||||
<fileset dir="htdocs/manual"> | |||||
<modified/> | |||||
</fileset> | |||||
</ftp> | |||||
</target> | |||||
</pre></blockquote> | |||||
<p>A useful scenario for this selector inside a build environment | |||||
for homepage generation (e.g. with <a href="http://xml.apache.org/forrest/"> | |||||
Apache Forrest</a>). Here all <b>changed</b> files are uploaded to the server. The | |||||
CacheSelector saves therefore much upload time.</p> | |||||
<a name="selectcontainers"></a> | <a name="selectcontainers"></a> | ||||
<h3>Selector Containers</h3> | <h3>Selector Containers</h3> | ||||
@@ -992,4 +1182,3 @@ | |||||
@@ -85,12 +85,12 @@ | |||||
<target name="cleanup.mirrorfiles"> | <target name="cleanup.mirrorfiles"> | ||||
<delete dir="${mirror.dir}" /> | <delete dir="${mirror.dir}" /> | ||||
</target> | </target> | ||||
<target name="cleanupregexp"> | <target name="cleanupregexp"> | ||||
<delete dir="${testregexpsrc.dir}" /> | <delete dir="${testregexpsrc.dir}" /> | ||||
<delete dir="${testregexpdest.dir}" /> | <delete dir="${testregexpdest.dir}" /> | ||||
</target> | </target> | ||||
<target name="containsregexp"> | <target name="containsregexp"> | ||||
<mkdir dir="${testregexpsrc.dir}" /> | <mkdir dir="${testregexpsrc.dir}" /> | ||||
<mkdir dir="${testregexpdest.dir}" /> | <mkdir dir="${testregexpdest.dir}" /> | ||||
@@ -108,4 +108,134 @@ | |||||
</copy> | </copy> | ||||
</target> | </target> | ||||
</project> | |||||
<!-- ========== Test for ModifiedSelector ========== --> | |||||
<target name="modifiedselectortest-makeDirty"> | |||||
<!-- Load propertyfile generated by SelectorTest-class --> | |||||
<property file="ModifiedSelectorTest.properties"/> | |||||
<!-- Modify only timestamp --> | |||||
<touch file="${test.dir}/${f2name}" datetime="02/28/2003 9:55 AM"/> | |||||
<!-- Change content but keep timestamp --> | |||||
<echo file="${test.dir}/${f3name}" append="true" message="new content"/> | |||||
<touch file="${test.dir}/${f3name}" datetime="11/21/2001 4:55 AM"/> | |||||
<!-- Change content and timestamp --> | |||||
<echo file="${test.dir}/${f4name}" append="true" message="new content"/> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-clean"> | |||||
<delete dir="${test.dir}"/> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-prepare"> | |||||
<mkdir dir="${test.dir}/src"/> | |||||
<copy todir="${test.dir}/src"> | |||||
<fileset dir="${ant.home}/lib" includes="ant.jar"/> | |||||
<fileset dir="${ant.home}/bin"/> | |||||
</copy> | |||||
<touch datetime="12/24/2002 4:00 pm"> | |||||
<fileset dir="${test.dir}"/> | |||||
</touch> | |||||
<mkdir dir="${test.dir}/to-1"/> | |||||
<mkdir dir="${test.dir}/to-2"/> | |||||
<mkdir dir="${test.dir}/to-3"/> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-makeDirty"> | |||||
<touch file="${test.dir}/src/ant.jar"/> | |||||
<echo file="${test.dir}/src/ant.bat" append="true" message="new-content"/> | |||||
<echo file="${test.dir}/src/antRun.pl" append="true" message="new-content"/> | |||||
<touch file="${test.dir}/src/antRun.pl" datetime="12/24/2002 4:00 pm"/> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-coreselector-defaults" depends="modifiedselectortest-scenario-prepare"> | |||||
<!-- copy first time and create cachefile --> | |||||
<copy todir="${test.dir}/to-1"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified/> | |||||
</fileset> | |||||
</copy> | |||||
<!-- copy second time: nothing should be copied --> | |||||
<copy todir="${test.dir}/to-2"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified/> | |||||
</fileset> | |||||
</copy> | |||||
<!-- 'modify' the source files --> | |||||
<antcall target="modifiedselectortest-scenario-makeDirty"/> | |||||
<!-- copy third time: only the files with new CONTENT should be copied --> | |||||
<copy todir="${test.dir}/to-3"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified/> | |||||
</fileset> | |||||
</copy> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-coreselector-settings" depends="modifiedselectortest-scenario-prepare"> | |||||
<!-- copy first time and create cachefile --> | |||||
<copy todir="${test.dir}/to-1"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified cache="propertyfile" algorithm="hashvalue" update="true"> | |||||
<param name="cache.cachefile" value="core.cache.properties" /> | |||||
</modified> | |||||
</fileset> | |||||
</copy> | |||||
<!-- copy second time: nothing should be copied --> | |||||
<copy todir="${test.dir}/to-2"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified cache="propertyfile" algorithm="hashvalue" update="true"> | |||||
<param name="cache.cachefile" value="core.cache.properties" /> | |||||
</modified> | |||||
</fileset> | |||||
</copy> | |||||
<!-- 'modify' the source files --> | |||||
<antcall target="modifiedselectortest-scenario-makeDirty"/> | |||||
<!-- copy third time: only the files with new CONTENT should be copied --> | |||||
<copy todir="${test.dir}/to-3"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<modified cache="propertyfile" algorithm="hashvalue" update="true"> | |||||
<param name="cache.cachefile" value="core.cache.properties" /> | |||||
</modified> | |||||
</fileset> | |||||
</copy> | |||||
</target> | |||||
<target name="modifiedselectortest-scenario-customselector-settings" depends="modifiedselectortest-scenario-prepare"> | |||||
<!-- copy first time and create cachefile --> | |||||
<copy todir="${test.dir}/to-1"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"> | |||||
<param name="cache" value="propertyfile"/> | |||||
<param name="algorithm" value="hashvalue"/> | |||||
<param name="update" value="true"/> | |||||
<param name="cache.cachefile" value="core.cache.properties"/> | |||||
</custom> | |||||
</fileset> | |||||
</copy> | |||||
<!-- copy second time: nothing should be copied --> | |||||
<copy todir="${test.dir}/to-2"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"> | |||||
<param name="cache" value="propertyfile"/> | |||||
<param name="algorithm" value="hashvalue"/> | |||||
<param name="update" value="true"/> | |||||
<param name="cache.cachefile" value="core.cache.properties"/> | |||||
</custom> | |||||
</fileset> | |||||
</copy> | |||||
<!-- 'modify' the source files --> | |||||
<antcall target="modifiedselectortest-scenario-makeDirty"/> | |||||
<!-- copy third time: only the files with new CONTENT should be copied --> | |||||
<copy todir="${test.dir}/to-3"> | |||||
<fileset dir="${test.dir}/src"> | |||||
<custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"> | |||||
<param name="cache" value="propertyfile"/> | |||||
<param name="algorithm" value="hashvalue"/> | |||||
<param name="update" value="true"/> | |||||
<param name="cache.cachefile" value="core.cache.properties"/> | |||||
</custom> | |||||
</fileset> | |||||
</copy> | |||||
</target> | |||||
</project> |
@@ -77,6 +77,7 @@ import org.apache.tools.ant.types.selectors.PresentSelector; | |||||
import org.apache.tools.ant.types.selectors.SelectSelector; | import org.apache.tools.ant.types.selectors.SelectSelector; | ||||
import org.apache.tools.ant.types.selectors.SizeSelector; | import org.apache.tools.ant.types.selectors.SizeSelector; | ||||
import org.apache.tools.ant.types.selectors.FileSelector; | import org.apache.tools.ant.types.selectors.FileSelector; | ||||
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; | |||||
/** | /** | ||||
* Deletes a file or directory, or set of files defined by a fileset. | * Deletes a file or directory, or set of files defined by a fileset. | ||||
@@ -443,6 +444,16 @@ public class Delete extends MatchingTask { | |||||
super.addContainsRegexp(selector); | super.addContainsRegexp(selector); | ||||
} | } | ||||
/** | |||||
* add the modified selector | |||||
* @param selector the selector to add | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void addModified(ModifiedSelector selector) { | |||||
usedMatchingTask = true; | |||||
super.addModified(selector); | |||||
} | |||||
/** | /** | ||||
* add an arbitrary selector | * add an arbitrary selector | ||||
* @param selector the selector to be added | * @param selector the selector to be added | ||||
@@ -676,4 +687,3 @@ public class Delete extends MatchingTask { | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -81,6 +81,7 @@ import org.apache.tools.ant.types.selectors.SelectSelector; | |||||
import org.apache.tools.ant.types.selectors.SelectorContainer; | import org.apache.tools.ant.types.selectors.SelectorContainer; | ||||
import org.apache.tools.ant.types.selectors.SizeSelector; | import org.apache.tools.ant.types.selectors.SizeSelector; | ||||
import org.apache.tools.ant.types.selectors.TypeSelector; | import org.apache.tools.ant.types.selectors.TypeSelector; | ||||
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; | |||||
/** | /** | ||||
* This is an abstract task that should be used by all those tasks that | * This is an abstract task that should be used by all those tasks that | ||||
@@ -454,6 +455,15 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||||
fileset.addType(selector); | fileset.addType(selector); | ||||
} | } | ||||
/** | |||||
* add the modified selector | |||||
* @param selector the selector to add | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void addModified(ModifiedSelector selector) { | |||||
fileset.addModified(selector); | |||||
} | |||||
/** | /** | ||||
* add an arbitary selector | * add an arbitary selector | ||||
* @param selector the selector to add | * @param selector the selector to add | ||||
@@ -471,4 +481,4 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||||
protected final FileSet getImplicitFileSet() { | protected final FileSet getImplicitFileSet() { | ||||
return fileset; | return fileset; | ||||
} | } | ||||
} | |||||
} |
@@ -82,6 +82,7 @@ import org.apache.tools.ant.types.selectors.SelectSelector; | |||||
import org.apache.tools.ant.types.selectors.SelectorContainer; | import org.apache.tools.ant.types.selectors.SelectorContainer; | ||||
import org.apache.tools.ant.types.selectors.SelectorScanner; | import org.apache.tools.ant.types.selectors.SelectorScanner; | ||||
import org.apache.tools.ant.types.selectors.SizeSelector; | import org.apache.tools.ant.types.selectors.SizeSelector; | ||||
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; | |||||
/** | /** | ||||
* Class that holds an implicit patternset and supports nested | * Class that holds an implicit patternset and supports nested | ||||
@@ -680,6 +681,15 @@ public abstract class AbstractFileSet extends DataType implements Cloneable, | |||||
appendSelector(selector); | appendSelector(selector); | ||||
} | } | ||||
/** | |||||
* add the modified selector | |||||
* @param selector the selector to add | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void addModified(ModifiedSelector selector) { | |||||
appendSelector(selector); | |||||
} | |||||
/** | /** | ||||
* add an arbitary selector | * add an arbitary selector | ||||
* @param selector the selector to add | * @param selector the selector to add | ||||
@@ -721,4 +731,4 @@ public abstract class AbstractFileSet extends DataType implements Cloneable, | |||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -60,6 +60,7 @@ import java.util.Vector; | |||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; | |||||
/** | /** | ||||
* This is the base class for selectors that can contain other selectors. | * This is the base class for selectors that can contain other selectors. | ||||
@@ -328,6 +329,14 @@ public abstract class BaseSelectorContainer extends BaseSelector | |||||
appendSelector(selector); | appendSelector(selector); | ||||
} | } | ||||
/** | |||||
* add the modified selector | |||||
* @param selector the selector to add | |||||
* @since ant 1.6 | |||||
*/ | |||||
public void addModified(ModifiedSelector selector) { | |||||
appendSelector(selector); | |||||
} | |||||
/** | /** | ||||
* add an arbitary selector | * add an arbitary selector | ||||
@@ -338,5 +347,4 @@ public abstract class BaseSelectorContainer extends BaseSelector | |||||
appendSelector(selector); | appendSelector(selector); | ||||
} | } | ||||
} | |||||
} |
@@ -55,8 +55,8 @@ | |||||
package org.apache.tools.ant.types.selectors; | package org.apache.tools.ant.types.selectors; | ||||
import java.util.Enumeration; | import java.util.Enumeration; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector; | |||||
/** | /** | ||||
* This is the interface for selectors that can contain other selectors. | * This is the interface for selectors that can contain other selectors. | ||||
@@ -207,6 +207,13 @@ public interface SelectorContainer { | |||||
*/ | */ | ||||
void addDifferent(DifferentSelector selector); | void addDifferent(DifferentSelector selector); | ||||
/** | |||||
* add the modified selector | |||||
* @param selector the selector to add | |||||
* @since ant 1.6 | |||||
*/ | |||||
void addModified(ModifiedSelector selector); | |||||
/** | /** | ||||
* add an arbitary selector | * add an arbitary selector | ||||
* @param selector the selector to add | * @param selector the selector to add | ||||
@@ -214,4 +221,3 @@ public interface SelectorContainer { | |||||
*/ | */ | ||||
void add(FileSelector selector); | void add(FileSelector selector); | ||||
} | } | ||||
@@ -0,0 +1,85 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.io.File; | |||||
/** | |||||
* The <i>Algorithm</i> defines how a value for a file is computed. | |||||
* It must be sure that multiple calls for the same file results in the | |||||
* same value. | |||||
* The implementing class should implement a useful toString() method. | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public interface Algorithm { | |||||
/** | |||||
* Checks its prerequisites. | |||||
* @return <i>true</i> if all is ok, otherwise <i>false</i>. | |||||
*/ | |||||
boolean isValid(); | |||||
/** | |||||
* Get the value for a file. | |||||
* @param file File object for which the value should be evaluated. | |||||
* @return The value for that file | |||||
*/ | |||||
String getValue(File file); | |||||
} |
@@ -0,0 +1,109 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.util.Iterator; | |||||
/** | |||||
* A Cache let the user store key-value-pairs in a permanent manner and access | |||||
* them. | |||||
* It is possible that a client uses get() before load() therefore the | |||||
* implementation must ensure that no error occured because of the wrong | |||||
* <i>order</i>. | |||||
* The implementing class should implement a useful toString() method. | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public interface Cache { | |||||
/** | |||||
* Checks its prerequisites. | |||||
* @return <i>true</i> if all is ok, otherwise <i>false</i>. | |||||
*/ | |||||
boolean isValid(); | |||||
/** Deletes the cache. If file based the file has to be deleted also. */ | |||||
void delete(); | |||||
/** Loads the cache, must handle not existing cache. */ | |||||
void load(); | |||||
/** Saves modification of the cache. */ | |||||
void save(); | |||||
/** | |||||
* Returns a value for a given key from the cache. | |||||
* @param key the key | |||||
* @return the stored value | |||||
*/ | |||||
Object get(Object key); | |||||
/** | |||||
* Saves a key-value-pair in the cache. | |||||
* @param key the key | |||||
* @param value the value | |||||
*/ | |||||
void put(Object key, Object value); | |||||
/** | |||||
* Returns an iterator over the keys in the cache. | |||||
* @return An iterator over the keys. | |||||
*/ | |||||
Iterator iterator(); | |||||
} |
@@ -0,0 +1,241 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.FileOutputStream; | |||||
import java.security.DigestInputStream; | |||||
import java.security.MessageDigest; | |||||
import java.security.NoSuchAlgorithmException; | |||||
import java.security.NoSuchProviderException; | |||||
import org.apache.tools.ant.BuildException; | |||||
/** | |||||
* Computes a 'hashvalue' for the content of file using | |||||
* java.security.MessageDigest. | |||||
* Use of this algorithm doesn´t require any additional nested <param>s. | |||||
* Supported <param>s are: | |||||
* <table> | |||||
* <tr> | |||||
* <th>name</th><th>values</th><th>description</th><th>required</th> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> algorithm.algorithm </td> | |||||
* <td> MD5 | SHA (default provider) </td> | |||||
* <td> name of the algorithm the provider should use </td> | |||||
* <td> no, defaults to MD5 </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> algorithm.provider </td> | |||||
* <td> </td> | |||||
* <td> name of the provider to use </td> | |||||
* <td> no, defaults to <i>null</i> </td> | |||||
* </tr> | |||||
* </table> | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class DigestAlgorithm implements Algorithm { | |||||
// ----- member variables ----- | |||||
/** | |||||
* MessageDigest algorithm to be used. | |||||
*/ | |||||
private String algorithm = "MD5"; | |||||
/** | |||||
* MessageDigest Algorithm provider | |||||
*/ | |||||
private String provider = null; | |||||
/** | |||||
* Message Digest instance | |||||
*/ | |||||
private MessageDigest messageDigest = null; | |||||
/** | |||||
* Size of the read buffer to use. | |||||
*/ | |||||
private int readBufferSize = 8 * 1024; | |||||
// ----- Algorithm-Configuration ----- | |||||
/** | |||||
* Specifies the algorithm to be used to compute the checksum. | |||||
* Defaults to "MD5". Other popular algorithms like "SHA" may be used as well. | |||||
* @param algorithm the digest algorithm to use | |||||
*/ | |||||
public void setAlgorithm(String algorithm) { | |||||
this.algorithm = algorithm; | |||||
} | |||||
/** | |||||
* Sets the MessageDigest algorithm provider to be used | |||||
* to calculate the checksum. | |||||
* @param provider provider to use | |||||
*/ | |||||
public void setProvider(String provider) { | |||||
this.provider = provider; | |||||
} | |||||
/** Initialize the security message digest. */ | |||||
public void initMessageDigest() { | |||||
if (messageDigest != null) { | |||||
return; | |||||
} | |||||
if ((provider != null) && !"".equals(provider) && !"null".equals(provider)) { | |||||
try { | |||||
messageDigest = MessageDigest.getInstance(algorithm, provider); | |||||
} catch (NoSuchAlgorithmException noalgo) { | |||||
throw new BuildException(noalgo); | |||||
} catch (NoSuchProviderException noprovider) { | |||||
throw new BuildException(noprovider); | |||||
} | |||||
} else { | |||||
try { | |||||
messageDigest = MessageDigest.getInstance(algorithm); | |||||
} catch (NoSuchAlgorithmException noalgo) { | |||||
throw new BuildException(noalgo); | |||||
} | |||||
} | |||||
} | |||||
// ----- Logic ----- | |||||
/** | |||||
* This algorithm doesn´t need any configuration. | |||||
* Therefore it´s always valid. | |||||
* @return <i>true</i> if all is ok, otherwise <i>false</i>. | |||||
*/ | |||||
public boolean isValid() { | |||||
return true; | |||||
} | |||||
/** | |||||
* Computes a value for a file content with the specified digest algorithm. | |||||
* @param file File object for which the value should be evaluated. | |||||
* @return The value for that file | |||||
*/ | |||||
// implementation adapted from ...taskdefs.Checksum, thanks to Magesh for hint | |||||
public String getValue(File file) { | |||||
initMessageDigest(); | |||||
String checksum = null; | |||||
try { | |||||
if (!file.canRead()) { | |||||
return null; | |||||
} | |||||
FileInputStream fis = null; | |||||
FileOutputStream fos = null; | |||||
byte[] buf = new byte[readBufferSize]; | |||||
try { | |||||
messageDigest.reset(); | |||||
fis = new FileInputStream(file); | |||||
DigestInputStream dis = new DigestInputStream(fis, | |||||
messageDigest); | |||||
while (dis.read(buf, 0, readBufferSize) != -1) { | |||||
// do nothing | |||||
} | |||||
dis.close(); | |||||
fis.close(); | |||||
fis = null; | |||||
byte[] fileDigest = messageDigest.digest(); | |||||
StringBuffer checksumSb = new StringBuffer(); | |||||
for (int i = 0; i < fileDigest.length; i++) { | |||||
String hexStr = Integer.toHexString(0x00ff & fileDigest[i]); | |||||
if (hexStr.length() < 2) { | |||||
checksumSb.append("0"); | |||||
} | |||||
checksumSb.append(hexStr); | |||||
} | |||||
checksum = checksumSb.toString(); | |||||
} catch (Exception e) { | |||||
return null; | |||||
} | |||||
} catch (Exception e) { | |||||
return null; | |||||
} | |||||
return checksum; | |||||
} | |||||
/** | |||||
* Override Object.toString(). | |||||
* @return some information about this algorithm. | |||||
*/ | |||||
public String toString() { | |||||
StringBuffer buf = new StringBuffer(); | |||||
buf.append("<DigestAlgorithm:"); | |||||
buf.append("algorithm=").append(algorithm); | |||||
buf.append(";provider=").append(provider); | |||||
buf.append(">"); | |||||
return buf.toString(); | |||||
} | |||||
} |
@@ -0,0 +1,97 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.util.Comparator; | |||||
/** | |||||
* Simple implementation of Comparator for use in CacheSelector. | |||||
* compare() returns '0' (should not be selected) if both parameter | |||||
* are equal otherwise '1' (should be selected). | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class EqualComparator implements Comparator { | |||||
/** | |||||
* Implements Comparator.compare(). | |||||
* @param o1 the first object | |||||
* @param o2 the second object | |||||
* @return 0, if both are equal, otherwise 1 | |||||
*/ | |||||
public int compare(Object o1, Object o2) { | |||||
if (o1 == null) { | |||||
if (o2 == null) { | |||||
return 1; | |||||
} else { | |||||
return 0; | |||||
} | |||||
} else { | |||||
return (o1.equals(o2)) ? 0 : 1; | |||||
} | |||||
} | |||||
/** | |||||
* Override Object.toString(). | |||||
* @return information about this comparator | |||||
*/ | |||||
public String toString() { | |||||
return "EqualComparator"; | |||||
} | |||||
} |
@@ -0,0 +1,116 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.io.File; | |||||
/** | |||||
* Computes a 'hashvalue' for the content of file using String.hashValue(). | |||||
* Use of this algorithm doesn´t require any additional nested <param>s and | |||||
* doesn´t support any. | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class HashvalueAlgorithm implements Algorithm { | |||||
/** | |||||
* This algorithm doesn´t need any configuration. | |||||
* Therefore it´s always valid. | |||||
* @return always true | |||||
*/ | |||||
public boolean isValid() { | |||||
return true; | |||||
} | |||||
/** | |||||
* Computes a 'hashvalue' for a file content. | |||||
* It reads the content of a file, convert that to String and use the | |||||
* String.hashCode() method. | |||||
* @param file The file for which the value should be computed | |||||
* @return the hashvalue or <i>null</i> if the file couldn´t be read | |||||
*/ | |||||
// Because the content is only read the file will not be damaged. I tested | |||||
// with JPG, ZIP and PDF as binary files. | |||||
public String getValue(File file) { | |||||
try { | |||||
if (!file.canRead()) { | |||||
return null; | |||||
} | |||||
java.io.FileInputStream fis = new java.io.FileInputStream(file); | |||||
byte[] content = new byte[fis.available()]; | |||||
fis.read(content); | |||||
fis.close(); | |||||
String s = new String(content); | |||||
int hash = s.hashCode(); | |||||
return Integer.toString(hash); | |||||
} catch (Exception e) { | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* Override Object.toString(). | |||||
* @return information about this comparator | |||||
*/ | |||||
public String toString() { | |||||
return "HashvalueAlgorithm"; | |||||
} | |||||
} |
@@ -0,0 +1,653 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
// Java | |||||
import java.util.Comparator; | |||||
import java.util.Vector; | |||||
import java.util.Iterator; | |||||
import java.io.File; | |||||
// Ant | |||||
import org.apache.tools.ant.Project; | |||||
import org.apache.tools.ant.IntrospectionHelper; | |||||
import org.apache.tools.ant.types.EnumeratedAttribute; | |||||
import org.apache.tools.ant.types.Parameter; | |||||
import org.apache.tools.ant.types.selectors.BaseExtendSelector; | |||||
/** | |||||
* <p>Selector class that uses <i>Algorithm</i>, <i>Cache</i> and <i>Comparator</i> | |||||
* for its work. | |||||
* The <i>Algorithm</i> is used for computing a hashvalue for a file. | |||||
* The <i>Comparator</i> decides whether to select or not. | |||||
* The <i>Cache</i> stores the other value for comparison by the <i>Comparator</i> | |||||
* in a persistent manner.</p> | |||||
* | |||||
* <p>The ModifiedSelector is implemented as a <b>CoreSelector</b> and uses default | |||||
* values for all its attributes therefore the simpliest example is <pre> | |||||
* <copy todir="dest"> | |||||
* <filelist dir="src"> | |||||
* <modified/> | |||||
* </filelist> | |||||
* </copy> | |||||
* </pre></p> | |||||
* | |||||
* <p>The same example rewritten as CoreSelector with setting the all values | |||||
* (same as defaults are) would be <pre> | |||||
* <copy todir="dest"> | |||||
* <filelist dir="src"> | |||||
* <modified update="true" | |||||
* cache="propertyfile" | |||||
* algorithm="digest" | |||||
* comparator="equal"> | |||||
* <param name="cache.cachefile" value="cache.properties"/> | |||||
* <param name="algorithm.algorithm" value="MD5"/> | |||||
* </modified> | |||||
* </filelist> | |||||
* </copy> | |||||
* </pre></p> | |||||
* | |||||
* <p>And the same rewritten as CustomSelector would be<pre> | |||||
* <copy todir="dest"> | |||||
* <filelist dir="src"> | |||||
* <custom class="org.apache.tools.ant.type.selectors.ModifiedSelector"> | |||||
* <param name="update" value="true"/> | |||||
* <param name="cache" value="propertyfile"/> | |||||
* <param name="algorithm" value="digest"/> | |||||
* <param name="comparator" value="equal"/> | |||||
* <param name="cache.cachefile" value="cache.properties"/> | |||||
* <param name="algorithm.algorithm" value="MD5"/> | |||||
* </custom> | |||||
* </filelist> | |||||
* </copy> | |||||
* </pre></p> | |||||
* | |||||
* <p>All these three examples copy the files from <i>src</i> to <i>dest</i> | |||||
* using the ModifiedSelector. The ModifiedSelector uses the <i>PropertyfileCache | |||||
* </i>, the <i>DigestAlgorithm</i> and the <i>EqualComparator</i> for its | |||||
* work. The PropertyfileCache stores key-value-pairs in a simple java | |||||
* properties file. The filename is <i>cache.properties</i>. The <i>update</i> | |||||
* flag lets the selector update the values in the cache (and on first call | |||||
* creates the cache). The <i>DigestAlgorithm</i> computes a hashvalue using the | |||||
* java.security.MessageDigest class with its MD5-Algorithm and its standard | |||||
* provider. The new computed hashvalue and the stored one are compared by | |||||
* the <i>EqualComparator</i> which returns 'true' (more correct a value not | |||||
* equals zero (1)) if the values are not the same using simple String | |||||
* comparison.</p> | |||||
* | |||||
* <p>A useful scenario for this selector is inside a build environment | |||||
* for homepage generation (e.g. with <a href="http://xml.apache.org/forrest/"> | |||||
* Apache Forrest</a>). <pre> | |||||
* <target name="generate-and-upload-site"> | |||||
* <echo> generate the site using forrest </echo> | |||||
* <antcall target="site"/> | |||||
* | |||||
* <echo> upload the changed files </echo> | |||||
* <ftp server="${ftp.server}" userid="${ftp.user}" password="${ftp.pwd}"> | |||||
* <fileset dir="htdocs/manual"> | |||||
* <modified/> | |||||
* </fileset> | |||||
* </ftp> | |||||
* </target> | |||||
* </pre> Here all <b>changed</b> files are uploaded to the server. The | |||||
* ModifiedSelector saves therefore much upload time.</p> | |||||
* | |||||
* <p>This selector supports the following nested param´s: | |||||
* <table> | |||||
* <tr><th>name</th><th>values</th><th>description</th><th>required</th></tr> | |||||
* <tr> | |||||
* <td> cache </td> | |||||
* <td> propertyfile </td> | |||||
* <td> which cache implementation should be used <ul> | |||||
* <li><b>propertyfile</b> - using java.util.Properties </li> | |||||
* </td> | |||||
* <td> no, defaults to 'propertyfile' </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> algorithm </td> | |||||
* <td> hashvalue | digest </td> | |||||
* <td> which algorithm implementation should be used | |||||
* <li><b>hashvalue</b> - loads the file content into a String and | |||||
* uses its hashValue() method </li> | |||||
* <li><b>digest</b> - uses java.security.MessageDigest class </i> | |||||
* </td> | |||||
* <td> no, defaults to digest </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> comparator </td> | |||||
* <td> equal | role </td> | |||||
* <td> which comparator implementation should be used | |||||
* <li><b>equal</b> - simple comparison using String.equals() </li> | |||||
* <li><b>role</b> - uses java.text.RuleBasedCollator class </i> | |||||
* </td> | |||||
* <td> no, defaults to equal </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> update </td> | |||||
* <td> true | false </td> | |||||
* <td> If set to <i>true</i>, the cache will be stored, otherwise the values | |||||
* will be lost. </td> | |||||
* <td> no, defaults to true </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> seldirs </td> | |||||
* <td> true | false </td> | |||||
* <td> If set to <i>true</i>, directories will be selected otherwise not </td> | |||||
* <td> no, defaults to true </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> cache.* </td> | |||||
* <td> depends on used cache </td> | |||||
* <td> value is stored and given to the Cache-Object for initialisation </td> | |||||
* <td> depends on used cache </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> algorithm.* </td> | |||||
* <td> depends on used algorithm </td> | |||||
* <td> value is stored and given to the Algorithm-Object for initialisation </td> | |||||
* <td> depends on used algorithm </td> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> comparator.* </td> | |||||
* <td> depends on used comparator </td> | |||||
* <td> value is stored and given to the Comparator-Object for initialisation </td> | |||||
* <td> depends on used comparator </td> | |||||
* </tr> | |||||
* </table> | |||||
* If another name is used a BuildException "Invalid parameter" is thrown. </p> | |||||
* | |||||
* <p>This selector uses reflection for setting the values of its three interfaces | |||||
* (using org.apache.tools.ant.IntrospectionHelper) therefore no special | |||||
* 'configuration interfaces' has to be implemented by new caches, algorithms or | |||||
* comparators. All present <i>set</i>XX methods can be used. E.g. the DigestAlgorithm | |||||
* can use a specified provider for computing its value. For selecting this | |||||
* there is a <i>setProvider(String providername)</i> method. So you can use | |||||
* a nested <i><param name="algorithm.provider" value="MyProvider"/></i>. | |||||
* | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class ModifiedSelector extends BaseExtendSelector { | |||||
// ----- member variables - configuration | |||||
/** The Cache containing the old values. */ | |||||
private Cache cache = null; | |||||
/** Algorithm for computing new values and updating the cache. */ | |||||
private Algorithm algorithm = null; | |||||
/** How should the cached value and the new one compared? */ | |||||
private Comparator comparator = null; | |||||
/** Should the cache be updated? */ | |||||
private boolean update = true; | |||||
/** Are directories selected? */ | |||||
private boolean selectDirectories = true; | |||||
// ----- member variables - internal use | |||||
/** Flag whether this object is configured. Configuration is only done once. */ | |||||
private boolean isConfigured = false; | |||||
/** Algorithm name for later instantiation. */ | |||||
private AlgorithmName algoName = null; | |||||
/** Cache name for later instantiation. */ | |||||
private CacheName cacheName = null; | |||||
/** Comparator name for later instantiation. */ | |||||
private ComparatorName compName = null; | |||||
/** | |||||
* Parameter vector with parameters for later initialization. | |||||
* @see #configure | |||||
*/ | |||||
private Vector configParameter = new Vector(); | |||||
/** | |||||
* Parameter vector with special parameters for later initialization. | |||||
* The names have the pattern '*.*', e.g. 'cache.cachefile'. | |||||
* These parameters are used <b>after</b> the parameters with the pattern '*'. | |||||
* @see #configure | |||||
*/ | |||||
private Vector specialParameter = new Vector(); | |||||
// ----- constructors ----- | |||||
/** Bean-Constructor. */ | |||||
public ModifiedSelector() { | |||||
} | |||||
// ----- configuration ----- | |||||
/** Overrides BaseSelector.verifySettings(). */ | |||||
public void verifySettings() { | |||||
configure(); | |||||
if (cache == null) { | |||||
setError("Cache must be set."); | |||||
} else if (algorithm == null) { | |||||
setError("Algorithm must be set."); | |||||
} else if (!cache.isValid()) { | |||||
setError("Cache must be proper configured."); | |||||
} else if (!algorithm.isValid()) { | |||||
setError("Algorithm must be proper configured."); | |||||
} | |||||
} | |||||
/** | |||||
* Configures this Selector. | |||||
* Does this work only once per Selector object. | |||||
* <p>Because some problems while configuring from <custom>Selector | |||||
* the configuration is done in the following order:<ol> | |||||
* <li> collect the configuration data </li> | |||||
* <li> wait for the first isSelected() call </li> | |||||
* <li> set the default values </li> | |||||
* <li> set values for name pattern '*': update, cache, algorithm, comparator </li> | |||||
* <li> set values for name pattern '*.*: cache.cachefile, ... </li> | |||||
* </ol></p> | |||||
* <p>This configuration algorithm is needed because you don´t know | |||||
* the order of arriving config-data. E.g. if you first set the | |||||
* <i>cache.cachefilename</i> and after that the <i>cache</i> itself, | |||||
* the default value for cachefilename is used, because setting the | |||||
* cache implies creating a new Cache instance - with its defaults.</p> | |||||
*/ | |||||
public void configure() { | |||||
// | |||||
// ----- The "Singleton" ----- | |||||
// | |||||
if (isConfigured) { | |||||
return; | |||||
} | |||||
isConfigured = true; | |||||
// | |||||
// ----- Set default values ----- | |||||
// | |||||
org.apache.tools.ant.Project project = getProject(); | |||||
String filename = "cache.properties"; | |||||
File cachefile = null; | |||||
if (project != null) { | |||||
// normal use inside Ant | |||||
cachefile = new File(project.getBaseDir(), filename); | |||||
} else { | |||||
// no reference to project - e.g. during JUnit tests | |||||
cachefile = new File(filename); | |||||
} | |||||
cache = new PropertiesfileCache(cachefile); | |||||
algorithm = new DigestAlgorithm(); | |||||
comparator = new EqualComparator(); | |||||
update = true; | |||||
selectDirectories = true; | |||||
// | |||||
// ----- Set the main attributes, pattern '*' ----- | |||||
// | |||||
for (Iterator itConfig = configParameter.iterator(); itConfig.hasNext();) { | |||||
Parameter par = (Parameter) itConfig.next(); | |||||
if (par.getName().indexOf(".") > 0) { | |||||
// this is a *.* parameter for later use | |||||
specialParameter.add(par); | |||||
} else { | |||||
useParameter(par); | |||||
} | |||||
} | |||||
configParameter = new Vector(); | |||||
// | |||||
// ----- Instantiate the interfaces ----- | |||||
// | |||||
String className = null; | |||||
String pkg = "org.apache.tools.ant.types.selectors.cacheselector"; | |||||
// the algorithm | |||||
if (algorithm == null) { | |||||
if ("hashvalue".equals(algoName.getValue())) { | |||||
className = pkg + ".HashvalueAlgorithm"; | |||||
} else if ("digest".equals(algoName.getValue())) { | |||||
className = pkg + ".DigestAlgorithm"; | |||||
} | |||||
if (className != null) { | |||||
try { | |||||
// load the specified Algorithm, save the reference and configure it | |||||
algorithm = (Algorithm) Class.forName(className).newInstance(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
// the cache | |||||
if (cache == null) { | |||||
if ("propertyfile".equals(cacheName.getValue())) { | |||||
className = pkg + ".PropertiesfileCache"; | |||||
} | |||||
if (className != null) { | |||||
try { | |||||
// load the specified Cache, save the reference and configure it | |||||
cache = (Cache) Class.forName(className).newInstance(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
// the comparator | |||||
if (comparator == null) { | |||||
if ("equal".equals(compName.getValue())) { | |||||
className = pkg + ".EqualComparator"; | |||||
} else if ("role".equals(compName.getValue())) { | |||||
className = "java.text.RuleBasedCollator"; | |||||
} | |||||
if (className != null) { | |||||
try { | |||||
// load the specified Cache, save the reference and configure it | |||||
comparator = (Comparator) Class.forName(className).newInstance(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
// | |||||
// ----- Set the special attributes, pattern '*.*' ----- | |||||
// | |||||
for (Iterator itSpecial = specialParameter.iterator(); itSpecial.hasNext();) { | |||||
Parameter par = (Parameter) itSpecial.next(); | |||||
useParameter(par); | |||||
} | |||||
specialParameter = new Vector(); | |||||
} | |||||
// ----- the selection work ----- | |||||
/** | |||||
* Implementation of BaseExtendSelector.isSelected(). | |||||
* @param basedir as described in BaseExtendSelector | |||||
* @param filename as described in BaseExtendSelector | |||||
* @param file as described in BaseExtendSelector | |||||
* @return as described in BaseExtendSelector | |||||
*/ | |||||
public boolean isSelected(File basedir, String filename, File file) { | |||||
validate(); | |||||
File f = new File(basedir, filename); | |||||
// You can not compute a value for a directory | |||||
if (f.isDirectory()) { | |||||
return selectDirectories; | |||||
} | |||||
// Get the values and do the comparison | |||||
String cachedValue = String.valueOf(cache.get(f.getAbsolutePath())); | |||||
String newValue = algorithm.getValue(f); | |||||
boolean rv = (comparator.compare(cachedValue, newValue) != 0); | |||||
// Maybe update the cache | |||||
if (update && !cachedValue.equals(newValue)) { | |||||
cache.put(f.getAbsolutePath(), newValue); | |||||
cache.save(); | |||||
} | |||||
return rv; | |||||
} | |||||
// ----- attribute and nested element support ----- | |||||
/** | |||||
* Support for <i>update</i> attribute. | |||||
* @param update new value | |||||
*/ | |||||
public void setUpdate(boolean update) { | |||||
this.update = update; | |||||
} | |||||
/** | |||||
* Support for <i>seldirs</i> attribute. | |||||
* @param seldirs new value | |||||
*/ | |||||
public void setSeldirs(boolean seldirs) { | |||||
selectDirectories = seldirs; | |||||
} | |||||
/** | |||||
* Support for nested <param> tags. | |||||
* @param key the key of the parameter | |||||
* @param value the value of the parameter | |||||
*/ | |||||
public void addParam(String key, Object value) { | |||||
Parameter par = new Parameter(); | |||||
par.setName(key); | |||||
par.setValue(String.valueOf(value)); | |||||
configParameter.add(par); | |||||
} | |||||
/** | |||||
* Support for nested <param> tags. | |||||
* @param parameter the parameter object | |||||
*/ | |||||
public void addParam(Parameter parameter) { | |||||
configParameter.add(parameter); | |||||
} | |||||
/** | |||||
* Defined in org.apache.tools.ant.types.Parameterizable. | |||||
* Overwrite implementation in superclass because only special | |||||
* parameters are valid. | |||||
* @see #addParam(String,String). | |||||
*/ | |||||
public void setParameters(Parameter[] parameters) { | |||||
if (parameters != null) { | |||||
for (int i = 0; i < parameters.length; i++) { | |||||
configParameter.add(parameters[i]); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Support for nested <param name="" value=""/> tags. | |||||
* Parameter named <i>cache</i>, <i>algorithm</i>, | |||||
* <i>comparator</i> or <i>update</i> are mapped to | |||||
* the respective set-Method. | |||||
* Parameter which names starts with <i>cache.</i> or | |||||
* <i>algorithm.</i> or <i>comparator.</i> are tried | |||||
* to set on the appropriate object via its set-methods. | |||||
* Other parameters are invalid and an BuildException will | |||||
* be thrown. | |||||
* | |||||
* @param parameter Key and value as parameter object | |||||
*/ | |||||
public void useParameter(Parameter parameter) { | |||||
String key = parameter.getName(); | |||||
String value = parameter.getValue(); | |||||
if ("cache".equals(key)) { | |||||
CacheName cn = new CacheName(); | |||||
cn.setValue(value); | |||||
setCache(cn); | |||||
} else if ("algorithm".equals(key)) { | |||||
AlgorithmName an = new AlgorithmName(); | |||||
an.setValue(value); | |||||
setAlgorithm(an); | |||||
} else if ("comparator".equals(key)) { | |||||
ComparatorName cn = new ComparatorName(); | |||||
cn.setValue(value); | |||||
setComparator(cn); | |||||
} else if ("update".equals(key)) { | |||||
boolean updateValue = | |||||
("true".equalsIgnoreCase(value)) | |||||
? true | |||||
: false; | |||||
setUpdate(updateValue); | |||||
} else if ("seldirs".equals(key)) { | |||||
boolean sdValue = | |||||
("true".equalsIgnoreCase(value)) | |||||
? true | |||||
: false; | |||||
setSeldirs(sdValue); | |||||
} else if (key.startsWith("cache.")) { | |||||
String name = key.substring(6); | |||||
tryToSetAParameter(cache, name, value); | |||||
} else if (key.startsWith("algorithm.")) { | |||||
String name = key.substring(10); | |||||
tryToSetAParameter(algorithm, name, value); | |||||
} else if (key.startsWith("comparator.")) { | |||||
String name = key.substring(11); | |||||
tryToSetAParameter(comparator, name, value); | |||||
} else { | |||||
setError("Invalid parameter " + key); | |||||
} | |||||
} | |||||
/** | |||||
* Try to set a value on an object using reflection. | |||||
* Helper method for easier access to IntrospectionHelper.setAttribute(). | |||||
* @param obj the object on which the attribute should be set | |||||
* @param name the attributename | |||||
* @param value the new value | |||||
*/ | |||||
protected void tryToSetAParameter(Object obj, String name, String value) { | |||||
Project prj = (getProject() != null) ? getProject() : new Project(); | |||||
IntrospectionHelper iHelper | |||||
= IntrospectionHelper.getHelper(prj, obj.getClass()); | |||||
try { | |||||
iHelper.setAttribute(prj, obj, name, value); | |||||
} catch (org.apache.tools.ant.BuildException e) { | |||||
// no-op | |||||
} | |||||
} | |||||
// ----- 'beautiful' output ----- | |||||
/** | |||||
* Override Object.toString(). | |||||
* @return information about this selector | |||||
*/ | |||||
public String toString() { | |||||
StringBuffer buf = new StringBuffer("{modifiedselector"); | |||||
buf.append(" update=").append(update); | |||||
buf.append(" seldirs=").append(selectDirectories); | |||||
buf.append(" cache=").append(cache); | |||||
buf.append(" algorithm=").append(algorithm); | |||||
buf.append(" comparator=").append(comparator); | |||||
buf.append("}"); | |||||
return buf.toString(); | |||||
} | |||||
// The EnumeratedAttributes for the three interface implementations. | |||||
// Name-Classname mapping is done in the configure() method. | |||||
public Cache getCache() { return cache; } | |||||
public void setCache(CacheName name) { | |||||
cacheName = name; | |||||
} | |||||
public static class CacheName extends EnumeratedAttribute { | |||||
public String[] getValues() { | |||||
return new String[] {"propertyfile" }; | |||||
} | |||||
} | |||||
public Algorithm getAlgorithm() { return algorithm; } | |||||
public void setAlgorithm(AlgorithmName name) { | |||||
algoName = name; | |||||
} | |||||
public static class AlgorithmName extends EnumeratedAttribute { | |||||
public String[] getValues() { | |||||
return new String[] {"hashvalue", "digest" }; | |||||
} | |||||
} | |||||
public Comparator getComparator() { return comparator; } | |||||
public void setComparator(ComparatorName name) { | |||||
compName = name; | |||||
} | |||||
public static class ComparatorName extends EnumeratedAttribute { | |||||
public String[] getValues() { | |||||
return new String[] {"equal", "rule" }; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,255 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors.modifiedselector; | |||||
import java.util.Iterator; | |||||
import java.util.Vector; | |||||
import java.util.Enumeration; | |||||
import java.util.Properties; | |||||
import java.io.File; | |||||
import java.io.BufferedInputStream; | |||||
import java.io.FileInputStream; | |||||
import java.io.BufferedOutputStream; | |||||
import java.io.FileOutputStream; | |||||
/** | |||||
* Use java.util.Properties for storing the values. | |||||
* The use of this Cache-implementation requires the use of the parameter | |||||
* <param name="cache.cachefile" .../> for defining, where to store the | |||||
* properties file. | |||||
* | |||||
* The ModifiedSelector sets the <i>cachefile</i> to the default value | |||||
* <i>cache.properties</i>. | |||||
* | |||||
* Supported <param>s are: | |||||
* <table> | |||||
* <tr> | |||||
* <th>name</th><th>values</th><th>description</th><th>required</th> | |||||
* </tr> | |||||
* <tr> | |||||
* <td> cache.cachefile </td> | |||||
* <td> <i>path to file</i> </td> | |||||
* <td> the name of the properties file </td> | |||||
* <td> yes </td> | |||||
* </tr> | |||||
* </table> | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class PropertiesfileCache implements Cache { | |||||
// ----- member variables - configuration ----- | |||||
/** Where to store the properties? */ | |||||
private File cachefile = null; | |||||
/** Object for storing the key-value-pairs. */ | |||||
private Properties cache = new Properties(); | |||||
// ----- member variables - internal use ----- | |||||
/** Is the cache already loaded? Prevents from multiple load operations. */ | |||||
private boolean cacheLoaded = false; | |||||
/** Must the cache be saved? Prevents from multiple save operations. */ | |||||
private boolean cacheDirty = true; | |||||
// ----- Constructors ----- | |||||
/** Bean-Constructor. */ | |||||
public PropertiesfileCache() { | |||||
} | |||||
/** | |||||
* Constructor. | |||||
* @param cachefile set the cachefile | |||||
*/ | |||||
public PropertiesfileCache(File cachefile) { | |||||
this.cachefile = cachefile; | |||||
} | |||||
// ----- Cache-Configuration ----- | |||||
public void setCachefile(File file) { | |||||
cachefile = file; | |||||
} | |||||
public File getCachefile() { return cachefile; } | |||||
public boolean isValid() { | |||||
return (cachefile != null); | |||||
} | |||||
// ----- Data Access | |||||
public void load() { | |||||
if ((cachefile != null) && cachefile.isFile() && cachefile.canRead()) { | |||||
try { | |||||
BufferedInputStream bis = new BufferedInputStream( | |||||
new FileInputStream(cachefile)); | |||||
cache.load(bis); | |||||
bis.close(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
// after loading the cache is up to date with the file | |||||
cacheLoaded = true; | |||||
cacheDirty = false; | |||||
} | |||||
/** | |||||
* Saves modification of the cache. | |||||
* Cache is only saved if there is one ore more entries. | |||||
* Because entries can not be deleted by this API, this Cache | |||||
* implementation checks the existence of entries before creating the file | |||||
* for performance optimisation. | |||||
*/ | |||||
public void save() { | |||||
if (!cacheDirty) { | |||||
return; | |||||
} | |||||
if ((cachefile != null) && cache.propertyNames().hasMoreElements()) { | |||||
try { | |||||
BufferedOutputStream bos = new BufferedOutputStream( | |||||
new FileOutputStream(cachefile)); | |||||
cache.store(bos, null); | |||||
bos.flush(); | |||||
bos.close(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
cacheDirty = false; | |||||
} | |||||
/** Deletes the cache and its underlying file. */ | |||||
public void delete() { | |||||
cache = new Properties(); | |||||
cachefile.delete(); | |||||
cacheLoaded = true; | |||||
cacheDirty = false; | |||||
} | |||||
/** | |||||
* Returns a value for a given key from the cache. | |||||
* @param key the key | |||||
* @return the stored value | |||||
*/ | |||||
public Object get(Object key) { | |||||
if (!cacheLoaded) { | |||||
load(); | |||||
} | |||||
try { | |||||
return cache.getProperty(String.valueOf(key)); | |||||
} catch (ClassCastException e) { | |||||
return null; | |||||
} | |||||
} | |||||
/** | |||||
* Saves a key-value-pair in the cache. | |||||
* @param key the key | |||||
* @param value the value | |||||
*/ | |||||
public void put(Object key, Object value) { | |||||
cache.put(String.valueOf(key), String.valueOf(value)); | |||||
cacheDirty = true; | |||||
} | |||||
/** | |||||
* Returns an iterator over the keys in the cache. | |||||
* @return An iterator over the keys. | |||||
*/ | |||||
public Iterator iterator() { | |||||
Vector v = new java.util.Vector(); | |||||
Enumeration en = cache.propertyNames(); | |||||
while (en.hasMoreElements()) { | |||||
v.add(en.nextElement()); | |||||
} | |||||
return v.iterator(); | |||||
} | |||||
// ----- additional ----- | |||||
/** | |||||
* Override Object.toString(). | |||||
* @return information about this cache | |||||
*/ | |||||
public String toString() { | |||||
StringBuffer buf = new StringBuffer(); | |||||
buf.append("<PropertiesfileCache:"); | |||||
buf.append("cachefile=").append(cachefile); | |||||
buf.append(";noOfEntries=").append(cache.size()); | |||||
buf.append(">"); | |||||
return buf.toString(); | |||||
} | |||||
} |
@@ -108,6 +108,18 @@ public abstract class BaseSelectorTest extends TestCase { | |||||
public abstract BaseSelector getInstance(); | public abstract BaseSelector getInstance(); | ||||
/** | |||||
* Return a preconfigured selector (with a set reference to | |||||
* project instance). | |||||
* @return the selector | |||||
*/ | |||||
public BaseSelector getSelector() { | |||||
BaseSelector selector = getInstance(); | |||||
selector.setProject( getProject() ); | |||||
return selector; | |||||
} | |||||
public Project getProject() { | public Project getProject() { | ||||
return project; | return project; | ||||
} | } | ||||
@@ -171,6 +183,66 @@ public abstract class BaseSelectorTest extends TestCase { | |||||
return buf.toString(); | return buf.toString(); | ||||
} | } | ||||
/** | |||||
* Does the selection test for a given selector and prints the | |||||
* filenames of the differing files (selected but shouldn´t, | |||||
* not selected but should). | |||||
* @param selector The selector to test | |||||
* @param expected The expected result | |||||
*/ | |||||
public void performTests(FileSelector selector, String expected) { | |||||
String result = selectionString(selector); | |||||
String diff = diff(expected, result); | |||||
String resolved = resolve(diff); | |||||
assertEquals("Differing files: " + resolved, result, expected); | |||||
} | |||||
/** | |||||
* Checks which files are selected and shouldn´t be or which | |||||
* are not selected but should. | |||||
* @param expected String containing 'F's and 'T's | |||||
* @param result String containing 'F's and 'T's | |||||
* @return Difference as String containing '-' (equal) and | |||||
* 'X' (difference). | |||||
*/ | |||||
public String diff(String expected, String result) { | |||||
int length1 = expected.length(); | |||||
int length2 = result.length(); | |||||
int min = (length1 > length2) ? length2 : length1; | |||||
StringBuffer sb = new StringBuffer(); | |||||
for (int i=0; i<min; i++) { | |||||
sb.append( | |||||
(expected.charAt(i) == result.charAt(i)) | |||||
? "-" | |||||
: "X" | |||||
); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
/** | |||||
* Resolves a diff-String (@see diff()) against the (inherited) filenames- | |||||
* and files arrays. | |||||
* @param filelist Diff-String | |||||
* @return String containing the filenames for all differing files, | |||||
* separated with semicolons ';' | |||||
*/ | |||||
public String resolve(String filelist) { | |||||
StringBuffer sb = new StringBuffer(); | |||||
int min = (filenames.length > filelist.length()) | |||||
? filelist.length() | |||||
: filenames.length; | |||||
for (int i=0; i<min; i++) { | |||||
if ('X'==filelist.charAt(i)) { | |||||
sb.append(filenames[i]); | |||||
sb.append(";"); | |||||
} | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
/** | /** | ||||
* <p>Creates a testbed. We avoid the dreaded "test" word so that we | * <p>Creates a testbed. We avoid the dreaded "test" word so that we | ||||
* don't falsely identify this as a test to be run. The actual | * don't falsely identify this as a test to be run. The actual | ||||
@@ -252,4 +324,4 @@ public abstract class BaseSelectorTest extends TestCase { | |||||
} | |||||
} |
@@ -0,0 +1,707 @@ | |||||
/* | |||||
* The Apache Software License, Version 1.1 | |||||
* | |||||
* Copyright (c) 2003 The Apache Software Foundation. All rights | |||||
* reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in | |||||
* the documentation and/or other materials provided with the | |||||
* distribution. | |||||
* | |||||
* 3. The end-user documentation included with the redistribution, if | |||||
* any, must include the following acknowlegement: | |||||
* "This product includes software developed by the | |||||
* Apache Software Foundation (http://www.apache.org/)." | |||||
* Alternately, this acknowlegement may appear in the software itself, | |||||
* if and wherever such third-party acknowlegements normally appear. | |||||
* | |||||
* 4. The names "Ant" and "Apache Software | |||||
* Foundation" must not be used to endorse or promote products derived | |||||
* from this software without prior written permission. For written | |||||
* permission, please contact apache@apache.org. | |||||
* | |||||
* 5. Products derived from this software may not be called "Apache" | |||||
* nor may "Apache" appear in their names without prior written | |||||
* permission of the Apache Group. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* ==================================================================== | |||||
* | |||||
* This software consists of voluntary contributions made by many | |||||
* individuals on behalf of the Apache Software Foundation. For more | |||||
* information on the Apache Software Foundation, please see | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.types.selectors; | |||||
// Java | |||||
import java.io.File; | |||||
import java.io.FileWriter; | |||||
import java.util.Comparator; | |||||
import java.util.Iterator; | |||||
import java.text.RuleBasedCollator; | |||||
// Ant | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.types.Parameter; | |||||
// The classes to test | |||||
import org.apache.tools.ant.types.selectors.modifiedselector.*; | |||||
/** | |||||
* Unit tests for ModifiedSelector. | |||||
* | |||||
* @author Jan Matèrne | |||||
* @version 2003-09-13 | |||||
* @since Ant 1.6 | |||||
*/ | |||||
public class ModifiedSelectorTest extends BaseSelectorTest { | |||||
/** Package of the CacheSelector classes. */ | |||||
private static String pkg = "org.apache.tools.ant.types.selectors.modifiedselector"; | |||||
public ModifiedSelectorTest(String name) { | |||||
super(name); | |||||
} | |||||
/** | |||||
* Factory method from base class. This should be overriden in child | |||||
* classes to return a specific Selector class (like here). | |||||
*/ | |||||
public BaseSelector getInstance() { | |||||
return new ModifiedSelector(); | |||||
} | |||||
/** Test right use of cache names. */ | |||||
public void testValidateWrongCache() { | |||||
String name = "this-is-not-a-valid-cache-name"; | |||||
try { | |||||
ModifiedSelector.CacheName cacheName = new ModifiedSelector.CacheName(); | |||||
cacheName.setValue(name); | |||||
fail("CacheSelector.CacheName accepted invalid value."); | |||||
} catch (BuildException be) { | |||||
assertEquals(name + " is not a legal value for this attribute", | |||||
be.getMessage()); | |||||
} | |||||
} | |||||
/** Test right use of cache names. */ | |||||
public void testValidateWrongAlgorithm() { | |||||
String name = "this-is-not-a-valid-algorithm-name"; | |||||
try { | |||||
ModifiedSelector.AlgorithmName algoName | |||||
= new ModifiedSelector.AlgorithmName(); | |||||
algoName.setValue(name); | |||||
fail("CacheSelector.AlgorithmName accepted invalid value."); | |||||
} catch (BuildException be) { | |||||
assertEquals(name + " is not a legal value for this attribute", | |||||
be.getMessage()); | |||||
} | |||||
} | |||||
/** Test right use of comparator names. */ | |||||
public void testValidateWrongComparator() { | |||||
String name = "this-is-not-a-valid-comparator-name"; | |||||
try { | |||||
ModifiedSelector.ComparatorName compName | |||||
= new ModifiedSelector.ComparatorName(); | |||||
compName.setValue(name); | |||||
fail("ModifiedSelector.ComparatorName accepted invalid value."); | |||||
} catch (BuildException be) { | |||||
assertEquals(name + " is not a legal value for this attribute", | |||||
be.getMessage()); | |||||
} | |||||
} | |||||
/** | |||||
* Propertycache must have a set 'cachefile' attribute. | |||||
* The default in ModifiedSelector "cache.properties" is set by the selector. | |||||
*/ | |||||
public void testPropcacheInvalid() { | |||||
Cache cache = new PropertiesfileCache(); | |||||
if (cache.isValid()) | |||||
fail("PropertyfilesCache does not check its configuration."); | |||||
} | |||||
/** | |||||
* Tests whether the seldirs attribute is used. | |||||
*/ | |||||
public void testSeldirs() { | |||||
ModifiedSelector s = (ModifiedSelector)getSelector(); | |||||
try { | |||||
makeBed(); | |||||
StringBuffer sbTrue = new StringBuffer(); | |||||
StringBuffer sbFalse = new StringBuffer(); | |||||
for (int i=0; i<filenames.length; i++) { | |||||
if (files[i].isDirectory()) { | |||||
sbTrue.append("T"); | |||||
sbFalse.append("F"); | |||||
} else { | |||||
sbTrue.append("T"); | |||||
sbFalse.append("T"); | |||||
} | |||||
} | |||||
s.setSeldirs(true); | |||||
performTests(s, sbTrue.toString()); | |||||
s.getCache().delete(); | |||||
s.setSeldirs(false); | |||||
performTests(s, sbFalse.toString()); | |||||
s.getCache().delete(); | |||||
} finally { | |||||
cleanupBed(); | |||||
if (s!=null) s.getCache().delete(); | |||||
} | |||||
} | |||||
/** | |||||
* Complex test scenario using default values (DigestAlgorithm with MD5, | |||||
* PropertiesfileCache with file=cache.properties, EqualComparator | |||||
* and update=true). <ol> | |||||
* <li> try fist time --> should select all </li> | |||||
* <li> try second time --> should select no files (only directories) </li> | |||||
* <li> modify timestamp of one file and content of a nother one </li> | |||||
* <li> try third time --> should select only the file with modified | |||||
* content </li> | |||||
*/ | |||||
public void testScenario1() { | |||||
BFT bft = null; | |||||
ModifiedSelector s = null; | |||||
try { | |||||
// | |||||
// ***** initialize test environment (called "bed") ***** | |||||
// | |||||
makeBed(); | |||||
String results = null; | |||||
// Configure the selector - only defaults are used | |||||
s = (ModifiedSelector)getSelector(); | |||||
// | |||||
// ***** First Run ***** | |||||
// the first call should get all files, because nothing is in | |||||
// the cache | |||||
// | |||||
performTests(s, "TTTTTTTTTTTT"); | |||||
// | |||||
// ***** Second Run ***** | |||||
// the second call should get no files, because no content | |||||
// has changed | |||||
// | |||||
performTests(s, "TFFFFFFFFFFT"); | |||||
// | |||||
// ***** make some files dirty ***** | |||||
// | |||||
// these files are made dirty --> 3+4 with different content | |||||
String f2name = "tar/bz2/asf-logo-huge.tar.bz2"; | |||||
String f3name = "asf-logo.gif.md5"; | |||||
String f4name = "copy.filterset.filtered"; | |||||
// AccessObject to the test-Ant-environment | |||||
bft = new BFT(); | |||||
// give some values (via property file) to that environment | |||||
bft.writeProperties("f2name="+f2name); | |||||
bft.writeProperties("f3name="+f3name); | |||||
bft.writeProperties("f4name="+f4name); | |||||
// call the target for making the files dirty | |||||
bft.doTarget("modifiedselectortest-makeDirty"); | |||||
// | |||||
// ***** Third Run ***** | |||||
// third call should get only those files, which CONTENT changed | |||||
// (no timestamp changes required!) | |||||
results = selectionString(s); | |||||
// | |||||
// ***** Check the result ***** | |||||
// | |||||
// Mark all files which should be selected as (T)rue and all others | |||||
// as (F)alse. Directories are always selected so they always are | |||||
// (T)rue. | |||||
StringBuffer expected = new StringBuffer(); | |||||
for (int i=0; i<filenames.length; i++) { | |||||
String ch = "F"; | |||||
if (files[i].isDirectory()) ch = "T"; | |||||
// f2name shouldn´t be selected: only timestamp has changed! | |||||
if (filenames[i].equalsIgnoreCase(f3name)) ch = "T"; | |||||
if (filenames[i].equalsIgnoreCase(f4name)) ch = "T"; | |||||
expected.append(ch); | |||||
} | |||||
assertEquals( | |||||
"Wrong files selected. Differing files: " // info text | |||||
+ resolve(diff(expected.toString(), results)), // list of files | |||||
expected.toString(), // expected result | |||||
results // result | |||||
); | |||||
} finally { | |||||
// cleanup the environment | |||||
cleanupBed(); | |||||
if (s!=null) s.getCache().delete(); | |||||
if (bft!=null) bft.deletePropertiesfile(); | |||||
} | |||||
} | |||||
/** | |||||
* This scenario is based on scenario 1, but does not use any | |||||
* default value and its based on <custom> selector. Used values are:<ul> | |||||
* <li><b>Cache: </b> Propertyfile, | |||||
* cachefile={java.io.tmpdir}/mycache.txt </li> | |||||
* <li><b>Algorithm: </b> Digest | |||||
* algorithm=SHA, Provider=null </li> | |||||
* <li><b>Comparator: </b> java.text.RuleBasedCollator | |||||
* <li><b>Update: </b> true </li> | |||||
*/ | |||||
public void testScenario2() { | |||||
ExtendSelector s = new ExtendSelector(); | |||||
BFT bft = new BFT(); | |||||
String cachefile = System.getProperty("java.io.tmpdir")+"/mycache.txt"; | |||||
try { | |||||
makeBed(); | |||||
s.setClassname("org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"); | |||||
s.addParam(createParam("cache.cachefile", cachefile)); | |||||
//s.addParam(createParam("algorithm.provider","---")); // i don´t know any valid | |||||
s.addParam(createParam("cache","propertyfile")); | |||||
s.addParam(createParam("update","true")); | |||||
s.addParam(createParam("comparator","rule")); | |||||
s.addParam(createParam("algorithm.name","sha")); | |||||
s.addParam(createParam("algorithm","digest")); | |||||
// first and second run | |||||
performTests(s, "TTTTTTTTTTTT"); | |||||
performTests(s, "TFFFFFFFFFFT"); | |||||
// make dirty | |||||
String f2name = "tar/bz2/asf-logo-huge.tar.bz2"; | |||||
String f3name = "asf-logo.gif.md5"; | |||||
String f4name = "copy.filterset.filtered"; | |||||
bft.writeProperties("f2name="+f2name); | |||||
bft.writeProperties("f3name="+f3name); | |||||
bft.writeProperties("f4name="+f4name); | |||||
bft.doTarget("modifiedselectortest-makeDirty"); | |||||
// third run | |||||
String results = selectionString(s); | |||||
StringBuffer expected = new StringBuffer(); | |||||
for (int i=0; i<filenames.length; i++) { | |||||
String ch = "F"; | |||||
if (files[i].isDirectory()) ch = "T"; | |||||
if (filenames[i].equalsIgnoreCase(f3name)) ch = "T"; | |||||
if (filenames[i].equalsIgnoreCase(f4name)) ch = "T"; | |||||
expected.append(ch); | |||||
} | |||||
assertEquals( | |||||
"Wrong files selected. Differing files: " // info text | |||||
+ resolve(diff(expected.toString(), results)), // list of files | |||||
expected.toString(), // expected result | |||||
results // result | |||||
); | |||||
} finally { | |||||
// cleanup the environment | |||||
cleanupBed(); | |||||
(new java.io.File(cachefile)).delete(); | |||||
if (bft!=null) bft.deletePropertiesfile(); | |||||
} | |||||
} | |||||
/** Checks whether a cache file is created. */ | |||||
public void testCreatePropertiesCacheDirect() { | |||||
File basedir = getSelector().getProject().getBaseDir(); | |||||
File cachefile = new File(basedir, "cachefile.properties"); | |||||
PropertiesfileCache cache = new PropertiesfileCache(); | |||||
cache.setCachefile(cachefile); | |||||
cache.put("key", "value"); | |||||
cache.save(); | |||||
assertTrue("Cachefile not created.", cachefile.exists()); | |||||
cache.delete(); | |||||
assertFalse("Cachefile not deleted.", cachefile.exists()); | |||||
} | |||||
/** Checks whether a cache file is created. */ | |||||
public void testCreatePropertiesCacheViaModifiedSelector() { | |||||
File basedir = getSelector().getProject().getBaseDir(); | |||||
File cachefile = new File(basedir, "cachefile.properties"); | |||||
try { | |||||
// initialize test environment (called "bed") | |||||
makeBed(); | |||||
// Configure the selector | |||||
ModifiedSelector s = (ModifiedSelector)getSelector(); | |||||
s.addParam("cache.cachefile", cachefile); | |||||
ModifiedSelector.CacheName cacheName = new ModifiedSelector.CacheName(); | |||||
cacheName.setValue("propertyfile"); | |||||
s.setCache(cacheName); | |||||
s.setUpdate(true); | |||||
// does the selection | |||||
String results = selectionString(s); | |||||
// evaluate correctness | |||||
assertTrue("Cache file is not created.", cachefile.exists()); | |||||
} finally { | |||||
cleanupBed(); | |||||
if (cachefile!=null) cachefile.delete(); | |||||
} | |||||
} | |||||
/** | |||||
* In earlier implementations there were problems with the <i>order</i> | |||||
* of the <param>s. The scenario was <pre> | |||||
* <custom class="ModifiedSelector"> | |||||
* <param name="cache.cachefile" value="mycache.properties" /> | |||||
* <param name="cache" value="propertyfiles" /> | |||||
* </custom> | |||||
* </pre> It was important first to set the cache and then to set | |||||
* the cache´s configuration parameters. That results in the reorganized | |||||
* configure() method of ModifiedSelector. This testcase tests that. | |||||
*/ | |||||
public void testCreatePropertiesCacheViaCustomSelector() { | |||||
File cachefile = org.apache.tools.ant.util.FileUtils.newFileUtils() | |||||
.createTempFile("tmp-cache-", ".properties", null); | |||||
try { | |||||
// initialize test environment (called "bed") | |||||
makeBed(); | |||||
// Configure the selector | |||||
ExtendSelector s = new ExtendSelector(); | |||||
s.setClassname("org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"); | |||||
s.addParam(createParam("update", "true")); | |||||
s.addParam(createParam("cache.cachefile", cachefile.getAbsolutePath())); | |||||
s.addParam(createParam("cache", "propertyfile")); | |||||
// does the selection | |||||
String results = selectionString(s); | |||||
// evaluate correctness | |||||
assertTrue("Cache file is not created.", cachefile.exists()); | |||||
} finally { | |||||
cleanupBed(); | |||||
if (cachefile!=null) cachefile.delete(); | |||||
} | |||||
} | |||||
public void testEqualComparatorViaSelector() { | |||||
ModifiedSelector s = (ModifiedSelector)getSelector(); | |||||
ModifiedSelector.ComparatorName compName = new ModifiedSelector.ComparatorName(); | |||||
compName.setValue("equal"); | |||||
s.setComparator(compName); | |||||
try { | |||||
performTests(s, "TTTTTTTTTTTT"); | |||||
} finally { | |||||
s.getCache().delete(); | |||||
} | |||||
} | |||||
public void testRuleComparatorViaSelector() { | |||||
ModifiedSelector s = (ModifiedSelector)getSelector(); | |||||
ModifiedSelector.ComparatorName compName = new ModifiedSelector.ComparatorName(); | |||||
compName.setValue("rule"); | |||||
s.setComparator(compName); | |||||
try { | |||||
performTests(s, "TTTTTTTTTTTT"); | |||||
} finally { | |||||
s.getCache().delete(); | |||||
} | |||||
} | |||||
public void testHashvalueAlgorithm() { | |||||
HashvalueAlgorithm algo = new HashvalueAlgorithm(); | |||||
doTest(algo); | |||||
} | |||||
public void testDigestAlgorithmMD5() { | |||||
DigestAlgorithm algo = new DigestAlgorithm(); | |||||
algo.setAlgorithm("MD5"); | |||||
doTest(algo); | |||||
} | |||||
public void testDigestAlgorithmSHA() { | |||||
DigestAlgorithm algo = new DigestAlgorithm(); | |||||
algo.setAlgorithm("SHA"); | |||||
doTest(algo); | |||||
} | |||||
public void testPropertyfileCache() { | |||||
PropertiesfileCache cache = new PropertiesfileCache(); | |||||
File cachefile = new File("cache.properties"); | |||||
cache.setCachefile(cachefile); | |||||
doTest(cache); | |||||
assertFalse("Cache file not deleted.", cachefile.exists()); | |||||
} | |||||
public void testEqualComparator() { | |||||
EqualComparator comp = new EqualComparator(); | |||||
doTest(comp); | |||||
} | |||||
public void testRuleComparator() { | |||||
RuleBasedCollator comp = (RuleBasedCollator)RuleBasedCollator.getInstance(); | |||||
doTest(comp); | |||||
} | |||||
public void testScenarioCoreSelectorDefaults() { | |||||
doScenarioTest("modifiedselectortest-scenario-coreselector-defaults", "cache.properties"); | |||||
} | |||||
public void testSceanrioCoreSelectorSettings() { | |||||
doScenarioTest("modifiedselectortest-scenario-coreselector-settings", "core.cache.properties"); | |||||
} | |||||
public void testScenarioCustomSelectorSettings() { | |||||
doScenarioTest("modifiedselectortest-scenario-customselector-settings", "core.cache.properties"); | |||||
} | |||||
public void doScenarioTest(String target, String cachefilename) { | |||||
BFT bft = new BFT(); | |||||
bft.setUp(); | |||||
File basedir = bft.getProject().getBaseDir(); | |||||
File cachefile = new File(basedir, cachefilename); | |||||
try { | |||||
// do the actions | |||||
bft.doTarget("modifiedselectortest-scenario-clean"); | |||||
bft.doTarget(target); | |||||
// the directories to check | |||||
File to1 = new File(basedir, "selectortest/to-1"); | |||||
File to2 = new File(basedir, "selectortest/to-2"); | |||||
File to3 = new File(basedir, "selectortest/to-3"); | |||||
// do the checks | |||||
assertTrue("Cache file not created.", cachefile.exists()); | |||||
assertTrue("Not enough files copied on first time.", to1.list().length>5); | |||||
assertTrue("Too much files copied on second time.", to2.list().length==0); | |||||
assertTrue("Too much files copied on third time.", to3.list().length==2); | |||||
// don´t catch the JUnit exceptions | |||||
} finally { | |||||
bft.doTarget("modifiedselectortest-scenario-clean"); | |||||
bft.deletePropertiesfile(); | |||||
bft.tearDown(); | |||||
cachefile.delete(); | |||||
} | |||||
} | |||||
// ==================== Test interface semantic =================== | |||||
/** | |||||
* This method does some common test for algorithm implementations. | |||||
* An algorithm must return always the same value for the same file and | |||||
* it must not return <i>null</i>. | |||||
* | |||||
* @param algo configured test object | |||||
*/ | |||||
protected void doTest(Algorithm algo) { | |||||
assertTrue("Algorithm not proper configured.", algo.isValid()); | |||||
try { | |||||
makeBed(); | |||||
for (int i=0; i<files.length; i++) { | |||||
File file = files[i]; // must not be a directory | |||||
if (file.isFile()) { | |||||
// get the Hashvalues | |||||
String hash1 = algo.getValue(file); | |||||
String hash2 = algo.getValue(file); | |||||
String hash3 = algo.getValue(file); | |||||
String hash4 = algo.getValue(file); | |||||
String hash5 = algo.getValue(new File(file.getAbsolutePath())); | |||||
// Assert !=null and equality | |||||
assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash1); | |||||
assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash2); | |||||
assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash3); | |||||
assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash4); | |||||
assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash5); | |||||
assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash2); | |||||
assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash3); | |||||
assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash4); | |||||
assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash5); | |||||
}//if-isFile | |||||
}//for | |||||
} finally { | |||||
cleanupBed(); | |||||
} | |||||
} | |||||
/** | |||||
* This method does some common test for cache implementations. | |||||
* A cache must return a stored value and a valid iterator. | |||||
* After calling the delete() the cache must be empty. | |||||
* | |||||
* @param algo configured test object | |||||
*/ | |||||
protected void doTest(Cache cache) { | |||||
assertTrue("Cache not proper configured.", cache.isValid()); | |||||
String key1 = "key1"; | |||||
String value1 = "value1"; | |||||
String key2 = "key2"; | |||||
String value2 = "value2"; | |||||
// given cache must be empty | |||||
Iterator it1 = cache.iterator(); | |||||
assertFalse("Cache is not empty", it1.hasNext()); | |||||
// cache must return a stored value | |||||
cache.put(key1, value1); | |||||
cache.put(key2, value2); | |||||
assertEquals("cache returned wrong value", value1, cache.get(key1)); | |||||
assertEquals("cache returned wrong value", value2, cache.get(key2)); | |||||
// test the iterator | |||||
Iterator it2 = cache.iterator(); | |||||
Object returned = it2.next(); | |||||
boolean ok = (key1.equals(returned) || key2.equals(returned)); | |||||
String msg = "Iterator returned unexpected value." | |||||
+ " key1.equals(returned)="+key1.equals(returned) | |||||
+ " key2.equals(returned)="+key2.equals(returned) | |||||
+ " returned="+returned | |||||
+ " ok="+ok; | |||||
assertTrue(msg, ok); | |||||
// clear the cache | |||||
cache.delete(); | |||||
Iterator it3 = cache.iterator(); | |||||
assertFalse("Cache is not empty", it1.hasNext()); | |||||
} | |||||
/** | |||||
* This method does some common test for comparator implementations. | |||||
* | |||||
* @param algo configured test object | |||||
*/ | |||||
protected void doTest(Comparator comp) { | |||||
Object o1 = new String("string1"); | |||||
Object o2 = new String("string2"); | |||||
Object o3 = new String("string2"); // really "2" | |||||
assertTrue("Comparator gave wrong value.", comp.compare(o1, o2) != 0); | |||||
assertTrue("Comparator gave wrong value.", comp.compare(o1, o3) != 0); | |||||
assertTrue("Comparator gave wrong value.", comp.compare(o2, o3) == 0); | |||||
} | |||||
// ======================== Helper methods ======================== | |||||
private Parameter createParam(String name, String value) { | |||||
Parameter p = new Parameter(); | |||||
p.setName(name); | |||||
p.setValue(value); | |||||
return p; | |||||
} | |||||
private class BFT extends org.apache.tools.ant.BuildFileTest { | |||||
BFT() { super("nothing"); } | |||||
BFT(String name) { | |||||
super(name); | |||||
} | |||||
String propfile = "ModifiedSelectorTest.properties"; | |||||
boolean isConfigured = false; | |||||
public void setUp() { | |||||
configureProject("src/etc/testcases/types/selectors.xml"); | |||||
isConfigured = true; | |||||
} | |||||
public void tearDown() { } | |||||
public void doTarget(String target) { | |||||
if (!isConfigured) setUp(); | |||||
executeTarget(target); | |||||
} | |||||
public void writeProperties(String line) { | |||||
if (!isConfigured) setUp(); | |||||
File dir = getProject().getBaseDir(); | |||||
File file = new File(dir, propfile); | |||||
try { | |||||
java.io.FileWriter out = new java.io.FileWriter(file, true); | |||||
out.write(line); | |||||
out.write(System.getProperty("line.separator")); | |||||
out.flush(); | |||||
out.close(); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
public void deletePropertiesfile() { | |||||
if (!isConfigured) setUp(); | |||||
new File(getProject().getBaseDir(), propfile).delete(); | |||||
} | |||||
public org.apache.tools.ant.Project getProject() { | |||||
return super.getProject(); | |||||
} | |||||
}//class-BFT | |||||
}//class-ModifiedSelectorTest |