From 3c1db41ac7c7a94c4530a64c42b1b5b5278f5263 Mon Sep 17 00:00:00 2001 From: Jan Materne Date: Sat, 13 Sep 2003 16:35:52 +0000 Subject: [PATCH] New container. Bugzilla Report 20474 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275236 13f79535-47bb-0310-9956-ffa450edef68 --- WHATSNEW | 3 + docs/manual/CoreTypes/selectors-program.html | 132 +++- docs/manual/CoreTypes/selectors.html | 217 +++++- src/etc/testcases/types/selectors.xml | 136 +++- .../org/apache/tools/ant/taskdefs/Delete.java | 12 +- .../tools/ant/taskdefs/MatchingTask.java | 12 +- .../tools/ant/types/AbstractFileSet.java | 12 +- .../selectors/BaseSelectorContainer.java | 12 +- .../types/selectors/SelectorContainer.java | 10 +- .../selectors/modifiedselector/Algorithm.java | 85 +++ .../selectors/modifiedselector/Cache.java | 109 +++ .../modifiedselector/DigestAlgorithm.java | 241 ++++++ .../modifiedselector/EqualComparator.java | 97 +++ .../modifiedselector/HashvalueAlgorithm.java | 116 +++ .../modifiedselector/ModifiedSelector.java | 653 ++++++++++++++++ .../modifiedselector/PropertiesfileCache.java | 255 +++++++ .../ant/types/selectors/BaseSelectorTest.java | 74 +- .../types/selectors/ModifiedSelectorTest.java | 707 ++++++++++++++++++ 18 files changed, 2853 insertions(+), 30 deletions(-) create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java create mode 100644 src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java create mode 100644 src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java diff --git a/WHATSNEW b/WHATSNEW index 0e62d0a88..6e186d009 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -597,6 +597,9 @@ Other changes: * additional shortcuts for ant options (-d --> -debug, -e --> -emacs, -h --> -help, -p --> -projecthelp, -s --> -find). +* new selector . "cache" was renamed to "modified". + Bugzilla Report 20474. + Changes from Ant 1.5.3 to Ant 1.5.4 =================================== diff --git a/docs/manual/CoreTypes/selectors-program.html b/docs/manual/CoreTypes/selectors-program.html index 8d94edffa..15a225cb7 100755 --- a/docs/manual/CoreTypes/selectors-program.html +++ b/docs/manual/CoreTypes/selectors-program.html @@ -18,7 +18,7 @@
  1. Custom Selectors -

    This is the category that Ant provides specifically for youto +

    This is the category that Ant provides specifically for you to define your own Selectors. Anywhere you want to use your selector you use the <custom> element and specify the class name of your selector within it. See the @@ -86,7 +86,8 @@ org.apache.tools.ant.types.selectors.SelectorContainer. This is an interface, so you will also have to add an implementation for the method in the classes which implement it, namely - org.apache.tools.ant.types.AbstractFileSet and + org.apache.tools.ant.types.AbstractFileSet, + org.apache.tools.ant.taskdefs.MatchingTask and org.apache.tools.ant.types.selectors.BaseSelectorContainer. Once it is in there, it will be available everywhere that core selectors are appropriate.

    @@ -118,10 +119,131 @@
+

Testing Selectors

+ +

For a robust component (and selectors are (Project)Component´s) tests are + necessary. For testing Tasks we use JUnit TestCases - more specific + org.apache.tools.ant.BuildFileTest extends junit.framework.TestCase. + 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 BaseExtendSelector its features have to be tested also (e.g. setError()). +

+ +

That´s why we have a base class for doing our selector tests: + org.apache.tools.ant.types.selectors.BaseSelectorTest.

+ +

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.

+ +

Because the term "testcase" or "testenvironment" are so often used, this + special testenvironment got a new name: bed. Like you initialize the + test environment by calling setUp() and cleaning by calling tearDown() (or like + to make your bed before go sleeping) you have to do that work with your + bed by calling makeBed() respecitive cleanupBed().

+ +

A usual test scenario is

    +
  1. make the bed
  2. +
  3. instantiate the selector
  4. +
  5. configure the selector
  6. +
  7. let the selector do some work
  8. +
  9. verify the work
  10. +
  11. clean the bed
  12. +
+

+ +

