001package co.codewizards.cloudstore.server; 002 003import java.util.Date; 004import java.util.Timer; 005import java.util.TimerTask; 006 007import org.slf4j.Logger; 008import org.slf4j.LoggerFactory; 009 010import co.codewizards.cloudstore.core.config.Config; 011import co.codewizards.cloudstore.core.config.ConfigImpl; 012import co.codewizards.cloudstore.core.updater.CloudStoreUpdaterCore; 013 014public class CloudStoreUpdaterTimer { 015 016 /** 017 * Default value for {@link #CONFIG_KEY_TIMER_PERIOD} (15 minutes in milliseconds). 018 */ 019 public static final long DEFAULT_TIMER_PERIOD = 15 * 60 * 1000; 020 021 /** 022 * Configuration property key controlling how many milliseconds the timer waits between 023 * invocations of {@link CloudStoreUpdaterCore#createUpdaterDirIfUpdateNeeded()}. 024 * <p> 025 * Important: Setting this to 5 minutes does not necessarily mean that an update will be done 026 * 5 minutes after the new version was released. There's a local cache and a new release is only detected 027 * after this cache expired -- see {@link CloudStoreUpdaterCore#CONFIG_KEY_REMOTE_VERSION_CACHE_VALIDITY_PERIOD}. 028 * <p> 029 * The configuration can be overridden by a system property - see {@link Config#SYSTEM_PROPERTY_PREFIX}. 030 * 031 * @see #DEFAULT_TIMER_PERIOD 032 */ 033 public static final String CONFIG_KEY_TIMER_PERIOD = "updater.timer.period"; 034 035 /** 036 * The timer-period for the very first check, done after {@link #start()} (30 seconds in milliseconds). 037 * <p> 038 * Important: This is also the time it takes until the "updater/"-directory from a previous 039 * update is deleted. 040 */ 041 private static final long ON_START_TIMER_PERIOD = 30 * 1000; 042 043 private static final Logger logger = LoggerFactory.getLogger(CloudStoreUpdaterTimer.class); 044 045 private Timer timer; 046 private TimerTask timerTask; 047 048 public CloudStoreUpdaterTimer() { 049 } 050 051 public synchronized void start() { 052 if (timer == null) 053 schedule(true); 054 } 055 056 public synchronized void stop() { 057 cancelTimerTask(); 058 cancelTimer(); 059 } 060 061 protected synchronized void schedule(final boolean onStart) { 062 cancelTimerTask(); 063 064 final long timerPeriod = getTimerPeriod(); 065 if (timerPeriod <= 0) { 066 logger.info("schedule: timerPeriod={}. Disabling this timer!", timerPeriod); 067 cancelTimer(); 068 return; 069 } 070 071 if (timer == null) 072 timer = new Timer("CloudStoreUpdaterTimer"); 073 074 if (timerTask != null) // due to cancelTimerTask() above, this should never happen! 075 throw new IllegalStateException("timerTask != null"); 076 077 timerTask = new TimerTask() { 078 @Override 079 public void run() { 080 try { 081 CloudStoreUpdaterTimer.this.run(); 082 schedule(false); // reschedule, because we always schedule without period (one time execution). 083 } catch (Exception x) { 084 logger.error("timerTask.run: " + x, x); 085 } 086 } 087 }; 088 089 final Date nextRun; 090 if (onStart) { 091 nextRun = new Date(System.currentTimeMillis() + ON_START_TIMER_PERIOD); 092 logger.info("schedule: onStart=true nextRun={}", nextRun); 093 } 094 else { 095 nextRun = new Date(System.currentTimeMillis() + timerPeriod); 096 logger.info("schedule: timerPeriod={} nextRun={}", timerPeriod, nextRun); 097 } 098 timer.schedule(timerTask, nextRun); 099 } 100 101 protected synchronized void cancelTimerTask() { 102 if (timerTask != null) { 103 timerTask.cancel(); 104 timerTask = null; 105 } 106 } 107 108 protected synchronized void cancelTimer() { 109 if (timer != null) { 110 timer.cancel(); 111 timer = null; 112 } 113 } 114 115 protected long getTimerPeriod() { 116 final Config config = ConfigImpl.getInstance(); 117 return config.getPropertyAsLong(CONFIG_KEY_TIMER_PERIOD, DEFAULT_TIMER_PERIOD); 118 } 119 120 protected void run() { 121 final boolean updateNeeded = new CloudStoreUpdaterCore().createUpdaterDirIfUpdateNeeded(); 122 123 if (updateNeeded) 124 System.exit(0); 125 } 126}