summaryrefslogtreecommitdiffstats
path: root/src/main/java/net/sf/antcontrib/process/Limit.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net/sf/antcontrib/process/Limit.java')
-rw-r--r--src/main/java/net/sf/antcontrib/process/Limit.java402
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( );
+ }
+ }
+}
+
+
+