package org.jdesktop.application;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
public class TaskService extends AbstractBean {
private final String name;
private final ExecutorService executorService;
private final List<Task> tasks;
private final PropertyChangeListener taskPCL;
public TaskService(String name, ExecutorService executorService) {
if (name == null) {
throw new IllegalArgumentException("null name");
}
if (executorService == null) {
throw new IllegalArgumentException("null executorService");
}
this.name = name;
this.executorService = executorService;
this.tasks = new ArrayList<Task>();
this.taskPCL = new TaskPCL();
}
public TaskService(String name) {
this(name, new ThreadPoolExecutor(
3, // corePool size
10, // maximumPool size
1L, TimeUnit.SECONDS, // non-core threads time to live
new LinkedBlockingQueue<Runnable>()));
}
public final String getName() {
return name;
}
private List<Task> copyTasksList() {
synchronized(tasks) {
if (tasks.isEmpty()) {
return Collections.emptyList();
}
else {
return new ArrayList<Task>(tasks);
}
}
}
private class TaskPCL implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if ("done".equals(propertyName)) {
Task task = (Task)(e.getSource());
if (task.isDone()) {
List<Task> oldTaskList, newTaskList;
synchronized(tasks) {
oldTaskList = copyTasksList();
tasks.remove(task);
task.removePropertyChangeListener(taskPCL);
newTaskList = copyTasksList();
}
firePropertyChange("tasks", oldTaskList, newTaskList);
Task.InputBlocker inputBlocker = task.getInputBlocker();
if (inputBlocker != null) {
inputBlocker.unblock();
}
}
}
}
}
private void maybeBlockTask(Task task) {
final Task.InputBlocker inputBlocker = task.getInputBlocker();
if (inputBlocker == null) {
return;
}
if (inputBlocker.getScope() != Task.BlockingScope.NONE) {
if (SwingUtilities.isEventDispatchThread()) {
inputBlocker.block();
}
else {
Runnable doBlockTask = new Runnable() {
public void run() {
inputBlocker.block();
}
};
SwingUtilities.invokeLater(doBlockTask);
}
}
}
public void execute(Task task) {
if (task == null) {
throw new IllegalArgumentException("null task");
}
if (!task.isPending() || (task.getTaskService() != null)) {
throw new IllegalArgumentException("task has already been executed");
}
task.setTaskService(this);
// TBD: what if task has already been submitted?
List<Task> oldTaskList, newTaskList;
synchronized(tasks) {
oldTaskList = copyTasksList();
tasks.add(task);
newTaskList = copyTasksList();
task.addPropertyChangeListener(taskPCL);
}
firePropertyChange("tasks", oldTaskList, newTaskList);
maybeBlockTask(task);
executorService.execute(task);
}
public List<Task> getTasks() {
return copyTasksList();
}
public final void shutdown() {
executorService.shutdown();
}
public final List<Runnable> shutdownNow() {
return executorService.shutdownNow();
}
public final boolean isShutdown() {
return executorService.isShutdown();
}
public final boolean isTerminated() {
return executorService.isTerminated();
}
public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return executorService.awaitTermination(timeout, unit);
}
}