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 /** 32 * An event which executes the <code>run()</code> method on a <code>Runnable 33 * </code> when dispatched by the AWT event dispatcher thread. This class can 34 * be used as a reference implementation of <code>ActiveEvent</code> rather 35 * than declaring a new class and defining <code>dispatch()</code>.<p> 36 * 37 * Instances of this class are placed on the <code>EventQueue</code> by calls 38 * to <code>invokeLater</code> and <code>invokeAndWait</code>. Client code 39 * can use this fact to write replacement functions for <code>invokeLater 40 * </code> and <code>invokeAndWait</code> without writing special-case code 41 * in any <code>AWTEventListener</code> objects. 42 * <p> 43 * An unspecified behavior will be caused if the {@code id} parameter 44 * of any particular {@code InvocationEvent} instance is not 45 * in the range from {@code INVOCATION_FIRST} to {@code INVOCATION_LAST}. 46 * 47 * @author Fred Ecks 48 * @author David Mendenhall 49 * 50 * @see java.awt.ActiveEvent 51 * @see java.awt.EventQueue#invokeLater 52 * @see java.awt.EventQueue#invokeAndWait 53 * @see AWTEventListener 54 * 55 * @since 1.2 56 */ 57 public class InvocationEvent extends AWTEvent implements ActiveEvent { 58 59 /** 60 * Marks the first integer id for the range of invocation event ids. 61 */ 62 public static final int INVOCATION_FIRST = 1200; 63 64 /** 65 * The default id for all InvocationEvents. 66 */ 67 public static final int INVOCATION_DEFAULT = INVOCATION_FIRST; 68 69 /** 70 * Marks the last integer id for the range of invocation event ids. 71 */ 72 public static final int INVOCATION_LAST = INVOCATION_DEFAULT; 73 74 /** 75 * The Runnable whose run() method will be called. 76 */ 77 protected Runnable runnable; 78 79 /** 80 * The (potentially null) Object whose notifyAll() method will be called 81 * immediately after the Runnable.run() method has returned or thrown an exception. 82 * 83 * @see #isDispatched 84 */ 85 protected Object notifier; 86 87 /** 88 * Indicates whether the <code>run()</code> method of the <code>runnable</code> 89 * was executed or not. 90 * 91 * @see #isDispatched 92 * @since 1.7 93 */ 94 private volatile boolean dispatched = false; 95 96 /** 97 * Set to true if dispatch() catches Throwable and stores it in the 98 * exception instance variable. If false, Throwables are propagated up 99 * to the EventDispatchThread's dispatch loop. 100 */ 101 protected boolean catchExceptions; 102 103 /** 104 * The (potentially null) Exception thrown during execution of the 105 * Runnable.run() method. This variable will also be null if a particular 106 * instance does not catch exceptions. 107 */ 108 private Exception exception = null; 109 110 /** 111 * The (potentially null) Throwable thrown during execution of the 112 * Runnable.run() method. This variable will also be null if a particular 113 * instance does not catch exceptions. 114 */ 115 private Throwable throwable = null; 116 117 /** 118 * The timestamp of when this event occurred. 119 * 120 * @serial 121 * @see #getWhen 122 */ 123 private long when; 124 125 /* 126 * JDK 1.1 serialVersionUID. 127 */ 128 private static final long serialVersionUID = 436056344909459450L; 129 130 /** 131 * Constructs an <code>InvocationEvent</code> with the specified 132 * source which will execute the runnable's <code>run</code> 133 * method when dispatched. 134 * <p>This is a convenience constructor. An invocation of the form 135 * <tt>InvocationEvent(source, runnable)</tt> 136 * behaves in exactly the same way as the invocation of 137 * <tt>{@link #InvocationEvent(Object, Runnable, Object, boolean) InvocationEvent}(source, runnable, null, false)</tt>. 138 * <p> This method throws an <code>IllegalArgumentException</code> 139 * if <code>source</code> is <code>null</code>. 140 * 141 * @param source The <code>Object</code> that originated the event 142 * @param runnable The <code>Runnable</code> whose <code>run</code> 143 * method will be executed 144 * @throws IllegalArgumentException if <code>source</code> is null 145 * 146 * @see #getSource() 147 * @see #InvocationEvent(Object, Runnable, Object, boolean) 148 */ 149 public InvocationEvent(Object source, Runnable runnable) { 150 this(source, runnable, null, false); 151 } 152 153 /** 154 * Constructs an <code>InvocationEvent</code> with the specified 155 * source which will execute the runnable's <code>run</code> 156 * method when dispatched. If notifier is non-<code>null</code>, 157 * <code>notifyAll()</code> will be called on it 158 * immediately after <code>run</code> has returned or thrown an exception. 159 * <p>An invocation of the form <tt>InvocationEvent(source, 160 * runnable, notifier, catchThrowables)</tt> 161 * behaves in exactly the same way as the invocation of 162 * <tt>{@link #InvocationEvent(Object, int, Runnable, Object, boolean) InvocationEvent}(source, InvocationEvent.INVOCATION_DEFAULT, runnable, notifier, catchThrowables)</tt>. 163 * <p>This method throws an <code>IllegalArgumentException</code> 164 * if <code>source</code> is <code>null</code>. 165 * 166 * @param source The <code>Object</code> that originated 167 * the event 168 * @param runnable The <code>Runnable</code> whose 169 * <code>run</code> method will be 170 * executed 171 * @param notifier The {@code Object} whose <code>notifyAll</code> 172 * method will be called after 173 * <code>Runnable.run</code> has returned or 174 * thrown an exception 175 * @param catchThrowables Specifies whether <code>dispatch</code> 176 * should catch Throwable when executing 177 * the <code>Runnable</code>'s <code>run</code> 178 * method, or should instead propagate those 179 * Throwables to the EventDispatchThread's 180 * dispatch loop 181 * @throws IllegalArgumentException if <code>source</code> is null 182 * 183 * @see #getSource() 184 * @see #InvocationEvent(Object, int, Runnable, Object, boolean) 185 */ 186 public InvocationEvent(Object source, Runnable runnable, Object notifier, 187 boolean catchThrowables) { 188 this(source, INVOCATION_DEFAULT, runnable, notifier, catchThrowables); 189 } 190 191 /** 192 * Constructs an <code>InvocationEvent</code> with the specified 193 * source and ID which will execute the runnable's <code>run</code> 194 * method when dispatched. If notifier is non-<code>null</code>, 195 * <code>notifyAll</code> will be called on it immediately after 196 * <code>run</code> has returned or thrown an exception. 197 * <p>This method throws an 198 * <code>IllegalArgumentException</code> if <code>source</code> 199 * is <code>null</code>. 200 * 201 * @param source The <code>Object</code> that originated 202 * the event 203 * @param id An integer indicating the type of event. 204 * For information on allowable values, see 205 * the class description for {@link InvocationEvent} 206 * @param runnable The <code>Runnable</code> whose 207 * <code>run</code> method will be executed 208 * @param notifier The <code>Object</code> whose <code>notifyAll</code> 209 * method will be called after 210 * <code>Runnable.run</code> has returned or 211 * thrown an exception 212 * @param catchThrowables Specifies whether <code>dispatch</code> 213 * should catch Throwable when executing the 214 * <code>Runnable</code>'s <code>run</code> 215 * method, or should instead propagate those 216 * Throwables to the EventDispatchThread's 217 * dispatch loop 218 * @throws IllegalArgumentException if <code>source</code> is null 219 * @see #getSource() 220 * @see #getID() 221 */ 222 protected InvocationEvent(Object source, int id, Runnable runnable, 223 Object notifier, boolean catchThrowables) { 224 super(source, id); 225 this.runnable = runnable; 226 this.notifier = notifier; 227 this.catchExceptions = catchThrowables; 228 this.when = System.currentTimeMillis(); 229 } 230 231 /** 232 * Executes the Runnable's <code>run()</code> method and notifies the 233 * notifier (if any) when <code>run()</code> has returned or thrown an exception. 234 * 235 * @see #isDispatched 236 */ 237 public void dispatch() { 238 try { 239 if (catchExceptions) { 240 try { 241 runnable.run(); 242 } 243 catch (Throwable t) { 244 if (t instanceof Exception) { 245 exception = (Exception) t; 246 } 247 throwable = t; 248 } 249 } 250 else { 251 runnable.run(); 252 } 253 } finally { 254 dispatched = true; 255 256 if (notifier != null) { 257 synchronized (notifier) { 258 notifier.notifyAll(); 259 } 260 } 261 } 262 } 263 264 /** 265 * Returns any Exception caught while executing the Runnable's <code>run() 266 * </code> method. 267 * 268 * @return A reference to the Exception if one was thrown; null if no 269 * Exception was thrown or if this InvocationEvent does not 270 * catch exceptions 271 */ 272 public Exception getException() { 273 return (catchExceptions) ? exception : null; 274 } 275 276 /** 277 * Returns any Throwable caught while executing the Runnable's <code>run() 278 * </code> method. 279 * 280 * @return A reference to the Throwable if one was thrown; null if no 281 * Throwable was thrown or if this InvocationEvent does not 282 * catch Throwables 283 * @since 1.5 284 */ 285 public Throwable getThrowable() { 286 return (catchExceptions) ? throwable : null; 287 } 288 289 /** 290 * Returns the timestamp of when this event occurred. 291 * 292 * @return this event's timestamp 293 * @since 1.4 294 */ 295 public long getWhen() { 296 return when; 297 } 298 299 /** 300 * Returns {@code true} if the event is dispatched or any exception is 301 * thrown while dispatching, {@code false} otherwise. The method should 302 * be called by a waiting thread that calls the {@code notifier.wait()} method. 303 * Since spurious wakeups are possible (as explained in {@link Object#wait()}), 304 * this method should be used in a waiting loop to ensure that the event 305 * got dispatched: 306 * <pre> 307 * while (!event.isDispatched()) { 308 * notifier.wait(); 309 * } 310 * </pre> 311 * If the waiting thread wakes up without dispatching the event, 312 * the {@code isDispatched()} method returns {@code false}, and 313 * the {@code while} loop executes once more, thus, causing 314 * the awakened thread to revert to the waiting mode. 315 * <p> 316 * If the {@code notifier.notifyAll()} happens before the waiting thread 317 * enters the {@code notifier.wait()} method, the {@code while} loop ensures 318 * that the waiting thread will not enter the {@code notifier.wait()} method. 319 * Otherwise, there is no guarantee that the waiting thread will ever be woken 320 * from the wait. 321 * 322 * @return {@code true} if the event has been dispatched, or any exception 323 * has been thrown while dispatching, {@code false} otherwise 324 * @see #dispatch 325 * @see #notifier 326 * @see #catchExceptions 327 * @since 1.7 328 */ 329 public boolean isDispatched() { 330 return dispatched; 331 } 332 333 /** 334 * Returns a parameter string identifying this event. 335 * This method is useful for event-logging and for debugging. 336 * 337 * @return A string identifying the event and its attributes 338 */ 339 public String paramString() { 340 String typeStr; 341 switch(id) { 342 case INVOCATION_DEFAULT: 343 typeStr = "INVOCATION_DEFAULT"; 344 break; 345 default: 346 typeStr = "unknown type"; 347 } 348 return typeStr + ",runnable=" + runnable + ",notifier=" + notifier + 349 ",catchExceptions=" + catchExceptions + ",when=" + when; 350 } 351 }