/**
TrakEM2 plugin for ImageJ(C).
Copyright (C) 2005-2009 Albert Cardona and Rodney Douglas.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt)
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
You may contact Albert Cardona at acardona at ini.phys.ethz.ch
Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
**/
package ini.trakem2.utils;
import ij.IJ;
import ini.trakem2.ControlWindow;
import java.util.HashMap;
public abstract class Worker implements Runnable {
private String thread_name;
private String task_name;
private Thread thread;
private volatile boolean working = false;
protected volatile boolean quit = false;
private volatile boolean started = false;
private volatile boolean background = false;
private boolean interrupt_on_quit = false;
/** Extending classes may store a resulting piece of data. */
protected Object result = null;
public Worker(String task_name) {
this(task_name, !ControlWindow.isGUIEnabled() || null == IJ.getInstance());
}
public Worker(String task_name, boolean headless_mode) {
super(); // the Run$_ tag is for ImageJ to properly grant it Macro.getOptions()
this.thread_name = (headless_mode ? "Run$_": "") + "Worker";
this.task_name = task_name;
}
public Worker(String task_name, boolean headless_mode, boolean interrupt_on_quit) {
this(task_name, headless_mode);
this.interrupt_on_quit = interrupt_on_quit;
}
// private to the package
void setThread(Thread t) {
this.thread = t;
}
public void setTaskName(String name) { this.task_name = name; }
protected void startedWorking() {
this.working = true;
this.started = true;
}
public boolean hasStarted() { return started; }
protected void finishedWorking() { this.working = false; this.quit = true; }
public boolean isWorking() { return working; }
public String getTaskName() { return task_name; }
public String getThreadName() { return thread_name; }
public void setPriority(int priority) {
if (null != this.thread) thread.setPriority(priority);
}
/** If interrupt_on_quit, then it will call thread.getThreadGroup().interrupt() to set a quit flag to each child thread. */
public void quit() {
this.quit = true;
if (interrupt_on_quit) {
if (null != thread) thread.getThreadGroup().interrupt();
}
}
public void join() throws InterruptedException {
if (null != thread) thread.join();
}
public boolean hasQuitted() { return this.quit; }
protected void setAsBackground(boolean b) { this.background = b; }
/** Whether the work is done on the background, without need to bring ImageJ toolbar to front for instance. */
public boolean onBackground() { return this.background; }
private boolean cleaned_up = false;
// private to the package
void cleanup2() {
synchronized (this) {
if (cleaned_up) return;
cleaned_up = true;
}
cleanup();
}
/** When quitted or interrupted, executes this method once. */
public void cleanup() {}
/** Returns data generated by the worker, or null if none was set. */
public Object getResult() { return this.result; }
// ugly, ugly ... why, java, do you make me do this, when all I need is a closure?
private HashMap<Object,Object> properties = null;
public synchronized void setProperty(Object key, Object value) {
if (null == key) return;
if (null == properties) properties = new HashMap<Object,Object>();
properties.put(key, value);
}
public synchronized Object getProperty(Object key) {
if (null == key || null == properties) return null;
return properties.get(key);
}
/** A class that calls run() wrapped properly for task monitoring;
* Create it like this:
*
* Bureaucrat b = Bureaucrat.createAndStart(new Worker.Task("Title") { public void exec() {
* doSomething();
* doSomethingElse();
* }}, project);
*
*/
static public abstract class Task extends Worker {
public Task(String title) {
super(title);
}
public Task(String title, boolean interrupt_on_quit) {
this(title);
super.interrupt_on_quit = interrupt_on_quit;
}
abstract public void exec();
public void run() {
try {
startedWorking();
exec();
} catch (Throwable t) {
IJError.print(t);
} finally {
finishedWorking();
}
}
}
}