• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2008 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 com.google.common.collect.Iterators;
19 import com.google.inject.Injector;
20 import com.google.inject.Key;
21 import com.google.inject.Scopes;
22 import com.google.inject.spi.BindingTargetVisitor;
23 import com.google.inject.spi.ProviderInstanceBinding;
24 import com.google.inject.spi.ProviderWithExtensionVisitor;
25 
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.atomic.AtomicReference;
32 
33 import javax.servlet.Filter;
34 import javax.servlet.FilterConfig;
35 import javax.servlet.ServletContext;
36 import javax.servlet.ServletException;
37 import javax.servlet.http.HttpServletRequest;
38 
39 /**
40  * An internal representation of a filter definition against a particular URI pattern.
41  *
42  * @author dhanji@gmail.com (Dhanji R. Prasanna)
43  */
44 class FilterDefinition implements ProviderWithExtensionVisitor<FilterDefinition> {
45   private final String pattern;
46   private final Key<? extends Filter> filterKey;
47   private final UriPatternMatcher patternMatcher;
48   private final Map<String, String> initParams;
49   // set only if this was bound to an instance of a Filter.
50   private final Filter filterInstance;
51 
52   // always set after init is called.
53   private final AtomicReference<Filter> filter = new AtomicReference<Filter>();
54 
FilterDefinition(String pattern, Key<? extends Filter> filterKey, UriPatternMatcher patternMatcher, Map<String, String> initParams, Filter filterInstance)55   public FilterDefinition(String pattern, Key<? extends Filter> filterKey,
56       UriPatternMatcher patternMatcher, Map<String, String> initParams, Filter filterInstance) {
57     this.pattern = pattern;
58     this.filterKey = filterKey;
59     this.patternMatcher = patternMatcher;
60     this.initParams = Collections.unmodifiableMap(new HashMap<String, String>(initParams));
61     this.filterInstance = filterInstance;
62   }
63 
get()64   public FilterDefinition get() {
65     return this;
66   }
67 
acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding)68   public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor,
69       ProviderInstanceBinding<? extends B> binding) {
70     if(visitor instanceof ServletModuleTargetVisitor) {
71       if(filterInstance != null) {
72         return ((ServletModuleTargetVisitor<B, V>)visitor).visit(
73             new InstanceFilterBindingImpl(initParams,
74                 pattern,
75                 filterInstance,
76                 patternMatcher));
77       } else {
78         return ((ServletModuleTargetVisitor<B, V>)visitor).visit(
79             new LinkedFilterBindingImpl(initParams,
80                 pattern,
81                 filterKey,
82                 patternMatcher));
83       }
84     } else {
85       return visitor.visit(binding);
86     }
87   }
88 
shouldFilter(String uri)89   private boolean shouldFilter(String uri) {
90     return uri != null && patternMatcher.matches(uri);
91   }
92 
init(final ServletContext servletContext, Injector injector, Set<Filter> initializedSoFar)93   public void init(final ServletContext servletContext, Injector injector,
94       Set<Filter> initializedSoFar) throws ServletException {
95 
96     // This absolutely must be a singleton, and so is only initialized once.
97     if (!Scopes.isSingleton(injector.getBinding(filterKey))) {
98       throw new ServletException("Filters must be bound as singletons. "
99         + filterKey + " was not bound in singleton scope.");
100     }
101 
102     Filter filter = injector.getInstance(filterKey);
103     this.filter.set(filter);
104 
105     // Only fire init() if this Singleton filter has not already appeared earlier
106     // in the filter chain.
107     if (initializedSoFar.contains(filter)) {
108       return;
109     }
110 
111     //initialize our filter with the configured context params and servlet context
112     filter.init(new FilterConfig() {
113       public String getFilterName() {
114         return filterKey.toString();
115       }
116 
117       public ServletContext getServletContext() {
118         return servletContext;
119       }
120 
121       public String getInitParameter(String s) {
122         return initParams.get(s);
123       }
124 
125       public Enumeration getInitParameterNames() {
126         return Iterators.asEnumeration(initParams.keySet().iterator());
127       }
128     });
129 
130     initializedSoFar.add(filter);
131   }
132 
destroy(Set<Filter> destroyedSoFar)133   public void destroy(Set<Filter> destroyedSoFar) {
134     // filters are always singletons
135     Filter reference = filter.get();
136 
137     // Do nothing if this Filter was invalid (usually due to not being scoped
138     // properly), or was already destroyed. According to Servlet Spec: it is
139     // "out of service", and does not need to be destroyed.
140     // Also prevent duplicate destroys to the same singleton that may appear
141     // more than once on the filter chain.
142     if (null == reference || destroyedSoFar.contains(reference)) {
143       return;
144     }
145 
146     try {
147       reference.destroy();
148     } finally {
149       destroyedSoFar.add(reference);
150     }
151   }
152 
getFilterIfMatching(HttpServletRequest request)153   public Filter getFilterIfMatching(HttpServletRequest request) {
154 
155     final String path = ServletUtils.getContextRelativePath(request);
156     if (shouldFilter(path)) {
157       return filter.get();
158     } else {
159       return null;
160     }
161   }
162 
163   //VisibleForTesting
getFilter()164   Filter getFilter() {
165     return filter.get();
166   }
167 }
168