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