Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: net/sf/acegisecurity/util/FilterToBeanProxy.java


1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package net.sf.acegisecurity.util;
17  
18  import org.springframework.beans.factory.BeanFactoryUtils;
19  
20  import org.springframework.context.ApplicationContext;
21  
22  import org.springframework.web.context.support.WebApplicationContextUtils;
23  
24  import java.io.IOException;
25  
26  import java.util.Map;
27  
28  import javax.servlet.Filter;
29  import javax.servlet.FilterChain;
30  import javax.servlet.FilterConfig;
31  import javax.servlet.ServletException;
32  import javax.servlet.ServletRequest;
33  import javax.servlet.ServletResponse;
34  
35  
36  /**
37   * Delegates <code>Filter</code> requests to a Spring-managed bean.
38   * 
39   * <p>
40   * This class acts as a proxy on behalf of a target <code>Filter</code> that is
41   * defined in the Spring bean context. It is necessary to specify which target
42   * <code>Filter</code> should be proxied as a filter initialization parameter.
43   * </p>
44   * 
45   * <p>
46   * On filter initialisation, the class will use Spring's {@link
47   * WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
48   * method to obtain an <code>ApplicationContext</code> instance. It will
49   * expect to find the target <code>Filter</code> in this
50   * <code>ApplicationContext</code>.
51   * </p>
52   * 
53   * <p>
54   * To use this filter, it is necessary to specify <b>one</b> of the following
55   * filter initialization parameters:
56   * </p>
57   * 
58   * <ul>
59   * <li>
60   * <code>targetClass</code> indicates the class of the target
61   * <code>Filter</code> defined in the bean context. The only requirements are
62   * that this target class implements the <code>javax.servlet.Filter</code>
63   * interface and at least one instance is available in the
64   * <code>ApplicationContext</code>.
65   * </li>
66   * <li>
67   * <code>targetBean</code> indicates the bean name of the target class.
68   * </li>
69   * </ul>
70   * 
71   * If both initialization parameters are specified, <code>targetBean</code>
72   * takes priority.
73   * 
74   * <P>
75   * An additional initialization parameter, <code>init</code>, is also
76   * supported. If set to "<code>lazy</code>" the initialization will take place
77   * on the first HTTP request, rather than at filter creation time. This makes
78   * it possible to use <code>FilterToBeanProxy</code> with the Spring
79   * <code>ContextLoaderServlet</code>. Where possible you should not use this
80   * initialization parameter, instead using <code>ContextLoaderListener</code>.
81   * </p>
82   * 
83   * <p>
84   * A final optional initialization parameter, <code>lifecycle</code>,
85   * determines whether the servlet container or the IoC container manages the
86   * lifecycle of the proxied filter. When possible you should write your
87   * filters to be managed via the IoC container interfaces such as {@link
88   * org.springframework.beans.factory.InitializingBean} and {@link
89   * org.springframework.beans.factory.DisposableBean}. If you cannot control
90   * the filters you wish to proxy (eg you do not have their source code) you
91   * might need to allow the servlet container to manage lifecycle via the
92   * {@link javax.servlet.Filter#init(javax.servlet.FilterConfig)} and {@link
93   * javax.servlet.Filter#destroy()} methods. If this case, set the
94   * <code>lifecycle</code> initialization parameter to
95   * <code>servlet-container-managed</code>. If the parameter is any other
96   * value, servlet container lifecycle methods will not be delegated through to
97   * the proxy.
98   * </p>
99   *
100  * @author Ben Alex
101  * @version $Id: FilterToBeanProxy.java,v 1.6 2005/02/20 05:38:57 benalex Exp $
102  */
103 public class FilterToBeanProxy implements Filter {
104     //~ Instance fields ========================================================
105 
106     private Filter delegate;
107     private FilterConfig filterConfig;
108     private boolean initialized = false;
109     private boolean servletContainerManaged = false;
110 
111     //~ Methods ================================================================
112 
113     public void destroy() {
114         if ((delegate != null) && servletContainerManaged) {
115             delegate.destroy();
116         }
117     }
118 
119     public void doFilter(ServletRequest request, ServletResponse response,
120         FilterChain chain) throws IOException, ServletException {
121         if (!initialized) {
122             doInit();
123         }
124 
125         delegate.doFilter(request, response, chain);
126     }
127 
128     public void init(FilterConfig filterConfig) throws ServletException {
129         this.filterConfig = filterConfig;
130 
131         String strategy = filterConfig.getInitParameter("init");
132 
133         if ((strategy != null) && strategy.toLowerCase().equals("lazy")) {
134             return;
135         }
136 
137         doInit();
138     }
139 
140     /**
141      * Allows test cases to override where application context obtained from.
142      *
143      * @param filterConfig which can be used to find the
144      *        <code>ServletContext</code>
145      *
146      * @return the Spring application context
147      */
148     protected ApplicationContext getContext(FilterConfig filterConfig) {
149         return WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig
150             .getServletContext());
151     }
152 
153     private void doInit() throws ServletException {
154         initialized = true;
155 
156         String targetBean = filterConfig.getInitParameter("targetBean");
157 
158         if ("".equals(targetBean)) {
159             targetBean = null;
160         }
161 
162         String lifecycle = filterConfig.getInitParameter("lifecycle");
163 
164         if ("servlet-container-managed".equals(lifecycle)) {
165             servletContainerManaged = true;
166         }
167 
168         ApplicationContext ctx = this.getContext(filterConfig);
169 
170         String beanName = null;
171 
172         if ((targetBean != null) && ctx.containsBean(targetBean)) {
173             beanName = targetBean;
174         } else if (targetBean != null) {
175             throw new ServletException("targetBean '" + targetBean
176                 + "' not found in context");
177         } else {
178             String targetClassString = filterConfig.getInitParameter(
179                     "targetClass");
180 
181             if ((targetClassString == null) || "".equals(targetClassString)) {
182                 throw new ServletException(
183                     "targetClass or targetBean must be specified");
184             }
185 
186             Class targetClass;
187 
188             try {
189                 targetClass = Thread.currentThread().getContextClassLoader()
190                                     .loadClass(targetClassString);
191             } catch (ClassNotFoundException ex) {
192                 throw new ServletException("Class of type " + targetClassString
193                     + " not found in classloader");
194             }
195 
196             Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx,
197                     targetClass, true, true);
198 
199             if (beans.size() == 0) {
200                 throw new ServletException(
201                     "Bean context must contain at least one bean of type "
202                     + targetClassString);
203             }
204 
205             beanName = (String) beans.keySet().iterator().next();
206         }
207 
208         Object object = ctx.getBean(beanName);
209 
210         if (!(object instanceof Filter)) {
211             throw new ServletException("Bean '" + beanName
212                 + "' does not implement javax.servlet.Filter");
213         }
214 
215         delegate = (Filter) object;
216 
217         if (servletContainerManaged) {
218             delegate.init(filterConfig);
219         }
220     }
221 }