Foxtrot

SourceForge.net Logo Java.net Logo

Overview

The Problem

Asynchronous Solution

Synchronous Solutions

Foxtrot

Foxtrot & Swing

Foxtrot API

The Foxtrot API is very small and simple, and consists of six main classes to be used in Swing applications:

  • class foxtrot.Worker
  • class foxtrot.ConcurrentWorker
  • class foxtrot.Task
  • class foxtrot.Job
  • class foxtrot.AsyncWorker
  • class foxtrot.AsyncTask

From Foxtrot 2.x, the API has been extended to allow customization of the part that handles event pumping and of the part that handles execution of Tasks and Jobs in a worker thread, via the following classes:

  • interface foxtrot.EventPump
  • interface foxtrot.WorkerThread
  • class foxtrot.AbstractWorkerThread

Normally users do not need to deal with the above three classes to use Foxtrot in their Swing applications, since Foxtrot will configure itself with the most suitable implementations; however, if a specific customization of the event pumping mechanism or of the worker thread mechanism is needed, the APIs provided by these classes allow fine grained control on Foxtrot's behavior.

Foxtrot API Details

The Worker class is used to post with blocking behavior Tasks or Jobs that will be executed sequentially in one Foxtrot Worker Thread.

The ConcurrentWorker class is used to post with blocking behavior Tasks or Jobs that will be executed each one in its own Foxtrot Worker Thread (thus Tasks or Jobs are executed concurrently).

The AsyncWorker class is used to post with non-blocking behavior AsyncTasks that will be executed each one in its own Foxtrot Worker Thread (thus AsyncTasks are executed concurrently).

The Task class is subclassed by the user to perform heavy tasks that throw checked exceptions.

The Job class, conversely, is subclassed by the user to perform heavy tasks that do not throw checked exceptions, but only RuntimeExceptions (or Errors).

The AsyncTask class is subclassed by the user to perform asynchronous heavy tasks and to post an event to the Event Dispatch Thread when the AsyncTask is completed.

The Worker and ConcurrentWorker classes have the following two public methods that can be used to post Tasks or Jobs:

  • public static Object post(Task task) throws Exception
  • public static Object post(Job job)

The Task class has a single abstract method that must be implemented by the user, with the time-consuming code that may throw checked exceptions:

  • public abstract Object run() throws Exception

The Job class, conversely, has a single abstract method that must be implemented by the user, with the time-consuming code that does not throw checked exceptions:

  • public abstract Object run()

The exceptions or errors thrown inside the Task.run() or Job.run() methods are re-thrown by the corrispondent Worker.post(...) method as is, i.e. without being wrapped into, for example, an InvocationTargetException.

The AsyncWorker class has only one public method that can be used to post AsyncTasks:

  • public static Object post(AsyncTask task)

The AsyncTask class has three abstract method that must be implemented by the user:

  • public abstract Object run() throws Exception
  • public abstract void success(Object result)
  • public abstract void failure(Throwable x)

The run() method must be implemented with the time-consuming code exactly like the Task class.
The success(Object result) method must be implemented with the code to execute in case the Task completed successfully, and will be run in the Event Dispatch Thread.
The failure(Throwable x) method must be implemented with the code to execute in case the Task threw an Exception or an Error, and will be run in the Event Dispatch Thread.

Here is an example of Worker with the Job class:


Worker.post(new Job()
{
   public Object run()
   {
      // Here write the time-consuming code
      // that does not throw checked exceptions
   }
});

and here is an example of Worker with the Task class:


try
{
   Worker.post(new Task()
   {
      public Object run() throws Exception
      {
         // Here write the time-consuming code
         // that may throw checked exceptions
      }
   });
}
catch (Exception x)
{
   // Handle the exception thrown by the Task
}

It is possible to narrow the throws clause of the Task class, but unfortunately not the one of the Worker or ConcurrentWorker classes.
So, when using the post(Task task) method, you have to surround it in a try...catch(Exception x) block (unless the method that contains post(Task task) throws Exception itself).


try
{
   Worker.post(new Task()
   {
      public Object run() throws FileNotFoundException
      {
         // Here write the time-consuming code
         // that accesses the file system
      }
   });
}
catch (FileNotFoundException x)
{
   // Handle the exception or rethrow.
}
catch (RuntimeException x)
{
   // RuntimeExceptions are always possible.
   // Catch them here to prevent they are
   // ignored by the catch(Exception ignored)
   // block below.
   throw x;
}
catch (Exception ignored)
{
   // No other checked exceptions are thrown
   // by the Task (the compiler will enforce this),
   // so we can safely ignore it, but we're forced
   // to write this catch block: Worker.post(Task t)
   // requires it.
}

Here's an example of AsyncWorker with the AsyncTask:


AsyncWorker.post(new AsyncTask()
{
   public Object run() throws Exception
   {
      // Here write the time-consuming code
      // that may throw checked exceptions
   }

   public void success(Object result)
   {
      // Here handle the result
   }

   public void failure(Throwable x)
   {
      // Here handle the exception possibly thrown by run(),
      // for example displaying a dialog to the user
   }
});

All worker classes (from Foxtrot 2.x) have the following public methods to deal with the WorkerThread component:

  • public static WorkerThread getWorkerThread()
  • public static void setWorkerThread(WorkerThread worker)

The Worker class (from Foxtrot 2.x) and the ConcurrentWorker class have also the following public methods to deal with the EventPump component:

  • public static EventPump getEventPump()
  • public static void setEventPump(EventPump pump)

Foxtrot configures itself automatically with the most suitable implementation of EventPump and WorkerThread. Some implementations of EventPump or WorkerThread allow an even further customization of the component.

For example, implementations of EventPump that also implement the foxtrot.pumps.EventFilterable interface may allow the user to filter events that are being dispatched by the java.awt.EventQueue. See also the Javadocs for further details.
However, it is recommended not to exploit these features unless knowing exactly what one is doing: Foxtrot's defaults may change from version to version to suit better implementations, and these defaults may depend on the Java Runtime Environment version Foxtrot is running on, so that features working in JDK 1.3.x may not work in JDK 1.4.x or viceversa.
Playing with AWT events too badly is normally looking for troubles, so consider you warned :)

The same holds for WorkerThread implementations, that should extend the abstract class AbstractWorkerThread: replacing the default WorkerThread implementation may lead to unexpected behavior.

Refer to the Javadoc documentation for further information, and to the examples for further details on how to use the Foxtrot classes with Swing.
And do not forget the Tips 'n' Tricks section !