1/* 2 * Copyright (c) 1997, 2014, 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 28package javax.swing; 29 30 31 32import java.util.*; 33import java.util.concurrent.atomic.AtomicBoolean; 34import java.util.concurrent.locks.*; 35import java.awt.*; 36import java.awt.event.*; 37import java.io.Serializable; 38import java.io.*; 39import java.security.AccessControlContext; 40import java.security.AccessController; 41import java.security.PrivilegedAction; 42import 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://docs.oracle.com/javase/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™ 141 * has been added to the <code>java.beans</code> package. 142 * Please see {@link java.beans.XMLEncoder}. 143 * 144 * @see java.util.Timer 145 * 146 * 147 * @author Dave Moore 148 * @since 1.2 149 */ 150@SuppressWarnings("serial") 151public class Timer implements Serializable 152{ 153 /* 154 * NOTE: all fields need to be handled in readResolve 155 */ 156 157 /** 158 * The collection of registered listeners 159 */ 160 protected EventListenerList listenerList = new EventListenerList(); 161 162 // The following field strives to maintain the following: 163 // If coalesce is true, only allow one Runnable to be queued on the 164 // EventQueue and be pending (ie in the process of notifying the 165 // ActionListener). If we didn't do this it would allow for a 166 // situation where the app is taking too long to process the 167 // actionPerformed, and thus we'ld end up queing a bunch of Runnables 168 // and the app would never return: not good. This of course implies 169 // you can get dropped events, but such is life. 170 // notify is used to indicate if the ActionListener can be notified, when 171 // the Runnable is processed if this is true it will notify the listeners. 172 // notify is set to true when the Timer fires and the Runnable is queued. 173 // It will be set to false after notifying the listeners (if coalesce is 174 // true) or if the developer invokes stop. 175 private final transient AtomicBoolean notify = new AtomicBoolean(false); 176 177 private volatile int initialDelay, delay; 178 private volatile boolean repeats = true, coalesce = true; 179 180 private final transient Runnable doPostEvent; 181 182 private static volatile boolean logTimers; 183 184 private final transient Lock lock = new ReentrantLock(); 185 186 // This field is maintained by TimerQueue. 187 // eventQueued can also be reset by the TimerQueue, but will only ever 188 // happen in applet case when TimerQueues thread is destroyed. 189 // access to this field is synchronized on getLock() lock. 190 transient TimerQueue.DelayedTimer delayedTimer = null; 191 192 private volatile String actionCommand; 193 194 /** 195 * Creates a {@code Timer} and initializes both the initial delay and 196 * between-event delay to {@code delay} milliseconds. If {@code delay} 197 * is less than or equal to zero, the timer fires as soon as it 198 * is started. If <code>listener</code> is not <code>null</code>, 199 * it's registered as an action listener on the timer. 200 * 201 * @param delay milliseconds for the initial and between-event delay 202 * @param listener an initial listener; can be <code>null</code> 203 * 204 * @see #addActionListener 205 * @see #setInitialDelay 206 * @see #setRepeats 207 */ 208 public Timer(int delay, ActionListener listener) { 209 super(); 210 this.delay = delay; 211 this.initialDelay = delay; 212 213 doPostEvent = new DoPostEvent(); 214 215 if (listener != null) { 216 addActionListener(listener); 217 } 218 } 219 220 /* 221 * The timer's AccessControlContext. 222 */ 223 private transient volatile AccessControlContext acc = 224 AccessController.getContext(); 225 226 /** 227 * Returns the acc this timer was constructed with. 228 */ 229 final AccessControlContext getAccessControlContext() { 230 if (acc == null) { 231 throw new SecurityException( 232 "Timer is missing AccessControlContext"); 233 } 234 return acc; 235 } 236 237 /** 238 * DoPostEvent is a runnable class that fires actionEvents to 239 * the listeners on the EventDispatchThread, via invokeLater. 240 * @see Timer#post 241 */ 242 class DoPostEvent implements Runnable 243 { 244 public void run() { 245 if (logTimers) { 246 System.out.println("Timer ringing: " + Timer.this); 247 } 248 if(notify.get()) { 249 fireActionPerformed(new ActionEvent(Timer.this, 0, getActionCommand(), 250 System.currentTimeMillis(), 251 0)); 252 if (coalesce) { 253 cancelEvent(); 254 } 255 } 256 } 257 258 Timer getTimer() { 259 return Timer.this; 260 } 261 } 262 263 /** 264 * Adds an action listener to the <code>Timer</code>. 265 * 266 * @param listener the listener to add 267 * 268 * @see #Timer 269 */ 270 public void addActionListener(ActionListener listener) { 271 listenerList.add(ActionListener.class, listener); 272 } 273 274 275 /** 276 * Removes the specified action listener from the <code>Timer</code>. 277 * 278 * @param listener the listener to remove 279 */ 280 public void removeActionListener(ActionListener listener) { 281 listenerList.remove(ActionListener.class, listener); 282 } 283 284 285 /** 286 * Returns an array of all the action listeners registered 287 * on this timer. 288 * 289 * @return all of the timer's <code>ActionListener</code>s or an empty 290 * array if no action listeners are currently registered 291 * 292 * @see #addActionListener 293 * @see #removeActionListener 294 * 295 * @since 1.4 296 */ 297 public ActionListener[] getActionListeners() { 298 return listenerList.getListeners(ActionListener.class); 299 } 300 301 302 /** 303 * Notifies all listeners that have registered interest for 304 * notification on this event type. 305 * 306 * @param e the action event to fire 307 * @see EventListenerList 308 */ 309 protected void fireActionPerformed(ActionEvent e) { 310 // Guaranteed to return a non-null array 311 Object[] listeners = listenerList.getListenerList(); 312 313 // Process the listeners last to first, notifying 314 // those that are interested in this event 315 for (int i=listeners.length-2; i>=0; i-=2) { 316 if (listeners[i]==ActionListener.class) { 317 ((ActionListener)listeners[i+1]).actionPerformed(e); 318 } 319 } 320 } 321 322 /** 323 * Returns an array of all the objects currently registered as 324 * <code><em>Foo</em>Listener</code>s 325 * upon this <code>Timer</code>. 326 * <code><em>Foo</em>Listener</code>s 327 * are registered using the <code>add<em>Foo</em>Listener</code> method. 328 * <p> 329 * You can specify the <code>listenerType</code> argument 330 * with a class literal, such as <code><em>Foo</em>Listener.class</code>. 331 * For example, you can query a <code>Timer</code> 332 * instance <code>t</code> 333 * for its action listeners 334 * with the following code: 335 * 336 * <pre>ActionListener[] als = (ActionListener[])(t.getListeners(ActionListener.class));</pre> 337 * 338 * If no such listeners exist, 339 * this method returns an empty array. 340 * 341 * @param <T> the type of {@code EventListener} class being requested 342 * @param listenerType the type of listeners requested; 343 * this parameter should specify an interface 344 * that descends from <code>java.util.EventListener</code> 345 * @return an array of all objects registered as 346 * <code><em>Foo</em>Listener</code>s 347 * on this timer, 348 * or an empty array if no such 349 * listeners have been added 350 * @exception ClassCastException if <code>listenerType</code> doesn't 351 * specify a class or interface that implements 352 * <code>java.util.EventListener</code> 353 * 354 * @see #getActionListeners 355 * @see #addActionListener 356 * @see #removeActionListener 357 * 358 * @since 1.3 359 */ 360 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 361 return listenerList.getListeners(listenerType); 362 } 363 364 /** 365 * Returns the timer queue. 366 */ 367 private TimerQueue timerQueue() { 368 return TimerQueue.sharedInstance(); 369 } 370 371 372 /** 373 * Enables or disables the timer log. When enabled, a message 374 * is posted to <code>System.out</code> whenever the timer goes off. 375 * 376 * @param flag <code>true</code> to enable logging 377 * @see #getLogTimers 378 */ 379 public static void setLogTimers(boolean flag) { 380 logTimers = flag; 381 } 382 383 384 /** 385 * Returns <code>true</code> if logging is enabled. 386 * 387 * @return <code>true</code> if logging is enabled; otherwise, false 388 * @see #setLogTimers 389 */ 390 public static boolean getLogTimers() { 391 return logTimers; 392 } 393 394 395 /** 396 * Sets the <code>Timer</code>'s between-event delay, the number of milliseconds 397 * between successive action events. This does not affect the initial delay 398 * property, which can be set by the {@code setInitialDelay} method. 399 * 400 * @param delay the delay in milliseconds 401 * @see #setInitialDelay 402 */ 403 public void setDelay(int delay) { 404 checkDelay(delay, "Invalid delay: "); 405 this.delay = delay; 406 } 407 408 private static void checkDelay(int delay, String message) { 409 if (delay < 0) { 410 throw new IllegalArgumentException(message + delay); 411 } 412 } 413 414 /** 415 * Returns the delay, in milliseconds, 416 * between firings of action events. 417 * 418 * @return the delay, in milliseconds, between firings of action events 419 * @see #setDelay 420 * @see #getInitialDelay 421 */ 422 public int getDelay() { 423 return delay; 424 } 425 426 427 /** 428 * Sets the <code>Timer</code>'s initial delay, the time 429 * in milliseconds to wait after the timer is started 430 * before firing the first event. Upon construction, this 431 * is set to be the same as the between-event delay, 432 * but then its value is independent and remains unaffected 433 * by changes to the between-event delay. 434 * 435 * @param initialDelay the initial delay, in milliseconds 436 * @see #setDelay 437 */ 438 public void setInitialDelay(int initialDelay) { 439 checkDelay(initialDelay, "Invalid initial delay: "); 440 this.initialDelay = initialDelay; 441 } 442 443 444 /** 445 * Returns the {@code Timer}'s initial delay. 446 * 447 * @return the {@code Timer}'s intial delay, in milliseconds 448 * @see #setInitialDelay 449 * @see #setDelay 450 */ 451 public int getInitialDelay() { 452 return initialDelay; 453 } 454 455 456 /** 457 * If <code>flag</code> is <code>false</code>, 458 * instructs the <code>Timer</code> to send only one 459 * action event to its listeners. 460 * 461 * @param flag specify <code>false</code> to make the timer 462 * stop after sending its first action event 463 */ 464 public void setRepeats(boolean flag) { 465 repeats = flag; 466 } 467 468 469 /** 470 * Returns <code>true</code> (the default) 471 * if the <code>Timer</code> will send 472 * an action event 473 * to its listeners multiple times. 474 * 475 * @return true if the {@code Timer} will send an action event to its 476 * listeners multiple times 477 * @see #setRepeats 478 */ 479 public boolean isRepeats() { 480 return repeats; 481 } 482 483 484 /** 485 * Sets whether the <code>Timer</code> coalesces multiple pending 486 * <code>ActionEvent</code> firings. 487 * A busy application may not be able 488 * to keep up with a <code>Timer</code>'s event generation, 489 * causing multiple 490 * action events to be queued. When processed, 491 * the application sends these events one after the other, causing the 492 * <code>Timer</code>'s listeners to receive a sequence of 493 * events with no delay between them. Coalescing avoids this situation 494 * by reducing multiple pending events to a single event. 495 * <code>Timer</code>s 496 * coalesce events by default. 497 * 498 * @param flag specify <code>false</code> to turn off coalescing 499 */ 500 public void setCoalesce(boolean flag) { 501 boolean old = coalesce; 502 coalesce = flag; 503 if (!old && coalesce) { 504 // We must do this as otherwise if the Timer once notified 505 // in !coalese mode notify will be stuck to true and never 506 // become false. 507 cancelEvent(); 508 } 509 } 510 511 512 /** 513 * Returns {@code true} if the {@code Timer} coalesces 514 * multiple pending action events. 515 * 516 * @return true if the {@code Timer} coalesces multiple pending 517 * action events 518 * @see #setCoalesce 519 */ 520 public boolean isCoalesce() { 521 return coalesce; 522 } 523 524 525 /** 526 * Sets the string that will be delivered as the action command 527 * in <code>ActionEvent</code>s fired by this timer. 528 * <code>null</code> is an acceptable value. 529 * 530 * @param command the action command 531 * @since 1.6 532 */ 533 public void setActionCommand(String command) { 534 this.actionCommand = command; 535 } 536 537 538 /** 539 * Returns the string that will be delivered as the action command 540 * in <code>ActionEvent</code>s fired by this timer. May be 541 * <code>null</code>, which is also the default. 542 * 543 * @return the action command used in firing events 544 * @since 1.6 545 */ 546 public String getActionCommand() { 547 return actionCommand; 548 } 549 550 551 /** 552 * Starts the <code>Timer</code>, 553 * causing it to start sending action events 554 * to its listeners. 555 * 556 * @see #stop 557 */ 558 public void start() { 559 timerQueue().addTimer(this, getInitialDelay()); 560 } 561 562 563 /** 564 * Returns {@code true} if the {@code Timer} is running. 565 * 566 * @return true if the {@code Timer} is running, false otherwise 567 * @see #start 568 */ 569 public boolean isRunning() { 570 return timerQueue().containsTimer(this); 571 } 572 573 574 /** 575 * Stops the <code>Timer</code>, 576 * causing it to stop sending action events 577 * to its listeners. 578 * 579 * @see #start 580 */ 581 public void stop() { 582 getLock().lock(); 583 try { 584 cancelEvent(); 585 timerQueue().removeTimer(this); 586 } finally { 587 getLock().unlock(); 588 } 589 } 590 591 592 /** 593 * Restarts the <code>Timer</code>, 594 * canceling any pending firings and causing 595 * it to fire with its initial delay. 596 */ 597 public void restart() { 598 getLock().lock(); 599 try { 600 stop(); 601 start(); 602 } finally { 603 getLock().unlock(); 604 } 605 } 606 607 608 /** 609 * Resets the internal state to indicate this Timer shouldn't notify 610 * any of its listeners. This does not stop a repeatable Timer from 611 * firing again, use <code>stop</code> for that. 612 */ 613 void cancelEvent() { 614 notify.set(false); 615 } 616 617 618 void post() { 619 if (notify.compareAndSet(false, true) || !coalesce) { 620 AccessController.doPrivileged(new PrivilegedAction<Void>() { 621 public Void run() { 622 SwingUtilities.invokeLater(doPostEvent); 623 return null; 624 } 625 }, getAccessControlContext()); 626 } 627 } 628 629 Lock getLock() { 630 return lock; 631 } 632 633 private void readObject(ObjectInputStream in) 634 throws ClassNotFoundException, IOException 635 { 636 this.acc = AccessController.getContext(); 637 ObjectInputStream.GetField f = in.readFields(); 638 639 EventListenerList newListenerList = (EventListenerList) 640 f.get("listenerList", null); 641 if (newListenerList == null) { 642 throw new InvalidObjectException("Null listenerList"); 643 } 644 listenerList = newListenerList; 645 646 int newInitialDelay = f.get("initialDelay", 0); 647 checkDelay(newInitialDelay, "Invalid initial delay: "); 648 initialDelay = newInitialDelay; 649 650 int newDelay = f.get("delay", 0); 651 checkDelay(newDelay, "Invalid delay: "); 652 delay = newDelay; 653 654 repeats = f.get("repeats", false); 655 coalesce = f.get("coalesce", false); 656 actionCommand = (String) f.get("actionCommand", null); 657 } 658 659 /* 660 * We have to use readResolve because we can not initialize final 661 * fields for deserialized object otherwise 662 */ 663 private Object readResolve() { 664 Timer timer = new Timer(getDelay(), null); 665 timer.listenerList = listenerList; 666 timer.initialDelay = initialDelay; 667 timer.delay = delay; 668 timer.repeats = repeats; 669 timer.coalesce = coalesce; 670 timer.actionCommand = actionCommand; 671 return timer; 672 } 673} 674