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}