001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 */
015 package org.springframework.richclient.util;
016
017 import java.lang.reflect.InvocationTargetException;
018
019 import javax.swing.SwingUtilities;
020
021 import EDU.oswego.cs.dl.util.concurrent.Callable;
022 import EDU.oswego.cs.dl.util.concurrent.FutureResult;
023 import EDU.oswego.cs.dl.util.concurrent.TimedCallable;
024
025 /**
026 * An abstract class that you subclass to perform GUI-related work in a
027 * dedicated thread.
028 * <p>
029 * This class was adapted from the SwingWorker class presented in "Using a Swing
030 * Worker Thread" in the Swing Connection archives
031 * http://java.sun.com/products/jfc/tsc/archive/archive.html
032 * <p>
033 * This version of SwingWorker extends FutureResult and implements Runnable.
034 * Timeouts are supported.
035 */
036 public abstract class SwingWorker extends FutureResult implements Runnable {
037 /** Worker thread. */
038 protected Thread thread;
039
040 /**
041 * Computes the value to be returned by the <code>get</code> method.
042 */
043 protected abstract Object construct() throws Exception;
044
045 /**
046 * Called on the event dispatching thread (not on the worker thread) after
047 * the <code>construct</code> method has returned.
048 */
049 protected void finished() {
050 }
051
052 protected Object getFinishedResult() {
053 try {
054 return get();
055 }
056 catch (InterruptedException e) {
057 throw new RuntimeException(
058 "Interrupted exception should not have occured; are you calling from finished()?");
059 }
060 catch (InvocationTargetException e) {
061 return null;
062 }
063 }
064
065 protected Throwable getTargetException() {
066 InvocationTargetException e = getException();
067 if (e != null) {
068 return e.getTargetException();
069 }
070 return e;
071 }
072
073 /**
074 * Override to return a timeout period, in milliseconds. The timeout is the
075 * maximum time to wait for the worker to complete. There is no time limit
076 * if the timeout is <code>0</code> (default).
077 */
078 public long getTimeout() {
079 return 0;
080 }
081
082 /**
083 * Calls the <code>construct</code> method to compute the result, and then
084 * invokes the <code>finished</code> method on the event dispatch thread.
085 */
086 public void run() {
087 Callable function = new Callable() {
088 public Object call() throws Exception {
089 return construct();
090 }
091 };
092 Runnable doFinished = new Runnable() {
093 public void run() {
094 finished();
095 }
096 };
097 /* Convert to TimedCallable if timeout is specified. */
098 long msecs = getTimeout();
099 if (msecs != 0) {
100 function = new TimedCallable(function, msecs);
101 }
102 setter(function).run();
103 SwingUtilities.invokeLater(doFinished);
104 }
105
106 /**
107 * Starts the worker thread.
108 */
109 public synchronized void start() {
110 if (thread == null) {
111 thread = new Thread(this);
112 }
113 thread.start();
114 }
115
116 /**
117 * Stops the worker and sets the exception to InterruptedException.
118 */
119 public synchronized void interrupt() {
120 if (thread != null) {
121 /*
122 * Try-catch is workaround for JDK1.2.1 applet security bug.
123 * JDK1.2.1 overzealously throws a security exception if an applet
124 * interrupts a thread that is no longer alive.
125 */
126 try {
127 thread.interrupt();
128 }
129 catch (Exception ex) {
130 }
131 }
132 setException(new InterruptedException());
133 }
134
135 /**
136 * Clears the worker thread variable and the FutureResult state, allowing
137 * this SwingWorker to be reused. This is not particularly recommended and
138 * must be done only when you know that the worker thread is finished and
139 * that no other object is depending on the properties of this SwingWorker.
140 */
141 public synchronized void clear() {
142 super.clear();
143 thread = null;
144 }
145 }