001 package org.picocontainer.web;
002
003 import java.io.IOException;
004
005 import javax.servlet.Filter;
006 import javax.servlet.FilterChain;
007 import javax.servlet.FilterConfig;
008 import javax.servlet.ServletException;
009 import javax.servlet.ServletRequest;
010 import javax.servlet.ServletResponse;
011 import javax.servlet.http.HttpServletRequest;
012
013 import org.picocontainer.PicoContainer;
014 import org.picocontainer.PicoCompositionException;
015
016 /**
017 *<p>
018 * ServletContainerProxyFilter is a Filter which delegates to any Filter which is registered in a PicoContainer,
019 * in any of the web scopes: context, session or request.
020 * This form of delegation is particularly useful as it brings dependency injections to filters.
021 * In fact the delegate filter may be implemented via any form of dependency injection.
022 *</p>
023 *
024 *<p>The delegate Filter must be registered via the <code>delegate-key</code> or <code>delegate-class</code>
025 * init-params of this Filter.
026 *</p>
027 *
028 *<p>The initialization is done lazily, using the <code>init-type</code> init-param
029 * to control it. Allowed values are:
030 * <ul>
031 * <li>"context": will call init() on the filter only once</li>
032 * <li>"request": will re-init it at every request</li>
033 * <li>"never": will never init it</li>
034 *</ul>
035 *The default is "context".
036 * </p>
037 *
038 * <p>The lookup in the PicoContainer is by default done for each request, but you
039 * can control that behaviour with the <code>lookup-only-once</code> init-param.
040 * If set to "true", ServletContainerProxyFilter will only lookup your delegate filter
041 * at the first request.
042 * </p>
043 *
044 * <p><b>Note</b>: Be aware that any dependency on your filter, in this setup, will stay
045 * referenced by your filter for its whole lifetime, even though this dependency
046 * might have been set up at request level in your composer!
047 * </p>
048 *
049 * @author Grégory Joseph
050 * @author Mauro Talevi
051 */
052 public class ServletContainerProxyFilter implements Filter {
053
054 private static final String CONTEXT_INIT_TYPE = "context";
055 private static final String REQUEST_INIT_TYPE = "request";
056
057 private String initType;
058 private boolean lookupOnlyOnce;
059 private FilterConfig filterConfig;
060 private Filter delegate;
061
062 public void init(FilterConfig filterConfig) throws ServletException {
063 this.filterConfig = filterConfig;
064 initType = filterConfig.getInitParameter("init-type");
065 if ( initType == null ){
066 initType = CONTEXT_INIT_TYPE;
067 }
068 lookupOnlyOnce = Boolean.valueOf(filterConfig.getInitParameter("lookup-only-once"));
069 }
070
071 public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
072 if (delegate == null || !lookupOnlyOnce) {
073 lookupDelegate((HttpServletRequest) request);
074 if (initType.equals(CONTEXT_INIT_TYPE) ) {
075 initDelegate();
076 }
077 }
078 if (initType.equals(REQUEST_INIT_TYPE)) {
079 initDelegate();
080 }
081 delegate.doFilter(request, response, filterChain);
082 }
083
084 public void destroy() {
085 if (delegate != null) {
086 delegate.destroy();
087 }
088 }
089
090 protected void initDelegate() throws ServletException {
091 if (delegate == null) {
092 throw new IllegalStateException("Delegate filter was not set up");
093 }
094 delegate.init(filterConfig);
095 }
096
097 /**
098 * Looks up delegate Filter in PicoContainer found in any of the web scopes.
099 *
100 * @param request the HttpServletRequest used to find the PicoContainer
101 * @throws PicoCompositionException if the delegate Filter cannot be found
102 */
103 protected void lookupDelegate(HttpServletRequest request) {
104 PicoContainer pico = PicoServletContainerFilter.ServletFilter.getRequestContainerForThread();
105 String delegateClassName = filterConfig.getInitParameter("delegate-class");
106 String delegateKey = filterConfig.getInitParameter("delegate-key");
107 if (delegateClassName != null) {
108 try {
109 Class<?> delegateClass = getClassLoader().loadClass(delegateClassName);
110 delegate = (Filter) pico.getComponent(delegateClass);
111 } catch (ClassNotFoundException e) {
112 throw new PicoCompositionException("Cannot load " + delegateClassName, e);
113 }
114 } else if (delegateKey != null) {
115 delegate = (Filter) pico.getComponent(delegateKey);
116 } else {
117 throw new PicoCompositionException("You must specify one of delegate-class or delegate-key in the filter config");
118 }
119
120 if (delegate == null) {
121 throw new PicoCompositionException("Cannot find delegate for class " + delegateClassName + " or key "+ delegateKey);
122 }
123 }
124
125 private ClassLoader getClassLoader() {
126 return this.getClass().getClassLoader();
127 }
128
129
130 }