View Javadoc

1   package nl.tudelft.simulation.language.swing;
2   
3   import javax.swing.SwingUtilities;
4   
5   /***
6    * This is the 3rd version of SwingWorker (also known as SwingWorker 3), an
7    * abstract class that you subclass to perform GUI-related work in a dedicated
8    * thread. For instructions on and examples of using this class, see:
9    * 
10   * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
11   * 
12   * Note that the API changed slightly in the 3rd version: You must now invoke
13   * start() on the SwingWorker after creating it.
14   */
15  public abstract class SwingWorker
16  {
17  	/*** the value of the worker */
18  	private Object value; // see getValue(), setValue()
19  
20  	/*** the thread to use. */
21  	protected ThreadVar threadVar;
22  
23  	/***
24  	 * @return Get the value produced by the worker thread, or null if it hasn't
25  	 *         been constructed yet.
26  	 */
27  	protected synchronized Object getValue()
28  	{
29  		return this.value;
30  	}
31  
32  	/***
33  	 * Set the value produced by worker thread
34  	 * 
35  	 * @param x the value
36  	 */
37  	protected synchronized void setValue(final Object x)
38  	{
39  		this.value = x;
40  	}
41  
42  	/***
43  	 * @return Compute the value to be returned by the <code>get</code>
44  	 *         method.
45  	 */
46  	public abstract Object construct();
47  
48  	/***
49  	 * Called on the event dispatching thread (not on the worker thread) after
50  	 * the <code>construct</code> method has returned.
51  	 */
52  	public void finished()
53  	{
54  		//Nothing to be done.
55  	}
56  
57  	/***
58  	 * A new method that interrupts the worker thread. Call this method to force
59  	 * the worker to stop what it's doing.
60  	 */
61  	public void interrupt()
62  	{
63  		Thread t = this.threadVar.get();
64  		if (t != null)
65  		{
66  			t.interrupt();
67  		}
68  		this.threadVar.clear();
69  	}
70  
71  	/***
72  	 * Return the value created by the <code>construct</code> method. Returns
73  	 * null if either the constructing thread or the current thread was
74  	 * interrupted before a value was produced.
75  	 * 
76  	 * @return the value created by the <code>construct</code> method
77  	 */
78  	public Object get()
79  	{
80  		while (true)
81  		{
82  			Thread t = this.threadVar.get();
83  			if (t == null)
84  			{
85  				return getValue();
86  			}
87  			try
88  			{
89  				t.join();
90  			} catch (InterruptedException e)
91  			{
92  				Thread.currentThread().interrupt(); // propagate
93  				return null;
94  			}
95  		}
96  	}
97  
98  
99  	/***
100 	 * Start a thread that will call the <code>construct</code> method and
101 	 * then exit.
102 	 */
103 	public SwingWorker()
104 	{
105 		final Runnable doFinished = new Runnable()
106 		{
107 			public void run()
108 			{
109 				finished();
110 			}
111 		};
112 
113 		Runnable doConstruct = new Runnable()
114 		{
115 			public void run()
116 			{
117 				try
118 				{
119 					SwingWorker.this.setValue(construct());
120 				} finally
121 				{
122 					SwingWorker.this.threadVar.clear();
123 				}
124 
125 				SwingUtilities.invokeLater(doFinished);
126 			}
127 		};
128 
129 		Thread t = new Thread(doConstruct);
130 		this.threadVar = new ThreadVar(t);
131 	}
132 
133 	/***
134 	 * Start the worker thread.
135 	 */
136 	public void start()
137 	{
138 		Thread t = this.threadVar.get();
139 		if (t != null)
140 		{
141 			t.start();
142 		}
143 	}
144 
145 	/***
146 	 * Class to maintain reference to current worker thread under separate
147 	 * synchronization control.
148 	 */
149 	private static class ThreadVar
150 	{
151 		/*** the thread to use */
152 		private Thread thread;
153 
154 		/***
155 		 * constructs a new ThreadVar
156 		 * 
157 		 * @param t the thread
158 		 */
159 		ThreadVar(final Thread t)
160 		{
161 			this.thread = t;
162 		}
163 
164 		/***
165 		 * returns the thread
166 		 * 
167 		 * @return Thread the thread
168 		 */
169 		synchronized Thread get()
170 		{
171 			return this.thread;
172 		}
173 
174 		/***
175 		 * clears the thread
176 		 */
177 		synchronized void clear()
178 		{
179 			this.thread = null;
180 		}
181 	}
182 }