View Javadoc

1   /*
2    * XMLCV - Gestion de CV sous forme XML
3    * 
4    * Copyright (C) 2004-2005, Damien Raude-Morvan
5    * 
6    * This file is part of XMLCV.
7    *
8    * XMLCV is free software; you can redistribute it and/or modify
9    * it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation; either version 2 of the License, or
11   * (at your option) any later version.
12   *
13   * XMLCV is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   *
18   * You should have received a copy of the GNU General Public License
19   * along with XMLCV; if not, write to the Free Software
20   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21   * 
22   * Contacts :
23   * - Sébastien Mathy <smathy@tuxfamily.org>
24   * - Emmanuel Berre <eberre@tuxfamily.org>
25   * - Damien Raude-Morvan <drazzib@drazzib.com>
26   */
27  package org.xmlcv.util;
28  
29  import javax.swing.SwingUtilities;
30  
31  /***
32   * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an
33   * abstract class that you subclass to perform GUI-related work in a dedicated
34   * thread. For instructions on and examples of using this class, see:
35   * 
36   * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
37   * 
38   * Note that the API changed slightly in the 3rd version: You must now invoke
39   * start() on the SwingWorker after creating it.
40   * 
41   * @version $Revision: 114 $
42   * @author <a href="mailto:drazzib@drazzib.com">Damien Raude-Morvan </a>
43   */
44  public abstract class SwingWorker {
45  
46  	private Object _value; // see getValue(), setValue()
47  
48  	/***
49  	 * Class to maintain reference to current worker thread under separate
50  	 * synchronization control.
51  	 */
52  	private static class ThreadVar {
53  		private Thread thread;
54  
55  		ThreadVar(Thread t) {
56  			this.thread = t;
57  		}
58  
59  		synchronized Thread get() {
60  			return this.thread;
61  		}
62  
63  		synchronized void clear() {
64  			this.thread = null;
65  		}
66  	}
67  
68  	ThreadVar threadVar;
69  
70  	/***
71  	 * Get the value produced by the worker thread, or null if it hasn't been
72  	 * constructed yet.
73  	 */
74  	protected synchronized Object getValue() {
75  		return this._value;
76  	}
77  
78  	/***
79  	 * Set the value produced by worker thread
80  	 */
81  	synchronized void setValue(Object x) {
82  		this._value = x;
83  	}
84  
85  	/***
86  	 * Compute the value to be returned by the <code>get</code> method.
87  	 */
88  	public abstract Object construct();
89  
90  	/***
91  	 * Called on the event dispatching thread (not on the worker thread) after
92  	 * the <code>construct</code> method has returned.
93  	 */
94  	public void finished() {
95  		// Should be implemented in sub-classes
96  	}
97  
98  	/***
99  	 * A new method that interrupts the worker thread. Call this method to force
100 	 * the worker to stop what it's doing.
101 	 */
102 	public void interrupt() {
103 		Thread t = this.threadVar.get();
104 		if (t != null) {
105 			t.interrupt();
106 		}
107 		this.threadVar.clear();
108 	}
109 
110 	/***
111 	 * Return the value created by the <code>construct</code> method. Returns
112 	 * null if either the constructing thread or the current thread was
113 	 * interrupted before a value was produced.
114 	 * 
115 	 * @return the value created by the <code>construct</code> method
116 	 */
117 	public Object get() {
118 		while (true) {
119 			Thread t = this.threadVar.get();
120 			if (t == null) {
121 				return getValue();
122 			}
123 			try {
124 				t.join();
125 			} catch (InterruptedException e) {
126 				Thread.currentThread().interrupt(); // propagate
127 				return null;
128 			}
129 		}
130 	}
131 
132 	/***
133 	 * Start a thread that will call the <code>construct</code> method and
134 	 * then exit.
135 	 */
136 	public SwingWorker() {
137 		final Runnable doFinished = new Runnable() {
138 			public void run() {
139 				finished();
140 			}
141 		};
142 
143 		Runnable doConstruct = new Runnable() {
144 			public void run() {
145 				try {
146 					setValue(construct());
147 				} finally {
148 					SwingWorker.this.threadVar.clear();
149 				}
150 
151 				SwingUtilities.invokeLater(doFinished);
152 			}
153 		};
154 
155 		Thread t = new Thread(doConstruct);
156 		t.setPriority(Thread.MIN_PRIORITY);
157 		this.threadVar = new ThreadVar(t);
158 	}
159 
160 	/***
161 	 * Start the worker thread.
162 	 */
163 	public void start() {
164 		Thread t = this.threadVar.get();
165 		if (t != null) {
166 			t.start();
167 		}
168 	}
169 }