[picocontainer-dev] Patch for web ... to close that static getter IoC problem

Paul Hammant <[email protected]> Fri, 20 Jun 2008 02:59:33 -0700
Newsgroups gmane.comp.java.picocontainer.devel
Message-ID <[email protected]>

Well it goes part way.
By extending a filter, we can use some private magic to hide the  
static thread local vars that would otherwise make things publicly  
available.

It dictates a scenario where there is only one pico-leveraging filter  
per web app. And only one 'ActionFactory' thing that is using that.   
Axis and Webwork1 have two things - so it needs more thought.

Axis - PicoMsgProvider, PicoRpcProvider
WebWork1 - PicoActionFactory, WebWorkVelocityServlet

Thoughts?

- Paul

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email
ham.patch (application/octet-stream, 22.1 KB)
Index: web-struts/src/java/org/picocontainer/web/struts/ActionFactory.java
===================================================================
--- web-struts/src/java/org/picocontainer/web/struts/ActionFactory.java	(revision 4659)
+++ web-struts/src/java/org/picocontainer/web/struts/ActionFactory.java	(working copy)
@@ -31,6 +31,26 @@
  */
 public final class ActionFactory {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+        private static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+    }
+
     private final Map<String,Class<?>> classCache = new HashMap<String, Class<?>>();
 
     /**
@@ -60,7 +80,7 @@
     public Action getAction(HttpServletRequest request, ActionMapping mapping, ActionServlet servlet)
             throws PicoCompositionException {
 
-        MutablePicoContainer actionsContainer = PicoServletContainerFilter.getRequestContainerForThread();
+        MutablePicoContainer actionsContainer = ServletFilter.getRequestContainerForThread();
         Object actionKey = mapping.getPath();
         Class<?> actionType = getActionClass(mapping.getType());
 
Index: web-struts2/src/java/org/picocontainer/web/struts2/PicoObjectFactory.java
===================================================================
--- web-struts2/src/java/org/picocontainer/web/struts2/PicoObjectFactory.java	(revision 4674)
+++ web-struts2/src/java/org/picocontainer/web/struts2/PicoObjectFactory.java	(working copy)
@@ -29,6 +29,33 @@
 @SuppressWarnings("serial")
 public class PicoObjectFactory extends ObjectFactory {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+
+        protected static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+        protected static MutablePicoContainer getSessionContainerForThread() {
+            return currentSessionContainer.get();
+        }
+        protected static MutablePicoContainer getApplicationContainerForThread() {
+            return currentAppContainer.get();
+        }
+
+    }
+
     @SuppressWarnings("unchecked")
     public Class getClassInstance(String name) throws ClassNotFoundException {
         Class clazz = super.getClassInstance(name);
@@ -40,7 +67,7 @@
 
         synchronized (this) {
 
-            MutablePicoContainer reqContainer = PicoServletContainerFilter.getRequestContainerForThread();
+            MutablePicoContainer reqContainer = ServletFilter.getRequestContainerForThread();
             if (reqContainer == null) {
                 return;
             }
@@ -65,9 +92,9 @@
     @SuppressWarnings("unchecked")
     public Object buildBean(Class clazz, Map extraContext) throws Exception {
 
-        MutablePicoContainer requestContainer = PicoServletContainerFilter.getRequestContainerForThread();
+        MutablePicoContainer requestContainer = ServletFilter.getRequestContainerForThread();
         if (requestContainer == null) {
-            MutablePicoContainer appContainer = PicoServletContainerFilter.getApplicationContainerForThread();
+            MutablePicoContainer appContainer = ServletFilter.getApplicationContainerForThread();
             Object comp = appContainer.getComponent(clazz);
             if (comp == null) {
                 appContainer.addComponent(clazz);
Index: web-core/src/java/org/picocontainer/web/PicoServletContainerFilter.java
===================================================================
--- web-core/src/java/org/picocontainer/web/PicoServletContainerFilter.java	(revision 4659)
+++ web-core/src/java/org/picocontainer/web/PicoServletContainerFilter.java	(working copy)
@@ -18,23 +18,21 @@
 import org.picocontainer.behaviors.Storing;
 
 @SuppressWarnings("serial")
-public class PicoServletContainerFilter implements Filter, Serializable {
+public abstract class PicoServletContainerFilter implements Filter, Serializable {
 
     public void init(FilterConfig filterConfig) throws ServletException {
         ServletContext servletContext = filterConfig.getServletContext();
         ApplicationContainerHolder ach = (ApplicationContainerHolder) servletContext
                 .getAttribute(ApplicationContainerHolder.class.getName());
-        currentAppContainer.set(ach.getContainer());
+        setAppContainer(ach.getContainer());
     }
 
+    protected abstract void setAppContainer(MutablePicoContainer container);
+
     public void destroy() {
     }
 
-    private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
 
-    public static MutablePicoContainer getRequestContainerForThread() {
-        return currentRequestContainer.get();
-    }
 
     public static Object getRequestComponentForThread(Class<?> type) {
         MutablePicoContainer requestContainer = getRequestContainerForThread();
@@ -42,19 +40,7 @@
         container.addComponent(type);
         return container.getComponent(type);
     }
-    
-    private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
 
-    public static MutablePicoContainer getSessionContainerForThread() {
-        return currentSessionContainer.get();
-    }
-
-    private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
-
-    public static MutablePicoContainer getApplicationContainerForThread() {
-        return currentAppContainer.get();
-    }
-
     public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException,
             ServletException {
 
@@ -78,15 +64,15 @@
         rch.getLifecycleStateModel().resetStateModelForThread();
         rch.getContainer().start();
 
-        currentAppContainer.set(ach.getContainer());
-        currentSessionContainer.set(sch.getContainer());
-        currentRequestContainer.set(rch.getContainer());
+        setAppContainer(ach.getContainer());
+        setSessionContainer(sch.getContainer());
+        setRequestContainer(rch.getContainer());
 
         filterChain.doFilter(req, resp);
 
-        currentAppContainer.set(null);
-        currentSessionContainer.set(null);
-        currentRequestContainer.set(null);
+        setAppContainer(null);
+        setSessionContainer(null);
+        setRequestContainer(null);
 
         rch.getContainer().stop();
         rch.getContainer().dispose();
@@ -96,4 +82,8 @@
 
     }
 
+    protected abstract void setRequestContainer(MutablePicoContainer container);
+
+    protected abstract void setSessionContainer(MutablePicoContainer container);
+
 }
Index: web-webwork/src/java/org/picocontainer/web/webwork/PicoActionFactory.java
===================================================================
--- web-webwork/src/java/org/picocontainer/web/webwork/PicoActionFactory.java	(revision 4659)
+++ web-webwork/src/java/org/picocontainer/web/webwork/PicoActionFactory.java	(working copy)
@@ -26,6 +26,33 @@
  */
 public final class PicoActionFactory extends ActionFactory {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+
+        protected static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+        protected static MutablePicoContainer getSessionContainerForThread() {
+            return currentSessionContainer.get();
+        }
+        protected static MutablePicoContainer getApplicationContainerForThread() {
+            return currentAppContainer.get();
+        }
+
+    }
+
     private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
 
     public Action getActionImpl(String className) {
@@ -44,7 +71,7 @@
     }
 
     protected Action instantiateAction(Class<?> actionClass) {
-        MutablePicoContainer actionsContainer = PicoServletContainerFilter.getRequestContainerForThread();
+        MutablePicoContainer actionsContainer = ServletFilter.getRequestContainerForThread();
         Action action = (Action) actionsContainer.getComponent(actionClass);
 
         if (action == null) {
Index: web-webwork/src/java/org/picocontainer/web/webwork/WebWorkVelocityServlet.java
===================================================================
--- web-webwork/src/java/org/picocontainer/web/webwork/WebWorkVelocityServlet.java	(revision 4659)
+++ web-webwork/src/java/org/picocontainer/web/webwork/WebWorkVelocityServlet.java	(working copy)
@@ -12,6 +12,7 @@
 import org.apache.velocity.context.Context;
 import org.apache.velocity.tools.view.servlet.VelocityViewServlet;
 import org.picocontainer.PicoContainer;
+import org.picocontainer.MutablePicoContainer;
 import org.picocontainer.containers.EmptyPicoContainer;
 import org.picocontainer.web.PicoServletContainerFilter;
 
@@ -31,6 +32,32 @@
 @SuppressWarnings("serial")
 public final class WebWorkVelocityServlet extends VelocityViewServlet {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+
+        protected static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+        protected static MutablePicoContainer getSessionContainerForThread() {
+            return currentSessionContainer.get();
+        }
+        protected static MutablePicoContainer getApplicationContainerForThread() {
+            return currentAppContainer.get();
+        }
+    }
+
     static final String WEBWORK_UTIL = "webwork";
     // those have to be removed once dependency problem is solved.
     // will bomb anyway.
@@ -41,7 +68,7 @@
 
     protected Context createContext(javax.servlet.http.HttpServletRequest request,
             javax.servlet.http.HttpServletResponse response) {
-        Context ctx = new NanocontainerVelocityContext(PicoServletContainerFilter.getRequestContainerForThread(),
+        Context ctx = new NanocontainerVelocityContext(ServletFilter.getRequestContainerForThread(),
                 ServletValueStack.getStack(request));
         ctx.put(REQUEST, request);
         ctx.put(RESPONSE, response);
Index: web-jsf/src/java/org/picocontainer/web/jsf/PicoDelegatingVariableResolver.java
===================================================================
--- web-jsf/src/java/org/picocontainer/web/jsf/PicoDelegatingVariableResolver.java	(revision 4659)
+++ web-jsf/src/java/org/picocontainer/web/jsf/PicoDelegatingVariableResolver.java	(working copy)
@@ -14,6 +14,7 @@
 import javax.faces.el.VariableResolver;
 
 import org.picocontainer.PicoContainer;
+import org.picocontainer.MutablePicoContainer;
 import org.picocontainer.web.PicoServletContainerFilter;
 
 /**
@@ -113,6 +114,32 @@
  */
 public class PicoDelegatingVariableResolver extends VariableResolver {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+
+        protected static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+        protected static MutablePicoContainer getSessionContainerForThread() {
+            return currentSessionContainer.get();
+        }
+        protected static MutablePicoContainer getApplicationContainerForThread() {
+            return currentAppContainer.get();
+        }
+
+    }
     /**
      * The nested variable resolver.
      */
@@ -180,7 +207,7 @@
 
         // First check request map.
         if (requestAttributeMap != null) {
-            container = PicoServletContainerFilter.getRequestContainerForThread();
+            container = ServletFilter.getRequestContainerForThread();
         }
 
         if (requestAttributeMap == null || container == null) {
@@ -189,13 +216,13 @@
             Map sessionMap = facesContext.getExternalContext().getSessionMap();
             if (sessionMap != null) {
                 // If there is a session.
-                container = PicoServletContainerFilter.getSessionContainerForThread();
+                container = ServletFilter.getSessionContainerForThread();
             }
 
             if (sessionMap == null || container == null) {
 
                 // If that fails, check for App level container.
-                container = PicoServletContainerFilter.getApplicationContainerForThread();
+                container = ServletFilter.getApplicationContainerForThread();
                 if (container == null) {
                     // If that fails... Fail.
                     throw new EvaluationException(
Index: web-webwork2/src/java/org/picocontainer/web/webwork2/PicoObjectFactory.java
===================================================================
--- web-webwork2/src/java/org/picocontainer/web/webwork2/PicoObjectFactory.java	(revision 4659)
+++ web-webwork2/src/java/org/picocontainer/web/webwork2/PicoObjectFactory.java	(working copy)
@@ -31,6 +31,32 @@
  */
 public class PicoObjectFactory extends ObjectFactory {
 
+    public static class ServletFilter extends PicoServletContainerFilter {
+        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
+        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
+
+        protected void setAppContainer(MutablePicoContainer container) {
+            currentAppContainer.set(container);
+        }
+        protected void setRequestContainer(MutablePicoContainer container) {
+            currentRequestContainer.set(container);
+        }
+        protected void setSessionContainer(MutablePicoContainer container) {
+            currentSessionContainer.set(container);
+        }
+
+        protected static MutablePicoContainer getRequestContainerForThread() {
+            return currentRequestContainer.get();
+        }
+        protected static MutablePicoContainer getSessionContainerForThread() {
+            return currentSessionContainer.get();
+        }
+        protected static MutablePicoContainer getApplicationContainerForThread() {
+            return currentAppContainer.get();
+        }
+    }
+
     private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
 
     public boolean isNoArgConstructorRequired() {
@@ -61,7 +87,7 @@
      * @see com.opensymphony.xwork.ObjectFactory#buildBean(java.lang.Class)
      */
     public Object buildBean(Class<?> actionClass) throws Exception {
-        PicoContainer actionsContainer = PicoServletContainerFilter.getRequestContainerForThread();
+        PicoContainer actionsContainer = ServletFilter.getRequestContainerForThread();
         Object action = actionsContainer.getComponent(actionClass);
 
         if (action == null) {
Index: examples/struts-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- examples/struts-webapp/src/main/webapp/WEB-INF/web.xml	(revision 4659)
+++ examples/struts-webapp/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -10,7 +10,7 @@
   
   <filter>
     <filter-name>picoFilter</filter-name>
-    <filter-class>org.picocontainer.web.PicoServletContainerFilter</filter-class>
+    <filter-class>org.picocontainer.web.struts.ActionFactory.ServletFilter</filter-class>
   </filter>
 
   <filter-mapping>
Index: examples/struts2-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- examples/struts2-webapp/src/main/webapp/WEB-INF/web.xml	(revision 4659)
+++ examples/struts2-webapp/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -10,7 +10,7 @@
 
   <filter>
     <filter-name>picoFilter</filter-name>
-    <filter-class>org.picocontainer.web.PicoServletContainerFilter</filter-class>
+    <filter-class>org.picocontainer.web.struts2.PicoObjectFactory.ServletFilter</filter-class>
   </filter>
 
   <filter>
Index: examples/webwork-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- examples/webwork-webapp/src/main/webapp/WEB-INF/web.xml	(revision 4659)
+++ examples/webwork-webapp/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -10,7 +10,7 @@
 
   <filter>
     <filter-name>picoFilter</filter-name>
-    <filter-class>org.picocontainer.web.PicoServletContainerFilter</filter-class>
+    <filter-class>org.picocontainer.web.webwork.PicoActionFactory.ServletFilter</filter-class>
   </filter>
 
   <filter-mapping>
Index: examples/jsf-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- examples/jsf-webapp/src/main/webapp/WEB-INF/web.xml	(revision 4659)
+++ examples/jsf-webapp/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -3,7 +3,7 @@
          xmlns="http://java.sun.com/xml/ns/j2ee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
-	<display-name>JSF Webapp</display-name>
+	<display-name>JSF Webapp</display-name>
   
 	<context-param>
 	  <param-name>webapp-composer-class</param-name>
@@ -12,16 +12,16 @@
 	
 	<!--  
 			Filter to build the request container with each request to the faces servlet.
-	 -->
-   <filter>
-        <filter-name>picoFilter</filter-name>
-        <filter-class>org.picocontainer.web.PicoServletContainerFilter</filter-class>
-    </filter>
-
+	 -->
+   <filter>
+        <filter-name>picoFilter</filter-name>
+        <filter-class>org.picocontainer.web.jsf.PicoDelegatingVariableResolver.ServletFilter</filter-class>
+    </filter>
+
   	<filter-mapping>
 		<filter-name>picoFilter</filter-name>
-        <url-pattern>*.jsf</url-pattern>
-	</filter-mapping>
+        <url-pattern>*.jsf</url-pattern>
+	</filter-mapping>
   
     <listener>
         <listener-class>org.picocontainer.web.PicoServletContainerListener</listener-class>
Index: examples/webwork2-webapp/src/main/webapp/WEB-INF/web.xml
===================================================================
--- examples/webwork2-webapp/src/main/webapp/WEB-INF/web.xml	(revision 4659)
+++ examples/webwork2-webapp/src/main/webapp/WEB-INF/web.xml	(working copy)
@@ -10,7 +10,7 @@
 
   <filter>
     <filter-name>picoFilter</filter-name>
-    <filter-class>org.picocontainer.web.PicoServletContainerFilter</filter-class>
+    <filter-class>org.picocontainer.web.webwork2.PicoObjectFactory.ServletFilter</filter-class>
   </filter>
 
   <filter-mapping>