• 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.common.base.Preconditions.checkState;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.inject.AbstractModule;
23 import com.google.inject.Key;
24 import java.util.Map;
25 import javax.servlet.Filter;
26 import javax.servlet.ServletContext;
27 import javax.servlet.http.HttpServlet;
28 
29 /**
30  * Configures the servlet scopes and creates bindings for the servlet API objects so you can inject
31  * the request, response, session, etc.
32  *
33  * <p>You should subclass this module to register servlets and filters in the {@link
34  * #configureServlets()} method.
35  *
36  * @author crazybob@google.com (Bob Lee)
37  * @author dhanji@gmail.com (Dhanji R. Prasanna)
38  */
39 public class ServletModule extends AbstractModule {
40 
41   @Override
configure()42   protected final void configure() {
43     checkState(filtersModuleBuilder == null, "Re-entry is not allowed.");
44     checkState(servletsModuleBuilder == null, "Re-entry is not allowed.");
45     filtersModuleBuilder = new FiltersModuleBuilder(binder());
46     servletsModuleBuilder = new ServletsModuleBuilder(binder());
47     try {
48       // Install common bindings (skipped if already installed).
49       install(new InternalServletModule());
50 
51       // Install local filter and servlet bindings.
52       configureServlets();
53     } finally {
54       filtersModuleBuilder = null;
55       servletsModuleBuilder = null;
56     }
57   }
58 
59   /**
60    *
61    *
62    * <h3>Servlet Mapping EDSL</h3>
63    *
64    * <p>Part of the EDSL builder language for configuring servlets and filters with guice-servlet.
65    * Think of this as an in-code replacement for web.xml. Filters and servlets are configured here
66    * using simple java method calls. Here is a typical example of registering a filter when creating
67    * your Guice injector:
68    *
69    * <pre>
70    *   Guice.createInjector(..., new ServletModule() {
71    *
72    *     {@literal @}Override
73    *     protected void configureServlets() {
74    *       <b>serve("*.html").with(MyServlet.class)</b>
75    *     }
76    *   }
77    * </pre>
78    *
79    * This registers a servlet (subclass of {@code HttpServlet}) called {@code MyServlet} to service
80    * any web pages ending in {@code .html}. You can also use a path-style syntax to register
81    * servlets:
82    *
83    * <pre>
84    *       <b>serve("/my/*").with(MyServlet.class)</b>
85    * </pre>
86    *
87    * Every servlet (or filter) is required to be a singleton. If you cannot annotate the class
88    * directly, you should add a separate {@code bind(..).in(Singleton.class)} rule elsewhere in your
89    * module. Mapping a servlet that is bound under any other scope is an error.
90    *
91    * <p>
92    *
93    * <h4>Dispatch Order</h4>
94    *
95    * You are free to register as many servlets and filters as you like this way. They will be
96    * compared and dispatched in the order in which the filter methods are called:
97    *
98    * <pre>
99    *
100    *   Guice.createInjector(..., new ServletModule() {
101    *
102    *     {@literal @}Override
103    *     protected void configureServlets() {
104    *       filter("/*").through(MyFilter.class);
105    *       filter("*.css").through(MyCssFilter.class);
106    *       filter("*.jpg").through(new MyJpgFilter());
107    *       // etc..
108    *
109    *       serve("*.html").with(MyServlet.class);
110    *       serve("/my/*").with(MyServlet.class);
111    *       serve("*.jpg").with(new MyServlet());
112    *       // etc..
113    *      }
114    *    }
115    * </pre>
116    *
117    * This will traverse down the list of rules in lexical order. For example, a url "{@code
118    * /my/file.js}" (after it runs through the matching filters) will first be compared against the
119    * servlet mapping:
120    *
121    * <pre>
122    *       serve("*.html").with(MyServlet.class);
123    * </pre>
124    *
125    * And failing that, it will descend to the next servlet mapping:
126    *
127    * <pre>
128    *       serve("/my/*").with(MyServlet.class);
129    * </pre>
130    *
131    * Since this rule matches, Guice Servlet will dispatch to {@code MyServlet}. These two mapping
132    * rules can also be written in more compact form using varargs syntax:
133    *
134    * <pre>
135    *       serve(<b>"*.html", "/my/*"</b>).with(MyServlet.class);
136    * </pre>
137    *
138    * This way you can map several URI patterns to the same servlet. A similar syntax is also
139    * available for filter mappings.
140    *
141    * <p>
142    *
143    * <h4>Regular Expressions</h4>
144    *
145    * You can also map servlets (or filters) to URIs using regular expressions:
146    *
147    * <pre>
148    *    <b>serveRegex("(.)*ajax(.)*").with(MyAjaxServlet.class)</b>
149    * </pre>
150    *
151    * This will map any URI containing the text "ajax" in it to {@code MyAjaxServlet}. Such as:
152    *
153    * <ul>
154    * <li>http://www.google.com/ajax.html
155    * <li>http://www.google.com/content/ajax/index
156    * <li>http://www.google.com/it/is_totally_ajaxian
157    * </ul>
158    *
159    * <h3>Initialization Parameters</h3>
160    *
161    * Servlets (and filters) allow you to pass in init params using the {@code <init-param>} tag in
162    * web.xml. You can similarly pass in parameters to Servlets and filters registered in
163    * Guice-servlet using a {@link java.util.Map} of parameter name/value pairs. For example, to
164    * initialize {@code MyServlet} with two parameters ({@code name="Dhanji", site="google.com"}) you
165    * could write:
166    *
167    * <pre>
168    *  Map&lt;String, String&gt; params = new HashMap&lt;String, String&gt;();
169    *  params.put("name", "Dhanji");
170    *  params.put("site", "google.com");
171    *
172    *  ...
173    *      serve("/*").with(MyServlet.class, <b>params</b>)
174    * </pre>
175    *
176    * <p>
177    *
178    * <h3>Binding Keys</h3>
179    *
180    * You can also bind keys rather than classes. This lets you hide implementations with
181    * package-local visbility and expose them using only a Guice module and an annotation:
182    *
183    * <pre>
184    *  ...
185    *      filter("/*").through(<b>Key.get(Filter.class, Fave.class)</b>);
186    * </pre>
187    *
188    * Where {@code Filter.class} refers to the Servlet API interface and {@code Fave.class} is a
189    * custom binding annotation. Elsewhere (in one of your own modules) you can bind this filter's
190    * implementation:
191    *
192    * <pre>
193    *   bind(Filter.class)<b>.annotatedWith(Fave.class)</b>.to(MyFilterImpl.class);
194    * </pre>
195    *
196    * See {@link com.google.inject.Binder} for more information on binding syntax.
197    *
198    * <p>
199    *
200    * <h3>Multiple Modules</h3>
201    *
202    * It is sometimes useful to capture servlet and filter mappings from multiple different modules.
203    * This is essential if you want to package and offer drop-in Guice plugins that provide servlet
204    * functionality.
205    *
206    * <p>Guice Servlet allows you to register several instances of {@code ServletModule} to your
207    * injector. The order in which these modules are installed determines the dispatch order of
208    * filters and the precedence order of servlets. For example, if you had two servlet modules,
209    * {@code RpcModule} and {@code WebServiceModule} and they each contained a filter that mapped to
210    * the same URI pattern, {@code "/*"}:
211    *
212    * <p>In {@code RpcModule}:
213    *
214    * <pre>
215    *     filter("/*").through(RpcFilter.class);
216    * </pre>
217    *
218    * In {@code WebServiceModule}:
219    *
220    * <pre>
221    *     filter("/*").through(WebServiceFilter.class);
222    * </pre>
223    *
224    * Then the order in which these filters are dispatched is determined by the order in which the
225    * modules are installed:
226    *
227    * <pre>
228    *   <b>install(new WebServiceModule());</b>
229    *   install(new RpcModule());
230    * </pre>
231    *
232    * In the case shown above {@code WebServiceFilter} will run first.
233    *
234    * @since 2.0
235    */
configureServlets()236   protected void configureServlets() {}
237 
238   private FiltersModuleBuilder filtersModuleBuilder;
239   private ServletsModuleBuilder servletsModuleBuilder;
240 
getFiltersModuleBuilder()241   private FiltersModuleBuilder getFiltersModuleBuilder() {
242     checkState(
243         filtersModuleBuilder != null, "This method can only be used inside configureServlets()");
244     return filtersModuleBuilder;
245   }
246 
getServletModuleBuilder()247   private ServletsModuleBuilder getServletModuleBuilder() {
248     checkState(
249         servletsModuleBuilder != null, "This method can only be used inside configureServlets()");
250     return servletsModuleBuilder;
251   }
252 
253   /**
254    * @param urlPattern Any Servlet-style pattern. examples: /*, /html/*, *.html, etc.
255    * @since 2.0
256    */
filter(String urlPattern, String... morePatterns)257   protected final FilterKeyBindingBuilder filter(String urlPattern, String... morePatterns) {
258     return getFiltersModuleBuilder()
259         .filter(ImmutableList.<String>builder().add(urlPattern).add(morePatterns).build());
260   }
261 
262   /**
263    * @param urlPatterns Any Servlet-style patterns. examples: /*, /html/*, *.html, etc.
264    * @since 4.1
265    */
filter(Iterable<String> urlPatterns)266   protected final FilterKeyBindingBuilder filter(Iterable<String> urlPatterns) {
267     return getFiltersModuleBuilder().filter(ImmutableList.copyOf(urlPatterns));
268   }
269 
270   /**
271    * @param regex Any Java-style regular expression.
272    * @since 2.0
273    */
filterRegex(String regex, String... regexes)274   protected final FilterKeyBindingBuilder filterRegex(String regex, String... regexes) {
275     return getFiltersModuleBuilder()
276         .filterRegex(ImmutableList.<String>builder().add(regex).add(regexes).build());
277   }
278 
279   /**
280    * @param regexes Any Java-style regular expressions.
281    * @since 4.1
282    */
filterRegex(Iterable<String> regexes)283   protected final FilterKeyBindingBuilder filterRegex(Iterable<String> regexes) {
284     return getFiltersModuleBuilder().filterRegex(ImmutableList.copyOf(regexes));
285   }
286 
287   /**
288    * @param urlPattern Any Servlet-style pattern. examples: /*, /html/*, *.html, etc.
289    * @since 2.0
290    */
serve(String urlPattern, String... morePatterns)291   protected final ServletKeyBindingBuilder serve(String urlPattern, String... morePatterns) {
292     return getServletModuleBuilder()
293         .serve(ImmutableList.<String>builder().add(urlPattern).add(morePatterns).build());
294   }
295 
296   /**
297    * @param urlPatterns Any Servlet-style patterns. examples: /*, /html/*, *.html, etc.
298    * @since 4.1
299    */
serve(Iterable<String> urlPatterns)300   protected final ServletKeyBindingBuilder serve(Iterable<String> urlPatterns) {
301     return getServletModuleBuilder().serve(ImmutableList.copyOf(urlPatterns));
302   }
303 
304   /**
305    * @param regex Any Java-style regular expression.
306    * @since 2.0
307    */
serveRegex(String regex, String... regexes)308   protected final ServletKeyBindingBuilder serveRegex(String regex, String... regexes) {
309     return getServletModuleBuilder()
310         .serveRegex(ImmutableList.<String>builder().add(regex).add(regexes).build());
311   }
312 
313   /**
314    * @param regexes Any Java-style regular expressions.
315    * @since 4.1
316    */
serveRegex(Iterable<String> regexes)317   protected final ServletKeyBindingBuilder serveRegex(Iterable<String> regexes) {
318     return getServletModuleBuilder().serveRegex(ImmutableList.copyOf(regexes));
319   }
320 
321   /**
322    * This method only works if you are using the {@linkplain GuiceServletContextListener} to create
323    * your injector. Otherwise, it returns null.
324    *
325    * @return The current servlet context.
326    * @since 3.0
327    */
getServletContext()328   protected final ServletContext getServletContext() {
329     return GuiceFilter.getServletContext();
330   }
331 
332   /**
333    * See the EDSL examples at {@link ServletModule#configureServlets()}
334    *
335    * @since 2.0
336    */
337   public static interface FilterKeyBindingBuilder {
through(Class<? extends Filter> filterKey)338     void through(Class<? extends Filter> filterKey);
339 
through(Key<? extends Filter> filterKey)340     void through(Key<? extends Filter> filterKey);
341     /** @since 3.0 */
through(Filter filter)342     void through(Filter filter);
343 
through(Class<? extends Filter> filterKey, Map<String, String> initParams)344     void through(Class<? extends Filter> filterKey, Map<String, String> initParams);
345 
through(Key<? extends Filter> filterKey, Map<String, String> initParams)346     void through(Key<? extends Filter> filterKey, Map<String, String> initParams);
347     /** @since 3.0 */
through(Filter filter, Map<String, String> initParams)348     void through(Filter filter, Map<String, String> initParams);
349   }
350 
351   /**
352    * See the EDSL examples at {@link ServletModule#configureServlets()}
353    *
354    * @since 2.0
355    */
356   public static interface ServletKeyBindingBuilder {
with(Class<? extends HttpServlet> servletKey)357     void with(Class<? extends HttpServlet> servletKey);
358 
with(Key<? extends HttpServlet> servletKey)359     void with(Key<? extends HttpServlet> servletKey);
360     /** @since 3.0 */
with(HttpServlet servlet)361     void with(HttpServlet servlet);
362 
with(Class<? extends HttpServlet> servletKey, Map<String, String> initParams)363     void with(Class<? extends HttpServlet> servletKey, Map<String, String> initParams);
364 
with(Key<? extends HttpServlet> servletKey, Map<String, String> initParams)365     void with(Key<? extends HttpServlet> servletKey, Map<String, String> initParams);
366     /** @since 3.0 */
with(HttpServlet servlet, Map<String, String> initParams)367     void with(HttpServlet servlet, Map<String, String> initParams);
368   }
369 }
370