1 /*
2  * Copyright (C) 2009 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 package com.google.inject.servlet;
17 
18 import static com.google.inject.servlet.ServletScopes.REQUEST;
19 import static com.google.inject.servlet.ServletScopes.SESSION;
20 
21 import com.google.inject.AbstractModule;
22 import com.google.inject.Inject;
23 import com.google.inject.Key;
24 import com.google.inject.Provider;
25 import com.google.inject.Provides;
26 import com.google.inject.Singleton;
27 import java.util.Map;
28 import java.util.logging.Logger;
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletRequest;
31 import javax.servlet.ServletResponse;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34 import javax.servlet.http.HttpSession;
35 
36 /**
37  * This is a left-factoring of all ServletModules installed in the system. In other words, this
38  * module contains the bindings common to all ServletModules, and is bound exactly once per
39  * injector.
40  *
41  * @author dhanji@gmail.com (Dhanji R. Prasanna)
42  */
43 final class InternalServletModule extends AbstractModule {
44 
45   /**
46    * Special Provider that tries to obtain an injected servlet context, specific to the current
47    * injector, failing which, it falls back to the static singleton instance that is available in
48    * the legacy Guice Servlet.
49    */
50   @Singleton
51   static class BackwardsCompatibleServletContextProvider implements Provider<ServletContext> {
52     private ServletContext injectedServletContext;
53 
54     @Inject
BackwardsCompatibleServletContextProvider()55     BackwardsCompatibleServletContextProvider() {}
56 
57     // This setter is called by the GuiceServletContextListener
set(ServletContext injectedServletContext)58     void set(ServletContext injectedServletContext) {
59       this.injectedServletContext = injectedServletContext;
60     }
61 
62     @Override
get()63     public ServletContext get() {
64       if (null != injectedServletContext) {
65         return injectedServletContext;
66       }
67 
68       Logger.getLogger(InternalServletModule.class.getName())
69           .warning(
70               "You are attempting to use a deprecated API (specifically,"
71                   + " attempting to @Inject ServletContext inside an eagerly created"
72                   + " singleton. While we allow this for backwards compatibility, be"
73                   + " warned that this MAY have unexpected behavior if you have more"
74                   + " than one injector (with ServletModule) running in the same JVM."
75                   + " Please consult the Guice documentation at"
76                   + " https://github.com/google/guice/wiki/Servlets for more"
77                   + " information.");
78       return GuiceFilter.getServletContext();
79     }
80   }
81 
82   @Override
configure()83   protected void configure() {
84     bindScope(RequestScoped.class, REQUEST);
85     bindScope(SessionScoped.class, SESSION);
86     bind(ServletRequest.class).to(HttpServletRequest.class);
87     bind(ServletResponse.class).to(HttpServletResponse.class);
88 
89     // inject the pipeline into GuiceFilter so it can route requests correctly
90     // Unfortunate staticness... =(
91     // NOTE(dhanji): This is maintained for legacy purposes.
92     requestStaticInjection(GuiceFilter.class);
93 
94     bind(ManagedFilterPipeline.class);
95     bind(ManagedServletPipeline.class);
96     bind(FilterPipeline.class).to(ManagedFilterPipeline.class).asEagerSingleton();
97 
98     bind(ServletContext.class).toProvider(BackwardsCompatibleServletContextProvider.class);
99     bind(BackwardsCompatibleServletContextProvider.class);
100   }
101 
102   @Provides
103   @Singleton
104   @ScopingOnly
provideScopingOnlyGuiceFilter()105   GuiceFilter provideScopingOnlyGuiceFilter() {
106     return new GuiceFilter(new DefaultFilterPipeline());
107   }
108 
109   @Provides
110   @RequestScoped
provideHttpServletRequest()111   HttpServletRequest provideHttpServletRequest() {
112     return GuiceFilter.getRequest(Key.get(HttpServletRequest.class));
113   }
114 
115   @Provides
116   @RequestScoped
provideHttpServletResponse()117   HttpServletResponse provideHttpServletResponse() {
118     return GuiceFilter.getResponse(Key.get(HttpServletResponse.class));
119   }
120 
121   @Provides
provideHttpSession()122   HttpSession provideHttpSession() {
123     return GuiceFilter.getRequest(Key.get(HttpSession.class)).getSession();
124   }
125 
126   @SuppressWarnings("unchecked") // defined by getParameterMap()
127   @Provides
128   @RequestScoped
129   @RequestParameters
provideRequestParameters(ServletRequest req)130   Map<String, String[]> provideRequestParameters(ServletRequest req) {
131     return req.getParameterMap();
132   }
133 
134   @Override
equals(Object o)135   public boolean equals(Object o) {
136     // Is only ever installed internally, so we don't need to check state.
137     return o instanceof InternalServletModule;
138   }
139 
140   @Override
hashCode()141   public int hashCode() {
142     return InternalServletModule.class.hashCode();
143   }
144 }
145