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