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.