For common way of instantiation you have to override the getInstance() + simply by returning a new object of your selector. For easier "selection and verification work" + BaseSelectorTest provides the method performTests() which + iterates over all files (and directories) in the String array filenames + 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.

+ +

An example test would be:

+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();
+        }
+    }
+}
+    
+ As an example of an error JUnit could log
+    [junit]     FAILED
+    [junit] Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz
+    [junit] expected:<FTTTFTTTF...> but was:<TTTTTTTTT...>
+    [junit] junit.framework.ComparisonFailure: Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz
+    [junit] expected:<FTTTFTTTF...> but was:<TTTTTTTTT...>
+    [junit]     at junit.framework.Assert.assertEquals(Assert.java:81)
+    [junit]     at org.apache.tools.ant.types.selectors.BaseSelectorTest.performTest(BaseSelectorTest.java:194)
+    

+ +

Described above the test class should provide a getInstance() + method. But that isn´t used here. The used getSelector() method is + implemented in the base class and gives an instance of an Ant Project to + the selector. This is usually done inside normal build file runs, but not + inside this special environment, so this method gives the selector the + ability to use its own Project object (getProject()), for example + for logging.

+ + +

Logging

+ +

During development and maybe later you sometimes need the output of information. + Therefore Logging is needed. Because the selector extends BaseExtendSelector or directly + BaseSelector it is an Ant DataType and therefore a ProjectComponent.
+ That means that you have access to the project object and its logging capability. + ProjectComponent itself provides log methods which will do the + access to the project instance. Logging is therefore done simply with: +

+        log( "message" );
+    
+ or +
+        log( "message" , loglevel );
+    
+ where the loglevel is one of the values
    +
  • org.apache.tools.ant.Project.MSG_ERR
  • +
  • org.apache.tools.ant.Project.MSG_WARN
  • +
  • org.apache.tools.ant.Project.MSG_INFO (= default)
  • +
  • org.apache.tools.ant.Project.MSG_VERBOSE
  • +
  • org.apache.tools.ant.Project.MSG_DEBUG
  • +
+

+
-

Copyright © 2002 Apache Software +

Copyright © 2002-2003 Apache Software Foundation. All rights Reserved.

- - + \ No newline at end of file diff --git a/docs/manual/CoreTypes/selectors.html b/docs/manual/CoreTypes/selectors.html index 8e807d25f..fad6ec0c0 100755 --- a/docs/manual/CoreTypes/selectors.html +++ b/docs/manual/CoreTypes/selectors.html @@ -40,28 +40,31 @@
  • <contains> - Select - files that contain a particular text string + files that contain a particular text string
  • <date> - Select files that have been modified either before or after a particular date - and time + and time
  • <depend> - Select files that have been modified more recently than equivalent files - elsewhere + elsewhere
  • <depth> - Select files - that appear so many directories down in a directory tree + that appear so many directories down in a directory tree
  • <different> - Select files - that are different from those elsewhere + that are different from those elsewhere
  • <filename> - Select 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.
  • <present> - 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
  • <containsregexp> - Select - files that match a regular expression + files that match a regular expression
  • <size> - Select files - that are larger or smaller than a particular number of bytes. + that are larger or smaller than a particular number of bytes.
  • <type> - Select files - that are either regular files or directories. + that are either regular files or directories.
  • +
  • <modified> - Select files if + the return value of the configured algorithm is different from that + stored in a cache.
@@ -465,7 +468,7 @@ expression - Specifies the regular expression that must + Specifies the regular expression that must match true in every file Yes @@ -479,10 +482,10 @@ </fileset> -

Selects all the text files that match the regular expression +

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). - +

Size Selector

@@ -592,6 +595,193 @@ + +

Modified Selector

+

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.

+

Because this selector is highly configurable the order in which the selection is done + is:

    +
  1. get the absolute path for the file
  2. +
  3. get the cached value from the configured cache (absolute path as key)
  4. +
  5. get the new value from the configured algorithm
  6. +
  7. compare these two values with the configured comparator
  8. +
  9. update the cache if needed and wished
  10. +
  11. do the selection according to the comparison result
  12. +
+ The comparison, computing of the hashvalue and the store is done by implementation + of special interfaces. Therefore they may provide additional parameters.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
algorithm The type of algorithm should be used. + Acceptable values are (further information see later): +
    +
  • hashvalue - HashvalueAlgorithm
  • +
  • digest - DigestAlgorithm
  • +
