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 /* 182 * The timer's AccessControlContext. 183 */ 184 private transient volatile AccessControlContext acc = 185 AccessController.getContext(); 186 187 /** 188 * Returns the acc this timer was constructed with. 189 */ 190 final AccessControlContext getAccessControlContext() { 191 if (acc == null) { 192 throw new SecurityException( 193 "Timer is missing AccessControlContext"); 194 } 195 return acc; 196 } 197 198 // This field is maintained by TimerQueue. 199 // eventQueued can also be reset by the TimerQueue, but will only ever 200 // happen in applet case when TimerQueues thread is destroyed. 201 // access to this field is synchronized on getLock() lock. 202 transient TimerQueue.DelayedTimer delayedTimer = null; 203 204 private volatile String actionCommand; 205 206 /** 207 * Creates a {@code Timer} and initializes both the initial delay and 208 * between-event delay to {@code delay} milliseconds. If {@code delay} 209 * is less than or equal to zero, the timer fires as soon as it 210 * is started. If <code>listener</code> is not <code>null</code>, 211 * it's registered as an action listener on the timer. 212 * 213 * @param delay milliseconds for the initial and between-event delay 214 * @param listener an initial listener; can be <code>null</code> 215 216 * @see #addActionListener 217 * @see #setInitialDelay 218 * @see #setRepeats 219 */ 220 public Timer(int delay, ActionListener listener) { 221 super(); 222 this.delay = delay; 223 this.initialDelay = delay; 224 225 doPostEvent = new DoPostEvent(); 226 227 if (listener != null) { 228 addActionListener(listener); 229 } 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 (ActionListener[])listenerList.getListeners( 294 ActionListener.class); 295 } 296 297 298 /** 299 * Notifies all listeners that have registered interest for 300 * notification on this event type. 301 * 302 * @param e the action event to fire 303 * @see EventListenerList 304 */ 305 protected void fireActionPerformed(ActionEvent e) { 306 // Guaranteed to return a non-null array 307 Object[] listeners = listenerList.getListenerList(); 308 309 // Process the listeners last to first, notifying 310 // those that are interested in this event 311 for (int i=listeners.length-2; i>=0; i-=2) { 312 if (listeners[i]==ActionListener.class) { 313 ((ActionListener)listeners[i+1]).actionPerformed(e); 314 } 315 } 316 } 317 318 /** 319 * Returns an array of all the objects currently registered as 320 * <code><em>Foo</em>Listener</code>s 321 * upon this <code>Timer</code>. 322 * <code><em>Foo</em>Listener</code>s 323 * are registered using the <code>add<em>Foo</em>Listener</code> method. 324 * <p> 325 * You can specify the <code>listenerType</code> argument 326 * with a class literal, such as <code><em>Foo</em>Listener.class</code>. 327 * For example, you can query a <code>Timer</code> 328 * instance <code>t</code> 329 * for its action listeners 330 * with the following code: 331 * 332 * <pre>ActionListener[] als = (ActionListener[])(t.getListeners(ActionListener.class));</pre> 333 * 334 * If no such listeners exist, 335 * this method returns an empty array. 336 * 337 * @param listenerType the type of listeners requested; 338 * this parameter should specify an interface 339 * that descends from <code>java.util.EventListener</code> 340 * @return an array of all objects registered as 341 * <code><em>Foo</em>Listener</code>s 342 * on this timer, 343 * or an empty array if no such 344 * listeners have been added 345 * @exception ClassCastException if <code>listenerType</code> doesn't 346 * specify a class or interface that implements 347 * <code>java.util.EventListener</code> 348 * 349 * @see #getActionListeners 350 * @see #addActionListener 351 * @see #removeActionListener 352 * 353 * @since 1.3 354 */ 355 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 356 return listenerList.getListeners(listenerType); 357 } 358 359 /** 360 * Returns the timer queue. 361 */ 362 private TimerQueue timerQueue() { 363 return TimerQueue.sharedInstance(); 364 } 365 366 367 /** 368 * Enables or disables the timer log. When enabled, a message 369 * is posted to <code>System.out</code> whenever the timer goes off. 370 * 371 * @param flag <code>true</code> to enable logging 372 * @see #getLogTimers 373 */ 374 public static void setLogTimers(boolean flag) { 375 logTimers = flag; 376 } 377 378 379 /** 380 * Returns <code>true</code> if logging is enabled. 381 * 382 * @return <code>true</code> if logging is enabled; otherwise, false 383 * @see #setLogTimers 384 */ 385 public static boolean getLogTimers() { 386 return logTimers; 387 } 388 389 390 /** 391 * Sets the <code>Timer</code>'s between-event delay, the number of milliseconds 392 * between successive action events. This does not affect the initial delay 393 * property, which can be set by the {@code setInitialDelay} method. 394 * 395 * @param delay the delay in milliseconds 396 * @see #setInitialDelay 397 */ 398 public void setDelay(int delay) { 399 if (delay < 0) { 400 throw new IllegalArgumentException("Invalid delay: " + delay); 401 } 402 else { 403 this.delay = delay; 404 } 405 } 406 407 408 /** 409 * Returns the delay, in milliseconds, 410 * between firings of action events. 411 * 412 * @see #setDelay 413 * @see #getInitialDelay 414 */ 415 public int getDelay() { 416 return delay; 417 } 418 419 420 /** 421 * Sets the <code>Timer</code>'s initial delay, the time 422 * in milliseconds to wait after the timer is started 423 * before firing the first event. Upon construction, this 424 * is set to be the same as the between-event delay, 425 * but then its value is independent and remains unaffected 426 * by changes to the between-event delay. 427 * 428 * @param initialDelay the initial delay, in milliseconds 429 * @see #setDelay 430 */ 431 public void setInitialDelay(int initialDelay) { 432 if (initialDelay < 0) { 433 throw new IllegalArgumentException("Invalid initial delay: " + 434 initialDelay); 435 } 436 else { 437 this.initialDelay = initialDelay; 438 } 439 } 440 441 442 /** 443 * Returns the <code>Timer</code>'s initial delay. 444 * 445 * @see #setInitialDelay 446 * @see #setDelay 447 */ 448 public int getInitialDelay() { 449 return initialDelay; 450 } 451 452 453 /** 454 * If <code>flag</code> is <code>false</code>, 455 * instructs the <code>Timer</code> to send only one 456 * action event to its listeners. 457 * 458 * @param flag specify <code>false</code> to make the timer 459 * stop after sending its first action event 460 */ 461 public void setRepeats(boolean flag) { 462 repeats = flag; 463 } 464 465 466 /** 467 * Returns <code>true</code> (the default) 468 * if the <code>Timer</code> will send 469 * an action event 470 * to its listeners multiple times. 471 * 472 * @see #setRepeats 473 */ 474 public boolean isRepeats() { 475 return repeats; 476 } 477 478 479 /** 480 * Sets whether the <code>Timer</code> coalesces multiple pending 481 * <code>ActionEvent</code> firings. 482 * A busy application may not be able 483 * to keep up with a <code>Timer</code>'s event generation, 484 * causing multiple 485 * action events to be queued. When processed, 486 * the application sends these events one after the other, causing the 487 * <code>Timer</code>'s listeners to receive a sequence of 488 * events with no delay between them. Coalescing avoids this situation 489 * by reducing multiple pending events to a single event. 490 * <code>Timer</code>s 491 * coalesce events by default. 492 * 493 * @param flag specify <code>false</code> to turn off coalescing 494 */ 495 public void setCoalesce(boolean flag) { 496 boolean old = coalesce; 497 coalesce = flag; 498 if (!old && coalesce) { 499 // We must do this as otherwise if the Timer once notified 500 // in !coalese mode notify will be stuck to true and never 501 // become false. 502 cancelEvent(); 503 } 504 } 505 506 507 /** 508 * Returns <code>true</code> if the <code>Timer</code> coalesces 509 * multiple pending action events. 510 * 511 * @see #setCoalesce 512 */ 513 public boolean isCoalesce() { 514 return coalesce; 515 } 516 517 518 /** 519 * Sets the string that will be delivered as the action command 520 * in <code>ActionEvent</code>s fired by this timer. 521 * <code>null</code> is an acceptable value. 522 * 523 * @param command the action command 524 * @since 1.6 525 */ 526 public void setActionCommand(String command) { 527 this.actionCommand = command; 528 } 529 530 531 /** 532 * Returns the string that will be delivered as the action command 533 * in <code>ActionEvent</code>s fired by this timer. May be 534 * <code>null</code>, which is also the default. 535 * 536 * @return the action command used in firing events 537 * @since 1.6 538 */ 539 public String getActionCommand() { 540 return actionCommand; 541 } 542 543 544 /** 545 * Starts the <code>Timer</code>, 546 * causing it to start sending action events 547 * to its listeners. 548 * 549 * @see #stop 550 */ 551 public void start() { 552 timerQueue().addTimer(this, getInitialDelay()); 553 } 554 555 556 /** 557 * Returns <code>true</code> if the <code>Timer</code> is running. 558 * 559 * @see #start 560 */ 561 public boolean isRunning() { 562 return timerQueue().containsTimer(this); 563 } 564 565 566 /** 567 * Stops the <code>Timer</code>, 568 * causing it to stop sending action events 569 * to its listeners. 570 * 571 * @see #start 572 */ 573 public void stop() { 574 getLock().lock(); 575 try { 576 cancelEvent(); 577 timerQueue().removeTimer(this); 578 } finally { 579 getLock().unlock(); 580 } 581 } 582 583 584 /** 585 * Restarts the <code>Timer</code>, 586 * canceling any pending firings and causing 587 * it to fire with its initial delay. 588 */ 589 public void restart() { 590 getLock().lock(); 591 try { 592 stop(); 593 start(); 594 } finally { 595 getLock().unlock(); 596 } 597 } 598 599 600 /** 601 * Resets the internal state to indicate this Timer shouldn't notify 602 * any of its listeners. This does not stop a repeatable Timer from 603 * firing again, use <code>stop</code> for that. 604 */ 605 void cancelEvent() { 606 notify.set(false); 607 } 608 609 610 void post() { 611 if (notify.compareAndSet(false, true) || !coalesce) { 612 AccessController.doPrivileged(new PrivilegedAction<Void>() { 613 public Void run() { 614 SwingUtilities.invokeLater(doPostEvent); 615 return null; 616 } 617 }, getAccessControlContext()); 618 } 619 } 620 621 Lock getLock() { 622 return lock; 623 } 624 625 /* 626 * We have to use readResolve because we can not initialize final 627 * fields for deserialized object otherwise 628 */ 629 private Object readResolve() { 630 Timer timer = new Timer(getDelay(), null); 631 timer.listenerList = listenerList; 632 timer.initialDelay = initialDelay; 633 timer.delay = delay; 634 timer.repeats = repeats; 635 timer.coalesce = coalesce; 636 timer.actionCommand = actionCommand; 637 return timer; 638 } 639 640 private void readObject(ObjectInputStream in) 641 throws ClassNotFoundException, IOException 642 { 643 this.acc = AccessController.getContext(); 644 in.defaultReadObject(); 645 } 646 }