• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject.servlet;
18 
19 import static com.google.inject.Asserts.assertContains;
20 import static com.google.inject.Asserts.reserialize;
21 import static com.google.inject.servlet.ServletTestUtils.newFakeHttpServletRequest;
22 import static com.google.inject.servlet.ServletTestUtils.newFakeHttpServletResponse;
23 import static java.lang.annotation.ElementType.FIELD;
24 import static java.lang.annotation.ElementType.METHOD;
25 import static java.lang.annotation.ElementType.PARAMETER;
26 import static java.lang.annotation.RetentionPolicy.RUNTIME;
27 
28 import com.google.common.collect.ImmutableMap;
29 import com.google.common.collect.Lists;
30 import com.google.inject.AbstractModule;
31 import com.google.inject.BindingAnnotation;
32 import com.google.inject.CreationException;
33 import com.google.inject.Guice;
34 import com.google.inject.Inject;
35 import com.google.inject.Injector;
36 import com.google.inject.Key;
37 import com.google.inject.Module;
38 import com.google.inject.Provider;
39 import com.google.inject.Provides;
40 import com.google.inject.ProvisionException;
41 import com.google.inject.internal.Errors;
42 import com.google.inject.name.Named;
43 import com.google.inject.name.Names;
44 import com.google.inject.servlet.ServletScopes.NullObject;
45 import com.google.inject.util.Providers;
46 
47 import junit.framework.TestCase;
48 
49 import java.io.IOException;
50 import java.io.Serializable;
51 import java.lang.annotation.Retention;
52 import java.lang.annotation.Target;
53 import java.util.Map;
54 
55 import javax.servlet.Filter;
56 import javax.servlet.FilterChain;
57 import javax.servlet.FilterConfig;
58 import javax.servlet.ServletException;
59 import javax.servlet.ServletRequest;
60 import javax.servlet.ServletResponse;
61 import javax.servlet.http.HttpServlet;
62 import javax.servlet.http.HttpServletRequest;
63 import javax.servlet.http.HttpServletRequestWrapper;
64 import javax.servlet.http.HttpServletResponse;
65 import javax.servlet.http.HttpServletResponseWrapper;
66 import javax.servlet.http.HttpSession;
67 
68 /**
69  * @author crazybob@google.com (Bob Lee)
70  */
71 public class ServletTest extends TestCase {
72   private static final Key<HttpServletRequest> HTTP_REQ_KEY = Key.get(HttpServletRequest.class);
73   private static final Key<HttpServletResponse> HTTP_RESP_KEY = Key.get(HttpServletResponse.class);
74   private static final Key<Map<String, String[]>> REQ_PARAMS_KEY
75       = new Key<Map<String, String[]>>(RequestParameters.class) {};
76 
77   private static final Key<InRequest> IN_REQUEST_NULL_KEY = Key.get(InRequest.class, Null.class);
78   private static final Key<InSession> IN_SESSION_KEY = Key.get(InSession.class);
79   private static final Key<InSession> IN_SESSION_NULL_KEY = Key.get(InSession.class, Null.class);
80 
81   @Override
setUp()82   public void setUp() {
83     //we need to clear the reference to the pipeline every test =(
84     GuiceFilter.reset();
85   }
86 
testScopeExceptions()87   public void testScopeExceptions() throws Exception {
88     Injector injector = Guice.createInjector(new AbstractModule() {
89       @Override protected void configure() {
90         install(new ServletModule());
91       }
92       @Provides @RequestScoped String provideString() { return "foo"; }
93       @Provides @SessionScoped Integer provideInteger() { return 1; }
94       @Provides @RequestScoped @Named("foo") String provideNamedString() { return "foo"; }
95     });
96 
97     try {
98       injector.getInstance(String.class);
99       fail();
100     } catch(ProvisionException oose) {
101       assertContains(oose.getMessage(), "Cannot access scoped [java.lang.String].");
102     }
103 
104     try {
105       injector.getInstance(Integer.class);
106       fail();
107     } catch(ProvisionException oose) {
108       assertContains(oose.getMessage(), "Cannot access scoped [java.lang.Integer].");
109     }
110 
111     Key<?> key = Key.get(String.class, Names.named("foo"));
112     try {
113       injector.getInstance(key);
114       fail();
115     } catch(ProvisionException oose) {
116       assertContains(oose.getMessage(), "Cannot access scoped [" + Errors.convert(key) + "]");
117     }
118   }
119 
testRequestAndResponseBindings()120   public void testRequestAndResponseBindings() throws Exception {
121     final Injector injector = createInjector();
122     final HttpServletRequest request = newFakeHttpServletRequest();
123     final HttpServletResponse response = newFakeHttpServletResponse();
124 
125     final boolean[] invoked = new boolean[1];
126     GuiceFilter filter = new GuiceFilter();
127     FilterChain filterChain = new FilterChain() {
128       public void doFilter(ServletRequest servletRequest,
129           ServletResponse servletResponse) {
130         invoked[0] = true;
131         assertSame(request, servletRequest);
132         assertSame(request, injector.getInstance(ServletRequest.class));
133         assertSame(request, injector.getInstance(HTTP_REQ_KEY));
134 
135         assertSame(response, servletResponse);
136         assertSame(response, injector.getInstance(ServletResponse.class));
137         assertSame(response, injector.getInstance(HTTP_RESP_KEY));
138 
139         assertSame(servletRequest.getParameterMap(), injector.getInstance(REQ_PARAMS_KEY));
140       }
141     };
142     filter.doFilter(request, response, filterChain);
143 
144     assertTrue(invoked[0]);
145   }
146 
testRequestAndResponseBindings_wrappingFilter()147   public void testRequestAndResponseBindings_wrappingFilter() throws Exception {
148     final HttpServletRequest request = newFakeHttpServletRequest();
149     final ImmutableMap<String, String[]> wrappedParamMap
150         = ImmutableMap.of("wrap", new String[]{"a", "b"});
151     final HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
152       @Override public Map getParameterMap() {
153         return wrappedParamMap;
154       }
155 
156       @Override public Object getAttribute(String attr) {
157         // Ensure that attributes are stored on the original request object.
158         throw new UnsupportedOperationException();
159       }
160     };
161     final HttpServletResponse response = newFakeHttpServletResponse();
162     final HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response);
163 
164     final boolean[] filterInvoked = new boolean[1];
165     final Injector injector = createInjector(new ServletModule() {
166       @Override protected void configureServlets() {
167         filter("/*").through(new Filter() {
168           @Inject Provider<ServletRequest> servletReqProvider;
169           @Inject Provider<HttpServletRequest> reqProvider;
170           @Inject Provider<ServletResponse> servletRespProvider;
171           @Inject Provider<HttpServletResponse> respProvider;
172 
173           public void init(FilterConfig filterConfig) {}
174 
175           public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
176               throws IOException, ServletException {
177             filterInvoked[0] = true;
178             assertSame(req, servletReqProvider.get());
179             assertSame(req, reqProvider.get());
180 
181             assertSame(resp, servletRespProvider.get());
182             assertSame(resp, respProvider.get());
183 
184             chain.doFilter(requestWrapper, responseWrapper);
185 
186             assertSame(req, reqProvider.get());
187             assertSame(resp, respProvider.get());
188           }
189 
190           public void destroy() {}
191         });
192       }
193     });
194 
195     GuiceFilter filter = new GuiceFilter();
196     final boolean[] chainInvoked = new boolean[1];
197     FilterChain filterChain = new FilterChain() {
198       public void doFilter(ServletRequest servletRequest,
199           ServletResponse servletResponse) {
200         chainInvoked[0] = true;
201         assertSame(requestWrapper, servletRequest);
202         assertSame(requestWrapper, injector.getInstance(ServletRequest.class));
203         assertSame(requestWrapper, injector.getInstance(HTTP_REQ_KEY));
204 
205         assertSame(responseWrapper, servletResponse);
206         assertSame(responseWrapper, injector.getInstance(ServletResponse.class));
207         assertSame(responseWrapper, injector.getInstance(HTTP_RESP_KEY));
208 
209         assertSame(servletRequest.getParameterMap(), injector.getInstance(REQ_PARAMS_KEY));
210 
211         InRequest inRequest = injector.getInstance(InRequest.class);
212         assertSame(inRequest, injector.getInstance(InRequest.class));
213       }
214     };
215     filter.doFilter(request, response, filterChain);
216 
217     assertTrue(chainInvoked[0]);
218     assertTrue(filterInvoked[0]);
219   }
220 
testRequestAndResponseBindings_matchesPassedParameters()221   public void testRequestAndResponseBindings_matchesPassedParameters() throws Exception {
222     final int[] filterInvoked = new int[1];
223     final boolean[] servletInvoked = new boolean[1];
224     createInjector(new ServletModule() {
225       @Override protected void configureServlets() {
226         final HttpServletRequest[] previousReq = new HttpServletRequest[1];
227         final HttpServletResponse[] previousResp = new HttpServletResponse[1];
228 
229         final Provider<ServletRequest> servletReqProvider = getProvider(ServletRequest.class);
230         final Provider<HttpServletRequest> reqProvider = getProvider(HttpServletRequest.class);
231         final Provider<ServletResponse> servletRespProvider = getProvider(ServletResponse.class);
232         final Provider<HttpServletResponse> respProvider = getProvider(HttpServletResponse.class);
233 
234         Filter filter = new Filter() {
235           public void init(FilterConfig filterConfig) {}
236 
237           public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
238               throws IOException, ServletException {
239             filterInvoked[0]++;
240             assertSame(req, servletReqProvider.get());
241             assertSame(req, reqProvider.get());
242             if (previousReq[0] != null) {
243               assertEquals(req, previousReq[0]);
244             }
245 
246             assertSame(resp, servletRespProvider.get());
247             assertSame(resp, respProvider.get());
248             if (previousResp[0] != null) {
249               assertEquals(resp, previousResp[0]);
250             }
251 
252             chain.doFilter(
253                 previousReq[0] = new HttpServletRequestWrapper((HttpServletRequest) req),
254                 previousResp[0] = new HttpServletResponseWrapper((HttpServletResponse) resp));
255 
256             assertSame(req, reqProvider.get());
257             assertSame(resp, respProvider.get());
258           }
259 
260           public void destroy() {}
261         };
262 
263         filter("/*").through(filter);
264         filter("/*").through(filter);  // filter twice to test wrapping in filters
265         serve("/*").with(new HttpServlet() {
266           @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
267             servletInvoked[0] = true;
268             assertSame(req, servletReqProvider.get());
269             assertSame(req, reqProvider.get());
270 
271             assertSame(resp, servletRespProvider.get());
272             assertSame(resp, respProvider.get());
273           }
274         });
275       }
276     });
277 
278     GuiceFilter filter = new GuiceFilter();
279     filter.doFilter(newFakeHttpServletRequest(), newFakeHttpServletResponse(), new FilterChain() {
280       public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) {
281         throw new IllegalStateException("Shouldn't get here");
282       }
283     });
284 
285     assertEquals(2, filterInvoked[0]);
286     assertTrue(servletInvoked[0]);
287   }
288 
testNewRequestObject()289   public void testNewRequestObject()
290       throws CreationException, IOException, ServletException {
291     final Injector injector = createInjector();
292     final HttpServletRequest request = newFakeHttpServletRequest();
293 
294     GuiceFilter filter = new GuiceFilter();
295     final boolean[] invoked = new boolean[1];
296     FilterChain filterChain = new FilterChain() {
297       public void doFilter(ServletRequest servletRequest,
298           ServletResponse servletResponse) {
299         invoked[0] = true;
300         assertNotNull(injector.getInstance(InRequest.class));
301         assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
302       }
303     };
304 
305     filter.doFilter(request, null, filterChain);
306 
307     assertTrue(invoked[0]);
308   }
309 
testExistingRequestObject()310   public void testExistingRequestObject()
311       throws CreationException, IOException, ServletException {
312     final Injector injector = createInjector();
313     final HttpServletRequest request = newFakeHttpServletRequest();
314 
315     GuiceFilter filter = new GuiceFilter();
316     final boolean[] invoked = new boolean[1];
317     FilterChain filterChain = new FilterChain() {
318       public void doFilter(ServletRequest servletRequest,
319           ServletResponse servletResponse) {
320         invoked[0] = true;
321 
322         InRequest inRequest = injector.getInstance(InRequest.class);
323         assertSame(inRequest, injector.getInstance(InRequest.class));
324 
325         assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
326         assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
327       }
328     };
329 
330     filter.doFilter(request, null, filterChain);
331 
332     assertTrue(invoked[0]);
333   }
334 
testNewSessionObject()335   public void testNewSessionObject()
336       throws CreationException, IOException, ServletException {
337     final Injector injector = createInjector();
338     final HttpServletRequest request = newFakeHttpServletRequest();
339 
340     GuiceFilter filter = new GuiceFilter();
341     final boolean[] invoked = new boolean[1];
342     FilterChain filterChain = new FilterChain() {
343       public void doFilter(ServletRequest servletRequest,
344           ServletResponse servletResponse) {
345         invoked[0] = true;
346         assertNotNull(injector.getInstance(InSession.class));
347         assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
348       }
349     };
350 
351     filter.doFilter(request, null, filterChain);
352 
353     assertTrue(invoked[0]);
354   }
355 
testExistingSessionObject()356   public void testExistingSessionObject()
357       throws CreationException, IOException, ServletException {
358     final Injector injector = createInjector();
359     final HttpServletRequest request = newFakeHttpServletRequest();
360 
361     GuiceFilter filter = new GuiceFilter();
362     final boolean[] invoked = new boolean[1];
363     FilterChain filterChain = new FilterChain() {
364       public void doFilter(ServletRequest servletRequest,
365           ServletResponse servletResponse) {
366         invoked[0] = true;
367 
368         InSession inSession = injector.getInstance(InSession.class);
369         assertSame(inSession, injector.getInstance(InSession.class));
370 
371         assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
372         assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
373       }
374     };
375 
376     filter.doFilter(request, null, filterChain);
377 
378     assertTrue(invoked[0]);
379   }
380 
testHttpSessionIsSerializable()381   public void testHttpSessionIsSerializable() throws Exception {
382     final Injector injector = createInjector();
383     final HttpServletRequest request = newFakeHttpServletRequest();
384     final HttpSession session = request.getSession();
385 
386     GuiceFilter filter = new GuiceFilter();
387     final boolean[] invoked = new boolean[1];
388     FilterChain filterChain = new FilterChain() {
389       public void doFilter(ServletRequest servletRequest,
390           ServletResponse servletResponse) {
391         invoked[0] = true;
392         assertNotNull(injector.getInstance(InSession.class));
393         assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
394       }
395     };
396 
397     filter.doFilter(request, null, filterChain);
398 
399     assertTrue(invoked[0]);
400 
401     HttpSession deserializedSession = reserialize(session);
402 
403     String inSessionKey = IN_SESSION_KEY.toString();
404     String inSessionNullKey = IN_SESSION_NULL_KEY.toString();
405     assertTrue(deserializedSession.getAttribute(inSessionKey) instanceof InSession);
406     assertEquals(NullObject.INSTANCE, deserializedSession.getAttribute(inSessionNullKey));
407   }
408 
testGuiceFilterConstructors()409   public void testGuiceFilterConstructors() throws Exception {
410     final RuntimeException servletException = new RuntimeException();
411     final RuntimeException chainException = new RuntimeException();
412     final Injector injector = createInjector(new ServletModule() {
413       @Override protected void configureServlets() {
414         serve("/*").with(new HttpServlet() {
415           @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
416             throw servletException;
417           }
418         });
419       }
420     });
421     final HttpServletRequest request = newFakeHttpServletRequest();
422     FilterChain filterChain = new FilterChain() {
423       public void doFilter(ServletRequest servletRequest,
424           ServletResponse servletResponse) {
425         throw chainException;
426       }
427     };
428 
429     try {
430       new GuiceFilter().doFilter(request, null, filterChain);
431       fail();
432     } catch (RuntimeException e) {
433       assertSame(servletException, e);
434     }
435     try {
436       injector.getInstance(GuiceFilter.class).doFilter(request, null, filterChain);
437       fail();
438     } catch (RuntimeException e) {
439       assertSame(servletException, e);
440     }
441     try {
442       injector.getInstance(Key.get(GuiceFilter.class, ScopingOnly.class))
443           .doFilter(request, null, filterChain);
444       fail();
445     } catch (RuntimeException e) {
446       assertSame(chainException, e);
447     }
448   }
449 
createInjector(Module... modules)450   private Injector createInjector(Module... modules) throws CreationException {
451     return Guice.createInjector(Lists.<Module>asList(new AbstractModule() {
452       @Override
453       protected void configure() {
454         install(new ServletModule());
455         bind(InSession.class);
456         bind(IN_SESSION_NULL_KEY).toProvider(Providers.<InSession>of(null)).in(SessionScoped.class);
457         bind(InRequest.class);
458         bind(IN_REQUEST_NULL_KEY).toProvider(Providers.<InRequest>of(null)).in(RequestScoped.class);
459       }
460     }, modules));
461   }
462 
463   @SessionScoped
464   static class InSession implements Serializable {}
465 
466   @RequestScoped
467   static class InRequest {}
468 
469   @BindingAnnotation @Retention(RUNTIME) @Target({PARAMETER, METHOD, FIELD})
470   @interface Null {}
471 }
472