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="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&trade;
 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")
 151 public 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 }
--- EOF ---