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    }