1 /* 2 * Copyright (c) 1997, 2011, 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 27 28 package javax.swing; 29 30 31 32 import java.util.*; 33 import java.util.concurrent.atomic.AtomicBoolean; 34 import java.util.concurrent.locks.*; 35 import java.awt.*; 36 import java.awt.event.*; 37 import java.io.Serializable; 38 import java.io.*; 39 import java.security.AccessControlContext; 40 import java.security.AccessController; 41 import java.security.PrivilegedAction; 42 import javax.swing.event.EventListenerList; 43 44 45 46 /** 47 * Fires one or more {@code ActionEvent}s at specified 48 * intervals. An example use is an animation object that uses a 49 * <code>Timer</code> as the trigger for drawing its frames. 50 *<p> 51 * Setting up a timer 52 * involves creating a <code>Timer</code> object, 53 * registering one or more action listeners on it, 54 * and starting the timer using 55 * the <code>start</code> method. 56 * For example, 57 * the following code creates and starts a timer 58 * that fires an action event once per second 59 * (as specified by the first argument to the <code>Timer</code> constructor). 60 * The second argument to the <code>Timer</code> constructor 61 * specifies a listener to receive the timer's action events. 62 * 63 *<pre> 64 * int delay = 1000; //milliseconds 65 * ActionListener taskPerformer = new ActionListener() { 66 * public void actionPerformed(ActionEvent evt) { 67 * <em>//...Perform a task...</em> 68 * } 69 * }; 70 * new Timer(delay, taskPerformer).start();</pre> 71 * 72 * <p> 73 * {@code Timers} are constructed by specifying both a delay parameter 74 * and an {@code ActionListener}. The delay parameter is used 75 * to set both the initial delay and the delay between event 76 * firing, in milliseconds. Once the timer has been started, 77 * it waits for the initial delay before firing its 78 * first <code>ActionEvent</code> to registered listeners. 79 * After this first event, it continues to fire events 80 * every time the between-event delay has elapsed, until it 81 * is stopped. 82 * <p> 83 * After construction, the initial delay and the between-event 84 * delay can be changed independently, and additional 85 * <code>ActionListeners</code> may be added. 86 * <p> 87 * If you want the timer to fire only the first time and then stop, 88 * invoke <code>setRepeats(false)</code> on the timer. 89 * <p> 90 * Although all <code>Timer</code>s perform their waiting 91 * using a single, shared thread 92 * (created by the first <code>Timer</code> object that executes), 93 * the action event handlers for <code>Timer</code>s 94 * execute on another thread -- the event-dispatching thread. 95 * This means that the action handlers for <code>Timer</code>s 96 * can safely perform operations on Swing components. 97 * However, it also means that the handlers must execute quickly 98 * to keep the GUI responsive. 99 * 100 * <p> 101 * In v 1.3, another <code>Timer</code> class was added 102 * to the Java platform: <code>java.util.Timer</code>. 103 * Both it and <code>javax.swing.Timer</code> 104 * provide the same basic functionality, 105 * but <code>java.util.Timer</code> 106 * is more general and has more features. 107 * The <code>javax.swing.Timer</code> has two features 108 * that can make it a little easier to use with GUIs. 109 * First, its event handling metaphor is familiar to GUI programmers 110 * and can make dealing with the event-dispatching thread 111 * a bit simpler. 112 * Second, its 113 * automatic thread sharing means that you don't have to 114 * take special steps to avoid spawning 115 * too many threads. 116 * Instead, your timer uses the same thread 117 * used to make cursors blink, 118 * tool tips appear, 119 * and so on. 120 * 121 * <p> 122 * You can find further documentation 123 * and several examples of using timers by visiting 124 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html" 125 * target = "_top">How to Use Timers</a>, 126 * a section in <em>The Java Tutorial.</em> 127 * For more examples and help in choosing between 128 * this <code>Timer</code> class and 129 * <code>java.util.Timer</code>, 130 * see 131 * <a href="http://java.sun.com/products/jfc/tsc/articles/timer/" 132 * target="_top">Using Timers in Swing Applications</a>, 133 * an article in <em>The Swing Connection.</em> 134 * <p> 135 * <strong>Warning:</strong> 136 * Serialized objects of this class will not be compatible with 137 * future Swing releases. The current serialization support is 138 * appropriate for short term storage or RMI between applications running 139 * the same version of Swing. As of 1.4, support for long term storage 140 * of all JavaBeans<sup><font size="-2">TM</font></sup> 141 * has been added to the <code>java.beans</code> package. 142 * Please see {@link java.beans.XMLEncoder}. 143 * 144 * @see java.util.Timer <code>java.util.Timer</code> 145 * 146 * 147 * @author Dave Moore 148 */ 149 public class Timer implements Serializable 150 { 151 /* 152 * NOTE: all fields need to be handled in readResolve 153 */ 154 155 protected EventListenerList listenerList = new EventListenerList(); 156 157 // The following field strives to maintain the following: 158 // If coalesce is true, only allow one Runnable to be queued on the 159 // EventQueue and be pending (ie in the process of notifying the 160 // ActionListener). If we didn't do this it would allow for a 161 // situation where the app is taking too long to process the 162 // actionPerformed, and thus we'ld end up queing a bunch of Runnables 163 // and the app would never return: not good. This of course implies 164 // you can get dropped events, but such is life. 165 // notify is used to indicate if the ActionListener can be notified, when 166 // the Runnable is processed if this is true it will notify the listeners. 167 // notify is set to true when the Timer fires and the Runnable is queued. 168 // It will be set to false after notifying the listeners (if coalesce is 169 // true) or if the developer invokes stop. 170 private transient final AtomicBoolean notify = new AtomicBoolean(false); 171 172 private volatile int initialDelay, delay; 173 private volatile boolean repeats = true, coalesce = true; 174 175 private transient final Runnable doPostEvent; 176 177 private static volatile boolean logTimers; 178 179 private transient final Lock lock = new ReentrantLock(); 180 181 // This field is maintained by TimerQueue. 182 // eventQueued can also be reset by the TimerQueue, but will only ever 183 // happen in applet case when TimerQueues thread is destroyed. 184 // access to this field is synchronized on getLock() lock. 185 transient TimerQueue.DelayedTimer delayedTimer = null; 186 187 private volatile String actionCommand; 188 189 /** 190 * Creates a {@code Timer} and initializes both the initial delay and 191 * between-event delay to {@code delay} milliseconds. If {@code delay} 192 * is less than or equal to zero, the timer fires as soon as it 193 * is started. If <code>listener</code> is not <code>null</code>, 194 * it's registered as an action listener on the timer. 195 * 196 * @param delay milliseconds for the initial and between-event delay 197 * @param listener an initial listener; can be <code>null</code> 198 * 199 * @see #addActionListener 200 * @see #setInitialDelay 201 * @see #setRepeats 202 */ 203 public Timer(int delay, ActionListener listener) { 204 super(); 205 this.delay = delay; 206 this.initialDelay = delay; 207 208 doPostEvent = new DoPostEvent(); 209 210 if (listener != null) { 211 addActionListener(listener); 212 } 213 } 214 215 /* 216 * The timer's AccessControlContext. 217 */ 218 private transient volatile AccessControlContext acc = 219 AccessController.getContext(); 220 221 /** 222 * Returns the acc this timer was constructed with. 223 */ 224 final AccessControlContext getAccessControlContext() { 225 if (acc == null) { 226 throw new SecurityException( 227 "Timer is missing AccessControlContext"); 228 } 229 return acc; 230 } 231 232 /** 233 * DoPostEvent is a runnable class that fires actionEvents to 234 * the listeners on the EventDispatchThread, via invokeLater. 235 * @see Timer#post 236 */ 237 class DoPostEvent implements Runnable 238 { 239 public void run() { 240 if (logTimers) { 241 System.out.println("Timer ringing: " + Timer.this); 242 } 243 if(notify.get()) { 244 fireActionPerformed(new ActionEvent(Timer.this, 0, getActionCommand(), 245 System.currentTimeMillis(), 246 0)); 247 if (coalesce) { 248 cancelEvent(); 249 } 250 } 251 } 252 253 Timer getTimer() { 254 return Timer.this; 255 } 256 } 257 258 /** 259 * Adds an action listener to the <code>Timer</code>. 260 * 261 * @param listener the listener to add 262 * 263 * @see #Timer 264 */ 265 public void addActionListener(ActionListener listener) { 266 listenerList.add(ActionListener.class, listener); 267 } 268 269 270 /** 271 * Removes the specified action listener from the <code>Timer</code>. 272 * 273 * @param listener the listener to remove 274 */ 275 public void removeActionListener(ActionListener listener) { 276 listenerList.remove(ActionListener.class, listener); 277 } 278 279 280 /** 281 * Returns an array of all the action listeners registered 282 * on this timer. 283 * 284 * @return all of the timer's <code>ActionListener</code>s or an empty 285 * array if no action listeners are currently registered 286 * 287 * @see #addActionListener 288 * @see #removeActionListener 289 * 290 * @since 1.4 291 */ 292 public ActionListener[] getActionListeners() { 293 return listenerList.getListeners(ActionListener.class); 294 } 295 296 297 /** 298 * Notifies all listeners that have registered interest for 299 * notification on this event type. 300 * 301 * @param e the action event to fire 302 * @see EventListenerList 303 */ 304 protected void fireActionPerformed(ActionEvent e) { 305 // Guaranteed to return a non-null array 306 Object[] listeners = listenerList.getListenerList(); 307 308 // Process the listeners last to first, notifying 309 // those that are interested in this event 310 for (int i=listeners.length-2; i>=0; i-=2) { 311 if (listeners[i]==ActionListener.class) { 312 ((ActionListener)listeners[i+1]).actionPerformed(e); 313 } 314 } 315 } 316 317 /** 318 * Returns an array of all the objects currently registered as 319 * <code><em>Foo</em>Listener</code>s 320 * upon this <code>Timer</code>. 321 * <code><em>Foo</em>Listener</code>s 322 * are registered using the <code>add<em>Foo</em>Listener</code> method. 323 * <p> 324 * You can specify the <code>listenerType</code> argument 325 * with a class literal, such as <code><em>Foo</em>Listener.class</code>. 326 * For example, you can query a <code>Timer</code> 327 * instance <code>t</code> 328 * for its action listeners 329 * with the following code: 330 * 331 * <pre>ActionListener[] als = (ActionListener[])(t.getListeners(ActionListener.class));</pre> 332 * 333 * If no such listeners exist, 334 * this method returns an empty array. 335 * 336 * @param listenerType the type of listeners requested; 337 * this parameter should specify an interface 338 * that descends from <code>java.util.EventListener</code> 339 * @return an array of all objects registered as 340 * <code><em>Foo</em>Listener</code>s 341 * on this timer, 342 * or an empty array if no such 343 * listeners have been added 344 * @exception ClassCastException if <code>listenerType</code> doesn't 345 * specify a class or interface that implements 346 * <code>java.util.EventListener</code> 347 * 348 * @see #getActionListeners 349 * @see #addActionListener 350 * @see #removeActionListener 351 * 352 * @since 1.3 353 */ 354 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 355 return listenerList.getListeners(listenerType); 356 } 357 358 /** 359 * Returns the timer queue. 360 */ 361 private TimerQueue timerQueue() { 362 return TimerQueue.sharedInstance(); 363 } 364 365 366 /** 367 * Enables or disables the timer log. When enabled, a message 368 * is posted to <code>System.out</code> whenever the timer goes off. 369 * 370 * @param flag <code>true</code> to enable logging 371 * @see #getLogTimers 372 */ 373 public static void setLogTimers(boolean flag) { 374 logTimers = flag; 375 } 376 377 378 /** 379 * Returns <code>true</code> if logging is enabled. 380 * 381 * @return <code>true</code> if logging is enabled; otherwise, false 382 * @see #setLogTimers 383 */ 384 public static boolean getLogTimers() { 385 return logTimers; 386 } 387 388 389 /** 390 * Sets the <code>Timer</code>'s between-event delay, the number of milliseconds 391 * between successive action events. This does not affect the initial delay 392 * property, which can be set by the {@code setInitialDelay} method. 393 * 394 * @param delay the delay in milliseconds 395 * @see #setInitialDelay 396 */ 397 public void setDelay(int delay) { 398 if (delay < 0) { 399 throw new IllegalArgumentException("Invalid delay: " + delay); 400 } 401 else { 402 this.delay = delay; 403 } 404 } 405 406 407 /** 408 * Returns the delay, in milliseconds, 409 * between firings of action events. 410 * 411 * @see #setDelay 412 * @see #getInitialDelay 413 */ 414 public int getDelay() { 415 return delay; 416 } 417 418 419 /** 420 * Sets the <code>Timer</code>'s initial delay, the time 421 * in milliseconds to wait after the timer is started 422 * before firing the first event. Upon construction, this 423 * is set to be the same as the between-event delay, 424 * but then its value is independent and remains unaffected 425 * by changes to the between-event delay. 426 * 427 * @param initialDelay the initial delay, in milliseconds 428 * @see #setDelay 429 */ 430 public void setInitialDelay(int initialDelay) { 431 if (initialDelay < 0) { 432 throw new IllegalArgumentException("Invalid initial delay: " + 433 initialDelay); 434 } 435 else { 436 this.initialDelay = initialDelay; 437 } 438 } 439 440 441 /** 442 * Returns the <code>Timer</code>'s initial delay. 443 * 444 * @see #setInitialDelay 445 * @see #setDelay 446 */ 447 public int getInitialDelay() { 448 return initialDelay; 449 } 450 451 452 /** 453 * If <code>flag</code> is <code>false</code>, 454 * instructs the <code>Timer</code> to send only one 455 * action event to its listeners. 456 * 457 * @param flag specify <code>false</code> to make the timer 458 * stop after sending its first action event 459 */ 460 public void setRepeats(boolean flag) { 461 repeats = flag; 462 } 463 464 465 /** 466 * Returns <code>true</code> (the default) 467 * if the <code>Timer</code> will send 468 * an action event 469 * to its listeners multiple times. 470 * 471 * @see #setRepeats 472 */ 473 public boolean isRepeats() { 474 return repeats; 475 } 476 477 478 /** 479 * Sets whether the <code>Timer</code> coalesces multiple pending 480 * <code>ActionEvent</code> firings. 481 * A busy application may not be able 482 * to keep up with a <code>Timer</code>'s event generation, 483 * causing multiple 484 * action events to be queued. When processed, 485 * the application sends these events one after the other, causing the 486 * <code>Timer</code>'s listeners to receive a sequence of 487 * events with no delay between them. Coalescing avoids this situation 488 * by reducing multiple pending events to a single event. 489 * <code>Timer</code>s 490 * coalesce events by default. 491 * 492 * @param flag specify <code>false</code> to turn off coalescing 493 */ 494 public void setCoalesce(boolean flag) { 495 boolean old = coalesce; 496 coalesce = flag; 497 if (!old && coalesce) { 498 // We must do this as otherwise if the Timer once notified 499 // in !coalese mode notify will be stuck to true and never 500 // become false. 501 cancelEvent(); 502 } 503 } 504 505 506 /** 507 * Returns <code>true</code> if the <code>Timer</code> coalesces 508 * multiple pending action events. 509 * 510 * @see #setCoalesce 511 */ 512 public boolean isCoalesce() { 513 return coalesce; 514 } 515 516 517 /** 518 * Sets the string that will be delivered as the action command 519 * in <code>ActionEvent</code>s fired by this timer. 520 * <code>null</code> is an acceptable value. 521 * 522 * @param command the action command 523 * @since 1.6 524 */ 525 public void setActionCommand(String command) { 526 this.actionCommand = command; 527 } 528 529 530 /** 531 * Returns the string that will be delivered as the action command 532 * in <code>ActionEvent</code>s fired by this timer. May be 533 * <code>null</code>, which is also the default. 534 * 535 * @return the action command used in firing events 536 * @since 1.6 537 */ 538 public String getActionCommand() { 539 return actionCommand; 540 } 541 542 543 /** 544 * Starts the <code>Timer</code>, 545 * causing it to start sending action events 546 * to its listeners. 547 * 548 * @see #stop 549 */ 550 public void start() { 551 timerQueue().addTimer(this, getInitialDelay()); 552 } 553 554 555 /** 556 * Returns <code>true</code> if the <code>Timer</code> is running. 557 * 558 * @see #start 559 */ 560 public boolean isRunning() { 561 return timerQueue().containsTimer(this); 562 } 563 564 565 /** 566 * Stops the <code>Timer</code>, 567 * causing it to stop sending action events 568 * to its listeners. 569 * 570 * @see #start 571 */ 572 public void stop() { 573 getLock().lock(); 574 try { 575 cancelEvent(); 576 timerQueue().removeTimer(this); 577 } finally { 578 getLock().unlock(); 579 } 580 } 581 582 583 /** 584 * Restarts the <code>Timer</code>, 585 * canceling any pending firings and causing 586 * it to fire with its initial delay. 587 */ 588 public void restart() { 589 getLock().lock(); 590 try { 591 stop(); 592 start(); 593 } finally { 594 getLock().unlock(); 595 } 596 } 597 598 599 /** 600 * Resets the internal state to indicate this Timer shouldn't notify 601 * any of its listeners. This does not stop a repeatable Timer from 602 * firing again, use <code>stop</code> for that. 603 */ 604 void cancelEvent() { 605 notify.set(false); 606 } 607 608 609 void post() { 610 if (notify.compareAndSet(false, true) || !coalesce) { 611 AccessController.doPrivileged(new PrivilegedAction<Void>() { 612 public Void run() { 613 SwingUtilities.invokeLater(doPostEvent); 614 return null; 615 } 616 }, getAccessControlContext()); 617 } 618 } 619 620 Lock getLock() { 621 return lock; 622 } 623 624 private void readObject(ObjectInputStream in) 625 throws ClassNotFoundException, IOException 626 { 627 this.acc = AccessController.getContext(); 628 in.defaultReadObject(); 629 } 630 631 /* 632 * We have to use readResolve because we can not initialize final 633 * fields for deserialized object otherwise 634 */ 635 private Object readResolve() { 636 Timer timer = new Timer(getDelay(), null); 637 timer.listenerList = listenerList; 638 timer.initialDelay = initialDelay; 639 timer.delay = delay; 640 timer.repeats = repeats; 641 timer.coalesce = coalesce; 642 timer.actionCommand = actionCommand; 643 return timer; 644 } 645 }