001package jmri.util;
002
003import java.util.Date;
004import java.util.Timer;
005import java.util.TimerTask;
006import javax.annotation.Nonnull;
007
008
009/**
010 * Common utility methods for working with (@link java.util.Timer)
011 * <p>
012 * Each {@link java.util.Timer} uses a thread, which means that they're
013 * not throw-away timers:  You either track when you can destroy them 
014 * (and that destruction is not obvious), or they stick around consuming
015 * resources.
016 * <p>
017 * This class provides most of the functionality of a Timer.
018 * Some differences:
019 * <ul>
020 * <li>When migrating code that uses Timer.cancel() to end operation, you have to
021 *     retain references to the individual TimerTask objects and cancel them instead.
022 * </ul>
023 * <p>
024 * For convenience, this also provides methods to ensure that the task is invoked
025 * on a specific JMRI thread.
026 * <p>
027 * Please note the comment in the {@link Timer} Javadoc about how
028 * {@link java.util.concurrent.ScheduledThreadPoolExecutor} might provide a better
029 * underlying implementation.
030 *
031 * @author Bob Jacobsen Copyright 2018
032 */
033@javax.annotation.concurrent.Immutable
034final public class TimerUtil {
035
036    // Timer implementation methods
037    
038    static public void schedule(@Nonnull TimerTask task, @Nonnull Date time) {
039        commonTimer.schedule(task, time);
040    }
041
042    static public void schedule(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
043        commonTimer.schedule(task, firstTime, period);
044    }
045    
046    static public void schedule(@Nonnull TimerTask task, long delay) {
047        commonTimer.schedule(task, delay);
048    }
049    
050    static public void schedule(@Nonnull TimerTask task, long delay, long period) {
051        commonTimer.schedule(task, delay, period);
052    }
053    
054    static public void scheduleAtFixedRate(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
055        commonTimer.schedule(task, firstTime, period);
056    }
057    
058    static public void scheduleAtFixedRate(@Nonnull TimerTask task, long delay, long period) {
059        commonTimer.schedule(task, delay, period);
060    }
061   
062   
063    // GUI-thread implementation methods
064    
065    // arrange to run on GUI thread
066    static private TimerTask gtask(TimerTask task) {
067        return new TimerTask(){
068                @Override
069                public void run() {
070                    ThreadingUtil.runOnGUIEventually(() -> {task.run();});
071                }
072        };
073    }
074
075    static public void scheduleOnGUIThread(@Nonnull TimerTask task, @Nonnull Date time) {
076        commonTimer.schedule(gtask(task), time);
077    }
078
079    static public void scheduleOnGUIThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
080        commonTimer.schedule(gtask(task), firstTime, period);
081    }
082    
083    static public void scheduleOnGUIThread(@Nonnull TimerTask task, long delay) {
084        commonTimer.schedule(gtask(task), delay);
085    }
086    
087    static public void scheduleOnGUIThread(@Nonnull TimerTask task, long delay, long period) {
088        commonTimer.schedule(gtask(task), delay, period);
089    }
090    
091    static public void scheduleAtFixedRateOnGUIThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
092        commonTimer.schedule(gtask(task), firstTime, period);
093    }
094    
095    static public void scheduleAtFixedRateOnGUIThread(@Nonnull TimerTask task, long delay, long period) {
096        commonTimer.schedule(gtask(task), delay, period);
097    }
098   
099   
100    // arrange to run on layout thread
101    static private TimerTask ltask(TimerTask task) {
102        return new TimerTask(){
103                @Override
104                public void run() {
105                    ThreadingUtil.runOnLayoutEventually(() -> {task.run();});
106                }
107        };
108    }
109    
110    static public void scheduleOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date time) {
111        commonTimer.schedule(ltask(task), time);
112    }
113
114    static public void scheduleOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
115        commonTimer.schedule(ltask(task), firstTime, period);
116    }
117    
118    static public void scheduleOnLayoutThread(@Nonnull TimerTask task, long delay) {
119        commonTimer.schedule(ltask(task), delay);
120    }
121    
122    static public void scheduleOnLayoutThread(@Nonnull TimerTask task, long delay, long period) {
123        commonTimer.schedule(ltask(task), delay, period);
124    }
125    
126    static public void scheduleAtFixedRateOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) {
127        commonTimer.schedule(ltask(task), firstTime, period);
128    }
129    
130    static public void scheduleAtFixedRateOnLayoutThread(@Nonnull TimerTask task, long delay, long period) {
131        commonTimer.schedule(ltask(task), delay, period);
132    }
133   
134   
135    final static Timer commonTimer = new Timer("JMRI Common Timer", true);
136    
137    // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TimerUtil.class);
138}