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 | |||||