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 <param/> tags. With <param/>
@@ -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 <param> 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