001    package com.mockrunner.mock.web;
002    
003    import org.apache.struts.Globals;
004    import org.apache.struts.action.ActionMapping;
005    
006    import com.mockrunner.struts.ActionMappingProxyGenerator;
007    
008    /**
009     * Used to create all types of struts mock objects. Maintains
010     * the necessary dependencies between the mock objects.
011     * If you use the mock objects returned by this
012     * factory in your tests you can be sure that they are all
013     * up to date.
014     */
015    public class ActionMockObjectFactory extends WebMockObjectFactory
016    {
017        private MockActionMapping mockMapping;
018        private ActionMapping mapping;
019        private MockActionServlet mockActionServlet;
020        private MockModuleConfig mockModuleConfig;
021        
022        /**
023         * Creates a new set of mock objects.
024         */
025        public ActionMockObjectFactory()
026        {
027            createMockObjects();
028        }
029        
030        /**
031         * Creates a set of mock objects based on another one.
032         * The created mock objects will have their own
033         * request and session objects, but they will share
034         * one <code>ServletContext</code>.
035         * @param factory the other factory
036         * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory)
037         */
038        public ActionMockObjectFactory(WebMockObjectFactory factory)
039        {
040            super(factory);
041            createMockObjects();
042        }
043        
044        /**
045         * Creates a set of mock objects based on another one.
046         * You can specify, if the created mock objects should
047         * share the same session. They will share one
048         * <code>ServletContext</code> anyway.
049         * @param factory the other factory
050         * @param createNewSession <code>true</code> creates a new session,
051         *                         <code>false</code> uses the session from factory
052         * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory, boolean)
053         */
054        public ActionMockObjectFactory(WebMockObjectFactory factory, boolean createNewSession)
055        {
056            super(factory, createNewSession);
057            createMockObjects();
058        }
059        
060        private void createMockObjects()
061        {
062            mockMapping = createMockActionMapping();
063            mapping = mockMapping;
064            mockModuleConfig = createMockModuleConfig();
065            mockActionServlet = createMockActionServlet();
066            mockActionServlet.setServletConfig(getMockServletConfig());
067            mockActionServlet.setServletContext(getMockServletContext());
068            refresh();
069        }
070    
071        /**
072         * Refreshes the mock objects dependencies. May be called after setting request
073         * and response wrappers.
074         */
075        public void refresh()
076        {
077            super.refresh();
078            getWrappedRequest().setAttribute(Globals.MAPPING_KEY, mapping);
079            getWrappedRequest().setAttribute(Globals.MODULE_KEY, mockModuleConfig);
080        }
081        
082        /**
083         * Creates the {@link com.mockrunner.mock.web.MockActionServlet} using <code>new</code>.
084         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockActionServlet}.
085         * @return the {@link com.mockrunner.mock.web.MockActionServlet}
086         */
087        public MockActionServlet createMockActionServlet()
088        {
089            return new MockActionServlet();
090        }
091    
092        /**
093         * Creates the {@link com.mockrunner.mock.web.MockModuleConfig} using <code>new</code>.
094         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockModuleConfig}.
095         * @return the {@link com.mockrunner.mock.web.MockModuleConfig}
096         */
097        public MockModuleConfig createMockModuleConfig()
098        {
099            return new MockModuleConfig("testmodule");
100        }
101    
102        /**
103         * Creates the {@link com.mockrunner.mock.web.MockActionMapping} using <code>new</code>.
104         * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockActionMapping}.
105         * @return the {@link com.mockrunner.mock.web.MockActionMapping}
106         */
107        public MockActionMapping createMockActionMapping()
108        {
109            return new MockActionMapping();
110        }
111        
112        /**
113         * Prepares an <code>ActionMapping</code>. If your actions rely
114         * on a custom subclass of <code>ActionMapping</code>, use this
115         * method to prepare it. Since {@link com.mockrunner.struts.ActionTestModule}
116         * relies on the behaviour of {@link com.mockrunner.mock.web.MockActionMapping},
117         * this method creates a subclass CGLib proxy of the specified mapping class.
118         * You can cast the returned <code>ActionMapping</code> to your custom
119         * mapping class and the subclass proxy will redirect the necessary
120         * methods to the {@link com.mockrunner.mock.web.MockActionMapping}.
121         * Redirected are methods for retrieving forwards. If an <code>ActionMapping</code>
122         * is prepared, {@link #getActionMapping} returns the prepared mapping while
123         * {@link #getMockActionMapping} returns the the underlying {@link com.mockrunner.mock.web.MockActionMapping}.
124         * This method relies on CGLib. CGLib is not required by the Struts test framework
125         * if this method is not used.
126         * @param mappingClass the class of the custom action mapping
127         * @return an instance of the custom action mapping class
128         */
129        public ActionMapping prepareActionMapping(Class mappingClass)
130        {
131            ActionMappingProxyGenerator generator = new ActionMappingProxyGenerator(mockMapping);
132            mapping = generator.createActionMappingProxy(mappingClass);
133            refresh();
134            return mapping;
135        }
136        
137        /**
138         * Resets <code>ActionMapping</code> configuration, i.e. sets
139         * the current <code>ActionMapping</code> returned by {@link #getActionMapping}
140         * to the mock action mapping returned by {@link #getMockActionMapping}.
141         */
142        public void resetActionMapping()
143        {
144            mapping = mockMapping;
145        }
146        
147        /**
148         * Returns the <code>ActionMapping</code>. Unless you prepare an
149         * <code>ActionMapping</code> using {@link #prepareActionMapping},
150         * this method returns the same object as {@link #getMockActionMapping}.
151         * If an <code>ActionMapping</code> is prepared, this method returns
152         * the prepared <code>ActionMapping</code> while {@link #getMockActionMapping}
153         * returns the underlying {@link com.mockrunner.mock.web.MockActionMapping}.
154         * @return the <code>ActionMapping</code>
155         */
156        public ActionMapping getActionMapping()
157        {
158            return mapping;
159        }
160        
161        /**
162         * Returns the {@link com.mockrunner.mock.web.MockActionMapping}.
163         * @return the {@link com.mockrunner.mock.web.MockActionMapping}
164         */
165        public MockActionMapping getMockActionMapping()
166        {
167            return mockMapping;
168        }
169        
170        /**
171         * Returns the {@link com.mockrunner.mock.web.MockModuleConfig}.
172         * @return the {@link com.mockrunner.mock.web.MockModuleConfig}
173         */
174        public MockModuleConfig getMockModuleConfig()
175        {
176            return mockModuleConfig;
177        }
178        
179        /**
180         * Returns the {@link com.mockrunner.mock.web.MockActionServlet}.
181         * @return the {@link com.mockrunner.mock.web.MockActionServlet}
182         */
183        public MockActionServlet getMockActionServlet()
184        {
185            return mockActionServlet;
186        }
187    }