You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by jh...@apache.org on 2004/07/10 19:15:37 UTC

cvs commit: ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector DigestAlgorithm.java ModifiedSelector.java PropertiesfileCache.java

jhm         2004/07/10 10:15:37

  Modified:    src/etc/testcases/types selectors.xml
               src/testcases/org/apache/tools/ant/types/selectors
                        ModifiedSelectorTest.java
               docs/manual/CoreTypes selectors.html
               src/main/org/apache/tools/ant/types/selectors/modifiedselector
                        DigestAlgorithm.java ModifiedSelector.java
                        PropertiesfileCache.java
  Added:       src/testcases/org/apache/tools/ant/types/selectors
                        MockAlgorithm.java MockCache.java
                        MockComparator.java
  Log:
  Small redesign of ModifiedSelector. Integrating BugIDs 29742+29743. Adding support of custom classes. Checkstyle.
  
  Revision  Changes    Path
  1.8       +15 -0     ant/src/etc/testcases/types/selectors.xml
  
  Index: selectors.xml
  ===================================================================
  RCS file: /home/cvs/ant/src/etc/testcases/types/selectors.xml,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- selectors.xml	30 Sep 2003 09:45:21 -0000	1.7
  +++ selectors.xml	10 Jul 2004 17:15:37 -0000	1.8
  @@ -242,4 +242,19 @@
         </copy>
     </target>
   
  +  <target name="modifiedselectortest-customClasses" depends="modifiedselectortest-scenario-prepare">
  +      <property name="pkg.live" value="org.apache.tools.ant.types.selectors.modifiedselector"/>
  +      <property name="pkg.test" value="org.apache.tools.ant.types.selectors"/>
  +      <fileset id="fs.mod" dir="${test.dir}/src">
  +          <modified
  +              algorithmclass="${pkg.test}.MockAlgorithm"
  +              cacheclass="${pkg.test}.MockCache"
  +              comparatorclass="${pkg.test}.MockComparator"
  +          />
  +      </fileset>
  +      <fileset id="fs.full" dir="${test.dir}/src"/>
  +      <property name="fs.mod.value"  refid="fs.mod"/>
  +      <property name="fs.full.value" refid="fs.full"/>
  +  </target>
  +
   </project>
  
  
  
  1.8       +632 -289  ant/src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java
  
  Index: ModifiedSelectorTest.java
  ===================================================================
  RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ModifiedSelectorTest.java	9 Mar 2004 16:49:07 -0000	1.7
  +++ ModifiedSelectorTest.java	10 Jul 2004 17:15:37 -0000	1.8
  @@ -29,6 +29,12 @@
   import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.types.Parameter;
   
  +// inside MockProject
  +import org.apache.tools.ant.Project;
  +import org.apache.tools.ant.Target;
  +import org.apache.tools.ant.Task;
  +import org.apache.tools.ant.BuildEvent;
  +
   // The classes to test
   import org.apache.tools.ant.types.selectors.modifiedselector.*;
   
  @@ -36,15 +42,22 @@
   /**
    * Unit tests for ModifiedSelector.
    *
  - * @version 2003-09-13
  + * @version 2004-07-07
    * @since  Ant 1.6
    */
   public class ModifiedSelectorTest extends BaseSelectorTest {
   
  +
  +    //  =====================  attributes  =====================
  +
  +
       /** Package of the CacheSelector classes. */
       private static String pkg = "org.apache.tools.ant.types.selectors.modifiedselector";
   
   
  +    //  =====================  constructors, factories  =====================
  +
  +
       public ModifiedSelectorTest(String name) {
           super(name);
       }
  @@ -59,6 +72,68 @@
       }
   
   
  +    //  =====================  JUnit stuff  =====================
  +
  +
  +
  +    /* There are two tests which cannot run until the test package is added
  +     * to the core classloader. See comment in ModifiedSelelector.loadClass().
  +     * The tests should pass then - but because the usual build wont add
  +     * these classes I exclude them from being executed:
  +     * - classloaderProblem_testCustomAlgorithm2
  +     * - classloaderProblem_testCustomClasses
  +     *
  +     * For activating decomment the suite method.
  +     *
  +     * the addTest-part can be generated via grep and sed:
  +     *   grep "void test" ModifiedSelectorTest.java
  +     *   | sed -e 's/() {/"));/'
  +     *         -e 's/public void /    suite.addTest(new ModifiedSelectorTest("/'
  +     */
  +
  +    /* * /
  +    // for test only - ignore tests where we arent work at the moment
  +    public static junit.framework.Test suite() {
  +        junit.framework.TestSuite suite= new junit.framework.TestSuite();
  +        suite.addTest(new ModifiedSelectorTest("testValidateWrongCache"));
  +        suite.addTest(new ModifiedSelectorTest("testValidateWrongAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testValidateWrongComparator"));
  +        suite.addTest(new ModifiedSelectorTest("testIllegalCustomAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testNonExistentCustomAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testCustomAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testPropcacheInvalid"));
  +        suite.addTest(new ModifiedSelectorTest("testPropertyfileCache"));
  +        suite.addTest(new ModifiedSelectorTest("testCreatePropertiesCacheDirect"));
  +        suite.addTest(new ModifiedSelectorTest("testCreatePropertiesCacheViaModifiedSelector"));
  +        suite.addTest(new ModifiedSelectorTest("testCreatePropertiesCacheViaCustomSelector"));
  +        suite.addTest(new ModifiedSelectorTest("testHashvalueAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testDigestAlgorithmMD5"));
  +        suite.addTest(new ModifiedSelectorTest("testDigestAlgorithmSHA"));
  +        suite.addTest(new ModifiedSelectorTest("testChecksumAlgorithm"));
  +        suite.addTest(new ModifiedSelectorTest("testChecksumAlgorithmCRC"));
  +        suite.addTest(new ModifiedSelectorTest("testChecksumAlgorithmAdler"));
  +        suite.addTest(new ModifiedSelectorTest("testEqualComparator"));
  +        suite.addTest(new ModifiedSelectorTest("testRuleComparator"));
  +        suite.addTest(new ModifiedSelectorTest("testEqualComparatorViaSelector"));
  +        suite.addTest(new ModifiedSelectorTest("testSeldirs"));
  +        suite.addTest(new ModifiedSelectorTest("testScenario1"));
  +        suite.addTest(new ModifiedSelectorTest("testScenarioCoreSelectorDefaults"));
  +        suite.addTest(new ModifiedSelectorTest("testScenarioCoreSelectorSettings"));
  +        suite.addTest(new ModifiedSelectorTest("testScenarioCustomSelectorSettings"));
  +
  +        suite.addTest(new ModifiedSelectorTest("classloaderProblem_testDelayUpdateTaskFinished"));
  +        suite.addTest(new ModifiedSelectorTest("classloaderProblem_testDelayUpdateTargetFinished"));
  +        suite.addTest(new ModifiedSelectorTest("classloaderProblem_testDelayUpdateBuildFinished"));
  +        suite.addTest(new ModifiedSelectorTest("classloaderProblem_testCustomAlgorithm2"));
  +        suite.addTest(new ModifiedSelectorTest("classloaderProblem_testCustomClasses"));
  +        return suite;
  +    }
  +    /* */
  +
  +
  +    // =======  testcases for the attributes and nested elements of the selector  =====
  +
  +
       /** Test right use of cache names. */
       public void testValidateWrongCache() {
           String name = "this-is-not-a-valid-cache-name";
  @@ -103,209 +178,177 @@
       }
   
   
  -    /**
  -     * 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.");
  +    public void testIllegalCustomAlgorithm() {
  +        try {
  +            String algo = getAlgoName("javax.swing.JFrame");
  +            fail("Illegal classname used.");
  +        } catch (Exception e) {
  +            assertTrue("Wrong exception type: " + e.getClass().getName(), e instanceof BuildException);
  +            assertEquals("Wrong exception message.",
  +                         "Specified class (javax.swing.JFrame) is not an Algorithm.",
  +                         e.getMessage());
  +
  +        }
       }
   
   
  -    /**
  -     * Tests whether the seldirs attribute is used.
  -     */
  -    public void testSeldirs() {
  -        ModifiedSelector s = (ModifiedSelector)getSelector();
  +    public void testNonExistentCustomAlgorithm() {
  +        boolean noExcThrown = false;
           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");
  -                }
  +            String algo = getAlgoName("non.existent.custom.Algorithm");
  +            noExcThrown = true;
  +        } catch (Exception e) {
  +            if (noExcThrown) {
  +                fail("does 'non.existent.custom.Algorithm' really exist?");
               }
  +            assertTrue("Wrong exception type: " + e.getClass().getName(), e instanceof BuildException);
  +            assertEquals("Wrong exception message.",
  +                         "Specified class (non.existent.custom.Algorithm) not found.",
  +                         e.getMessage());
  +
  +        }
  +    }
   
   
  -            s.setSeldirs(true);
  -            performTests(s, sbTrue.toString());
  -            s.getCache().delete();
  +    public void testCustomAlgorithm() {
  +        String algo = getAlgoName("org.apache.tools.ant.types.selectors.modifiedselector.HashvalueAlgorithm");
  +        assertTrue("Wrong algorithm used: "+algo, algo.startsWith("HashvalueAlgorithm"));
  +    }
   
  -            s.setSeldirs(false);
  -            performTests(s, sbFalse.toString());
  -            s.getCache().delete();
   
  -        } finally {
  -            cleanupBed();
  -            if (s!=null) s.getCache().delete();
  -        }
  +    public void classloaderProblem_testCustomAlgorithm2() {
  +        String algo = getAlgoName("org.apache.tools.ant.types.selectors.MockAlgorithm");
  +        assertTrue("Wrong algorithm used: "+algo, algo.startsWith("MockAlgorithm"));
       }
   
   
  -    /**
  -     * 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;
  +    public void classloaderProblem_testCustomClasses() {
  +        BFT bft = new BFT();
  +        bft.setUp();
           try {
  -            //
  -            // *****  initialize test environment (called "bed")  *****
  -            //
  -            makeBed();
  -            String results = null;
  +            // do the actions
  +            bft.doTarget("modifiedselectortest-customClasses");
  +            // do the checks - the buildfile stores the fileset as property
  +            String fsFullValue = bft.getProperty("fs.full.value");
  +            String fsModValue  = bft.getProperty("fs.mod.value");
  +
  +            assertNotNull("'fs.full.value' must be set.", fsFullValue);
  +            assertTrue("'fs.full.value' must not be null.", !"".equals(fsFullValue));
  +            assertTrue("'fs.full.value' must contain ant.bat.", fsFullValue.indexOf("ant.bat")>-1);
  +
  +            assertNotNull("'fs.mod.value' must be set.", fsModValue);
  +            // must be empty according to the Mock* implementations
  +            assertTrue("'fs.mod.value' must be empty.", "".equals(fsModValue));
  +        // don't catch the JUnit exceptions
  +        } finally {
  +            bft.doTarget("modifiedselectortest-scenario-clean");
  +            bft.deletePropertiesfile();
  +            bft.tearDown();
  +        }
  +    }
   
  -            // 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");
  +    public void classloaderProblem_testDelayUpdateTaskFinished() {
  +        doDelayUpdateTest(1);
  +    }
   
  -            //
  -            // *****  Second Run  *****
  -            // the second call should get no files, because no content
  -            // has changed
  -            //
  -            performTests(s, "TFFFFFFFFFFT");
   
  -            //
  -            // *****  make some files dirty  *****
  -            //
  +    public void classloaderProblem_testDelayUpdateTargetFinished() {
  +        doDelayUpdateTest(2);
  +    }
   
  -            // 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");
  +    public void classloaderProblem_testDelayUpdateBuildFinished() {
  +        doDelayUpdateTest(3);
  +    }
   
   
  -            //
  -            // *****  Third Run  *****
  -            // third call should get only those files, which CONTENT changed
  -            // (no timestamp changes required!)
  -            results = selectionString(s);
  +    public void doDelayUpdateTest(int kind) {
  +        // no check for 1<=kind<=3 - only internal use therefore check it
  +        // while development
   
  -            //
  -            // *****  Check the result  *****
  -            //
  +        // readable form of parameter kind
  +        String[] kinds = {"task", "target", "build"};
   
  -            // 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);
  -            }
  +        // setup the "Ant project"
  +        MockProject project = new MockProject();
  +        File base  = new File("base");
  +        File file1 = new File("file1");
  +        File file2 = new File("file2");
   
  -            assertEquals(
  -                "Wrong files selected. Differing files: "       // info text
  -                + resolve(diff(expected.toString(), results)),  // list of files
  -                expected.toString(),                            // expected result
  -                results                                         // result
  -            );
  +        // setup the selector
  +        ModifiedSelector sel = new ModifiedSelector();
  +        sel.setProject(project);
  +        sel.setUpdate(true);
  +        sel.setDelayUpdate(true);
  +        sel.setAlgorithmClass("org.apache.tools.ant.types.selectors.MockAlgorithm");
  +        sel.setCacheClass("org.apache.tools.ant.types.selectors.MockCache");
  +        sel.configure();
   
  -        } finally {
  -            // cleanup the environment
  -            cleanupBed();
  -            if (s!=null) s.getCache().delete();
  -            if (bft!=null) bft.deletePropertiesfile();
  +        // get the cache, so we can check our things
  +        MockCache cache = (MockCache)sel.getCache();
  +
  +        // the test
  +        assertFalse("Cache must not be saved before 1st selection.", cache.saved);
  +        sel.isSelected(base, "file1", file1);
  +        assertFalse("Cache must not be saved after 1st selection.", cache.saved);
  +        sel.isSelected(base, "file2", file2);
  +        assertFalse("Cache must not be saved after 2nd selection.", cache.saved);
  +        switch (kind) {
  +            case 1 : project.fireTaskFinished();   break;
  +            case 2 : project.fireTargetFinished(); break;
  +            case 3 : project.fireBuildFinished();  break;
           }
  -    }
  +        assertTrue("Cache must be saved after " + kinds[kind-1] + "Finished-Event.", cache.saved);
   
  +        // MockCache doesnt create a file - therefore no cleanup needed
  +    }
   
   
       /**
  -     * 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>
  +     * Extracts the real used algorithm name from the ModifiedSelector using
  +     * its toString() method.
  +     * @param classname  the classname from the algorithm to use
  +     * @return  the algorithm part from the toString() (without brackets)
        */
  -    public void testScenario2() {
  -        ExtendSelector s = new ExtendSelector();
  -        BFT bft = new BFT();
  -        String cachefile = System.getProperty("java.io.tmpdir")+"/mycache.txt";
  -        try {
  -            makeBed();
  +    private String getAlgoName(String classname) {
  +        ModifiedSelector sel = new ModifiedSelector();
  +        sel.setAlgorithmClass(classname);
  +        // let the selector do its checks
  +        sel.validate();
  +        // extract the algorithm name (and config) from the selectors output
  +        String s1 = sel.toString();
  +        int posStart = s1.indexOf("algorithm=") + 10;
  +        int posEnd   = s1.indexOf(" comparator=");
  +        String algo  = s1.substring(posStart, posEnd);
  +        // '<' and '>' are only used if the algorithm has properties
  +        if (algo.startsWith("<")) algo = algo.substring(1);
  +        if (algo.endsWith(">"))   algo = algo.substring(0, algo.length()-1);
  +        // return the clean value
  +        return algo;
  +    }
   
  -            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"));
  +    // ================  testcases for the cache implementations  ================
   
  -            // 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();
  -        }
  +
  +    /**
  +     * 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.");
  +    }
  +
  +
  +    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());
       }
   
   
  @@ -338,6 +381,7 @@
   
               // Configure the selector
               ModifiedSelector s = (ModifiedSelector)getSelector();
  +            s.setDelayUpdate(false);
               s.addParam("cache.cachefile", cachefile);
   
               ModifiedSelector.CacheName cacheName = new ModifiedSelector.CacheName();
  @@ -396,30 +440,56 @@
       }
   
   
  -    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 _testCustomCache() {
  +        // same logic as on algorithm, no testcases created
       }
   
   
  -    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();
  -        }
  -    }
  +    /**
  +     * Test the interface semantic of Caches.
  +     * 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());
  +    }
  +
  +
  +    // ==============  testcases for the algorithm implementations  ==============
   
   
       public void testHashvalueAlgorithm() {
  @@ -427,12 +497,14 @@
           doTest(algo);
       }
   
  +
       public void testDigestAlgorithmMD5() {
           DigestAlgorithm algo = new DigestAlgorithm();
           algo.setAlgorithm("MD5");
           doTest(algo);
       }
   
  +
       public void testDigestAlgorithmSHA() {
           DigestAlgorithm algo = new DigestAlgorithm();
           algo.setAlgorithm("SHA");
  @@ -440,77 +512,28 @@
       }
   
   
  -    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 testChecksumAlgorithm() {
  +        ChecksumAlgorithm algo = new ChecksumAlgorithm();
  +        doTest(algo);
       }
   
   
  -    public void testScenarioCustomSelectorSettings() {
  -        doScenarioTest("modifiedselectortest-scenario-customselector-settings", "core.cache.properties");
  +    public void testChecksumAlgorithmCRC() {
  +        ChecksumAlgorithm algo = new ChecksumAlgorithm();
  +        algo.setAlgorithm("CRC");
  +        doTest(algo);
       }
   
   
  -    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();
  -        }
  +    public void testChecksumAlgorithmAdler() {
  +        ChecksumAlgorithm algo = new ChecksumAlgorithm();
  +        algo.setAlgorithm("Adler");
  +        doTest(algo);
       }
   
   
  -    //  ====================  Test interface semantic  ===================
  -
  -
       /**
  +     * Test the interface semantic of Algorithms.
        * 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>.
  @@ -550,50 +573,55 @@
       }
   
   
  -    /**
  -     * 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";
  +    // ==============  testcases for the comparator implementations  ==============
   
  -        // 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));
  +    public void testEqualComparator() {
  +        EqualComparator comp = new EqualComparator();
  +        doTest(comp);
  +    }
   
  -        // 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());
  +    public void testRuleComparator() {
  +        RuleBasedCollator comp = (RuleBasedCollator)RuleBasedCollator.getInstance();
  +        doTest(comp);
  +    }
  +
  +
  +    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() { //not yet supported see note in selector
  +        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 _testCustomComparator() {
  +        // same logic as on algorithm, no testcases created
       }
   
   
       /**
  +     * Test the interface semantic of Comparators.
        * This method does some common test for comparator implementations.
        *
        * @param algo   configured test object
  @@ -609,9 +637,255 @@
       }
   
   
  -    //  ========================  Helper methods  ========================
  +    // =====================  scenario tests  =====================
  +
  +
  +    /**
  +     * 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() { // RuleBasedCollator not yet supported - see Selector:375 note
  +        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();
  +        }
  +    }
  +
  +
  +    public void testScenarioCoreSelectorDefaults() {
  +        doScenarioTest("modifiedselectortest-scenario-coreselector-defaults", "cache.properties");
  +    }
  +
  +
  +    public void testScenarioCoreSelectorSettings() {
  +        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();
  +        }
  +    }
  +
  +
  +    //  =====================  helper methods and classes  ====================
  +
  +
  +    /**
  +     * Creates a configured parameter object.
  +     * @param name   name of the parameter
  +     * @param value  value of the parameter
  +     * @return the parameter object
  +     */
       private Parameter createParam(String name, String value) {
           Parameter p = new Parameter();
           p.setName(name);
  @@ -620,6 +894,11 @@
       }
   
   
  +    /**
  +     * The BFT class wrapps the selector test-builfile inside an
  +     * ant project (BuildFileTest). It supports target execution
  +     * and property transfer to that project.
  +     */
       private class BFT extends org.apache.tools.ant.BuildFileTest {
           BFT() { super("nothing"); }
           BFT(String name) {
  @@ -641,6 +920,10 @@
               executeTarget(target);
           }
   
  +        public String getProperty(String property) {
  +            return project.getProperty(property);
  +        }
  +
           public void writeProperties(String line) {
               if (!isConfigured) setUp();
               File dir = getProject().getBaseDir();
  @@ -667,4 +950,64 @@
           }
       }//class-BFT
   
  -}//class-ModifiedSelectorTest
  +
  +    /**
  +     * MockProject wrappes a very small ant project (one target, one task)
  +     * but provides public methods to fire the build events.
  +     */
  +    private class MockProject extends Project {
  +        private Task   task;
  +        private Target target;
  +
  +        public MockProject() {
  +            task = new Task(){
  +                public void execute() {
  +                }
  +            };
  +            task.setTaskName("testTask");
  +            target = new Target();
  +            target.setName("testTarget");
  +            target.setProject(this);
  +            target.addTask(task);
  +            task.setOwningTarget(target);
  +        }
  +
  +        public void fireBuildStarted() {
  +            super.fireBuildStarted();
  +        }
  +        public void fireBuildFinished() {
  +            super.fireBuildFinished(null);
  +        }
  +        public void fireSubBuildStarted() {
  +            super.fireSubBuildStarted();
  +        }
  +        public void fireSubBuildFinished() {
  +            super.fireSubBuildFinished(null);
  +        }
  +        public void fireTargetStarted() {
  +            super.fireTargetStarted(target);
  +        }
  +        public void fireTargetFinished() {
  +            super.fireTargetFinished(target, null);
  +        }
  +        public void fireTaskStarted() {
  +            super.fireTaskStarted(task);
  +        }
  +        public void fireTaskFinished() {
  +            super.fireTaskFinished(task, null);
  +        }
  +        private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) {
  +        }
  +        private void fireMessageLoggedProject(String message) {
  +            super.fireMessageLogged(this, message, Project.MSG_INFO);
  +        }
  +        private void fireMessageLoggedTarget(String message) {
  +            super.fireMessageLogged(target, message, Project.MSG_INFO);
  +        }
  +        private void fireMessageLoggedTask(String message) {
  +            super.fireMessageLogged(task, message, Project.MSG_INFO);
  +        }
  +    }//class-MockProject
  +
  +
  +}//class-ModifiedSelectorTest
  \ No newline at end of file
  
  
  
  1.1                  ant/src/testcases/org/apache/tools/ant/types/selectors/MockAlgorithm.java
  
  Index: MockAlgorithm.java
  ===================================================================
  /*
   * Copyright  2003-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.tools.ant.types.selectors;
  
  
  import java.io.File;
  import org.apache.tools.ant.types.selectors.modifiedselector.Algorithm;
  
  public class MockAlgorithm implements Algorithm {
      public boolean isValid() {
          return true;
      }
  
      public String getValue(File file) {
          return "TEST";
      }
  
      public String toString() {
          return "MockAlgorithm@" + hashCode();
      }
  }
  
  
  1.1                  ant/src/testcases/org/apache/tools/ant/types/selectors/MockCache.java
  
  Index: MockCache.java
  ===================================================================
  /*
   * Copyright  2003-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.tools.ant.types.selectors;
  
  
  import java.util.Iterator;
  import org.apache.tools.ant.types.selectors.modifiedselector.Cache;
  
  public class MockCache implements Cache {
  
      public boolean debug = false;
      public boolean saved = false;
  
  
      public MockCache() {
          log("()");
      }
  
      public boolean isValid() {
          log(".isValid()");
          return true;
      }
      public void delete() {
          log(".delete()");
      }
      public void load() {
          log(".load()");
      }
      public void save() {
          log(".save()");
          saved = true;
      }
      public Object get(Object key) {
          log(".get("+key+")");
          return key;
      }
      public void put(Object key, Object value) {
          log(".put("+key+", "+value+")");
          saved = false;
      }
      public Iterator iterator() {
          log("iterator()");
          return null;
      }
      public String toString() {
          return "MockCache@" + hashCode();
      }
  
      private void log(String msg) {
          if (debug) System.out.println(this+msg);
      }
  }//class-MockCache
  
  
  1.1                  ant/src/testcases/org/apache/tools/ant/types/selectors/MockComparator.java
  
  Index: MockComparator.java
  ===================================================================
  /*
   * Copyright  2003-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.tools.ant.types.selectors;
  
  import java.util.Comparator;
  
  public class MockComparator implements Comparator {
  
      public int compare(Object o1, Object o2) {
          return 0;
      }
  
      public String toString() {
          return "MockComparator";
      }
  }//class-MockCache
  
  
  1.23      +70 -3     ant/docs/manual/CoreTypes/selectors.html
  
  Index: selectors.html
  ===================================================================
  RCS file: /home/cvs/ant/docs/manual/CoreTypes/selectors.html,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- selectors.html	26 Apr 2004 19:22:21 -0000	1.22
  +++ selectors.html	10 Jul 2004 17:15:37 -0000	1.23
  @@ -2,7 +2,7 @@
     <head>
       <meta http-equiv="Content-Language" content="en-us">
       <title>Selectors in Ant</title>
  -<link rel="stylesheet" type="text/css" href="../stylesheets/antmanual.css">
  +    <link rel="stylesheet" type="text/css" href="../stylesheets/antmanual.css">
     </head>
   
     <body>
  @@ -652,6 +652,7 @@
               <ul>
                   <li> hashvalue - HashvalueAlgorithm </li>
                   <li> digest - DigestAlgorithm </li>
  +                <li> checksum - ChecksumAlgorithm </li>
               </ul>
           </td>
           <td valign="top" align="center"> No, defaults to <i>digest</i> </td>
  @@ -672,12 +673,36 @@
               Acceptable values are (further information see later):
               <ul>
                   <li> equal - EqualComparator </li>
  -                <li> rule - java.text.RuleBasedCollator </li>
  +                <li> rule - java.text.RuleBasedCollator
  +                  <!-- NOTE -->
  +                  <i>(see <a href="#ModSelNote">note</a> for restrictions)</i>
  +                </li>
               </ul>
           </td>
           <td valign="top" align="center"> No, defaults to <i>equal</i> </td>
         </tr>
         <tr>
  +        <td valign="top"> algorithmclass </td>
  +        <td valign="top"> Classname of custom algorithm implementation. Lower
  +          priority than <i>algorithm</i>.
  +          <!-- NOTE --> (see <a href="#ModSelNote">note</a> for restrictions) </td>
  +        <td valign="top" align="center"> No </td>
  +      </tr>
  +      <tr>
  +        <td valign="top"> cacheclass </td>
  +        <td valign="top"> Classname of custom cache implementation. Lower
  +          priority than <i>cache</i>.
  +          <!-- NOTE --> (see <a href="#ModSelNote">note</a> for restrictions) </td>
  +        <td valign="top" align="center"> No </td>
  +      </tr>
  +      <tr>
  +        <td valign="top"> comparatorclass </td>
  +        <td valign="top"> Classname of custom comparator implementation. Lower
  +          priority than <i>comparator</i>.
  +          <!-- NOTE --> (see <a href="#ModSelNote">note</a> for restrictions) </td>
  +        <td valign="top" align="center"> No </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>
  @@ -687,6 +712,15 @@
           <td valign="top"> Should directories be selected? (boolean) </td>
           <td valign="top" align="center"> No, defaults to <i>true</i> </td>
         </tr>
  +      <tr>
  +        <td valign="top"> delayupdate </td>
  +        <td valign="top"> If set to <i>true</i>, the storage of the cache will be delayed until the
  +             next finished BuildEvent; task finished, target finished or build finished,
  +             whichever comes first.  This is provided for increased performance.  If set
  +             to <i>false</i>, the storage of the cache will happen with each change.  This
  +             attribute depends upon the <i>update</i> attribute. (boolean)</td>
  +        <td valign="top" align="center"> No, defaults to <i>true</i> </td>
  +      </tr>
       </table>
   
       <p>These attributes can be set with nested &lt;param/&gt; tags. With &lt;param/&gt;
  @@ -695,6 +729,9 @@
           <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 comparator </li>
  +        <li> <b> algorithmclass </b>: same as attribute algorithmclass </li>
  +        <li> <b> cacheclass </b>: same as attribute cacheclass </li>
  +        <li> <b> comparatorclass </b>: same as attribute comparatorclass </li>
           <li> <b> update </b>: same as attribute update </li>
           <li> <b> seldirs </b>: same as attribute seldirs </li>
           <li> <b> algorithm.* </b>: Value is transfered to the algorithm via its
  @@ -729,6 +766,16 @@
             </ul>
           </td>
         </tr>
  +      <tr>
  +        <td valign="top"> checksum </td>
  +        <td valign="top"> Uses java.util.zip.Checksum. This Algorithm supports
  +          the following attributes:
  +          <ul>
  +            <li><i>algorithm.algorithm</i> (optional): Name of the algorithm
  +                (e.g. 'CRC' or 'ADLER', default = <i>CRC</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>
  @@ -750,6 +797,8 @@
           <td valign="top"> rule </td>
           <td valign="top"> Uses <i>java.text.RuleBasedCollator</i> for Object
             comparison.
  +          <!-- NOTE -->
  +          <i>(see <a href="#ModSelNote">note</a> for restrictions)</i>
           </td>
         </tr>
       </table>
  @@ -820,6 +869,24 @@
     CacheSelector saves therefore much upload time.</p>
   
   
  +  <!-- NOTE -->
  +  <i>(see <a href="#ModSelNote">note</a> for restrictions)</i>
  +  <a name="ModSelNote"></a>
  +  <h4>Note on RuleBasedCollator</h4>
  +  <p>The RuleBasedCollator needs a format for its work, but its needed while
  +  instantiation. There is a problem in the initialization algorithm for this
  +  case. Therefore you should not use this (or tell me the workaround :-).</p>
  +
  +  <p>The selector can not find the specified algorithm-, cache- or comparator-
  +  class if the selector is loaded from a different classloader.
  +  To be able to use your own classes you have to ensure that the selector
  +  can find the classes by adding the your package to the core: <ul>
  +  <li> by placing your JAR in %ANT_HOME/lib </li>
  +  <li> by adding '-lib myclasses/' while invocation </li>
  +  <li> by placing your JAR in ${ant.home}/.ant/lib </li>
  +  </ul></p>
  +
  +
       <a name="selectcontainers"></a>
       <h3>Selector Containers</h3>
   
  @@ -1216,4 +1283,4 @@
   
     </body>
   
  -</html>
  +</html>
  \ No newline at end of file
  
  
  
  1.7       +4 -5      ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java
  
  Index: DigestAlgorithm.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DigestAlgorithm.java	9 Mar 2004 16:48:49 -0000	1.6
  +++ DigestAlgorithm.java	10 Jul 2004 17:15:37 -0000	1.7
  @@ -51,7 +51,7 @@
    * </tr>
    * </table>
    *
  - * @version 2003-09-13
  + * @version 2004-07-08
    * @since  Ant 1.6
    */
   public class DigestAlgorithm implements Algorithm {
  @@ -132,12 +132,11 @@
   
   
       /**
  -     * This algorithm doesn't need any configuration.
  -     * Therefore it's always valid.
  +     * This algorithm supports only MD5 and SHA.
        * @return <i>true</i> if all is ok, otherwise <i>false</i>.
        */
       public boolean isValid() {
  -        return true;
  +        return "SHA".equalsIgnoreCase(algorithm) || "MD5".equalsIgnoreCase(algorithm);
       }
   
   
  @@ -200,4 +199,4 @@
           buf.append(">");
           return buf.toString();
       }
  -}
  +}
  \ No newline at end of file
  
  
  
  1.7       +331 -69   ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java
  
  Index: ModifiedSelector.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ModifiedSelector.java	9 Mar 2004 16:48:49 -0000	1.6
  +++ ModifiedSelector.java	10 Jul 2004 17:15:37 -0000	1.7
  @@ -27,6 +27,9 @@
   // Ant
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.IntrospectionHelper;
  +import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.BuildListener;
  +import org.apache.tools.ant.BuildEvent;
   import org.apache.tools.ant.types.EnumeratedAttribute;
   import org.apache.tools.ant.types.Parameter;
   import org.apache.tools.ant.types.selectors.BaseExtendSelector;
  @@ -93,7 +96,7 @@
    * 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/">
  + * for homepage generation (e.g. with <a href="http://forrest.apache.org/">
    * Apache Forrest</a>). <pre>
    * <target name="generate-and-upload-site">
    *     <echo> generate the site using forrest </echo>
  @@ -109,7 +112,7 @@
    * </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:
  + * <p>This selector supports the following attributes:
    * <table>
    * <tr><th>name</th><th>values</th><th>description</th><th>required</th></tr>
    * <tr>
  @@ -122,20 +125,21 @@
    * </tr>
    * <tr>
    *     <td> algorithm </td>
  - *     <td> hashvalue | digest </td>
  + *     <td> hashvalue | digest | checksum </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>
  + *          <li><b>checksum</b> - uses java.util.zip.Checksum interface </i>
    *     </td>
    *     <td> no, defaults to digest </td>
    * </tr>
    * <tr>
    *     <td> comparator </td>
  - *     <td> equal | role </td>
  + *     <td> equal | rule </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>
  + *          <li><b>rule</b> - uses java.text.RuleBasedCollator class </i>
    *     </td>
    *     <td> no, defaults to equal </td>
    * </tr>
  @@ -153,6 +157,34 @@
    *     <td> no, defaults to true </td>
    * </tr>
    * <tr>
  + *     <td> delayupdate </td>
  + *     <td> true | false </td>
  + *     <td> If set to <i>true</i>, the storage of the cache will be delayed until the
  + *          next finished BuildEvent; task finished, target finished or build finished,
  + *          whichever comes first.  This is provided for increased performance.  If set
  + *          to <i>false</i>, the storage of the cache will happen with each change.  This
  + *          attribute depends upon the <i>update</i> attribute.</td>
  + *     <td> no, defaults to true </td>
  + * </tr>
  + * <tr>
  + *     <td> cacheclass </td>
  + *     <td> <i>classname</i> </td>
  + *     <td> which custom cache implementation should be used </td>
  + *     <td> no </td>
  + * </tr>
  + * <tr>
  + *     <td> algorithmclass </td>
  + *     <td> <i>classname</i> </td>
  + *     <td> which custom algorithm implementation should be used </td>
  + *     <td> no </td>
  + * </tr>
  + * <tr>
  + *     <td> comparatorclass </td>
  + *     <td> <i>classname</i> </td>
  + *     <td> which custom comparator implementation should be used </td>
  + *     <td> no </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>
  @@ -182,23 +214,32 @@
    * a nested <i><param name="algorithm.provider" value="MyProvider"/></i>.
    *
    *
  - * @version 2003-09-13
  + * @version 2004-07-09
    * @since  Ant 1.6
  -*/
  -public class ModifiedSelector extends BaseExtendSelector {
  + */
  +public class ModifiedSelector extends BaseExtendSelector implements BuildListener {
   
   
  -    // -----  member variables - configuration
  +    // -----  attributes  -----
   
   
  -    /** The Cache containing the old values. */
  -    private Cache cache = null;
  +    /** Cache name for later instantiation. */
  +    private CacheName cacheName = null;
   
  -    /** Algorithm for computing new values and updating the cache. */
  -    private Algorithm algorithm = null;
  +    /** User specified classname for Cache. */
  +    private String cacheClass;
   
  -    /** How should the cached value and the new one compared? */
  -    private Comparator comparator = null;
  +    /** Algorithm name for later instantiation. */
  +    private AlgorithmName algoName = null;
  +
  +    /** User specified classname for Algorithm. */
  +    private String algorithmClass;
  +
  +    /** Comparator name for later instantiation. */
  +    private ComparatorName compName = null;
  +
  +    /** User specified classname for Comparator. */
  +    private String comparatorClass;
   
       /** Should the cache be updated? */
       private boolean update = true;
  @@ -206,22 +247,27 @@
       /** Are directories selected? */
       private boolean selectDirectories = true;
   
  +    /** Delay the writing of the cache file */
  +    private boolean delayUpdate = true;
   
  -    // -----  member variables - internal use
   
  +    // ----- internal member variables -----
   
  -    /** Flag whether this object is configured. Configuration is only done once. */
  -    private boolean isConfigured = false;
   
  -    /** Algorithm name for later instantiation. */
  -    private AlgorithmName algoName = null;
  +    /** How should the cached value and the new one compared? */
  +    private Comparator comparator = null;
   
  -    /** Cache name for later instantiation. */
  -    private CacheName cacheName = null;
  +    /** Algorithm for computing new values and updating the cache. */
  +    private Algorithm algorithm = null;
   
  -    /** Comparator name for later instantiation. */
  -    private ComparatorName compName = null;
  +    /** The Cache containing the old values. */
  +    private Cache cache = null;
   
  +    /** Count of modified properties */
  +    private int modified = 0;
  +
  +    /** Flag whether this object is configured. Configuration is only done once. */
  +    private boolean isConfigured = false;
   
       /**
        * Parameter vector with parameters for later initialization.
  @@ -293,23 +339,26 @@
           //
           // -----  Set default values  -----
           //
  -        org.apache.tools.ant.Project project = getProject();
  +        Project project = getProject();
           String filename = "cache.properties";
           File cachefile = null;
           if (project != null) {
               // normal use inside Ant
               cachefile = new File(project.getBaseDir(), filename);
  +
  +            // set self as a BuildListener to delay cachefile saves
  +            getProject().addBuildListener(this);
           } else {
  -            // no reference to project - e.g. during JUnit tests
  +            // no reference to project - e.g. during normal JUnit tests
               cachefile = new File(filename);
  +            setDelayUpdate(false);
           }
  -        cache = new PropertiesfileCache(cachefile);
  -        algorithm = new DigestAlgorithm();
  -        comparator = new EqualComparator();
  +        Cache      defaultCache      = new PropertiesfileCache(cachefile);
  +        Algorithm  defaultAlgorithm  = new DigestAlgorithm();
  +        Comparator defaultComparator = new EqualComparator();
           update = true;
           selectDirectories = true;
   
  -
           //
           // -----  Set the main attributes, pattern '*'  -----
           //
  @@ -328,54 +377,70 @@
           // -----  Instantiate the interfaces  -----
           //
           String className = null;
  -        String pkg = "org.apache.tools.ant.types.selectors.cacheselector";
  +        String pkg = "org.apache.tools.ant.types.selectors.modifiedselector";
   
  -        // the algorithm
  -        if (algorithm == null) {
  +        // specify the algorithm classname
  +        if (algoName != null) {
  +            // use Algorithm defined via name
               if ("hashvalue".equals(algoName.getValue())) {
  -                className = pkg + ".HashvalueAlgorithm";
  +                algorithm = new HashvalueAlgorithm();
               } else if ("digest".equals(algoName.getValue())) {
  -                className = pkg + ".DigestAlgorithm";
  +                algorithm = new DigestAlgorithm();
  +            } else if ("checksum".equals(algoName.getValue())) {
  +                algorithm = new ChecksumAlgorithm();
               }
  -            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();
  -                }
  +        } else {
  +            if (algorithmClass != null) {
  +                // use Algorithm specified by classname
  +                algorithm = (Algorithm) loadClass(
  +                    algorithmClass,
  +                    "is not an Algorithm.",
  +                    Algorithm.class);
  +            } else {
  +                // nothing specified - use default
  +                algorithm = defaultAlgorithm;
               }
           }
   
  -        // the cache
  -        if (cache == null) {
  +        // specify the cache classname
  +        if (cacheName != null) {
  +            // use Cache defined via name
               if ("propertyfile".equals(cacheName.getValue())) {
  -                className = pkg + ".PropertiesfileCache";
  +                cache = new 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();
  -                }
  +        } else {
  +            if (cacheClass != null) {
  +                // use Cache specified by classname
  +                cache = (Cache) loadClass(cacheClass, "is not a Cache.", Cache.class);
  +            } else {
  +                // nothing specified - use default
  +                cache = defaultCache;
               }
           }
   
  -        // the comparator
  -        if (comparator == null) {
  +        // specify the comparator classname
  +        if (compName != null) {
  +            // use Algorithm defined via name
               if ("equal".equals(compName.getValue())) {
  -                className = pkg + ".EqualComparator";
  -            } else if ("role".equals(compName.getValue())) {
  -                className = "java.text.RuleBasedCollator";
  +                comparator = new EqualComparator();
  +             } else if ("rule".equals(compName.getValue())) {
  +                // TODO there is a problem with the constructor for the RBC.
  +                // you have to provide the rules in the constructors - no setters
  +                // available.
  +                throw new BuildException("RuleBasedCollator not yet supported.");
  +                // Have to think about lazy initialization here...  JHM
  +                // comparator = new 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();
  -                }
  +        } else {
  +            if (comparatorClass != null) {
  +                // use Algorithm specified by classname
  +                comparator = (Comparator) loadClass(
  +                    comparatorClass,
  +                    "is not a Comparator.",
  +                    Comparator.class);
  +            } else {
  +                // nothing specified - use default
  +                comparator = defaultComparator;
               }
           }
   
  @@ -390,6 +455,47 @@
       }
   
   
  +    /**
  +     * Loads the specified class and initializes an object of that class.
  +     * Throws a BuildException using the given message if an error occurs during
  +     * loading/instantiation or if the object is not from the given type.
  +     * @param classname the classname
  +     * @param msg the message-part for the BuildException
  +     * @param type the type to check against
  +     * @return a castable object
  +     */
  +    protected Object loadClass(String classname, String msg, Class type) {
  +        try {
  +            // load the specified class
  +
  +            /* TODO: the selector cant find the specified class if the
  +             * selector is loaded from a different classloader.
  +             * See ModifiedSelectorTest.testCustom<Algorithm|Cache|Comparator|Classes>().
  +             * To be able to run these tests you have to ensure that <junit> can find
  +             * the classes by adding the test package to the core:
  +             * - by placing the ant-testutils.jar in %ANT_HOME/lib
  +             * - by adding '-lib build/testcases' while invocation
  +             *
  +             * IMO this is not only a problem for the Mock-Classes inside the
  +             * tests. The *classname attributes are designed for the user to
  +             * provide his own implementations. Therefore they should be
  +             * found ... Workaround again: -lib, ~/.ant/lib, ant.home/lib
  +             * JHM
  +             */
  +            Object rv = Class.forName(classname).newInstance();
  +            if (!type.isInstance(rv)) {
  +                throw new BuildException("Specified class (" + classname + ") " + msg);
  +            }
  +            return rv;
  +        } catch (ClassNotFoundException e) {
  +            throw new BuildException("Specified class (" + classname + ") not found.");
  +        } catch (Exception e) {
  +            throw new BuildException(e);
  +        }
  +    }
  +
  +
  +
       // -----  the selection work  -----
   
   
  @@ -412,22 +518,64 @@
           // 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)) {
  +        if (update && rv) {
               cache.put(f.getAbsolutePath(), newValue);
  -            cache.save();
  +            setModified(getModified() + 1);
  +            if (!getDelayUpdate()) {
  +                saveCache();
  +            }
           }
   
           return rv;
       }
   
   
  +   /**
  +    * save the cache file
  +    */
  +    protected void saveCache() {
  +        if (getModified() > 1) {
  +            cache.save();
  +            setModified(0);
  +        }
  +    }
  +
  +
       // -----  attribute and nested element support  -----
   
   
       /**
  +     * Setter for algorithmClass.
  +     * @param classname  new value
  +     */
  +    public void setAlgorithmClass(String classname) {
  +        algorithmClass = classname;
  +    }
  +
  +
  +    /**
  +     * Setter for comparatorClass.
  +     * @param classname  new value
  +     */
  +    public void setComparatorClass(String classname) {
  +        comparatorClass = classname;
  +    }
  +
  +
  +    /**
  +     * Setter for cacheClass.
  +     * @param classname  new value
  +     */
  +    public void setCacheClass(String classname) {
  +        cacheClass = classname;
  +    }
  +
  +
  +    /**
        * Support for <i>update</i> attribute.
        * @param update new value
        */
  @@ -446,6 +594,42 @@
   
   
       /**
  +     * Getter for the modified count
  +     * @return modified count
  +     */
  +    public int getModified() {
  +        return modified;
  +    }
  +
  +
  +    /**
  +     * Setter for the modified count
  +     * @param modified count
  +     */
  +    public void setModified(int modified) {
  +        this.modified = modified;
  +    }
  +
  +
  +    /**
  +     * Getter for the delay update
  +     * @return true if we should delay for performance
  +     */
  +    public boolean getDelayUpdate() {
  +        return delayUpdate;
  +    }
  +
  +
  +    /**
  +     * Setter for the delay update
  +     * @param delayUpdate true if we should delay for performance
  +     */
  +    public void setDelayUpdate(boolean delayUpdate) {
  +        this.delayUpdate = delayUpdate;
  +    }
  +
  +
  +    /**
        * Support for nested &lt;param&gt; tags.
        * @param key the key of the parameter
        * @param value the value of the parameter
  @@ -516,6 +700,12 @@
                   ? true
                   : false;
               setUpdate(updateValue);
  +        } else if ("delayupdate".equals(key)) {
  +            boolean updateValue =
  +                ("true".equalsIgnoreCase(value))
  +                ? true
  +                : false;
  +            setDelayUpdate(updateValue);
           } else if ("seldirs".equals(key)) {
               boolean sdValue =
                   ("true".equalsIgnoreCase(value))
  @@ -548,7 +738,6 @@
           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) {
  @@ -576,6 +765,79 @@
       }
   
   
  +    // ----- BuildListener interface methods -----
  +
  +
  +    /**
  +     * Signals that the last target has finished.
  +     * @param event recieved BuildEvent
  +    */
  +    public void buildFinished(BuildEvent event) {
  +        if (getDelayUpdate()) {
  +            saveCache();
  +        }
  +    }
  +
  +
  +    /**
  +     * Signals that a target has finished.
  +     * @param event recieved BuildEvent
  +    */
  +    public void targetFinished(BuildEvent event) {
  +        if (getDelayUpdate()) {
  +            saveCache();
  +        }
  +    }
  +
  +
  +    /**
  +     * Signals that a task has finished.
  +     * @param event recieved BuildEvent
  +    */
  +    public void taskFinished(BuildEvent event) {
  +        if (getDelayUpdate()) {
  +            saveCache();
  +        }
  +    }
  +
  +
  +    /**
  +     * Signals that a build has started.
  +     * @param event recieved BuildEvent
  +    */
  +    public void buildStarted(BuildEvent event) {
  +        // no-op
  +    }
  +
  +
  +    /**
  +     * Signals that a target is starting.
  +     * @param event recieved BuildEvent
  +    */
  +    public void targetStarted(BuildEvent event) {
  +        // no-op
  +    }
  +
  +
  +
  +    /**
  +     * Signals that a task is starting.
  +     * @param event recieved BuildEvent
  +    */
  +    public void taskStarted(BuildEvent event) {
  +        // no-op
  +    }
  +
  +
  +    /**
  +     * Signals a message logging event.
  +     * @param event recieved BuildEvent
  +    */
  +    public void messageLogged(BuildEvent event) {
  +        // no-op
  +    }
  +
  +
       // The EnumeratedAttributes for the three interface implementations.
       // Name-Classname mapping is done in the configure() method.
   
  @@ -597,7 +859,7 @@
       }
       public static class AlgorithmName extends EnumeratedAttribute {
           public String[] getValues() {
  -            return new String[] {"hashvalue", "digest" };
  +            return new String[] {"hashvalue", "digest", "checksum" };
           }
       }
   
  @@ -612,4 +874,4 @@
           }
       }
   
  -}
  +} //class-ModifiedSelector
  \ No newline at end of file
  
  
  
  1.7       +20 -2     ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java
  
  Index: PropertiesfileCache.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- PropertiesfileCache.java	9 Mar 2004 16:48:49 -0000	1.6
  +++ PropertiesfileCache.java	10 Jul 2004 17:15:37 -0000	1.7
  @@ -96,12 +96,27 @@
       // -----  Cache-Configuration  -----
   
   
  +    /**
  +     * Setter.
  +     * @param file new value
  +     */
       public void setCachefile(File file) {
           cachefile = file;
       }
   
  -    public File getCachefile() { return cachefile; }
   
  +    /**
  +     * Getter.
  +     * @return the cachefile
  +     */
  +    public File getCachefile() {
  +        return cachefile;
  +    }
  +
  +    /**
  +     * This cache is valid if the cachefile is set.
  +     * @return true if all is ok false otherwise
  +     */
       public boolean isValid() {
           return (cachefile != null);
       }
  @@ -110,6 +125,9 @@
       // -----  Data Access
   
   
  +    /**
  +     * Load the cache from underlying properties file.
  +     */
       public void load() {
           if ((cachefile != null) && cachefile.isFile() && cachefile.canRead()) {
               try {
  @@ -214,4 +232,4 @@
           buf.append(">");
           return buf.toString();
       }
  -}
  +}
  \ No newline at end of file
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org