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 synchronized (commonTimer) { 040 try { 041 commonTimer.schedule(task, time); 042 } catch (IllegalStateException e) { 043 log.warn("During schedule()", e); 044 } 045 } 046 } 047 048 static public void schedule(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 049 synchronized (commonTimer) { 050 try { 051 commonTimer.schedule(task, firstTime, period); 052 } catch (IllegalStateException e) { 053 log.warn("During schedule()", e); 054 } 055 } 056 } 057 058 static public void schedule(@Nonnull TimerTask task, long delay) { 059 synchronized (commonTimer) { 060 try { 061 commonTimer.schedule(task, delay); 062 } catch (IllegalStateException e) { 063 log.warn("During schedule()", e); 064 } 065 } 066 } 067 068 static public void schedule(@Nonnull TimerTask task, long delay, long period) { 069 synchronized (commonTimer) { 070 try { 071 commonTimer.schedule(task, delay, period); 072 } catch (IllegalStateException e) { 073 log.warn("During schedule()", e); 074 } 075 } 076 } 077 078 static public void scheduleAtFixedRate(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 079 synchronized (commonTimer) { 080 try { 081 commonTimer.schedule(task, firstTime, period); 082 } catch (IllegalStateException e) { 083 log.warn("During schedule()", e); 084 } 085 } 086 } 087 088 static public void scheduleAtFixedRate(@Nonnull TimerTask task, long delay, long period) { 089 synchronized (commonTimer) { 090 try { 091 commonTimer.schedule(task, delay, period); 092 } catch (IllegalStateException e) { 093 log.warn("During schedule()", e); 094 } 095 } 096 } 097 098 099 // GUI-thread implementation methods 100 101 // arrange to run on GUI thread 102 static private TimerTask gtask(TimerTask task) { 103 return new TimerTask(){ 104 @Override 105 public void run() { 106 ThreadingUtil.runOnGUIEventually(() -> {task.run();}); 107 } 108 }; 109 } 110 111 static public void scheduleOnGUIThread(@Nonnull TimerTask task, @Nonnull Date time) { 112 synchronized (commonTimer) { 113 try { 114 commonTimer.schedule(gtask(task), time); 115 } catch (IllegalStateException e) { 116 log.warn("During schedule()", e); 117 } 118 } 119 } 120 121 static public void scheduleOnGUIThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 122 synchronized (commonTimer) { 123 try { 124 commonTimer.schedule(gtask(task), firstTime, period); 125 } catch (IllegalStateException e) { 126 log.warn("During schedule()", e); 127 } 128 } 129 } 130 131 static public void scheduleOnGUIThread(@Nonnull TimerTask task, long delay) { 132 synchronized (commonTimer) { 133 try { 134 commonTimer.schedule(gtask(task), delay); 135 } catch (IllegalStateException e) { 136 log.warn("During schedule()", e); 137 } 138 } 139 } 140 141 static public void scheduleOnGUIThread(@Nonnull TimerTask task, long delay, long period) { 142 synchronized (commonTimer) { 143 try { 144 commonTimer.schedule(gtask(task), delay, period); 145 } catch (IllegalStateException e) { 146 log.warn("During schedule()", e); 147 } 148 } 149 } 150 151 static public void scheduleAtFixedRateOnGUIThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 152 synchronized (commonTimer) { 153 try { 154 commonTimer.schedule(gtask(task), firstTime, period); 155 } catch (IllegalStateException e) { 156 log.warn("During schedule()", e); 157 } 158 } 159 } 160 161 static public void scheduleAtFixedRateOnGUIThread(@Nonnull TimerTask task, long delay, long period) { 162 synchronized (commonTimer) { 163 try { 164 commonTimer.schedule(gtask(task), delay, period); 165 } catch (IllegalStateException e) { 166 log.warn("During schedule()", e); 167 } 168 } 169 } 170 171 172 // arrange to run on layout thread 173 static private TimerTask ltask(TimerTask task) { 174 return new TimerTask(){ 175 @Override 176 public void run() { 177 ThreadingUtil.runOnLayoutEventually(() -> {task.run();}); 178 } 179 }; 180 } 181 182 static public void scheduleOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date time) { 183 synchronized (commonTimer) { 184 try { 185 commonTimer.schedule(ltask(task), time); 186 } catch (IllegalStateException e) { 187 log.warn("During schedule()", e); 188 } 189 } 190 } 191 192 static public void scheduleOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 193 synchronized (commonTimer) { 194 try { 195 commonTimer.schedule(ltask(task), firstTime, period); 196 } catch (IllegalStateException e) { 197 log.warn("During schedule()", e); 198 } 199 } 200 } 201 202 static public void scheduleOnLayoutThread(@Nonnull TimerTask task, long delay) { 203 synchronized (commonTimer) { 204 try { 205 commonTimer.schedule(ltask(task), delay); 206 } catch (IllegalStateException e) { 207 log.warn("During schedule()", e); 208 } 209 } 210 } 211 212 static public void scheduleOnLayoutThread(@Nonnull TimerTask task, long delay, long period) { 213 synchronized (commonTimer) { 214 try { 215 commonTimer.schedule(ltask(task), delay, period); 216 } catch (IllegalStateException e) { 217 log.warn("During schedule()", e); 218 } 219 } 220 } 221 222 static public void scheduleAtFixedRateOnLayoutThread(@Nonnull TimerTask task, @Nonnull Date firstTime, long period) { 223 synchronized (commonTimer) { 224 try { 225 commonTimer.schedule(ltask(task), firstTime, period); 226 } catch (IllegalStateException e) { 227 log.warn("During schedule()", e); 228 } 229 } 230 } 231 232 static public void scheduleAtFixedRateOnLayoutThread(@Nonnull TimerTask task, long delay, long period) { 233 synchronized (commonTimer) { 234 try { 235 commonTimer.schedule(ltask(task), delay, period); 236 } catch (IllegalStateException e) { 237 log.warn("During schedule()", e); 238 } 239 } 240 } 241 242 243 final static Timer commonTimer = new Timer("JMRI Common Timer", true); 244 245 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TimerUtil.class); 246}