• 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