Didn't worry too much about WaitFor's backward compatibility issues as it is hardly a week old. WaitFor has ben modified this way so that it is consistent with Tstamp and takes in enumerated attributes for unit instead of allowing arbitrary letters/ words suffixed to the time. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270074 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -9,67 +9,76 @@ | |||
| <h2>Waitfor</h2> | |||
| <h3>Description</h3> | |||
| <p>Blocks execution until a set of specified conditions become true. This is intended | |||
| to be used with the <a href="parallel.html">parallel</a> task to | |||
| <p>Blocks execution until a set of specified conditions become true. This is intended | |||
| to be used with the <a href="parallel.html">parallel</a> task to | |||
| synchronize a set of processes.</p> | |||
| <p>The conditions to wait for are defined in <a href="waitfor.html#nested">nested elements</a>, if multiple conditions | |||
| are specified, then the task will wait until all conditions are true..</p> | |||
| <p>The conditions to wait for are defined in <a href="waitfor.html#nested">nested elements</a>, | |||
| if multiple conditions are specified, then the task will wait until all conditions are true..</p> | |||
| <p></p> | |||
| <p>The time attributes (maxwait and checkevery) are specified in milliseconds | |||
| unless the values are followed by one of the following suffixes: "ms", | |||
| "s", "m", "h" which cause the value to be interpreted | |||
| as milliseconds, seconds, minutes or hours.</p> | |||
| <p>If both maxwait and maxwaitunit are not specified, the maxwait is 3 minutes (180000 milliseconds).</p> | |||
| <h3>Parameters</h3> | |||
| <table border="1" cellpadding="2" cellspacing="0"> | |||
| <tr> | |||
| <tr> | |||
| <td valign="top"><b>Attribute</b></td> | |||
| <td valign="top"><b>Description</b></td> | |||
| <td align="center" valign="top"><b>Required</b></td> | |||
| </tr> | |||
| <tr> | |||
| <tr> | |||
| <td valign="top">maxwait</td> | |||
| <td valign="top">The maximum amount of time to wait for all the required conditions | |||
| to become true before failing the task. Defaults to 5 minutes.</td> | |||
| <td valign="top">The maximum amount of time to wait for all the required conditions | |||
| to become true before failing the task. Defaults to 180000 maxwaitunits.</td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <tr> | |||
| <td valign="top">maxwaitunit</td> | |||
| <td valign="top">The unit of time that must be used to interpret the value of the | |||
| maxwait attribute. Defaults to millisecond.</td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">checkevery</td> | |||
| <td valign="top">The amount of time to wait between each test of the conditions. | |||
| Defaults to 200mS.</td> | |||
| <td valign="top">The amount of time to wait between each test of the conditions. | |||
| Defaults to 500 checkeveryunits.</td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">checkeveryunit</td> | |||
| <td valign="top">The unit of time that must be used to interpret the value of the | |||
| checkevery attribute. Defaults to millisecond.</td> | |||
| <td valign="top" align="center">No</td> | |||
| </tr> | |||
| </table> | |||
| <h3><a name="nested">Nested Elements</a></h3> | |||
| <p>The available conditions that satisfy the | |||
| <code><waitfor></code> task are the same as those for the | |||
| <code><waitfor></code> task are the same as those for the | |||
| <a href="condition.html"><code><condition></code></a> task. See | |||
| <a href="conditions.html">here</a> for the full list.</p> | |||
| <h3>Examples</h3> | |||
| <blockquote> | |||
| <p><code><waitfor maxwait="30s"><br> | |||
| <blockquote> | |||
| <p><code><waitfor maxwait="30" maxwaitunit="second"><br> | |||
| <available file="errors.log"/><br> | |||
| </waitfor></code></p> | |||
| </blockquote> | |||
| <p>waits up to 30 seconds for a file called errors.log to appear.</p> | |||
| <blockquote> | |||
| <p><code><waitfor maxwait="3m" checkevery="500ms"><br> | |||
| <p><code><waitfor maxwait="3" maxwaitunit="minute" checkevery="500"><br> | |||
| <http url="http://localhost/myapp/index.html"/><br> | |||
| </waitfor></code></p> | |||
| </blockquote> | |||
| <p>waits up to 3 minutes (and checks every 500mS) for a web server on localhost | |||
| <p>waits up to 3 minutes (and checks every 500 milliseconds) for a web server on localhost | |||
| to serve up the specified URL.</p> | |||
| <blockquote> | |||
| <p><code><waitfor maxwait="10s"><br> | |||
| <blockquote> | |||
| <p><code><waitfor maxwait="10" maxwait="second"><br> | |||
| <and><br> | |||
| <socket server="dbserver" port="1521"/><br> | |||
| <http url="http://webserver/mypage.html"/><br> | |||
| </and><br> | |||
| </waitfor></code></p> | |||
| </blockquote> | |||
| <p>waits up to 10 seconds for a server on the dbserver machine to begin listening | |||
| on port 1521 and for the http://webserver/mypage.html web page | |||
| <p>waits up to 10 seconds for a server on the dbserver machine to begin listening | |||
| on port 1521 and for the http://webserver/mypage.html web page | |||
| to become available.</p> | |||
| <hr><p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | |||
| Reserved.</p> | |||
| @@ -75,13 +75,13 @@ import java.util.Hashtable; | |||
| import java.util.Enumeration; | |||
| /** | |||
| * A consolidated copy task. Copies a file or directory to a new file | |||
| * A consolidated copy task. Copies a file or directory to a new file | |||
| * or directory. Files are only copied if the source file is newer | |||
| * than the destination file, or when the destination file does not | |||
| * than the destination file, or when the destination file does not | |||
| * exist. It is possible to explicitly overwrite existing files.</p> | |||
| * | |||
| * <p>This implementation is based on Arnout Kuiper's initial design | |||
| * document, the following mailing list discussions, and the | |||
| * document, the following mailing list discussions, and the | |||
| * copyfile/copydir tasks.</p> | |||
| * | |||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | |||
| @@ -90,8 +90,8 @@ import java.util.Enumeration; | |||
| * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | |||
| */ | |||
| public class Copy extends Task { | |||
| protected File file = null; // the source file | |||
| protected File destFile = null; // the destination file | |||
| protected File file = null; // the source file | |||
| protected File destFile = null; // the destination file | |||
| protected File destDir = null; // the destination directory | |||
| protected Vector filesets = new Vector(); | |||
| @@ -108,7 +108,7 @@ public class Copy extends Task { | |||
| protected Mapper mapperElement = null; | |||
| private Vector filterSets = new Vector(); | |||
| private FileUtils fileUtils; | |||
| public Copy() { | |||
| fileUtils = FileUtils.newFileUtils(); | |||
| } | |||
| @@ -144,12 +144,22 @@ public class Copy extends Task { | |||
| filterSets.addElement(filterSet); | |||
| return filterSet; | |||
| } | |||
| /** | |||
| * Give the copied files the same last modified time as the original files. | |||
| * @deprecated setPreserveLastModified(String) has been deprecated and | |||
| * replaced with setPreserveLastModified(boolean) to | |||
| * consistently let the Introspection mechanism work. | |||
| */ | |||
| public void setPreserveLastModified(String preserve) { | |||
| preserveLastModified = Project.toBoolean(preserve); | |||
| setPreserveLastModified(Project.toBoolean(preserve)); | |||
| } | |||
| /** | |||
| * Give the copied files the same last modified time as the original files. | |||
| */ | |||
| public void setPreserveLastModified(boolean preserve) { | |||
| preserveLastModified = preserve; | |||
| } | |||
| /** | |||
| @@ -160,7 +170,7 @@ public class Copy extends Task { | |||
| protected Vector getFilterSets() { | |||
| return filterSets; | |||
| } | |||
| /** | |||
| * Sets filtering. | |||
| */ | |||
| @@ -194,8 +204,8 @@ public class Copy extends Task { | |||
| this.verbosity = Project.MSG_INFO; | |||
| } else { | |||
| this.verbosity = Project.MSG_VERBOSE; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Used to copy empty directories. | |||
| @@ -228,7 +238,7 @@ public class Copy extends Task { | |||
| */ | |||
| public void execute() throws BuildException { | |||
| // make sure we don't have an illegal set of options | |||
| validateAttributes(); | |||
| validateAttributes(); | |||
| // deal with the single file | |||
| if (file != null) { | |||
| @@ -236,8 +246,8 @@ public class Copy extends Task { | |||
| if (destFile == null) { | |||
| destFile = new File(destDir, file.getName()); | |||
| } | |||
| if (forceOverwrite || | |||
| if (forceOverwrite || | |||
| (file.lastModified() > destFile.lastModified())) { | |||
| fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath()); | |||
| } else { | |||
| @@ -245,7 +255,7 @@ public class Copy extends Task { | |||
| Project.MSG_VERBOSE); | |||
| } | |||
| } else { | |||
| String message = "Could not find file " | |||
| String message = "Could not find file " | |||
| + file.getAbsolutePath() + " to copy."; | |||
| log(message); | |||
| throw new BuildException(message); | |||
| @@ -280,7 +290,7 @@ public class Copy extends Task { | |||
| /** | |||
| * Ensure we have a consistent and legal set of attributes, and set | |||
| * any internal flags necessary based on different combinations | |||
| * any internal flags necessary based on different combinations | |||
| * of attributes. | |||
| */ | |||
| protected void validateAttributes() throws BuildException { | |||
| @@ -299,7 +309,7 @@ public class Copy extends Task { | |||
| if (file != null && file.exists() && file.isDirectory()) { | |||
| throw new BuildException("Use a fileset to copy directories."); | |||
| } | |||
| if (destFile != null && filesets.size() > 0) { | |||
| if (filesets.size() > 1) { | |||
| throw new BuildException( | |||
| @@ -368,7 +378,7 @@ public class Copy extends Task { | |||
| SourceFileScanner ds = new SourceFileScanner(this); | |||
| toCopy = ds.restrict(names, fromDir, toDir, mapper); | |||
| } | |||
| for (int i = 0; i < toCopy.length; i++) { | |||
| File src = new File(fromDir, toCopy[i]); | |||
| File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]); | |||
| @@ -382,8 +392,8 @@ public class Copy extends Task { | |||
| */ | |||
| protected void doFileOperations() { | |||
| if (fileCopyMap.size() > 0) { | |||
| log("Copying " + fileCopyMap.size() + | |||
| " file" + (fileCopyMap.size() == 1 ? "" : "s") + | |||
| log("Copying " + fileCopyMap.size() + | |||
| " file" + (fileCopyMap.size() == 1 ? "" : "s") + | |||
| " to " + destDir.getAbsolutePath() ); | |||
| Enumeration e = fileCopyMap.keys(); | |||
| @@ -398,7 +408,7 @@ public class Copy extends Task { | |||
| try { | |||
| log("Copying " + fromFile + " to " + toFile, verbosity); | |||
| FilterSetCollection executionFilters = new FilterSetCollection(); | |||
| if (filtering) { | |||
| executionFilters.addFilterSet(project.getGlobalFilterSet()); | |||
| @@ -431,9 +441,9 @@ public class Copy extends Task { | |||
| } | |||
| if (count > 0) { | |||
| log("Copied " + count + | |||
| " empty director" + | |||
| (count==1?"y":"ies") + | |||
| log("Copied " + count + | |||
| " empty director" + | |||
| (count==1?"y":"ies") + | |||
| " to " + destDir.getAbsolutePath()); | |||
| } | |||
| } | |||
| @@ -55,14 +55,11 @@ | |||
| package org.apache.tools.ant.taskdefs; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.taskdefs.condition.ConditionBase; | |||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.net.*; | |||
| import java.util.Vector; | |||
| import java.util.Hashtable; | |||
| /** | |||
| * Wait for an external event to occur. | |||
| @@ -74,32 +71,48 @@ import java.util.Vector; | |||
| * The following attributes can be specified on a waitfor task: | |||
| * <ul> | |||
| * <li>maxwait - maximum length of time to wait before giving up</li> | |||
| * <li>maxwaitunit - The unit to be used to interpret maxwait attribute</li> | |||
| * <li>checkevery - amount of time to sleep between each check</li> | |||
| * <li>checkeveryunit - The unit to be used to interpret checkevery attribute</li> | |||
| * </ul> | |||
| * | |||
| * The time value can include a suffix of "ms", "s", "m", "h" to | |||
| * indicate that the value is in milliseconds, seconds, minutes or | |||
| * hours. The default is milliseconds. | |||
| * The maxwaitunit and checkeveryunit are allowed to have the following values: | |||
| * millesond, second, minute, hour, day and week. The default is millisecond. | |||
| * | |||
| * @author <a href="mailto:denis@network365.com">Denis Hennessy</a> | |||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||
| */ | |||
| public class WaitFor extends ConditionBase { | |||
| private long maxWaitMillis = 1000 * 60 * 3; // default max wait time | |||
| private long checkEveryMillis = 500; | |||
| private long maxWaitMillis = 1000l * 60l * 3l; // default max wait time | |||
| private long checkEveryMillis = 500l; | |||
| /** | |||
| * Set the maximum length of time to wait | |||
| */ | |||
| public void setMaxWait(String time) { | |||
| maxWaitMillis = parseTime(time); | |||
| public void setMaxWait(long time) { | |||
| maxWaitMillis = time; | |||
| } | |||
| /** | |||
| * Set the max wait time unit | |||
| */ | |||
| public void setMaxWaitUnit(Unit unit) { | |||
| maxWaitMillis *= unit.getMultiplier(); | |||
| } | |||
| /** | |||
| * Set the time between each check | |||
| */ | |||
| public void setCheckEvery(String time) { | |||
| checkEveryMillis = parseTime(time); | |||
| public void setCheckEvery(long time) { | |||
| checkEveryMillis = time; | |||
| } | |||
| /** | |||
| * Set the check every time unit | |||
| */ | |||
| public void setCheckEveryUnit(Unit unit) { | |||
| checkEveryMillis *= unit.getMultiplier(); | |||
| } | |||
| /** | |||
| @@ -131,44 +144,38 @@ public class WaitFor extends ConditionBase { | |||
| throw new BuildException("Task did not complete in time"); | |||
| } | |||
| /** | |||
| * Parse a time in the format nnnnnxx where xx is a common time | |||
| * multiplier suffix. | |||
| */ | |||
| protected long parseTime(String value) { | |||
| int i = 0; | |||
| for (i = 0; i < value.length(); i++) { | |||
| char ch = value.charAt(i); | |||
| if (ch < '0' || ch > '9') { | |||
| break; | |||
| } | |||
| } | |||
| if (i == 0) { | |||
| throw new NumberFormatException(); | |||
| } | |||
| String digits = value.substring(0, i); | |||
| return Long.parseLong(digits) * getMultiplier(value.substring(i)); | |||
| } | |||
| public static class Unit extends EnumeratedAttribute { | |||
| /** | |||
| * Look for and decipher a multiplier suffix in the string. | |||
| * @param value - a string with a series of digits followed by the | |||
| * scale suffix. | |||
| */ | |||
| protected long getMultiplier(String value) { | |||
| String lowercaseValue = value.toLowerCase(); | |||
| if (lowercaseValue.startsWith("ms")) { | |||
| return 1; | |||
| } | |||
| if (lowercaseValue.startsWith("s")) { | |||
| return 1000; | |||
| private static final String MILLISECOND = "millisecond"; | |||
| private static final String SECOND = "second"; | |||
| private static final String MINUTE = "minute"; | |||
| private static final String HOUR = "hour"; | |||
| private static final String DAY = "day"; | |||
| private static final String WEEK = "week"; | |||
| private final static String[] units = { | |||
| MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK | |||
| }; | |||
| private Hashtable timeTable = new Hashtable(); | |||
| public Unit() { | |||
| timeTable.put(MILLISECOND, new Long(1l)); | |||
| timeTable.put(SECOND, new Long(1000l)); | |||
| timeTable.put(MINUTE, new Long(1000l * 60l)); | |||
| timeTable.put(HOUR, new Long(1000l * 60l * 60l)); | |||
| timeTable.put(DAY, new Long(1000l * 60l * 60l * 24l)); | |||
| timeTable.put(WEEK, new Long(1000l * 60l * 60l * 24l * 7l)); | |||
| } | |||
| if (lowercaseValue.startsWith("m")) { | |||
| return 1000 * 60; | |||
| public long getMultiplier() { | |||
| String key = getValue().toLowerCase(); | |||
| Long l = (Long) timeTable.get(key); | |||
| return l.longValue(); | |||
| } | |||
| if (lowercaseValue.startsWith("h")) { | |||
| return 1000 * 60 * 60; | |||
| public String[] getValues() { | |||
| return units; | |||
| } | |||
| return 1; | |||
| } | |||
| } | |||