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