001    /*******************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.
003     * --------------------------------------------------------------------------
004     * The software in this package is published under the terms of the BSD style
005     * license a copy of which has been included with this distribution in the
006     * LICENSE.txt file.
007     ******************************************************************************/
008    package org.picocontainer.web;
009    
010    import java.io.IOException;
011    import java.io.Serializable;
012    import java.lang.reflect.Type;
013    
014    import javax.servlet.Filter;
015    import javax.servlet.FilterChain;
016    import javax.servlet.FilterConfig;
017    import javax.servlet.ServletContext;
018    import javax.servlet.ServletException;
019    import javax.servlet.ServletRequest;
020    import javax.servlet.ServletResponse;
021    import javax.servlet.http.HttpServletRequest;
022    import javax.servlet.http.HttpSession;
023    import javax.servlet.http.HttpServletResponse;
024    
025    import org.picocontainer.DefaultPicoContainer;
026    import org.picocontainer.MutablePicoContainer;
027    import org.picocontainer.Characteristics;
028    import org.picocontainer.PicoContainer;
029    import org.picocontainer.PicoCompositionException;
030    import org.picocontainer.adapters.AbstractAdapter;
031    import org.picocontainer.behaviors.Storing;
032    
033    @SuppressWarnings("serial")
034    public abstract class PicoServletContainerFilter implements Filter, Serializable {
035    
036        private static final String APP_CONTAINER = ApplicationContainerHolder.class.getName();
037        private static final String SESS_CONTAINER = SessionContainerHolder.class.getName();
038        private static final String REQ_CONTAINER = RequestContainerHolder.class.getName();
039        private boolean exposeServletInfrastructure;
040    
041        public void init(FilterConfig filterConfig) throws ServletException {
042            ServletContext context = filterConfig.getServletContext();
043            ApplicationContainerHolder ach = (ApplicationContainerHolder) context.getAttribute(APP_CONTAINER);
044            setAppContainer(ach.getContainer());
045            SessionContainerHolder sch = (SessionContainerHolder) context.getAttribute(SESS_CONTAINER);
046            RequestContainerHolder rch = (RequestContainerHolder) context.getAttribute(REQ_CONTAINER);
047    
048            String exposeServletInfrastructureString = filterConfig.getInitParameter("exposeServletInfrastructure");
049            if (exposeServletInfrastructureString == null || Boolean.parseBoolean(exposeServletInfrastructureString)) {
050                exposeServletInfrastructure = true;
051            }
052    
053            rch.getContainer().as(Characteristics.NO_CACHE).addAdapter(new HttpSessionInjector());
054            rch.getContainer().as(Characteristics.NO_CACHE).addAdapter(new HttpServletRequestInjector());
055            rch.getContainer().as(Characteristics.NO_CACHE).addAdapter(new HttpServletResponseInjector());
056    
057            initAdditionalScopedComponents(sch.getContainer(), rch.getContainer());
058        }
059    
060        protected void initAdditionalScopedComponents(MutablePicoContainer sessionContainer, MutablePicoContainer reqContainer) {
061        }
062    
063        public void destroy() {
064        }
065    
066        public static Object getRequestComponentForThread(Class<?> type) {
067            MutablePicoContainer requestContainer = ServletFilter.currentRequestContainer.get();
068            MutablePicoContainer container = new DefaultPicoContainer(requestContainer);
069            container.addComponent(type);
070            return container.getComponent(type);
071        }
072    
073        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
074    
075            HttpSession sess = ((HttpServletRequest) req).getSession();
076            if (exposeServletInfrastructure) {
077                session.set(sess);
078                request.set(req);
079                response.set(resp);
080            }
081    
082            ServletContext context = sess.getServletContext();
083    
084            ApplicationContainerHolder ach = (ApplicationContainerHolder) context.getAttribute(APP_CONTAINER);
085            SessionContainerHolder sch = (SessionContainerHolder) context.getAttribute(SESS_CONTAINER);
086            RequestContainerHolder rch = (RequestContainerHolder) context.getAttribute(REQ_CONTAINER);
087    
088            Storing sessionStoring = sch.getStoring();
089            Storing requestStoring = rch.getStoring();
090    
091            SessionStoreHolder ssh = (SessionStoreHolder) sess.getAttribute(SessionStoreHolder.class.getName());
092            sessionStoring.putCacheForThread(ssh.getStoreWrapper());
093            requestStoring.resetCacheForThread();
094            rch.getLifecycleStateModel().resetStateModelForThread();
095            rch.getContainer().start();
096    
097            setAppContainer(ach.getContainer());
098            setSessionContainer(sch.getContainer());
099            setRequestContainer(rch.getContainer());
100    
101            containersSetupForRequest(ach.getContainer(), sch.getContainer(), rch.getContainer(), req, resp);
102    
103            filterChain.doFilter(req, resp);
104    
105            setAppContainer(null);
106            setSessionContainer(null);
107            setRequestContainer(null);
108    
109            rch.getContainer().stop();
110            rch.getContainer().dispose();
111            rch.getLifecycleStateModel().invalidateStateModelForThread();
112            sessionStoring.invalidateCacheForThread();
113            requestStoring.invalidateCacheForThread();
114    
115            if (exposeServletInfrastructure) {
116                session.set(null);
117                request.set(null);
118                response.set(null);
119            }
120    
121        }
122    
123        protected void containersSetupForRequest(MutablePicoContainer appcontainer, MutablePicoContainer sessionContainer,
124                                                 MutablePicoContainer requestContainer, ServletRequest req, ServletResponse resp) {
125        }
126    
127        private static ThreadLocal<HttpSession> session = new ThreadLocal<HttpSession>();
128        private static ThreadLocal<ServletRequest> request = new ThreadLocal<ServletRequest>();
129        private static ThreadLocal<ServletResponse> response = new ThreadLocal<ServletResponse>();
130    
131        protected abstract void setAppContainer(MutablePicoContainer container);
132    
133        protected abstract void setSessionContainer(MutablePicoContainer container);
134    
135        protected abstract void setRequestContainer(MutablePicoContainer container);
136    
137        public static class ServletFilter extends PicoServletContainerFilter {
138    
139            private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
140            private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
141            private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
142    
143            protected void setAppContainer(MutablePicoContainer container) {
144                currentAppContainer.set(container);
145            }
146    
147            protected void setRequestContainer(MutablePicoContainer container) {
148                currentRequestContainer.set(container);
149            }
150    
151            protected void setSessionContainer(MutablePicoContainer container) {
152                currentSessionContainer.set(container);
153            }
154        }
155    
156        public static class HttpSessionInjector extends AbstractAdapter {
157    
158            public HttpSessionInjector() {
159                super(HttpSession.class, HttpSession.class);
160            }
161    
162            public Object getComponentInstance(PicoContainer picoContainer, Type type) throws PicoCompositionException {
163                return session.get();
164            }
165    
166            public void verify(PicoContainer picoContainer) throws PicoCompositionException {
167            }
168    
169            public String getDescriptor() {
170                return "HttpSessionInjector";
171            }
172        }
173    
174        public static class HttpServletRequestInjector extends AbstractAdapter {
175    
176            public HttpServletRequestInjector() {
177                super(HttpServletRequest.class, HttpServletRequest.class);
178            }
179    
180            public Object getComponentInstance(PicoContainer picoContainer, Type type) throws PicoCompositionException {
181                return request.get();
182            }
183    
184            public void verify(PicoContainer picoContainer) throws PicoCompositionException {
185            }
186    
187            public String getDescriptor() {
188                return "HttpServletRequestInjector";
189            }
190        }
191    
192        public static class HttpServletResponseInjector extends AbstractAdapter {
193    
194            public HttpServletResponseInjector() {
195                super(HttpServletResponse.class, HttpServletResponse.class);
196            }
197    
198            public Object getComponentInstance(PicoContainer picoContainer, Type type) throws PicoCompositionException {
199                return response.get();
200            }
201    
202            public void verify(PicoContainer picoContainer) throws PicoCompositionException {
203            }
204    
205            public String getDescriptor() {
206                return "HttpServletResponseInjector";
207            }
208        }
209    }