001 package org.nakedobjects.applib.fixtures;
002
003 import java.util.ArrayList;
004 import java.util.Collections;
005 import java.util.List;
006
007 import org.nakedobjects.applib.AbstractContainedObject;
008 import org.nakedobjects.applib.clock.Clock;
009 import org.nakedobjects.applib.switchuser.SwitchUserService;
010 import org.nakedobjects.applib.switchuser.SwitchUserServiceAware;
011
012
013 /**
014 * Convenience class for creating fixtures.
015 *
016 * <p>
017 * Most subclasses will simply override {@link #install()} to setup objects. In addition though
018 * fixtures may also:
019 * <ul>
020 * <li>change the date/time within the course of fixture installation, using {@link #setDate(int, int, int)} and
021 * {@link #setTime(int, int)}.
022 * <li>change the current user using {@link #switchUser(String, String...)}.
023 * <li>create composite fixtures using {@link #addFixture(Object)}.
024 * <li>search for existing objects using {@link #firstMatch(Class, org.nakedobjects.applib.Filter)} or
025 * {@link #uniqueMatch(Class, org.nakedobjects.applib.Filter)} (and various overloads thereof).
026 * </ul>
027 *
028 * <p>
029 * To automatically logon for the demo/test, use
030 */
031 public abstract class AbstractFixture extends AbstractContainedObject implements InstallableFixture, CompositeFixture, SwitchUserServiceAware {
032
033 private final List<Object> fixtures = new ArrayList<Object>();
034
035 // is initialized in constructor
036 private FixtureClock clock = null;
037 private final FixtureType fixtureType;
038
039 /**
040 * Assumed to be {@link FixtureType#OBJECT_STORE data} fixture.
041 */
042 public AbstractFixture() {
043 this(FixtureType.OBJECT_STORE);
044 }
045
046 public AbstractFixture(final FixtureType fixtureType) {
047 this.fixtureType = fixtureType;
048 try {
049 clock = FixtureClock.initialize();
050 } catch(IllegalStateException ex) {
051 clock = null;
052 System.err.println(ex.getMessage());
053 System.err.println("calls to change date or time will be ignored");
054 }
055 }
056
057 /**
058 * As specified in constructor.
059 */
060 public FixtureType getType() {
061 return fixtureType;
062 }
063
064 /**
065 * Most subclasses will override this method, but composite fixtures
066 * should instead call {@link #addFixture(Object)} in their constructor.
067 */
068 public void install() {}
069
070 /**
071 * Allows the fixture to act as a composite (call within constructor).
072 */
073 protected void addFixture(final Object fixture) {
074 fixtures.add(fixture);
075 }
076
077 /**
078 * Returns an array of any fixtures that have been {@link #addFixture(Object) added}.
079 */
080 public List<Object> getFixtures() {
081 return Collections.unmodifiableList(fixtures);
082 }
083
084
085
086 // {{ Clock
087 /**
088 * The {@link Clock} singleton, downcast to {@link FixtureClock}.
089 *
090 * <p>
091 * Will return <tt>null</tt> if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
092 */
093 public FixtureClock getFixtureClock() {
094 return clock;
095 }
096
097 /**
098 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
099 */
100 public void earlierDate(final int years, final int months, final int days) {
101 if (clockNotSetup("earlierDate")) return;
102 clock.addDate(-years, -months, -days);
103 }
104
105 /**
106 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
107 */
108 public void earlierTime(final int hours, final int minutes) {
109 if (clockNotSetup("earlierDate")) return;
110 clock.addTime(-hours, -minutes);
111 }
112
113 /**
114 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
115 */
116 public void laterDate(final int years, final int months, final int days) {
117 if (clockNotSetup("laterDate")) return;
118 clock.addDate(years, months, days);
119 }
120
121 /**
122 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
123 */
124 public void laterTime(final int hours, final int minutes) {
125 if (clockNotSetup("laterTime")) return;
126 clock.addTime(hours, minutes);
127 }
128
129 /**
130 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
131 */
132 public void resetClock() {
133 if (clockNotSetup("laterTime")) return;
134 clock.reset();
135 }
136
137 /**
138 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
139 */
140 public void setDate(final int year, final int month, final int day) {
141 if (clockNotSetup("setDate")) return;
142 clock.setDate(year, month, day);
143 }
144
145 /**
146 * Will print warning message and do nothing if {@link FixtureClock} could not be {@link FixtureClock#initialize() initialized}.
147 */
148 public void setTime(final int hour, final int minute) {
149 if (clockNotSetup("setTime")) return;
150 clock.setTime(hour, minute);
151 }
152
153 private boolean clockNotSetup(String methodName) {
154 if (clock == null) {
155 System.err.println("clock not set, call to " + methodName + " ignored");
156 return true;
157 }
158 return false;
159 }
160 // }}
161
162
163 // {{ User
164 protected void switchUser(final String username, final String... roles) {
165 switchUserService.switchUser(username, roles);
166 }
167 // }}
168
169
170 // {{ Injected: SwitchUserService
171 private SwitchUserService switchUserService;
172 public void setService(final SwitchUserService fixtureService) {
173 this.switchUserService = fixtureService;
174 }
175 // }}
176
177 }