Major cleanup of Utils class.
[trakem2.git] / ini / trakem2 / utils / Bureaucrat.java
bloba8b794584f4500eece292e726b6c267bf33b7ecc
1 /**
3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2005,2006 Albert Cardona and Rodney Douglas.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 You may contact Albert Cardona at acardona at ini.phys.ethz.ch
20 Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
21 **/
23 package ini.trakem2.utils;
25 import ini.trakem2.ControlWindow;
26 import ini.trakem2.Project;
27 import ini.trakem2.persistence.Loader;
28 import ini.trakem2.utils.Utils;
29 import java.util.ArrayList;
31 /** Sets a Worker thread to work, and waits until it finishes, blocking all user interface input until then, except for zoom and pan, for all given projects. */
32 public class Bureaucrat extends Thread {
33 private Worker worker;
34 private Thread worker_thread;
35 private long onset;
36 private Project[] project;
37 private boolean started = false;
38 /** A list of tasks to run when the Worker finishes of quits. */
39 private ArrayList<Runnable> post_tasks = new ArrayList<Runnable>();
41 /** Registers itself in the project loader job queue. */
42 private Bureaucrat(ThreadGroup tg, Worker worker, Project project) {
43 this(tg, worker, new Project[]{project});
45 private Bureaucrat(ThreadGroup tg, Worker worker, Project[] project) {
46 super(tg, "T2-Bureaucrat");
47 setPriority(Thread.NORM_PRIORITY);
48 this.worker = worker;
49 this.worker_thread = new Thread(tg, worker, worker.getThreadName());
50 this.worker_thread.setPriority(NORM_PRIORITY);
51 worker.setThread(worker_thread);
52 this.project = project;
53 onset = System.currentTimeMillis();
54 for (int i=0; i<project.length; i++) {
55 project[i].setReceivesInput(false);
56 project[i].getLoader().addJob(this);
60 /** Creates but does not start the Bureaucrat thread. */
61 static public Bureaucrat create(Worker worker, Project project) {
62 return create (worker, new Project[]{project});
65 /** Creates but does not start the Bureaucrat thread. */
66 static public Bureaucrat create(Worker worker, Project[] project) {
67 ThreadGroup tg = new ThreadGroup("T2-Bureaucrat for " + worker.getTaskName());
68 return new Bureaucrat(tg, worker, project);
71 /** Creates and start the Bureaucrat thread. */
72 static public Bureaucrat createAndStart(Worker worker, Project project) {
73 return createAndStart(worker, new Project[]{project});
76 /** Creates and start the Bureaucrat thread. */
77 static public Bureaucrat createAndStart(Worker worker, Project[] project) {
78 ThreadGroup tg = new ThreadGroup("T2-Bureaucrat for " + worker.getTaskName());
79 Bureaucrat burro = new Bureaucrat(tg, worker, project);
80 burro.goHaveBreakfast();
81 return burro;
84 /** Starts the Bureaucrat thread: sets the worker to work and monitors it until it finishes.*/
85 public void goHaveBreakfast() {
86 worker_thread.start();
87 // Make sure we start AFTER the worker has started.
88 while (!worker.hasStarted()) {
89 try { Thread.currentThread().sleep(50); } catch (InterruptedException ie) { ie.printStackTrace(); }
91 start();
92 // Make sure we return AFTER having started.
93 while (!started) {
94 try { Thread.currentThread().sleep(50); } catch (InterruptedException ie) { ie.printStackTrace(); }
97 private void cleanup() {
98 Utils.showProgress(1); // cleanup all possible interruptions
99 for (int i=0; i<project.length; i++) {
100 project[i].getLoader().removeJob(this);
101 project[i].setReceivesInput(true);
104 public void run() {
105 started = true;
106 // wait until worker starts
107 while (!worker.isWorking()) {
108 try { Thread.sleep(50); } catch (InterruptedException ie) {}
109 if (worker.hasQuitted() || worker_thread.isInterrupted()) {
110 //Utils.log("Cleaning up...");
111 worker.cleanup2();
112 cleanup();
113 //Utils.log("...done.");
114 return;
117 ControlWindow.startWaitingCursor();
118 int sandwitch = ControlWindow.isGUIEnabled() ? 100 : 5000; // 1 second or 5
119 Utils.showStatus("Started processing: " + worker.getTaskName(), false); // don't steal focus, ever
120 final StringBuffer sb = new StringBuffer("Processing... ").append(worker.getTaskName()).append(" - ");
121 final int base_len = sb.length();
122 while (worker.isWorking() && !worker.hasQuitted()) {
123 try { Thread.sleep(sandwitch); } catch (InterruptedException ie) {}
124 float elapsed_seconds = (System.currentTimeMillis() - onset) / 1000.0f;
125 if (elapsed_seconds < 60) {
126 sb.append(elapsed_seconds).append(" seconds");
127 } else {
128 sb.append(elapsed_seconds / 60).append("' ").append(elapsed_seconds % 60).append("''");
130 Utils.showStatus(sb.toString(), false); // don't steal focus
131 // Increment up to 1 second
132 if (sandwitch < 1000) sandwitch += 100;
133 // reset:
134 sb.setLength(base_len);
136 ControlWindow.endWaitingCursor();
137 Utils.showStatus("Done " + worker.getTaskName(), false); // don't steal focus
138 try {
139 if (null != post_tasks) {
140 for (final Runnable r : post_tasks) {
141 try {
142 r.run();
143 } catch (Throwable t) {
144 IJError.print(t);
148 } catch(Throwable t) {
149 IJError.print(t);
151 cleanup();
153 /** Returns the task the worker is currently executing, which may change over time. */
154 public String getTaskName() {
155 return worker.getTaskName();
157 /** Waits until worker finishes before returning.
158 * Calls quit() on the Worker and interrupt() on each threads in this ThreadGroup and subgroups. */
159 public void quit() {
160 try {
162 // Cancel post tasks:
163 synchronized (post_tasks) {
164 post_tasks.clear();
165 post_tasks = null;
168 Utils.log2("ThreadGroup is " + getThreadGroup());
170 Utils.log2("ThreadGroup active thread count: " + getThreadGroup().activeCount());
171 Utils.log2("ThreadGroup active group count: " + getThreadGroup().activeGroupCount());
173 Thread[] active = new Thread[getThreadGroup().activeCount()];
174 int count = getThreadGroup().enumerate(active);
175 Utils.log2("Active threads: " + count);
176 for (int i=0; i < count; i++) {
177 Utils.log2("Active thread: " + active[i]);
180 // Set flag to each thread and thread in subgroup to quit:
181 worker.quit();
182 getThreadGroup().interrupt();
184 } catch (Exception e) {
185 IJError.print(e);
187 // wait until worker finishes
188 try {
189 Utils.log("Waiting for worker to quit...");
190 worker_thread.join();
191 Utils.log("Worker quitted.");
192 } catch (InterruptedException ie) {
193 IJError.print(ie);
195 // wait for all others in a separate thread
196 final ThreadGroup tg = getThreadGroup();
197 new Thread() { public void run() {
198 try {
199 // Reasonable effort to join all threads
200 Thread[] t = new Thread[tg.activeCount() * 2];
201 int len = tg.enumerate(t);
202 for (int i=0; i<len && i<t.length; i++) {
203 try { t[i].join(); } catch (InterruptedException ie) {}
205 } catch (Exception e) {
206 IJError.print(e);
207 } finally {
208 Utils.showProgress(1);
210 }}.start();
212 public boolean isActive() {
213 return worker.isWorking();
215 public Worker getWorker() {
216 return worker;
218 /** Add a task to run after the Worker has finished or quit. Does not accept more tasks once the Worker no longer runs. */
219 public boolean addPostTask(final Runnable task) {
220 if (worker.hasQuitted() || null == post_tasks) return false;
221 synchronized (post_tasks) {
222 this.post_tasks.add(task);
224 return true;