/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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
 *
 *      https://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 org.apache.tools.ant.util;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

A worker ant executes a single task in a background thread. After the run, any exception thrown is turned into a BuildException, which can be rethrown, the finished attribute is set, then notifyAll() is called, so that anyone waiting on the same notify object gets woken up.

This class is effectively a superset of org.apache.tools.ant.taskdefs.Parallel.TaskRunnable

Since:Ant 1.8
/** * A worker ant executes a single task in a background thread. * After the run, any exception thrown is turned into a BuildException, which can be * rethrown, the finished attribute is set, then notifyAll() is called, * so that anyone waiting on the same notify object gets woken up. * <p> * This class is effectively a superset of * <code>org.apache.tools.ant.taskdefs.Parallel.TaskRunnable</code> * * @since Ant 1.8 */
public class WorkerAnt extends Thread { private Task task; private Object notify; private volatile boolean finished = false; private volatile BuildException buildException; private volatile Throwable exception;
Error message if invoked with no task
/** * Error message if invoked with no task */
public static final String ERROR_NO_TASK = "No task defined";
Create the worker.

This does not start the thread, merely configures it.

Params:
  • task – the task
  • notify – what to notify
/** * Create the worker. * <p> * This does not start the thread, merely configures it. * @param task the task * @param notify what to notify */
public WorkerAnt(Task task, Object notify) { this.task = task; this.notify = notify != null ? notify : this; }
Create the worker, using the worker as the notification point.

This does not start the thread, merely configures it.

Params:
  • task – the task
/** * Create the worker, using the worker as the notification point. * <p> * This does not start the thread, merely configures it. * @param task the task */
public WorkerAnt(Task task) { this(task, null); }
Get any build exception. This would seem to be oversynchronised, but know that Java pre-1.5 can reorder volatile access. The synchronized attribute is to force an ordering.
Returns:the exception or null
/** * Get any build exception. * This would seem to be oversynchronised, but know that Java pre-1.5 can * reorder volatile access. * The synchronized attribute is to force an ordering. * * @return the exception or null */
public synchronized BuildException getBuildException() { return buildException; }
Get whatever was thrown, which may or may not be a buildException. Assertion: getException() instanceof BuildException <=> getBuildException()==getException()
Returns:the exception.
/** * Get whatever was thrown, which may or may not be a buildException. * Assertion: getException() instanceof BuildException &lt;=&gt; getBuildException()==getException() * @return the exception. */
public synchronized Throwable getException() { return exception; }
Get the task
Returns:the task
/** * Get the task * @return the task */
public Task getTask() { return task; }
Query the task/thread for being finished. This would seem to be oversynchronised, but know that Java pre-1.5 can reorder volatile access. The synchronized attribute is to force an ordering.
Returns:true if the task is finished.
/** * Query the task/thread for being finished. * This would seem to be oversynchronised, but know that Java pre-1.5 can * reorder volatile access. * The synchronized attribute is to force an ordering. * @return true if the task is finished. */
public synchronized boolean isFinished() { return finished; }
Block on the notify object and so wait until the thread is finished.
Params:
  • timeout – timeout in milliseconds
Throws:
/** * Block on the notify object and so wait until the thread is finished. * @param timeout timeout in milliseconds * @throws InterruptedException if the execution was interrupted */
public void waitUntilFinished(long timeout) throws InterruptedException { final long start = System.currentTimeMillis(); final long end = start + timeout; synchronized (notify) { long now = System.currentTimeMillis(); while (!finished && now < end) { notify.wait(end - now); now = System.currentTimeMillis(); } } }
Raise an exception if one was caught
Throws:
  • BuildException – if one has been picked up
/** * Raise an exception if one was caught * * @throws BuildException if one has been picked up */
public void rethrowAnyBuildException() { BuildException ex = getBuildException(); if (ex != null) { throw ex; } }
Handle a caught exception, by recording it and possibly wrapping it in a BuildException for later rethrowing.
Params:
  • thrown – what was caught earlier
/** * Handle a caught exception, by recording it and possibly wrapping it * in a BuildException for later rethrowing. * @param thrown what was caught earlier */
private synchronized void caught(Throwable thrown) { exception = thrown; buildException = (thrown instanceof BuildException) ? (BuildException) thrown : new BuildException(thrown); }
Run the task, which is skipped if null. When invoked again, the task is re-run.
/** * Run the task, which is skipped if null. * When invoked again, the task is re-run. */
public void run() { try { if (task != null) { task.execute(); } } catch (Throwable thrown) { caught(thrown); } finally { synchronized (notify) { finished = true; //reset the task. //wake up our owner, if it is waiting notify.notifyAll(); } } } }