001    package com.mockrunner.mock.web;
002    
003    import java.lang.reflect.Constructor;
004    
005    import javax.servlet.http.HttpServletRequest;
006    import javax.servlet.http.HttpServletResponse;
007    
008    import com.mockrunner.base.NestedApplicationException;
009    
010    /**
011     * Used to create all types of web mock objects. Maintains
012     * the necessary dependencies between the mock objects.
013     * If you use the mock objects returned by this
014     * factory in your tests you can be sure, they are all
015     * up to date.
016     */
017    public class WebMockObjectFactory
018    {
019        private HttpServletRequest wrappedRequest;
020        private HttpServletResponse wrappedResponse;
021        private MockHttpServletRequest request;
022        private MockHttpServletResponse response;
023        private MockServletConfig config;
024        private MockServletContext context;
025        private MockHttpSession session;
026        private MockPageContext pageContext;
027        private MockFilterConfig filterConfig;
028        private MockFilterChain filterChain;
029    
030        /**
031         * Creates a new set of mock objects.
032         */
033        public WebMockObjectFactory()
034        {
035            createMockObjects();
036        }
037        
038        /**
039         * Creates a set of mock objects based on another one.
040         * The created mock objects will have their own
041         * request and session objects, but they will share
042         * one <code>ServletContext</code>.
043         * @param factory the other factory
044         * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory)
045         */
046        public WebMockObjectFactory(WebMockObjectFactory factory)
047        {
048            createMockObjectsBasedOn(factory);
049        }
050        
051        /**
052         * Creates a set of mock objects based on another one.
053         * You can specify, if the created mock objects should
054         * share the same session. They will share one
055         * <code>ServletContext</code> anyway.
056         * @param factory the other factory
057         * @param createNewSession <code>true</code> creates a new session,
058         *                         <code>false</code> uses the session from factory
059         * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory, boolean)
060         */
061        public WebMockObjectFactory(WebMockObjectFactory factory, boolean createNewSession)
062        {
063            createMockObjectsBasedOn(factory, createNewSession);
064        }
065     
066        private void createMockObjects()
067        {
068            createNewMockObjects(true);
069            config = new MockServletConfig();
070            context = new MockServletContext();
071            setUpDependencies();
072        }
073    
074        private void createMockObjectsBasedOn(WebMockObjectFactory factory)
075        {
076            createMockObjectsBasedOn(factory, true);
077        }
078        
079        private void createMockObjectsBasedOn(WebMockObjectFactory factory, boolean createNewSession)
080        {
081            createNewMockObjects(createNewSession);
082            if(!createNewSession) session = factory.getMockSession();
083            config = factory.getMockServletConfig();
084            context = factory.getMockServletContext();
085            setUpDependencies();
086        }
087    
088        private void createNewMockObjects(boolean createNewSession)
089        {
090            request = new MockHttpServletRequest();
091            response = new MockHttpServletResponse();
092            wrappedRequest = request;
093            wrappedResponse = response;
094            if(createNewSession) session = new MockHttpSession();
095            filterChain = new MockFilterChain();
096            filterConfig = new MockFilterConfig();
097        }
098    
099        private void setUpDependencies()
100        {
101            config.setServletContext(context);
102            request.setSession(session);
103            session.setupServletContext(context);
104            pageContext = new MockPageContext(config, request, response);
105            filterConfig.setupServletContext(context);
106        }
107        
108        /**
109         * Refreshes the mock objects dependencies. May be called after setting request
110         * and response wrappers.
111         */
112        public void refresh()
113        {
114            pageContext = new MockPageContext(config, wrappedRequest, wrappedResponse);
115        }
116        
117        /**
118         * Returns the <code>MockServletConfig</code>
119         * @return the <code>MockServletConfig</code>
120         */
121        public MockServletConfig getMockServletConfig()
122        {
123            return config;
124        }
125    
126        /**
127         * Returns the {@link com.mockrunner.mock.web.MockServletContext}.
128         * @return the {@link com.mockrunner.mock.web.MockServletContext}
129         */
130        public MockServletContext getMockServletContext()
131        {
132            return context;
133        }
134    
135        /**
136         * Returns the {@link com.mockrunner.mock.web.MockHttpServletRequest}.
137         * @return the {@link com.mockrunner.mock.web.MockHttpServletRequest}
138         */
139        public MockHttpServletRequest getMockRequest()
140        {
141            return request;
142        }
143    
144        /**
145         * Returns the {@link com.mockrunner.mock.web.MockHttpServletResponse}.
146         * @return the {@link com.mockrunner.mock.web.MockHttpServletResponse}
147         */
148        public MockHttpServletResponse getMockResponse()
149        {
150            return response;
151        }
152        
153        /**
154         * Returns the wrapped <code>HttpServletRequest</code>. If no
155         * wrapper is specified, this method returns the mock request itself.
156         * @return the wrapped <code>HttpServletRequest</code>
157         */
158        public HttpServletRequest getWrappedRequest()
159        {
160            return wrappedRequest;
161        }
162    
163        /**
164         * Returns the wrapped <code>HttpServletResponse</code>. If no
165         * wrapper is specified, this method returns the mock response itself.
166         * @return the wrapped <code>HttpServletRequest</code>
167         */
168        public HttpServletResponse getWrappedResponse()
169        {
170            return wrappedResponse;
171        }
172    
173        /**
174         * Returns the {@link com.mockrunner.mock.web.MockHttpSession}.
175         * @return the {@link com.mockrunner.mock.web.MockHttpSession}
176         */
177        public MockHttpSession getMockSession()
178        {
179            return session;
180        }
181    
182        /**
183         * Returns the {@link com.mockrunner.mock.web.MockHttpSession}.
184         * @return the {@link com.mockrunner.mock.web.MockHttpSession}
185         * @deprecated use {@link #getMockSession}
186         */
187        public MockHttpSession getSession()
188        {
189            return getMockSession();
190        }
191    
192        /**
193         * Returns the {@link com.mockrunner.mock.web.MockPageContext}.
194         * @return the {@link com.mockrunner.mock.web.MockPageContext}
195         */
196        public MockPageContext getMockPageContext()
197        {
198            return pageContext;
199        }
200        
201        /**
202         * Returns the {@link com.mockrunner.mock.web.MockFilterConfig}.
203         * @return the {@link com.mockrunner.mock.web.MockFilterConfig}
204         */
205        public MockFilterConfig getMockFilterConfig()
206        {
207            return filterConfig;
208        }
209    
210        /**
211         * Returns the {@link com.mockrunner.mock.web.MockFilterChain}.
212         * @return the {@link com.mockrunner.mock.web.MockFilterChain}
213         */
214        public MockFilterChain getMockFilterChain()
215        {
216            return filterChain;
217        }
218     
219        /**
220         * Can be used to add a request wrapper. All the
221         * test modules are using the wrapped request returned by
222         * {@link #getWrappedRequest}. The method {@link #getMockRequest}
223         * returns the mock request without any wrapper.
224         * Usually the wrapper is of type <code>javax.servlet.http.HttpServletRequestWrapper</code>.
225         * That's not absolutely necessary but the wrapper must define a constructor
226         * that takes a single <code>javax.servlet.http.HttpServletRequest</code> argument
227         * and must implement <code>javax.servlet.http.HttpServletRequest</code>.
228         * @param wrapper the wrapper class
229         */
230        public void addRequestWrapper(Class wrapper)
231        {
232            try
233            {
234                Constructor constructor = wrapper.getConstructor(new Class[] {HttpServletRequest.class});
235                wrappedRequest = (HttpServletRequest)constructor.newInstance(new Object[] {wrappedRequest});
236            }
237            catch(Exception exc)
238            {
239                throw new NestedApplicationException(exc);
240            }
241        }
242        
243        /**
244         * Can be used to add a request wrapper. 
245         * All the test modules are using the wrapped request returned by
246         * {@link #getWrappedRequest}. The method {@link #getMockRequest}
247         * returns the mock request without any wrapper. Usually the wrapper is
248         * an instance of <code>javax.servlet.http.HttpServletRequestWrapper</code>
249         * and wraps the current request but that's not absolutely necessary. 
250         * However, be careful if you want to add custom mock versions of 
251         * <code>javax.servlet.http.HttpServletRequest</code>.
252         * @param wrapper the request wrapper
253         */
254        public void addRequestWrapper(HttpServletRequest wrapper)
255        {
256            wrappedRequest = wrapper;
257        }
258        
259        /**
260         * Can be used to add a response wrapper. All the
261         * test modules are using the wrapped response returned by
262         * {@link #getWrappedResponse}. The method {@link #getMockResponse}
263         * returns the mock response without any wrapper.
264         * Usually the wrapper is of type <code>javax.servlet.http.HttpServletResponseWrapper</code>.
265         * That's not absolutely necessary but the wrapper must define a constructor
266         * that takes a single <code>javax.servlet.http.HttpServletResponse</code> argument
267         * and must implement <code>javax.servlet.http.HttpServletResponse</code>.
268         * @param wrapper the wrapper class
269         */
270        public void addResponseWrapper(Class wrapper)
271        {
272            try
273            {
274                Constructor constructor = wrapper.getConstructor(new Class[] {HttpServletResponse.class});
275                wrappedResponse = (HttpServletResponse)constructor.newInstance(new Object[] {wrappedResponse});
276            }
277            catch(Exception exc)
278            {
279                throw new NestedApplicationException(exc);
280            }
281        }
282        
283        /**
284         * Can be used to add a response wrapper. 
285         * All the test modules are using the wrapped response returned by
286         * {@link #getWrappedResponse}. The method {@link #getMockResponse}
287         * returns the mock response without any wrapper. Usually the wrapper is
288         * an instance of <code>javax.servlet.http.HttpServletResponseWrapper</code>
289         * and wraps the current response but that's not absolutely necessary. 
290         * However, be careful if you want to add custom mock versions of 
291         * <code>javax.servlet.http.HttpServletResponse</code>.
292         * @param wrapper the wrapper
293         */
294        public void addResponseWrapper(HttpServletResponse wrapper)
295        {
296            wrappedResponse = wrapper;
297        }
298    }