diff options
Diffstat (limited to 'src/main/java/net/sf/antcontrib/process/Limit.java')
-rw-r--r-- | src/main/java/net/sf/antcontrib/process/Limit.java | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/src/main/java/net/sf/antcontrib/process/Limit.java b/src/main/java/net/sf/antcontrib/process/Limit.java new file mode 100644 index 0000000..b9cd7df --- /dev/null +++ b/src/main/java/net/sf/antcontrib/process/Limit.java @@ -0,0 +1,402 @@ + +/* +* Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved. +* +* 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 net.sf.antcontrib.process; + + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.TaskContainer; +import org.apache.tools.ant.types.EnumeratedAttribute; + + +/** + * Limits the amount of time that a task or set of tasks can run. This is useful + * for tasks that may "hang" or otherwise not complete in a timely fashion. This + * task is done when either the maxwait time has expired or all nested tasks are + * complete, whichever is first. + * + * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003. + * + * @author Dale Anson + * @author Robert D. Rice + * @version $Revision: 1.6 $ + * @since Ant 1.5 + */ +public class Limit extends Task implements TaskContainer { + + + // storage for nested tasks + private Vector tasks = new Vector(); + + + // time units, default value is 3 minutes. + private long maxwait = 180; + protected TimeUnit unit = TimeUnit.SECOND_UNIT; + + // property to set if time limit is reached + private String timeoutProperty = null; + private String timeoutValue = "true"; + + + // storage for task currently executing + private Task currentTask = null; + + + // used to control thread stoppage + private Thread taskRunner = null; + + + // should the build fail if the time limit has expired? Default is no. + private boolean failOnError = false; + + + private Exception exception = null; + + + + + /** + * Add a task to wait on. + * + * @param task A task to execute + * @exception BuildException won't happen + */ + public void addTask( Task task ) throws BuildException { + tasks.addElement( task ); + } + + + + + /** + * How long to wait for all nested tasks to complete, in units. + * Default is to wait 3 minutes. + * + * @param wait time to wait, set to 0 to wait forever. + */ + public void setMaxwait( int wait ) { + maxwait = wait; + } + + /** + * Sets the unit for the max wait. Default is minutes. + + * @param unit valid values are "millisecond", "second", "minute", "hour", "day", and "week". + + */ + public void setUnit( String unit ) { + if ( unit == null ) + return ; + if ( unit.equals( TimeUnit.SECOND ) ) { + setMaxWaitUnit( TimeUnit.SECOND_UNIT ); + return ; + } + if ( unit.equals( TimeUnit.MILLISECOND ) ) { + setMaxWaitUnit( TimeUnit.MILLISECOND_UNIT ); + return ; + } + if ( unit.equals( TimeUnit.MINUTE ) ) { + setMaxWaitUnit( TimeUnit.MINUTE_UNIT ); + return ; + } + if ( unit.equals( TimeUnit.HOUR ) ) { + setMaxWaitUnit( TimeUnit.HOUR_UNIT ); + return ; + } + if ( unit.equals( TimeUnit.DAY ) ) { + setMaxWaitUnit( TimeUnit.DAY_UNIT ); + return ; + } + if ( unit.equals( TimeUnit.WEEK ) ) { + setMaxWaitUnit( TimeUnit.WEEK_UNIT ); + return ; + } + + } + + /** + * Set a millisecond wait value. + * @param value the number of milliseconds to wait. + */ + public void setMilliseconds( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.MILLISECOND_UNIT ); + } + + /** + * Set a second wait value. + * @param value the number of seconds to wait. + */ + public void setSeconds( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.SECOND_UNIT ); + } + + /** + * Set a minute wait value. + * @param value the number of milliseconds to wait. + */ + public void setMinutes( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.MINUTE_UNIT ); + } + + /** + * Set an hours wait value. + * @param value the number of hours to wait. + */ + public void setHours( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.HOUR_UNIT ); + } + + /** + * Set a day wait value. + * @param value the number of days to wait. + */ + public void setDays( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.DAY_UNIT ); + } + + /** + * Set a week wait value. + * @param value the number of weeks to wait. + */ + public void setWeeks( int value ) { + setMaxwait( value ); + setMaxWaitUnit( TimeUnit.WEEK_UNIT ); + } + + /** + * Set the max wait time unit, default is minutes. + */ + public void setMaxWaitUnit( TimeUnit unit ) { + this.unit = unit; + } + + + /** + * Determines whether the build should fail if the time limit has + * expired on this task. + * Default is no. + * + * @param fail if true, fail the build if the time limit has been reached. + */ + public void setFailonerror( boolean fail ) { + failOnError = fail; + } + + + /** + * Name the property to set after a timeout. + * + * @param p of property to set if the time limit has been reached. + */ + public void setProperty( String p ) { + timeoutProperty = p; + } + + + /** + * The value for the property to set after a timeout, defaults to true. + * + * @param v for the property to set if the time limit has been reached. + */ + public void setValue( String v ) { + timeoutValue = v; + } + + + /** + * Execute all nested tasks, but stopping execution of nested tasks after + * maxwait or when all tasks are done, whichever is first. + * + * @exception BuildException Description of the Exception + */ + public void execute() throws BuildException { + try { + // start executing nested tasks + final Thread runner = + new Thread() { + public void run() { + Enumeration e = tasks.elements(); + while ( e.hasMoreElements() ) { + if ( taskRunner != this ) { + break; + } + currentTask = ( Task ) e.nextElement(); + try { + currentTask.perform(); + } + catch ( Exception ex ) { + if ( failOnError ) { + exception = ex; + return ; + } + else { + exception = ex; + } + } + } + } + }; + taskRunner = runner; + runner.start(); + runner.join( unit.toMillis( maxwait ) ); + + + // stop executing the nested tasks + if ( runner.isAlive() ) { + taskRunner = null; + runner.interrupt(); + int index = tasks.indexOf( currentTask ); + StringBuffer not_ran = new StringBuffer(); + for ( int i = index + 1; i < tasks.size(); i++ ) { + not_ran.append( '<' ).append( ( ( Task ) tasks.get( i ) ).getTaskName() ).append( '>' ); + if ( i < tasks.size() - 1 ) { + not_ran.append( ", " ); + } + } + + + // maybe set timeout property + if ( timeoutProperty != null ) { + getProject().setNewProperty( timeoutProperty, timeoutValue ); + } + + + // create output message + StringBuffer msg = new StringBuffer(); + msg.append( "Interrupted task <" ) + .append( currentTask.getTaskName() ) + .append( ">. Waited " ) + .append( ( maxwait ) ).append( " " ).append( unit.getValue() ) + .append( ", but this task did not complete." ) + .append( ( not_ran.length() > 0 ? + " The following tasks did not execute: " + not_ran.toString() + "." : + "" ) ); + + + // deal with it + if ( failOnError ) { + throw new BuildException( msg.toString() ); + } + else { + log( msg.toString() ); + } + } + else if ( failOnError && exception != null ) { + throw new BuildException( exception ); + } + } + catch ( Exception e ) { + throw new BuildException( e ); + } + } + + + /** + * The enumeration of units: + * millisecond, second, minute, hour, day, week + * Todo: we use timestamps in many places, why not factor this out + */ + public static class TimeUnit extends EnumeratedAttribute { + + public static final String MILLISECOND = "millisecond"; + public static final String SECOND = "second"; + public static final String MINUTE = "minute"; + public static final String HOUR = "hour"; + public static final String DAY = "day"; + public static final String WEEK = "week"; + + /** static unit objects, for use as sensible defaults */ + public static final TimeUnit MILLISECOND_UNIT = + new TimeUnit( MILLISECOND ); + public static final TimeUnit SECOND_UNIT = + new TimeUnit( SECOND ); + public static final TimeUnit MINUTE_UNIT = + new TimeUnit( MINUTE ); + public static final TimeUnit HOUR_UNIT = + new TimeUnit( HOUR ); + public static final TimeUnit DAY_UNIT = + new TimeUnit( DAY ); + public static final TimeUnit WEEK_UNIT = + new TimeUnit( WEEK ); + + + private static final String[] units = { + MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK + }; + + private Hashtable timeTable = new Hashtable(); + + public TimeUnit() { + 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 ) ); + } + + /** + * private constructor + * used for static construction of TimeUnit objects. + * @param value String representing the value. + */ + private TimeUnit( String value ) { + this( ); + setValueProgrammatically( value ); + } + + /** + * set the inner value programmatically. + * @param value to set + */ + protected void setValueProgrammatically( String value ) { + this.value = value; + } + + public long getMultiplier() { + String key = getValue().toLowerCase(); + Long l = ( Long ) timeTable.get( key ); + return l.longValue(); + } + + public String[] getValues() { + return units; + } + + /** + * convert the time in the current unit, to millis + * @param numberOfUnits long expressed in the current objects units + * @return long representing the value in millis + */ + public long toMillis( long numberOfUnits ) { + return numberOfUnits * getMultiplier( ); + } + } +} + + + |