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 }