001: /*
002: ** $Id: SwingThread.java,v 1.1 2000/10/26 08:34:34 mrw Exp $
003: **
004: ** Mike Wilson, October 2000, mrw@whisperingwind.co.uk
005: **
006: ** (C) Copyright 2000, Mike Wilson, Reading, Berkshire, UK
007: **
008: ** This program is free software; you can redistribute it and/or modify
009: ** it under the terms of the GNU General Public License as published by
010: ** the Free Software Foundation; either version 2 of the License, or
011: ** (at your option) any later version.
012: **
013: ** This program is distributed in the hope that it will be useful,
014: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
015: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: ** GNU General Public License for more details.
017: **
018: ** You should have received a copy of the GNU Library General
019: ** Public License along with this library; if not, write to the
020: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
021: ** Boston, MA 02111-1307 USA.
022: */
023:
024: package uk.co.whisperingwind.framework;
025:
026: import javax.swing.SwingUtilities;
027:
028: /**
029: ** Inspired by, but <B>not</B> to identical to SwingWorker on Sun's
030: ** web site. Runs one part, <CODE>construct</CODE> in a separate
031: ** thread, then <CODE>finished</CODE> in the event dispatch thread.
032: ** The <CODE>construct</CODE> method should not modify any Swing
033: ** components as these are not thread safe. <CODE>finished</CODE>
034: ** <B>can</B> safely modify Swing components as it is run in the event
035: ** thread. <CODE>finished</CODE> does not run until
036: ** <CODE>construct</CODE> is complete.
037: **
038: ** When they say Swing is not Thread safe, they <B>really</B> mean it.
039: ** For example, poping up a dialog using JOptionPane from some thread
040: ** other than event dispatch can hang the application. Modifying the
041: ** TableModel in use for a visible JTable is really asking for it.
042: */
043:
044: public abstract class SwingThread {
045: protected boolean stopped = false;
046: private HelperThread helper;
047:
048: /**
049: ** The sub class must implement this method. It is run in a
050: ** separate thread and must not modify any Swing component.
051: */
052:
053: public abstract void construct();
054:
055: /**
056: ** The sub class must implement this method. It is run in the
057: ** event dispatch thread when <CODE>construct</CODE> is complete.
058: */
059:
060: public abstract void finished();
061:
062: /**
063: ** Create a SwingThread. Call <CODE>start</CODE> to start the
064: ** thread.
065: */
066:
067: public SwingThread() {
068: /**
069: ** This will be executed in the event dispatch thread when
070: ** doConstruct has completed.
071: */
072:
073: final Runnable doFinished = new Runnable() {
074: public void run() {
075: finished();
076: }
077: };
078:
079: /**
080: ** This is executed in a separate thread. It calls the
081: ** abstract method <CODE>construct</CODE> which should not
082: ** modify any Swing components.
083: */
084:
085: Runnable doConstruct = new Runnable() {
086: public void run() {
087: try {
088: construct();
089: } finally {
090: helper.clear();
091: }
092:
093: SwingUtilities.invokeLater(doFinished);
094: }
095: };
096:
097: helper = new HelperThread(new Thread(doConstruct));
098: }
099:
100: /**
101: ** Returns true if the thread has been interrupted. The thread may
102: ** not have yet completed.
103: */
104:
105: public synchronized boolean isInterrupted() {
106: return stopped;
107: }
108:
109: /**
110: ** This doesn't actually interrupt the thread. This class is used
111: ** for methods which communicate with the database server. Some
112: ** JDBC drivers (eg Oracle) don't like being interrupted and will
113: ** fail in subsequent calls if they are. This relies on construct
114: ** taking notice of the value of "stopped". Will not return
115: ** until the helper thread finishes.
116: */
117:
118: public void interrupt() {
119: Thread thread = helper.get();
120:
121: if (thread != null) {
122: synchronized (this ) {
123: stopped = true;
124: }
125:
126: try {
127: thread.join();
128: } catch (InterruptedException ex) {
129: // Do nothing
130: } finally {
131: helper.clear();
132: }
133: }
134: }
135:
136: /**
137: ** Start the helper thread. This will call <CODE>construct</CODE>
138: ** and, when the thread completes, <CODE>finished</CODE>.
139: */
140:
141: public void start() {
142: Thread thread = helper.get();
143:
144: if (thread != null)
145: thread.start();
146: }
147:
148: /**
149: ** Wrapper class for the helper thread which executes the
150: ** <CODE>construct</CODE> method.
151: */
152:
153: private static class HelperThread {
154: private Thread thread;
155:
156: public HelperThread(Thread thread) {
157: this .thread = thread;
158: }
159:
160: public synchronized void clear() {
161: thread = null;
162: }
163:
164: public Thread get() {
165: return thread;
166: }
167: }
168: }
|