From 0b9e558b4ddc8adde8a21aaead93266873cbf9be Mon Sep 17 00:00:00 2001 From: mdb Date: Wed, 6 Dec 2000 03:25:19 +0000 Subject: [PATCH] Created services to facilitate doing things asynchronously in swing applications. git-svn-id: https://samskivert.googlecode.com/svn/trunk@22 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../java/com/samskivert/swing/util/Makefile | 11 +++ .../java/com/samskivert/swing/util/Task.java | 33 +++++++ .../com/samskivert/swing/util/TaskMaster.java | 98 +++++++++++++++++++ .../samskivert/swing/util/TaskObserver.java | 33 +++++++ 4 files changed, 175 insertions(+) create mode 100644 projects/samskivert/src/java/com/samskivert/swing/util/Makefile create mode 100644 projects/samskivert/src/java/com/samskivert/swing/util/Task.java create mode 100644 projects/samskivert/src/java/com/samskivert/swing/util/TaskMaster.java create mode 100644 projects/samskivert/src/java/com/samskivert/swing/util/TaskObserver.java diff --git a/projects/samskivert/src/java/com/samskivert/swing/util/Makefile b/projects/samskivert/src/java/com/samskivert/swing/util/Makefile new file mode 100644 index 00000000..ab5fa631 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/util/Makefile @@ -0,0 +1,11 @@ +# +# $Id: Makefile,v 1.1 2000/12/06 03:25:19 mdb Exp $ + +ROOT = ../../../.. + +SRCS = \ + Task.java \ + TaskMaster.java \ + TaskObserver.java \ + +include $(ROOT)/build/Makefile.java diff --git a/projects/samskivert/src/java/com/samskivert/swing/util/Task.java b/projects/samskivert/src/java/com/samskivert/swing/util/Task.java new file mode 100644 index 00000000..bc7a4f89 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/util/Task.java @@ -0,0 +1,33 @@ +// +// $Id: Task.java,v 1.1 2000/12/06 03:25:19 mdb Exp $ + +package com.samskivert.swing.util; + +/** + * A swing application requests that a task be invoked by the task + * master. The task master invokes the task on a separate thread and + * informs the swing application when the task has completed via the task + * observer interface. It does so in a way that plays nicely with the + * swing event dispatch thread (the swing application is notified of the + * task's completion on the event dispatch thread so that it can wiggle + * its user interface elements to its heart's desire). + */ +public interface Task +{ + /** + * This method is called by the task master to invoke the task. The + * task should run to completion and return some value. + */ + public Object invoke (); + + /** + * This method is called by the task master when it has received a + * request to cancel this task. If the task can be cancelled, abort + * should return true and the currently running call to + * invoke() should immediately return (the return value + * will be ignored). If the task cannot be cancelled, abort should + * return false and the task master will simply abandon the task and + * the thread on which it is running. + */ + public boolean abort (); +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/util/TaskMaster.java b/projects/samskivert/src/java/com/samskivert/swing/util/TaskMaster.java new file mode 100644 index 00000000..f2acd1b1 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/util/TaskMaster.java @@ -0,0 +1,98 @@ +// +// $Id: TaskMaster.java,v 1.1 2000/12/06 03:25:19 mdb Exp $ + +package com.samskivert.swing.util; + +import java.util.Hashtable; +import com.samskivert.util.Log; + +/** + * The task master provides the ability for swing applications to invoke + * tasks on another thread and to conveniently receive the results of + * those tasks back on the swing event dispatch thread where the swing + * application can safely manipulate its user interface in response to the + * results of the task. + * + *

Each task is run in it's own thread. Tasks are assumed to be + * infrequently run and expensive, so the overhead of creating a new + * thread to run each task is considered acceptable. If the need arises, + * the task master can be extended to support more sophisticated thread + * pooling but we'll cross that bridge when we come to it. + */ +public class TaskMaster +{ + /** The log object to be used by the task master and services. */ + public static Log log = new Log("com.samskivert.swing.util.task"); + + /** + * Instructs the task master to run the supplied task. The task is + * given the supplied name and can be referenced by that name in + * subsequent dealings with the task master. The supplied observer (if + * non-null) will be notified when the task has completed. + */ + public static void invokeTask (String name, Task task, + TaskObserver observer) + { + // create a task runner and stick it in our task table + TaskRunner runner = new TaskRunner(name, task, observer); + _tasks.put(name, runner); + // then start the runner up + runner.start(); + } + + /** + * Called by the task runner to remove itself from the task table when + * the task has completed or been aborted. + */ + protected static void removeTask (String name) + { + _tasks.remove(name); + } + + protected static class TaskRunner extends Thread + { + public TaskRunner (String name, Task task, TaskObserver observer) + { + _name = name; + _task = task; + _observer = observer; + } + + public void run () + { + try { + Object result = _task.invoke(); + if (_observer != null) { + try { + _observer.taskCompleted(_name, result); + } catch (Throwable t) { + log.warning("Observer choked in " + + "taskCompleted(): " + t); + } + } + + } catch (Throwable t) { + if (_observer != null) { + try { + _observer.taskFailed(_name, t); + } catch (Throwable ot) { + log.warning("Observer choked in taskFailed(): " + ot); + } + } + } + + TaskMaster.removeTask(_name); + } + + public void abort () + { + log.warning("abort() not currently supported."); + } + + protected String _name; + protected Task _task; + protected TaskObserver _observer; + } + + protected static Hashtable _tasks = new Hashtable(); +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/util/TaskObserver.java b/projects/samskivert/src/java/com/samskivert/swing/util/TaskObserver.java new file mode 100644 index 00000000..d58e315a --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/util/TaskObserver.java @@ -0,0 +1,33 @@ +// +// $Id: TaskObserver.java,v 1.1 2000/12/06 03:25:19 mdb Exp $ + +package com.samskivert.swing.util; + +/** + * The task observer interface provides the means by which the task master + * can communicate the success or failure of a task invocation back to the + * originator of a task. + */ +public interface TaskObserver +{ + /** + * If the task successfully runs to completion and returns a result, + * this member function will be called on the supplied observer. + * + * @param name The name under which the task was originally invoked. + * @param result The result returned by the task's + * invoke() method. + */ + public void taskCompleted (String name, Object result); + + /** + * If the task fails to run to completion and instead throws an + * exception, this member function will be called on the supplied + * observer. + * + * @param name The name under which the task was originally invoked. + * @param exception The exception thrown by the task during the call + * to invoke(). + */ + public void taskFailed (String name, Throwable exception); +}