001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import java.util.HashMap;
022: import java.util.Map;
023: import org.apache.tools.ant.BuildException;
024: import org.apache.tools.ant.Project;
025: import org.apache.tools.ant.taskdefs.condition.Condition;
026: import org.apache.tools.ant.taskdefs.condition.ConditionBase;
027: import org.apache.tools.ant.types.EnumeratedAttribute;
028:
029: /**
030: * Wait for an external event to occur.
031: *
032: * Wait for an external process to start or to complete some
033: * task. This is useful with the <code>parallel</code> task to
034: * synchronize the execution of tests with server startup.
035: *
036: * The following attributes can be specified on a waitfor task:
037: * <ul>
038: * <li>maxwait - maximum length of time to wait before giving up</li>
039: * <li>maxwaitunit - The unit to be used to interpret maxwait attribute</li>
040: * <li>checkevery - amount of time to sleep between each check</li>
041: * <li>checkeveryunit - The unit to be used to interpret checkevery attribute</li>
042: * <li>timeoutproperty - name of a property to set if maxwait has been exceeded.</li>
043: * </ul>
044: *
045: * The maxwaitunit and checkeveryunit are allowed to have the following values:
046: * millisecond, second, minute, hour, day and week. The default is millisecond.
047: *
048: * For programmatic use/subclassing, there are two methods that may be overrridden,
049: * <code>processSuccess</code> and <code>processTimeout</code>
050: * @since Ant 1.5
051: *
052: * @ant.task category="control"
053: */
054: public class WaitFor extends ConditionBase {
055: /** default max wait time */
056: private long maxWaitMillis = 1000L * 60L * 3L;
057: private long maxWaitMultiplier = 1L;
058: private long checkEveryMillis = 500L;
059: private long checkEveryMultiplier = 1L;
060: private String timeoutProperty;
061:
062: /**
063: * Constructor, names this task "waitfor".
064: */
065: public WaitFor() {
066: super ("waitfor");
067: }
068:
069: /**
070: * Set the maximum length of time to wait.
071: * @param time a <code>long</code> value
072: */
073: public void setMaxWait(long time) {
074: maxWaitMillis = time;
075: }
076:
077: /**
078: * Set the max wait time unit
079: * @param unit an enumerated <code>Unit</code> value
080: */
081: public void setMaxWaitUnit(Unit unit) {
082: maxWaitMultiplier = unit.getMultiplier();
083: }
084:
085: /**
086: * Set the time between each check
087: * @param time a <code>long</code> value
088: */
089: public void setCheckEvery(long time) {
090: checkEveryMillis = time;
091: }
092:
093: /**
094: * Set the check every time unit
095: * @param unit an enumerated <code>Unit</code> value
096: */
097: public void setCheckEveryUnit(Unit unit) {
098: checkEveryMultiplier = unit.getMultiplier();
099: }
100:
101: /**
102: * Name the property to set after a timeout.
103: * @param p the property name
104: */
105: public void setTimeoutProperty(String p) {
106: timeoutProperty = p;
107: }
108:
109: /**
110: * Check repeatedly for the specified conditions until they become
111: * true or the timeout expires.
112: * @throws BuildException on error
113: */
114: public void execute() throws BuildException {
115: if (countConditions() > 1) {
116: throw new BuildException("You must not nest more than one "
117: + "condition into " + getTaskName());
118: }
119: if (countConditions() < 1) {
120: throw new BuildException("You must nest a condition into "
121: + getTaskName());
122: }
123: Condition c = (Condition) getConditions().nextElement();
124:
125: long savedMaxWaitMillis = maxWaitMillis;
126: long savedCheckEveryMillis = checkEveryMillis;
127: try {
128: maxWaitMillis *= maxWaitMultiplier;
129: checkEveryMillis *= checkEveryMultiplier;
130: long start = System.currentTimeMillis();
131: long end = start + maxWaitMillis;
132:
133: while (System.currentTimeMillis() < end) {
134: if (c.eval()) {
135: processSuccess();
136: return;
137: }
138: try {
139: Thread.sleep(checkEveryMillis);
140: } catch (InterruptedException e) {
141: // ignore
142: }
143: }
144: processTimeout();
145: } finally {
146: maxWaitMillis = savedMaxWaitMillis;
147: checkEveryMillis = savedCheckEveryMillis;
148: }
149: }
150:
151: /**
152: * Actions to be taken on a successful waitfor.
153: * This is an override point. The base implementation does nothing.
154: * @since Ant1.7
155: */
156: protected void processSuccess() {
157: log(getTaskName() + ": condition was met", Project.MSG_VERBOSE);
158: }
159:
160: /**
161: * Actions to be taken on an unsuccessful wait.
162: * This is an override point. It is where the timeout processing takes place.
163: * The base implementation sets the timeoutproperty if there was a timeout
164: * and the property was defined.
165: * @since Ant1.7
166: */
167: protected void processTimeout() {
168: log(getTaskName() + ": timeout", Project.MSG_VERBOSE);
169: if (timeoutProperty != null) {
170: getProject().setNewProperty(timeoutProperty, "true");
171: }
172: }
173:
174: /**
175: * The enumeration of units:
176: * millisecond, second, minute, hour, day, week
177: * @todo we use timestamps in many places, why not factor this out
178: */
179: public static class Unit extends EnumeratedAttribute {
180:
181: /** millisecond string */
182: public static final String MILLISECOND = "millisecond";
183: /** second string */
184: public static final String SECOND = "second";
185: /** minute string */
186: public static final String MINUTE = "minute";
187: /** hour string */
188: public static final String HOUR = "hour";
189: /** day string */
190: public static final String DAY = "day";
191: /** week string */
192: public static final String WEEK = "week";
193:
194: private static final String[] UNITS = { MILLISECOND, SECOND,
195: MINUTE, HOUR, DAY, WEEK };
196:
197: private Map timeTable = new HashMap();
198:
199: /** Constructor the Unit enumerated type. */
200: public Unit() {
201: timeTable.put(MILLISECOND, new Long(1L));
202: timeTable.put(SECOND, new Long(1000L));
203: timeTable.put(MINUTE, new Long(1000L * 60L));
204: timeTable.put(HOUR, new Long(1000L * 60L * 60L));
205: timeTable.put(DAY, new Long(1000L * 60L * 60L * 24L));
206: timeTable.put(WEEK, new Long(1000L * 60L * 60L * 24L * 7L));
207: }
208:
209: /**
210: * Convert the value to a multipler (millisecond to unit).
211: * @return a multipler (a long value)
212: */
213: public long getMultiplier() {
214: String key = getValue().toLowerCase();
215: Long l = (Long) timeTable.get(key);
216: return l.longValue();
217: }
218:
219: /**
220: * @see EnumeratedAttribute#getValues()
221: */
222: /** {@inheritDoc} */
223: public String[] getValues() {
224: return UNITS;
225: }
226: }
227: }
|