001    package org.nakedobjects.applib.clock;
002    
003    import java.util.Calendar;
004    
005    import org.nakedobjects.applib.ApplicationException;
006    import org.nakedobjects.applib.fixtures.FixtureClock;
007    
008    
009    /**
010     * Provides a mechanism to get (and possible to set) the current time.
011     * 
012     * <p>
013     * The clock is used primarily by the temporal value classes, and is accessed by the NOF as a singleton. The
014     * actual implementation used can be configured at startup, but once specified the clock instance cannot be
015     * changed.
016     * 
017     * <p>
018     * Unless another {@link Clock} implementation has been installed, the first call to {@link #getInstance()}
019     * will instantiate an implementation that just uses the system's own clock. Alternate implementations can be 
020     * created via suitable subclasses, but this must be done <b><i>before</i></b> the first call to {@link #getInstance()}.
021     * See for example {@link FixtureClock#getInstance()}.
022     */
023    public abstract class Clock {
024        private static Clock instance;
025        private static boolean isReplaceable = true;
026    
027        /**
028         * Returns the (singleton) instance of {@link Clock}.
029         * 
030         * <p>
031         * Unless it has been otherwise created, will lazily instantiate an
032         * implementation that just delegate to the computer's own system clock
033         * (as per {@link System#currentTimeMillis()}.
034         * 
035         * @return
036         */
037        public final static Clock getInstance() {
038            if (!isInitialized()) {
039                instance = new SystemClock();
040                isReplaceable = false;
041            }
042            return instance;
043        }
044    
045        /**
046         * Whether has been initialized or not.
047         */
048            public static boolean isInitialized() {
049                    return instance != null;
050            }
051    
052        public static long getTime() {
053            return getInstance().time();
054        }
055    
056        public static Calendar getTimeAsCalendar() {
057            return getInstance().timeAsCalendar();
058        }
059    
060            private static void ensureReplaceable() {
061                    if (!isReplaceable && instance != null) {
062                throw new ApplicationException("Clock already set up");
063            }
064            }
065    
066            /**
067             * Allows subclasses to remove their implementation.
068             * 
069             * @return whether a clock was removed.
070             */
071        protected static boolean remove()  {
072            ensureReplaceable();
073            if(instance == null) {
074                    return false;
075            }
076            instance = null;
077            return true;
078        }
079    
080        protected Clock() {
081            ensureReplaceable();
082            instance = this;
083        }
084    
085            public final Calendar timeAsCalendar() {
086                    Calendar cal = Calendar.getInstance();
087            cal.setTimeInMillis(Clock.getTime());
088                    return cal;
089            }
090    
091        /**
092         * The current time since midnight, January 1, 1970 UTC.
093         * 
094         * <p>
095         * Measured in milliseconds, modeled after (and possibly implemented by)
096         * {@link System#currentTimeMillis()}.
097         */
098        protected abstract long time();
099    
100    
101    }
102    
103    final class SystemClock extends Clock {
104        @Override
105        protected long time() {
106            return System.currentTimeMillis();
107        }
108    }
109    // Copyright (c) Naked Objects Group Ltd.