1 /* 2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt.event; 27 28 import java.awt.ActiveEvent; 29 import java.awt.AWTEvent; 30 31 import sun.awt.AWTAccessor; 32 import sun.awt.AWTInterruptedException; 33 34 /** 35 * An event which executes the <code>run()</code> method on a <code>Runnable 36 * </code> when dispatched by the AWT event dispatcher thread. This class can 37 * be used as a reference implementation of <code>ActiveEvent</code> rather 38 * than declaring a new class and defining <code>dispatch()</code>.<p> 39 * 40 * Instances of this class are placed on the <code>EventQueue</code> by calls 41 * to <code>invokeLater</code> and <code>invokeAndWait</code>. Client code 42 * can use this fact to write replacement functions for <code>invokeLater 43 * </code> and <code>invokeAndWait</code> without writing special-case code 44 * in any <code>AWTEventListener</code> objects. 45 * <p> 46 * An unspecified behavior will be caused if the {@code id} parameter 47 * of any particular {@code InvocationEvent} instance is not 48 * in the range from {@code INVOCATION_FIRST} to {@code INVOCATION_LAST}. 49 * 50 * @author Fred Ecks 51 * @author David Mendenhall 52 * 53 * @see java.awt.ActiveEvent 54 * @see java.awt.EventQueue#invokeLater 55 * @see java.awt.EventQueue#invokeAndWait 56 * @see AWTEventListener 57 * 58 * @since 1.2 59 */ 60 public class InvocationEvent extends AWTEvent implements ActiveEvent { 61 62 /** 63 * Marks the first integer id for the range of invocation event ids. 64 */ 65 public static final int INVOCATION_FIRST = 1200; 66 67 /** 68 * The default id for all InvocationEvents. 69 */ 70 public static final int INVOCATION_DEFAULT = INVOCATION_FIRST; 71 72 /** 73 * Marks the last integer id for the range of invocation event ids. 74 */ 75 public static final int INVOCATION_LAST = INVOCATION_DEFAULT; 76 77 /** 78 * The Runnable whose run() method will be called. 79 */ 80 protected Runnable runnable; 81 82 /** 83 * The (potentially null) Object whose notifyAll() method will be called 84 * immediately after the Runnable.run() method has returned or thrown an exception. 85 * 86 * @see #isDispatched 87 */ 88 protected Object notifier; 89 90 /** 91 * Indicates whether the <code>run()</code> method of the <code>runnable</code> 92 * was executed or not. 93 * 94 * @see #isDispatched 95 * @since 1.7 96 */ 97 private volatile boolean dispatched = false; 98 99 /** 100 * Set to true if dispatch() catches Throwable and stores it in the 101 * exception instance variable. If false, Throwables are propagated up 102 * to the EventDispatchThread's dispatch loop. 103 */ 104 protected boolean catchExceptions; 105 106 /** 107 * The (potentially null) Exception thrown during execution of the 108 * Runnable.run() method. This variable will also be null if a particular 109 * instance does not catch exceptions. 110 */ 111 private Exception exception = null; 112 113 /** 114 * The (potentially null) Throwable thrown during execution of the 115 * Runnable.run() method. This variable will also be null if a particular 116 * instance does not catch exceptions. 117 */ 118 private Throwable throwable = null; 119 120 /** 121 * The timestamp of when this event occurred. 122 * 123 * @serial 124 * @see #getWhen 125 */ 126 private long when; 127 128 /* 129 * JDK 1.1 serialVersionUID. 130 */ 131 private static final long serialVersionUID = 436056344909459450L; 132 133 static { 134 AWTAccessor.setInvocationEventAccessor( 135 new AWTAccessor.InvocationEventAccessor() { 136 @Override 137 public void dispose(InvocationEvent ie) { 138 ie.dispose(); 139 } 140 }); 141 } 142 143 /** 144 * Constructs an <code>InvocationEvent</code> with the specified 145 * source which will execute the runnable's <code>run</code> 146 * method when dispatched. 147 * <p>This is a convenience constructor. An invocation of the form 148 * <tt>InvocationEvent(source, runnable)</tt> 149 * behaves in exactly the same way as the invocation of 150 * <tt>{@link #InvocationEvent(Object, Runnable, Object, boolean) InvocationEvent}(source, runnable, null, false)</tt>. 151 * <p> This method throws an <code>IllegalArgumentException</code> 152 * if <code>source</code> is <code>null</code>. 153 * 154 * @param source The <code>Object</code> that originated the event 155 * @param runnable The <code>Runnable</code> whose <code>run</code> 156 * method will be executed 157 * @throws IllegalArgumentException if <code>source</code> is null 158 * 159 * @see #getSource() 160 * @see #InvocationEvent(Object, Runnable, Object, boolean) 161 */ 162 public InvocationEvent(Object source, Runnable runnable) { 163 this(source, runnable, null, false); 164 } 165 166 /** 167 * Constructs an <code>InvocationEvent</code> with the specified 168 * source which will execute the runnable's <code>run</code> 169 * method when dispatched. If notifier is non-<code>null</code>, 170 * <code>notifyAll()</code> will be called on it 171 * immediately after <code>run</code> has returned or thrown an exception. 172 * <p>An invocation of the form <tt>InvocationEvent(source, 173 * runnable, notifier, catchThrowables)</tt> 174 * behaves in exactly the same way as the invocation of 175 * <tt>{@link #InvocationEvent(Object, int, Runnable, Object, boolean) InvocationEvent}(source, InvocationEvent.INVOCATION_DEFAULT, runnable, notifier, catchThrowables)</tt>. 176 * <p>This method throws an <code>IllegalArgumentException</code> 177 * if <code>source</code> is <code>null</code>. 178 * 179 * @param source The <code>Object</code> that originated 180 * the event 181 * @param runnable The <code>Runnable</code> whose 182 * <code>run</code> method will be 183 * executed 184 * @param notifier The {@code Object} whose <code>notifyAll</code> 185 * method will be called after 186 * <code>Runnable.run</code> has returned or 187 * thrown an exception 188 * @param catchThrowables Specifies whether <code>dispatch</code> 189 * should catch Throwable when executing 190 * the <code>Runnable</code>'s <code>run</code> 191 * method, or should instead propagate those 192 * Throwables to the EventDispatchThread's 193 * dispatch loop 194 * @throws IllegalArgumentException if <code>source</code> is null 195 * 196 * @see #getSource() 197 * @see #InvocationEvent(Object, int, Runnable, Object, boolean) 198 */ 199 public InvocationEvent(Object source, Runnable runnable, Object notifier, 200 boolean catchThrowables) { 201 this(source, INVOCATION_DEFAULT, runnable, notifier, catchThrowables); 202 } 203 204 /** 205 * Constructs an <code>InvocationEvent</code> with the specified 206 * source and ID which will execute the runnable's <code>run</code> 207 * method when dispatched. If notifier is non-<code>null</code>, 208 * <code>notifyAll</code> will be called on it immediately after 209 * <code>run</code> has returned or thrown an exception. 210 * <p>This method throws an 211 * <code>IllegalArgumentException</code> if <code>source</code> 212 * is <code>null</code>. 213 * 214 * @param source The <code>Object</code> that originated 215 * the event 216 * @param id An integer indicating the type of event. 217 * For information on allowable values, see 218 * the class description for {@link InvocationEvent} 219 * @param runnable The <code>Runnable</code> whose 220 * <code>run</code> method will be executed 221 * @param notifier The <code>Object</code> whose <code>notifyAll</code> 222 * method will be called after 223 * <code>Runnable.run</code> has returned or 224 * thrown an exception 225 * @param catchThrowables Specifies whether <code>dispatch</code> 226 * should catch Throwable when executing the 227 * <code>Runnable</code>'s <code>run</code> 228 * method, or should instead propagate those 229 * Throwables to the EventDispatchThread's 230 * dispatch loop 231 * @throws IllegalArgumentException if <code>source</code> is null 232 * @see #getSource() 233 * @see #getID() 234 */ 235 protected InvocationEvent(Object source, int id, Runnable runnable, 236 Object notifier, boolean catchThrowables) { 237 super(source, id); 238 this.runnable = runnable; 239 this.notifier = notifier; 240 this.catchExceptions = catchThrowables; 241 this.when = System.currentTimeMillis(); 242 } 243 244 /* 245 * Marks the event as dispatched and notifies all interested parties. 246 */ 247 private void setDispatched() { 248 dispatched = true; 249 250 if (notifier != null) { 251 synchronized (notifier) { 252 notifier.notifyAll(); 253 } 254 } 255 } 256 257 /** 258 * Executes the Runnable's <code>run()</code> method and notifies the 259 * notifier (if any) when <code>run()</code> has returned or thrown an exception. 260 * 261 * @see #isDispatched 262 */ 263 public void dispatch() { 264 try { 265 if (catchExceptions) { 266 try { 267 runnable.run(); 268 } 269 catch (Throwable t) { 270 if (t instanceof Exception) { 271 exception = (Exception) t; 272 } 273 throwable = t; 274 } 275 } 276 else { 277 runnable.run(); 278 } 279 } finally { 280 setDispatched(); 281 } 282 } 283 284 private void dispose() { 285 throwable = exception = 286 new AWTInterruptedException( 287 "The event is discarded due to Event Thread interruption"); 288 289 setDispatched(); 290 } 291 292 /** 293 * Returns any Exception caught while executing the Runnable's <code>run() 294 * </code> method. 295 * 296 * @return A reference to the Exception if one was thrown; null if no 297 * Exception was thrown or if this InvocationEvent does not 298 * catch exceptions 299 */ 300 public Exception getException() { 301 return (catchExceptions) ? exception : null; 302 } 303 304 /** 305 * Returns any Throwable caught while executing the Runnable's <code>run() 306 * </code> method. 307 * 308 * @return A reference to the Throwable if one was thrown; null if no 309 * Throwable was thrown or if this InvocationEvent does not 310 * catch Throwables 311 * @since 1.5 312 */ 313 public Throwable getThrowable() { 314 return (catchExceptions) ? throwable : null; 315 } 316 317 /** 318 * Returns the timestamp of when this event occurred. 319 * 320 * @return this event's timestamp 321 * @since 1.4 322 */ 323 public long getWhen() { 324 return when; 325 } 326 327 /** 328 * Returns {@code true} if the event is dispatched or any exception is 329 * thrown while dispatching, {@code false} otherwise. The method should 330 * be called by a waiting thread that calls the {@code notifier.wait()} method. 331 * Since spurious wakeups are possible (as explained in {@link Object#wait()}), 332 * this method should be used in a waiting loop to ensure that the event 333 * got dispatched: 334 * <pre> 335 * while (!event.isDispatched()) { 336 * notifier.wait(); 337 * } 338 * </pre> 339 * If the waiting thread wakes up without dispatching the event, 340 * the {@code isDispatched()} method returns {@code false}, and 341 * the {@code while} loop executes once more, thus, causing 342 * the awakened thread to revert to the waiting mode. 343 * <p> 344 * If the {@code notifier.notifyAll()} happens before the waiting thread 345 * enters the {@code notifier.wait()} method, the {@code while} loop ensures 346 * that the waiting thread will not enter the {@code notifier.wait()} method. 347 * Otherwise, there is no guarantee that the waiting thread will ever be woken 348 * from the wait. 349 * 350 * @return {@code true} if the event has been dispatched, or any exception 351 * has been thrown while dispatching, {@code false} otherwise 352 * @see #dispatch 353 * @see #notifier 354 * @see #catchExceptions 355 * @since 1.7 356 */ 357 public boolean isDispatched() { 358 return dispatched; 359 } 360 361 /** 362 * Returns a parameter string identifying this event. 363 * This method is useful for event-logging and for debugging. 364 * 365 * @return A string identifying the event and its attributes 366 */ 367 public String paramString() { 368 String typeStr; 369 switch(id) { 370 case INVOCATION_DEFAULT: 371 typeStr = "INVOCATION_DEFAULT"; 372 break; 373 default: 374 typeStr = "unknown type"; 375 } 376 return typeStr + ",runnable=" + runnable + ",notifier=" + notifier + 377 ",catchExceptions=" + catchExceptions + ",when=" + when; 378 } 379 }