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 }