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> | <h2>Waitfor</h2> | ||||
| <h3>Description</h3> | <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> | 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></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> | <h3>Parameters</h3> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| <tr> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | <td valign="top"><b>Attribute</b></td> | ||||
| <td valign="top"><b>Description</b></td> | <td valign="top"><b>Description</b></td> | ||||
| <td align="center" valign="top"><b>Required</b></td> | <td align="center" valign="top"><b>Required</b></td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr> | |||||
| <td valign="top">maxwait</td> | <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> | <td valign="top" align="center">No</td> | ||||
| </tr> | </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">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> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| <h3><a name="nested">Nested Elements</a></h3> | <h3><a name="nested">Nested Elements</a></h3> | ||||
| <p>The available conditions that satisfy the | <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="condition.html"><code><condition></code></a> task. See | ||||
| <a href="conditions.html">here</a> for the full list.</p> | <a href="conditions.html">here</a> for the full list.</p> | ||||
| <h3>Examples</h3> | <h3>Examples</h3> | ||||
| <blockquote> | |||||
| <p><code><waitfor maxwait="30s"><br> | |||||
| <blockquote> | |||||
| <p><code><waitfor maxwait="30" maxwaitunit="second"><br> | |||||
| <available file="errors.log"/><br> | <available file="errors.log"/><br> | ||||
| </waitfor></code></p> | </waitfor></code></p> | ||||
| </blockquote> | </blockquote> | ||||
| <p>waits up to 30 seconds for a file called errors.log to appear.</p> | <p>waits up to 30 seconds for a file called errors.log to appear.</p> | ||||
| <blockquote> | <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> | <http url="http://localhost/myapp/index.html"/><br> | ||||
| </waitfor></code></p> | </waitfor></code></p> | ||||
| </blockquote> | </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> | 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> | <and><br> | ||||
| <socket server="dbserver" port="1521"/><br> | <socket server="dbserver" port="1521"/><br> | ||||
| <http url="http://webserver/mypage.html"/><br> | <http url="http://webserver/mypage.html"/><br> | ||||
| </and><br> | </and><br> | ||||
| </waitfor></code></p> | </waitfor></code></p> | ||||
| </blockquote> | </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> | to become available.</p> | ||||
| <hr><p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | <hr><p align="center">Copyright © 2000,2001 Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -75,13 +75,13 @@ import java.util.Hashtable; | |||||
| import java.util.Enumeration; | 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 | * 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> | * exist. It is possible to explicitly overwrite existing files.</p> | ||||
| * | * | ||||
| * <p>This implementation is based on Arnout Kuiper's initial design | * <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> | * copyfile/copydir tasks.</p> | ||||
| * | * | ||||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | * @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> | * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> | ||||
| */ | */ | ||||
| public class Copy extends Task { | 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 File destDir = null; // the destination directory | ||||
| protected Vector filesets = new Vector(); | protected Vector filesets = new Vector(); | ||||
| @@ -108,7 +108,7 @@ public class Copy extends Task { | |||||
| protected Mapper mapperElement = null; | protected Mapper mapperElement = null; | ||||
| private Vector filterSets = new Vector(); | private Vector filterSets = new Vector(); | ||||
| private FileUtils fileUtils; | private FileUtils fileUtils; | ||||
| public Copy() { | public Copy() { | ||||
| fileUtils = FileUtils.newFileUtils(); | fileUtils = FileUtils.newFileUtils(); | ||||
| } | } | ||||
| @@ -144,12 +144,22 @@ public class Copy extends Task { | |||||
| filterSets.addElement(filterSet); | filterSets.addElement(filterSet); | ||||
| return filterSet; | return filterSet; | ||||
| } | } | ||||
| /** | /** | ||||
| * Give the copied files the same last modified time as the original files. | * 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) { | 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() { | protected Vector getFilterSets() { | ||||
| return filterSets; | return filterSets; | ||||
| } | } | ||||
| /** | /** | ||||
| * Sets filtering. | * Sets filtering. | ||||
| */ | */ | ||||
| @@ -194,8 +204,8 @@ public class Copy extends Task { | |||||
| this.verbosity = Project.MSG_INFO; | this.verbosity = Project.MSG_INFO; | ||||
| } else { | } else { | ||||
| this.verbosity = Project.MSG_VERBOSE; | this.verbosity = Project.MSG_VERBOSE; | ||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Used to copy empty directories. | * Used to copy empty directories. | ||||
| @@ -228,7 +238,7 @@ public class Copy extends Task { | |||||
| */ | */ | ||||
| public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
| // make sure we don't have an illegal set of options | // make sure we don't have an illegal set of options | ||||
| validateAttributes(); | |||||
| validateAttributes(); | |||||
| // deal with the single file | // deal with the single file | ||||
| if (file != null) { | if (file != null) { | ||||
| @@ -236,8 +246,8 @@ public class Copy extends Task { | |||||
| if (destFile == null) { | if (destFile == null) { | ||||
| destFile = new File(destDir, file.getName()); | destFile = new File(destDir, file.getName()); | ||||
| } | } | ||||
| if (forceOverwrite || | |||||
| if (forceOverwrite || | |||||
| (file.lastModified() > destFile.lastModified())) { | (file.lastModified() > destFile.lastModified())) { | ||||
| fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath()); | fileCopyMap.put(file.getAbsolutePath(), destFile.getAbsolutePath()); | ||||
| } else { | } else { | ||||
| @@ -245,7 +255,7 @@ public class Copy extends Task { | |||||
| Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
| } | } | ||||
| } else { | } else { | ||||
| String message = "Could not find file " | |||||
| String message = "Could not find file " | |||||
| + file.getAbsolutePath() + " to copy."; | + file.getAbsolutePath() + " to copy."; | ||||
| log(message); | log(message); | ||||
| throw new BuildException(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 | * 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. | * of attributes. | ||||
| */ | */ | ||||
| protected void validateAttributes() throws BuildException { | protected void validateAttributes() throws BuildException { | ||||
| @@ -299,7 +309,7 @@ public class Copy extends Task { | |||||
| if (file != null && file.exists() && file.isDirectory()) { | if (file != null && file.exists() && file.isDirectory()) { | ||||
| throw new BuildException("Use a fileset to copy directories."); | throw new BuildException("Use a fileset to copy directories."); | ||||
| } | } | ||||
| if (destFile != null && filesets.size() > 0) { | if (destFile != null && filesets.size() > 0) { | ||||
| if (filesets.size() > 1) { | if (filesets.size() > 1) { | ||||
| throw new BuildException( | throw new BuildException( | ||||
| @@ -368,7 +378,7 @@ public class Copy extends Task { | |||||
| SourceFileScanner ds = new SourceFileScanner(this); | SourceFileScanner ds = new SourceFileScanner(this); | ||||
| toCopy = ds.restrict(names, fromDir, toDir, mapper); | toCopy = ds.restrict(names, fromDir, toDir, mapper); | ||||
| } | } | ||||
| for (int i = 0; i < toCopy.length; i++) { | for (int i = 0; i < toCopy.length; i++) { | ||||
| File src = new File(fromDir, toCopy[i]); | File src = new File(fromDir, toCopy[i]); | ||||
| File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]); | File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]); | ||||
| @@ -382,8 +392,8 @@ public class Copy extends Task { | |||||
| */ | */ | ||||
| protected void doFileOperations() { | protected void doFileOperations() { | ||||
| if (fileCopyMap.size() > 0) { | 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() ); | " to " + destDir.getAbsolutePath() ); | ||||
| Enumeration e = fileCopyMap.keys(); | Enumeration e = fileCopyMap.keys(); | ||||
| @@ -398,7 +408,7 @@ public class Copy extends Task { | |||||
| try { | try { | ||||
| log("Copying " + fromFile + " to " + toFile, verbosity); | log("Copying " + fromFile + " to " + toFile, verbosity); | ||||
| FilterSetCollection executionFilters = new FilterSetCollection(); | FilterSetCollection executionFilters = new FilterSetCollection(); | ||||
| if (filtering) { | if (filtering) { | ||||
| executionFilters.addFilterSet(project.getGlobalFilterSet()); | executionFilters.addFilterSet(project.getGlobalFilterSet()); | ||||
| @@ -431,9 +441,9 @@ public class Copy extends Task { | |||||
| } | } | ||||
| if (count > 0) { | if (count > 0) { | ||||
| log("Copied " + count + | |||||
| " empty director" + | |||||
| (count==1?"y":"ies") + | |||||
| log("Copied " + count + | |||||
| " empty director" + | |||||
| (count==1?"y":"ies") + | |||||
| " to " + destDir.getAbsolutePath()); | " to " + destDir.getAbsolutePath()); | ||||
| } | } | ||||
| } | } | ||||
| @@ -55,14 +55,11 @@ | |||||
| package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
| import org.apache.tools.ant.BuildException; | 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.ConditionBase; | ||||
| import org.apache.tools.ant.taskdefs.condition.Condition; | 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. | * 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: | * The following attributes can be specified on a waitfor task: | ||||
| * <ul> | * <ul> | ||||
| * <li>maxwait - maximum length of time to wait before giving up</li> | * <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>checkevery - amount of time to sleep between each check</li> | ||||
| * <li>checkeveryunit - The unit to be used to interpret checkevery attribute</li> | |||||
| * </ul> | * </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:denis@network365.com">Denis Hennessy</a> | ||||
| * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a> | |||||
| */ | */ | ||||
| public class WaitFor extends ConditionBase { | 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 | * 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 | * 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"); | 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; | |||||
| } | } | ||||
| } | } | ||||