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&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")
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