+
No, defaults to digest
cache The type of cache should be used. + Acceptable values are (further information see later): +
    +
  • propertyfile - PropertyfileCache
  • +
+
No, defaults to propertyfile
comparator The type of comparator should be used. + Acceptable values are (further information see later): +
    +
  • equal - EqualComparator
  • +
  • rule - java.text.RuleBasedCollator
  • +
+
No, defaults to equal
update Should the cache be updated when values differ? (boolean) No, defaults to true
seldirs Should directories be selected? (boolean) No, defaults to true
+ +

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:

    +
  • algorithm : same as attribute algorithm
  • +
  • cache : same as attribute cache
  • +
  • comparator : same as attribute cache
  • +
  • update : same as attribute comparator
  • +
  • seldirs : same as attribute seldirs
  • +
  • algorithm.* : Value is transfered to the algorithm via its + setXX-methods
  • +
  • cache.* : Value is transfered to the cache via its + setXX-methods
  • +
  • comparator.* : Value is transfered to the comparator via its + setXX-methods
  • +

+ + + + + + + + + + + + + + + + + + + + +
Algorithm´s
NameDescription
hashvalue Reads the content of a file into a java.lang.String + and use thats hashValue(). No additional configuration required. +
digest Uses java.security.MessageDigest. This Algorithm supports + the following attributes: +
    +
  • algorithm.algorithm (optional): Name of the Digest algorithm + (e.g. 'MD5' or 'SHA', default = MD5)
  • +
  • algorithm.provider (optional): Name of the Digest provider + (default = null)
  • +
+
Cache´s
propertyfile Use the java.util.Properties class and its possibility + to load and store to file. + This Cache implementation supports the following attributes: +
    +
  • cache.cachefile (optional): Name of the properties-file + (default = cache.properties)
  • +
+
+ +

Here are some examples of how to use the Modified Selector:

+ +
+    <copy todir="dest">
+        <filelist dir="src">
+            <modified/>
+        </filelist>
+    </copy
+    
+

This will copy all files from src to dest which content has changed. + Using an updating PropertyfileCache with cache.properties and + MD5-DigestAlgorithm.

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

This is the same example rewritten as CoreSelector with setting the all the values + (same as defaults are).

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

And this is the same rewritten as CustomSelector.

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

A useful scenario for this selector inside a build environment + for homepage generation (e.g. with + Apache Forrest). Here all changed files are uploaded to the server. The + CacheSelector saves therefore much upload time.

+ +

Selector Containers

