29 import java.util.TimerTask;
30 import java.util.concurrent.atomic.AtomicBoolean;
31
32 import java.security.PrivilegedAction;
33 import java.security.AccessController;
34
35 import sun.awt.PeerEvent;
36
37 import sun.util.logging.PlatformLogger;
38
39 /**
40 * This utility class is used to suspend execution on a thread
41 * while still allowing {@code EventDispatchThread} to dispatch events.
42 * The API methods of the class are thread-safe.
43 *
44 * @author Anton Tarasov, Artem Ananiev
45 *
46 * @since 1.7
47 */
48 class WaitDispatchSupport implements SecondaryLoop {
49
50 private final static PlatformLogger log =
51 PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
52
53 private EventDispatchThread dispatchThread;
54 private EventFilter filter;
55
56 private volatile Conditional extCondition;
57 private volatile Conditional condition;
58
59 private long interval;
60 // Use a shared daemon timer to serve all the WaitDispatchSupports
61 private static Timer timer;
62 // When this WDS expires, we cancel the timer task leaving the
63 // shared timer up and running
64 private TimerTask timerTask;
65
66 private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
67 private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
68
69 private static synchronized void initializeTimer() {
70 if (timer == null) {
71 timer = new Timer("AWT-WaitDispatchSupport-Timer", true);
72 }
73 }
74
75 /**
76 * Creates a {@code WaitDispatchSupport} instance to
77 * serve the given event dispatch thread.
78 *
79 * @param dispatchThread An event dispatch thread that
80 * should not stop dispatching events while waiting
81 *
82 * @since 1.7
83 */
84 public WaitDispatchSupport(EventDispatchThread dispatchThread) {
85 this(dispatchThread, null);
86 }
87
97 * @since 1.7
98 */
99 public WaitDispatchSupport(EventDispatchThread dispatchThread,
100 Conditional extCond)
101 {
102 if (dispatchThread == null) {
103 throw new IllegalArgumentException("The dispatchThread can not be null");
104 }
105
106 this.dispatchThread = dispatchThread;
107 this.extCondition = extCond;
108 this.condition = new Conditional() {
109 @Override
110 public boolean evaluate() {
111 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
112 log.finest("evaluate(): blockingEDT=" + keepBlockingEDT.get() +
113 ", blockingCT=" + keepBlockingCT.get());
114 }
115 boolean extEvaluate =
116 (extCondition != null) ? extCondition.evaluate() : true;
117 if (!keepBlockingEDT.get() || !extEvaluate) {
118 if (timerTask != null) {
119 timerTask.cancel();
120 timerTask = null;
121 }
122 return false;
123 }
124 return true;
125 }
126 };
127 }
128
129 /**
130 * Creates a {@code WaitDispatchSupport} instance to
131 * serve the given event dispatch thread.
132 * <p>
133 * The {@link EventFilter} is set on the {@code dispatchThread}
134 * while waiting. The filter is removed on completion of the
135 * waiting process.
136 * <p>
137 *
157 this.interval = interval;
158 if (interval != 0) {
159 initializeTimer();
160 }
161 }
162
163 /**
164 * {@inheritDoc}
165 */
166 @Override
167 public boolean enter() {
168 if (log.isLoggable(PlatformLogger.Level.FINE)) {
169 log.fine("enter(): blockingEDT=" + keepBlockingEDT.get() +
170 ", blockingCT=" + keepBlockingCT.get());
171 }
172
173 if (!keepBlockingEDT.compareAndSet(false, true)) {
174 log.fine("The secondary loop is already running, aborting");
175 return false;
176 }
177
178 final Runnable run = new Runnable() {
179 public void run() {
180 log.fine("Starting a new event pump");
181 if (filter == null) {
182 dispatchThread.pumpEvents(condition);
183 } else {
184 dispatchThread.pumpEventsForFilter(condition, filter);
185 }
186 }
187 };
188
189 // We have two mechanisms for blocking: if we're on the
190 // dispatch thread, start a new event pump; if we're
191 // on any other thread, call wait() on the treelock
192
193 Thread currentThread = Thread.currentThread();
194 if (currentThread == dispatchThread) {
195 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
196 log.finest("On dispatch thread: " + dispatchThread);
213 SequencedEvent currentSE = KeyboardFocusManager.
214 getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
215 if (currentSE != null) {
216 if (log.isLoggable(PlatformLogger.Level.FINE)) {
217 log.fine("Dispose current SequencedEvent: " + currentSE);
218 }
219 currentSE.dispose();
220 }
221 // In case the exit() method is called before starting
222 // new event pump it will post the waking event to EDT.
223 // The event will be handled after the new event pump
224 // starts. Thus, the enter() method will not hang.
225 //
226 // Event pump should be privileged. See 6300270.
227 AccessController.doPrivileged(new PrivilegedAction<Void>() {
228 public Void run() {
229 run.run();
230 return null;
231 }
232 });
233 } else {
234 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
235 log.finest("On non-dispatch thread: " + currentThread);
236 }
237 synchronized (getTreeLock()) {
238 if (filter != null) {
239 dispatchThread.addEventFilter(filter);
240 }
241 try {
242 EventQueue eq = dispatchThread.getEventQueue();
243 eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
244 keepBlockingCT.set(true);
245 if (interval > 0) {
246 long currTime = System.currentTimeMillis();
247 while (keepBlockingCT.get() &&
248 ((extCondition != null) ? extCondition.evaluate() : true) &&
249 (currTime + interval > System.currentTimeMillis()))
250 {
251 getTreeLock().wait(interval);
252 }
253 } else {
254 while (keepBlockingCT.get() &&
255 ((extCondition != null) ? extCondition.evaluate() : true))
256 {
257 getTreeLock().wait();
258 }
259 }
260 if (log.isLoggable(PlatformLogger.Level.FINE)) {
261 log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
262 }
263 } catch (InterruptedException e) {
264 if (log.isLoggable(PlatformLogger.Level.FINE)) {
265 log.fine("Exception caught while waiting: " + e);
266 }
267 } finally {
268 if (filter != null) {
269 dispatchThread.removeEventFilter(filter);
270 }
271 }
272 // If the waiting process has been stopped because of the
273 // time interval passed or an exception occurred, the state
274 // should be changed
275 keepBlockingEDT.set(false);
276 keepBlockingCT.set(false);
277 }
278 }
279
280 return true;
281 }
282
283 /**
284 * {@inheritDoc}
285 */
286 public boolean exit() {
287 if (log.isLoggable(PlatformLogger.Level.FINE)) {
288 log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
289 ", blockingCT=" + keepBlockingCT.get());
290 }
291 if (keepBlockingEDT.compareAndSet(true, false)) {
292 wakeupEDT();
293 return true;
294 }
295 return false;
296 }
297
298 private final static Object getTreeLock() {
299 return Component.LOCK;
300 }
301
302 private final Runnable wakingRunnable = new Runnable() {
303 public void run() {
304 log.fine("Wake up EDT");
305 synchronized (getTreeLock()) {
306 keepBlockingCT.set(false);
307 getTreeLock().notifyAll();
308 }
309 log.fine("Wake up EDT done");
310 }
311 };
312
313 private void wakeupEDT() {
314 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
315 log.finest("wakeupEDT(): EDT == " + dispatchThread);
|
29 import java.util.TimerTask;
30 import java.util.concurrent.atomic.AtomicBoolean;
31
32 import java.security.PrivilegedAction;
33 import java.security.AccessController;
34
35 import sun.awt.PeerEvent;
36
37 import sun.util.logging.PlatformLogger;
38
39 /**
40 * This utility class is used to suspend execution on a thread
41 * while still allowing {@code EventDispatchThread} to dispatch events.
42 * The API methods of the class are thread-safe.
43 *
44 * @author Anton Tarasov, Artem Ananiev
45 *
46 * @since 1.7
47 */
48 class WaitDispatchSupport implements SecondaryLoop {
49 private final static PlatformLogger log =
50 PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
51
52 private EventDispatchThread dispatchThread;
53 private EventFilter filter;
54
55 private volatile Conditional extCondition;
56 private volatile Conditional condition;
57
58 private long interval;
59 // Use a shared daemon timer to serve all the WaitDispatchSupports
60 private static Timer timer;
61 // When this WDS expires, we cancel the timer task leaving the
62 // shared timer up and running
63 private TimerTask timerTask;
64
65 private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
66 private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
67 private AtomicBoolean afterExit = new AtomicBoolean(false);
68
69 private static synchronized void initializeTimer() {
70 if (timer == null) {
71 timer = new Timer("AWT-WaitDispatchSupport-Timer", true);
72 }
73 }
74
75 /**
76 * Creates a {@code WaitDispatchSupport} instance to
77 * serve the given event dispatch thread.
78 *
79 * @param dispatchThread An event dispatch thread that
80 * should not stop dispatching events while waiting
81 *
82 * @since 1.7
83 */
84 public WaitDispatchSupport(EventDispatchThread dispatchThread) {
85 this(dispatchThread, null);
86 }
87
97 * @since 1.7
98 */
99 public WaitDispatchSupport(EventDispatchThread dispatchThread,
100 Conditional extCond)
101 {
102 if (dispatchThread == null) {
103 throw new IllegalArgumentException("The dispatchThread can not be null");
104 }
105
106 this.dispatchThread = dispatchThread;
107 this.extCondition = extCond;
108 this.condition = new Conditional() {
109 @Override
110 public boolean evaluate() {
111 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
112 log.finest("evaluate(): blockingEDT=" + keepBlockingEDT.get() +
113 ", blockingCT=" + keepBlockingCT.get());
114 }
115 boolean extEvaluate =
116 (extCondition != null) ? extCondition.evaluate() : true;
117 if (!keepBlockingEDT.get() || !extEvaluate || afterExit.get()) {
118 if (timerTask != null) {
119 timerTask.cancel();
120 timerTask = null;
121 }
122 return false;
123 }
124 return true;
125 }
126 };
127 }
128
129 /**
130 * Creates a {@code WaitDispatchSupport} instance to
131 * serve the given event dispatch thread.
132 * <p>
133 * The {@link EventFilter} is set on the {@code dispatchThread}
134 * while waiting. The filter is removed on completion of the
135 * waiting process.
136 * <p>
137 *
157 this.interval = interval;
158 if (interval != 0) {
159 initializeTimer();
160 }
161 }
162
163 /**
164 * {@inheritDoc}
165 */
166 @Override
167 public boolean enter() {
168 if (log.isLoggable(PlatformLogger.Level.FINE)) {
169 log.fine("enter(): blockingEDT=" + keepBlockingEDT.get() +
170 ", blockingCT=" + keepBlockingCT.get());
171 }
172
173 if (!keepBlockingEDT.compareAndSet(false, true)) {
174 log.fine("The secondary loop is already running, aborting");
175 return false;
176 }
177 if(afterExit.getAndSet(false)) {
178 log.fine("Exit was called already, aborting");
179 return false;
180 }
181
182 final Runnable run = new Runnable() {
183 public void run() {
184 log.fine("Starting a new event pump");
185 if (filter == null) {
186 dispatchThread.pumpEvents(condition);
187 } else {
188 dispatchThread.pumpEventsForFilter(condition, filter);
189 }
190 }
191 };
192
193 // We have two mechanisms for blocking: if we're on the
194 // dispatch thread, start a new event pump; if we're
195 // on any other thread, call wait() on the treelock
196
197 Thread currentThread = Thread.currentThread();
198 if (currentThread == dispatchThread) {
199 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
200 log.finest("On dispatch thread: " + dispatchThread);
217 SequencedEvent currentSE = KeyboardFocusManager.
218 getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
219 if (currentSE != null) {
220 if (log.isLoggable(PlatformLogger.Level.FINE)) {
221 log.fine("Dispose current SequencedEvent: " + currentSE);
222 }
223 currentSE.dispose();
224 }
225 // In case the exit() method is called before starting
226 // new event pump it will post the waking event to EDT.
227 // The event will be handled after the new event pump
228 // starts. Thus, the enter() method will not hang.
229 //
230 // Event pump should be privileged. See 6300270.
231 AccessController.doPrivileged(new PrivilegedAction<Void>() {
232 public Void run() {
233 run.run();
234 return null;
235 }
236 });
237 return true;
238 } else {
239 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
240 log.finest("On non-dispatch thread: " + currentThread);
241 }
242 keepBlockingCT.set(true);
243 synchronized (getTreeLock()) {
244 if (!afterExit.getAndSet(false)) {
245 if (filter != null) {
246 dispatchThread.addEventFilter(filter);
247 }
248 try {
249 EventQueue eq = dispatchThread.getEventQueue();
250 eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
251 if (interval > 0) {
252 long currTime = System.currentTimeMillis();
253 while (keepBlockingCT.get() &&
254 ((extCondition != null) ? extCondition.evaluate() : true) &&
255 (currTime + interval > System.currentTimeMillis()))
256 {
257 getTreeLock().wait(interval);
258 }
259 } else {
260 while (keepBlockingCT.get() &&
261 ((extCondition != null) ? extCondition.evaluate() : true))
262 {
263 getTreeLock().wait();
264 }
265 }
266 if (log.isLoggable(PlatformLogger.Level.FINE)) {
267 log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
268 }
269 } catch (InterruptedException e) {
270 if (log.isLoggable(PlatformLogger.Level.FINE)) {
271 log.fine("Exception caught while waiting: " + e);
272 }
273 } finally {
274 if (filter != null) {
275 dispatchThread.removeEventFilter(filter);
276 }
277 }
278 // If the waiting process has been stopped because of the
279 // time interval passed or an exception occurred, the state
280 // should be changed
281 keepBlockingEDT.set(false);
282 keepBlockingCT.set(false);
283 return true;
284 }
285 keepBlockingCT.set(false);
286 return false;
287 }
288 }
289 }
290
291 /**
292 * {@inheritDoc}
293 */
294 public boolean exit() {
295 if (log.isLoggable(PlatformLogger.Level.FINE)) {
296 log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
297 ", blockingCT=" + keepBlockingCT.get());
298 }
299 afterExit.set(true);
300 boolean noEnter = !keepBlockingEDT.getAndSet(false);
301 wakeupEDT();
302 return noEnter;
303 }
304
305 private final static Object getTreeLock() {
306 return Component.LOCK;
307 }
308
309 private final Runnable wakingRunnable = new Runnable() {
310 public void run() {
311 log.fine("Wake up EDT");
312 synchronized (getTreeLock()) {
313 keepBlockingCT.set(false);
314 getTreeLock().notifyAll();
315 }
316 log.fine("Wake up EDT done");
317 }
318 };
319
320 private void wakeupEDT() {
321 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
322 log.finest("wakeupEDT(): EDT == " + dispatchThread);
|