@@ -992,4 +1182,3 @@ - diff --git a/src/etc/testcases/types/selectors.xml b/src/etc/testcases/types/selectors.xml index 5759793ad..08e9d7c13 100644 --- a/src/etc/testcases/types/selectors.xml +++ b/src/etc/testcases/types/selectors.xml @@ -85,12 +85,12 @@ - + - + @@ -108,4 +108,134 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/taskdefs/Delete.java b/src/main/org/apache/tools/ant/taskdefs/Delete.java index 258892bdc..7c2fec628 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Delete.java +++ b/src/main/org/apache/tools/ant/taskdefs/Delete.java @@ -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.SizeSelector; 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. @@ -443,6 +444,16 @@ public class Delete extends MatchingTask { 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 * @param selector the selector to be added @@ -676,4 +687,3 @@ public class Delete extends MatchingTask { } } } - diff --git a/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java b/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java index 3257537dd..77616c716 100644 --- a/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java @@ -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.SizeSelector; 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 @@ -454,6 +455,15 @@ public abstract class MatchingTask extends Task implements SelectorContainer { 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 * @param selector the selector to add @@ -471,4 +481,4 @@ public abstract class MatchingTask extends Task implements SelectorContainer { protected final FileSet getImplicitFileSet() { return fileset; } -} +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java index 66ce5a8ff..b1c0e2461 100644 --- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java +++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java @@ -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.SelectorScanner; 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 @@ -680,6 +681,15 @@ public abstract class AbstractFileSet extends DataType implements Cloneable, 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 * @param selector the selector to add @@ -721,4 +731,4 @@ public abstract class AbstractFileSet extends DataType implements Cloneable, } } -} +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java index 62534fe98..9cfbb69cd 100644 --- a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java @@ -60,6 +60,7 @@ import java.util.Vector; import org.apache.tools.ant.BuildException; 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. @@ -328,6 +329,14 @@ public abstract class BaseSelectorContainer extends BaseSelector 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 @@ -338,5 +347,4 @@ public abstract class BaseSelectorContainer extends BaseSelector appendSelector(selector); } -} - +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java index bccbf6c0b..c121fcda4 100644 --- a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java +++ b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java @@ -55,8 +55,8 @@ package org.apache.tools.ant.types.selectors; import java.util.Enumeration; - 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. @@ -207,6 +207,13 @@ public interface SelectorContainer { */ 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 * @param selector the selector to add @@ -214,4 +221,3 @@ public interface SelectorContainer { */ void add(FileSelector selector); } - diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java new file mode 100644 index 000000000..8b3f94bf8 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java @@ -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 + * . + */ + +package org.apache.tools.ant.types.selectors.modifiedselector; + + +import java.io.File; + + +/** + * The Algorithm 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 true if all is ok, otherwise false. + */ + 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); +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java new file mode 100644 index 000000000..e21879a5d --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java @@ -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 + * . + */ + +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 + * order. + * 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 true if all is ok, otherwise false. + */ + 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(); +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java new file mode 100644 index 000000000..6e2462a65 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java @@ -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 + * . + */ + +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 s. + * Supported s are: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
namevaluesdescriptionrequired
algorithm.algorithm MD5 | SHA (default provider) name of the algorithm the provider should use no, defaults to MD5
algorithm.provider name of the provider to use no, defaults to null
+ * + * @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 true if all is ok, otherwise false. + */ + 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(""); + return buf.toString(); + } +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java new file mode 100644 index 000000000..665e13882 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java @@ -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 + * . + */ + +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"; + } +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java new file mode 100644 index 000000000..b4fc89fb5 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java @@ -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 + * . + */ + +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 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 null 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"; + } + +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java new file mode 100644 index 000000000..894450bfa --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java @@ -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 + * . + */ + +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; + + +/** + *

Selector class that uses Algorithm, Cache and Comparator + * for its work. + * The Algorithm is used for computing a hashvalue for a file. + * The Comparator decides whether to select or not. + * The Cache stores the other value for comparison by the Comparator + * in a persistent manner.

+ * + *

The ModifiedSelector is implemented as a CoreSelector and uses default + * values for all its attributes therefore the simpliest example is

+ *   
+ *       
+ *           
+ *       
+ *   
+ * 

+ * + *

The same example rewritten as CoreSelector with setting the all values + * (same as defaults are) would be

+ *   
+ *       
+ *           
+ *               
+ *               
+ *           
+ *       
+ *   
+ * 

+ * + *

And the same rewritten as CustomSelector would be

+ *   
+ *       
+ *           
+ *               
+ *               
+ *               
+ *               
+ *               
+ *               
+ *           
+ *       
+ *   
+ * 

+ * + *

All these three examples copy the files from src to dest + * using the ModifiedSelector. The ModifiedSelector uses the PropertyfileCache + * , the DigestAlgorithm and the EqualComparator for its + * work. The PropertyfileCache stores key-value-pairs in a simple java + * properties file. The filename is cache.properties. The update + * flag lets the selector update the values in the cache (and on first call + * creates the cache). The DigestAlgorithm 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 EqualComparator which returns 'true' (more correct a value not + * equals zero (1)) if the values are not the same using simple String + * comparison.

+ * + *

A useful scenario for this selector is inside a build environment + * for homepage generation (e.g. with + * Apache Forrest).

+ * 
+ *      generate the site using forrest 
+ *     
+ *
+ *      upload the changed files 
+ *     
+ *         
+ *             
+ *         
+ *     
+ * 
+ * 
Here all changed files are uploaded to the server. The + * ModifiedSelector saves therefore much upload time.

+ * + *

This selector supports the following nested param´s: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
namevaluesdescriptionrequired
cache propertyfile which cache implementation should be used
    + *
  • propertyfile - using java.util.Properties
  • + *
no, defaults to 'propertyfile'
algorithm hashvalue | digest which algorithm implementation should be used + *
  • hashvalue - loads the file content into a String and + * uses its hashValue() method
  • + *
  • digest - uses java.security.MessageDigest class + *
  • no, defaults to digest
    comparator equal | role which comparator implementation should be used + *
  • equal - simple comparison using String.equals()
  • + *
  • role - uses java.text.RuleBasedCollator class + *
  • no, defaults to equal
    update true | false If set to true, the cache will be stored, otherwise the values + * will be lost. no, defaults to true
    seldirs true | false If set to true, directories will be selected otherwise not no, defaults to true
    cache.* depends on used cache value is stored and given to the Cache-Object for initialisation depends on used cache
    algorithm.* depends on used algorithm value is stored and given to the Algorithm-Object for initialisation depends on used algorithm
    comparator.* depends on used comparator value is stored and given to the Comparator-Object for initialisation depends on used comparator
    + * If another name is used a BuildException "Invalid parameter" is thrown.

    + * + *

    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 setXX methods can be used. E.g. the DigestAlgorithm + * can use a specified provider for computing its value. For selecting this + * there is a setProvider(String providername) method. So you can use + * a nested . + * + * + * @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 after 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. + *

    Because some problems while configuring from Selector + * the configuration is done in the following order:

      + *
    1. collect the configuration data
    2. + *
    3. wait for the first isSelected() call
    4. + *
    5. set the default values
    6. + *
    7. set values for name pattern '*': update, cache, algorithm, comparator
    8. + *
    9. set values for name pattern '*.*: cache.cachefile, ...
    10. + *

    + *

    This configuration algorithm is needed because you don´t know + * the order of arriving config-data. E.g. if you first set the + * cache.cachefilename and after that the cache itself, + * the default value for cachefilename is used, because setting the + * cache implies creating a new Cache instance - with its defaults.

    + */ + 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 update attribute. + * @param update new value + */ + public void setUpdate(boolean update) { + this.update = update; + } + + + /** + * Support for seldirs 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 tags. + * Parameter named cache, algorithm, + * comparator or update are mapped to + * the respective set-Method. + * Parameter which names starts with cache. or + * algorithm. or comparator. 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" }; + } + } + +} \ No newline at end of file diff --git a/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java new file mode 100644 index 000000000..2b681a49b --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java @@ -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 + * . + */ + +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 + * for defining, where to store the + * properties file. + * + * The ModifiedSelector sets the cachefile to the default value + * cache.properties. + * + * Supported s are: + * + * + * + * + * + * + * + * + * + * + *
    namevaluesdescriptionrequired
    cache.cachefile path to file the name of the properties file yes
    + * + * @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(""); + return buf.toString(); + } +} \ No newline at end of file diff --git a/src/testcases/org/apache/tools/ant/types/selectors/BaseSelectorTest.java b/src/testcases/org/apache/tools/ant/types/selectors/BaseSelectorTest.java index 1d913abfb..6ed078851 100644 --- a/src/testcases/org/apache/tools/ant/types/selectors/BaseSelectorTest.java +++ b/src/testcases/org/apache/tools/ant/types/selectors/BaseSelectorTest.java @@ -108,6 +108,18 @@ public abstract class BaseSelectorTest extends TestCase { 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() { return project; } @@ -171,6 +183,66 @@ public abstract class BaseSelectorTest extends TestCase { 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 filelist.length()) + ? filelist.length() + : filenames.length; + for (int i=0; iCreates a testbed. We avoid the dreaded "test" word so that we * don't falsely identify this as a test to be run. The actual @@ -252,4 +324,4 @@ public abstract class BaseSelectorTest extends TestCase { -} +} \ No newline at end of file diff --git a/src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java b/src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java new file mode 100644 index 000000000..c229fb6d2 --- /dev/null +++ b/src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java @@ -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 + * . + */ + +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 + *
  • try fist time --> should select all
  • + *
  • try second time --> should select no files (only directories)
  • + *
  • modify timestamp of one file and content of a nother one
  • + *
  • try third time --> should select only the file with modified + * content
  • + */ + 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 selector. Used values are:
      + *
    • Cache: Propertyfile, + * cachefile={java.io.tmpdir}/mycache.txt
    • + *
    • Algorithm: Digest + * algorithm=SHA, Provider=null
    • + *
    • Comparator: java.text.RuleBasedCollator + *
    • Update: true
    • + */ + 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; iorder + * of the s. The scenario was
      +     *   
      +     *       
      +     *       
      +     *   
      +     * 
      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 null. + * + * @param algo configured test object + */ + protected void doTest(Algorithm algo) { + assertTrue("Algorithm not proper configured.", algo.isValid()); + try { + makeBed(); + + for (int i=0; i