Re: [picocontainer-dev] While looking at the streamlining of NanoWar ...

Paul Hammant <[email protected]>
Newsgroups gmane.comp.java.picocontainer.devel
Message-ID <[email protected]>
OK here is a from-scratch better attempt to replace the old NanoWar  
with a new one leveraging the ThreadLocal magic :-




There is still a much more to do, but you can see the over all design  
by looking at :

   NanoWarSessionListener.java (rewritten)
   NanoWarContextListener.java  (rewritten)

   and

   NewFilter (all new)

if taken to completion, this would mean that a few classes remaining  
would be deleted, and much renamed to make it right.

- Paul

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

    http://xircles.codehaus.org/manage_email
allnew.patch (application/octet-stream, 46.1 KB)
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NewFilter.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NewFilter.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NewFilter.java	(revision 0)
@@ -0,0 +1,61 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.MutablePicoContainer;
+import org.picocontainer.PicoContainer;
+import org.picocontainer.behaviors.Storing;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class NewFilter extends AbstractNanoWarListener implements Filter {
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+    public void destroy() {
+    }
+
+    public static ThreadLocal<PicoContainer> currentContainer = new ThreadLocal<PicoContainer>();
+
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
+
+        HttpServletRequest httpReq = (HttpServletRequest) req;
+        HttpServletResponse httpResp = (HttpServletResponse) resp;
+        HttpSession session = httpReq.getSession();
+        ServletContext context = session.getServletContext();
+
+        SessionContainerHolder sch = (SessionContainerHolder) context.getAttribute(SessionContainerHolder.class.getName());
+        RequestContainerHolder rch = (RequestContainerHolder) context.getAttribute(RequestContainerHolder.class.getName());
+
+        Storing sessionStoring = sch.getStoring();
+        Storing requestStoring = rch.getStoring();
+
+        SessionStoreHolder ssh = (SessionStoreHolder) session.getAttribute(SessionStoreHolder.class.getName());
+        sessionStoring.putCacheForThread(ssh.getStoreWrapper());
+        requestStoring.resetCacheForThread();
+        rch.getLifecycleStateModel().resetStateModelForThread();
+        rch.getContainer().start();
+        
+        currentContainer.set(rch.getContainer());
+
+          filterChain.doFilter(req, resp);
+
+        currentContainer.set(null);
+
+        rch.getContainer().stop();
+        rch.getContainer().dispose();
+        rch.getLifecycleStateModel().invalidateStateModelForThread();
+        sessionStoring.invalidateCacheForThread();
+        requestStoring.invalidateCacheForThread();
+
+    }
+
+}
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/AbstractNanoWarListener.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/AbstractNanoWarListener.java	(revision 4422)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/AbstractNanoWarListener.java	(working copy)
@@ -25,16 +25,4 @@
  */
 public class AbstractNanoWarListener implements Serializable {
 
-    protected PicoContainer buildContainer(ScriptedContainerBuilder builder) {
-        ObjectReference containerRef = new SimpleReference();
-        builder.buildContainer(containerRef, new SimpleReference(), new SimpleReference(), false);
-        return (PicoContainer) containerRef.get();
-    }
-
-    protected void killContainer(ObjectReference containerRef) {
-        ContainerBuilder containerKiller = new DefaultContainerBuilder(null);
-        if (containerRef.get() != null) {
-            containerKiller.killContainer(containerRef);
-        }
-    }
 }
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ThreadLocalLifecycleState.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ThreadLocalLifecycleState.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ThreadLocalLifecycleState.java	(revision 0)
@@ -0,0 +1,58 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.lifecycle.LifecycleState;
+import org.picocontainer.lifecycle.DefaultLifecycleState;
+
+public class ThreadLocalLifecycleState implements LifecycleState {
+
+    private LifecycleStateThreadLocal tl = new LifecycleStateThreadLocal();
+
+    public void removingComponent() {
+        tl.get().removingComponent();
+    }
+
+    public void starting() {
+        tl.get().starting();
+    }
+
+    public void stopping() {
+        tl.get().stopping();
+    }
+
+    public void stopped() {
+        tl.get().stopped();
+    }
+
+    public boolean isStarted() {
+        return tl.get().isStarted();
+    }
+
+    public void disposing() {
+        tl.get().disposing();
+    }
+
+    public void disposed() {
+        tl.get().disposed();
+    }
+
+    public void putLifecycleStateModelForThread(DefaultLifecycleState lifecycleState) {
+        tl.set(lifecycleState);
+    }
+
+    public DefaultLifecycleState resetStateModelForThread() {
+        DefaultLifecycleState dls = new DefaultLifecycleState();
+        tl.set(dls);
+        return dls;
+    }
+
+    public void invalidateStateModelForThread() {
+        tl.set(null);
+    }
+
+    private static class LifecycleStateThreadLocal extends ThreadLocal<DefaultLifecycleState> {
+        protected DefaultLifecycleState initialValue() {
+            return new DefaultLifecycleState();
+        }
+    }
+
+}
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ApplicationContainerHolder.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ApplicationContainerHolder.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/ApplicationContainerHolder.java	(revision 0)
@@ -0,0 +1,16 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.DefaultPicoContainer;
+
+public class ApplicationContainerHolder {
+
+    private final DefaultPicoContainer container;
+
+    public ApplicationContainerHolder(DefaultPicoContainer container) {
+        this.container = container;
+    }
+
+    DefaultPicoContainer getContainer() {
+        return container;
+    }
+}
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarSessionListener.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarSessionListener.java	(revision 4422)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarSessionListener.java	(working copy)
@@ -20,6 +20,9 @@
 
 import org.nanocontainer.integrationkit.ContainerBuilder;
 import org.picocontainer.ObjectReference;
+import org.picocontainer.MutablePicoContainer;
+import org.picocontainer.lifecycle.DefaultLifecycleState;
+import org.picocontainer.behaviors.Storing;
 import org.picocontainer.references.SimpleReference;
 
 /**
@@ -64,6 +67,8 @@
  */
 public class NanoWarSessionListener extends AbstractNanoWarListener implements HttpSessionListener, KeyConstants {
 
+    private static final String PICO_SESSION_LIFECYCLE_STATE_WRAPPER = "PICO-SESSION-LIFECYCLE-STATE-WRAPPER";
+
     private ContainerBuilder getBuilder(ServletContext context) {
         ObjectReference assemblerRef = new ApplicationScopeReference(context, BUILDER);
         return (ContainerBuilder) assemblerRef.get();
@@ -72,42 +77,32 @@
     public void sessionCreated(HttpSessionEvent event) {
         HttpSession session = event.getSession();
         ServletContext context = session.getServletContext();
-        ContainerBuilder containerBuilder = getBuilder(context);
-        ObjectReference sessionContainerRef = new SessionScopeReference(session, SESSION_CONTAINER);
-        ObjectReference webappContainerRef = new ApplicationScopeReference(context, APPLICATION_CONTAINER);
-        containerBuilder.buildContainer(sessionContainerRef, webappContainerRef, session, false);
 
-        session.setAttribute(KILLER_HELPER, new SessionContainerKillerHelper() {
-            public void valueBound(HttpSessionBindingEvent bindingEvent) {
-                HttpSession session = bindingEvent.getSession();
-                containerRef = new SimpleReference();
-                containerRef.set(new SessionScopeReference(session, SESSION_CONTAINER).get());
-            }
+        SessionContainerHolder sch = (SessionContainerHolder) context.getAttribute(SessionContainerHolder.class.getName());
+        Storing sessionStoring = sch.getStoring();
+        ThreadLocalLifecycleState tlLifecycleState = sch.getLifecycleStateModel();
 
-            public void valueUnbound(HttpSessionBindingEvent event) {
-                try {
-                    killContainer(containerRef);
-                } catch (IllegalStateException e) {
-                    //
-                    //Some servlet containers (Jetty) call contextDestroyed(ServletContextEvent event)
-                    //and then afterwards call valueUnbound(HttpSessionBindingEvent event).
+        session.setAttribute(SessionStoreHolder.class.getName(), new SessionStoreHolder(sessionStoring.resetCacheForThread(), tlLifecycleState.resetStateModelForThread()));
 
-                    //contextDestroyed will kill the top level (app level) pico container which will
-                    //cascade stop() down to the session children.
-
-                    //This means that when valueUnbound is called later, the session level container will
-                    //already be stopped.
-                    //
-                }
-            }
-        });
+        sch.getContainer().start();
     }
 
-    public void sessionDestroyed(HttpSessionEvent se) {
-        // no implementation - session scoped container killed by SessionContainerKillerHelper
-    }
+    public void sessionDestroyed(HttpSessionEvent event) {
+        HttpSession session = event.getSession();
+        ServletContext context = session.getServletContext();
 
-    private abstract class SessionContainerKillerHelper implements HttpSessionBindingListener, Serializable {
-        transient SimpleReference containerRef;
+        SessionStoreHolder ssh = (SessionStoreHolder) session.getAttribute(SessionStoreHolder.class.getName());
+
+        SessionContainerHolder sch = (SessionContainerHolder) context.getAttribute(SessionContainerHolder.class.getName());
+        ThreadLocalLifecycleState tlLifecycleState = sch.getLifecycleStateModel();
+
+        sch.getStoring().putCacheForThread(ssh.getStoreWrapper());
+        tlLifecycleState.putLifecycleStateModelForThread((DefaultLifecycleState) session.getAttribute(PICO_SESSION_LIFECYCLE_STATE_WRAPPER));
+
+        sch.getContainer().stop();
+        sch.getContainer().dispose();
+        sch.getStoring().invalidateCacheForThread();
+
     }
+
 }
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarContextListener.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarContextListener.java	(revision 4423)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/NanoWarContextListener.java	(working copy)
@@ -11,10 +11,9 @@
 
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.StringReader;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
@@ -24,17 +23,13 @@
 import org.nanocontainer.DefaultNanoContainer;
 import org.nanocontainer.NanoContainer;
 import org.nanocontainer.integrationkit.ContainerBuilder;
-import org.nanocontainer.integrationkit.ContainerComposer;
-import org.nanocontainer.integrationkit.DefaultContainerBuilder;
-import org.nanocontainer.script.ScriptBuilderResolver;
-import org.nanocontainer.script.ScriptedContainerBuilderFactory;
-import org.picocontainer.ComponentAdapter;
+import org.nanocontainer.integrationkit.ContainerPopulator;
 import org.picocontainer.MutablePicoContainer;
 import org.picocontainer.ObjectReference;
-import org.picocontainer.PicoCompositionException;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.containers.PropertiesPicoContainer;
-import org.picocontainer.containers.SystemPropertiesPicoContainer;
+import org.picocontainer.DefaultPicoContainer;
+import org.picocontainer.lifecycle.LifecycleState;
+import org.picocontainer.behaviors.Caching;
+import org.picocontainer.behaviors.Storing;
 import org.picocontainer.parameters.ConstantParameter;
 import org.picocontainer.references.SimpleReference;
 
@@ -49,24 +44,23 @@
  * <p>
  * The containers are configured via context-params in web.xml, in two ways:
  * <ol>
- *   <li>A NanoContainer script via a parameter whose name is nanocontainer.<language>,
- *       where <language> is one of the supported scripting languages,
- *       see {@link org.nanocontainer.script.ScriptedContainerBuilderFactory ScriptedContainerBuilderFactory}.
- *       The parameter value can be either an inlined script (enclosed in <![CDATA[]>), or a resource path for
- *       the script (relative to the webapp context).
- *   </li>
- *   <li>A ContainerComposer class via the parameter name
- *   {@link KeyConstants#CONTAINER_COMPOSER CONTAINER_COMPOSER},
- *   which can be configured via an optional parameter
- *   {@link KeyConstants#CONTAINER_COMPOSER_CONFIGURATION CONTAINER_COMPOSER_CONFIGURATION}.
- *   </li>
+ * <li>A NanoContainer script via a parameter whose name is nanocontainer.<language>,
+ * where <language> is one of the supported scripting languages,
+ * see {@link org.nanocontainer.script.ScriptedContainerBuilderFactory ScriptedContainerBuilderFactory}.
+ * The parameter value can be either an inlined script (enclosed in <![CDATA[]>), or a resource path for
+ * the script (relative to the webapp context).
+ * </li>
+ * <li>A ContainerComposer class via the parameter name
+ * {@link KeyConstants#CONTAINER_COMPOSER CONTAINER_COMPOSER},
+ * which can be configured via an optional parameter
+ * {@link KeyConstants#CONTAINER_COMPOSER_CONFIGURATION CONTAINER_COMPOSER_CONFIGURATION}.
+ * </li>
  * </ol>
  * </p>
- * <p><b>Note:</b> if one is interested in both application-scoped and session-scoped components, the 
+ * <p><b>Note:</b> if one is interested in both application-scoped and session-scoped components, the
  * {@link org.nanocontainer.nanowar.ServletContainerListener} should be configured in the web.xml.
  * </p>
- * @see org.nanocontainer.nanowar.NanoWarSessionListener
- * @see org.nanocontainer.nanowar.ServletContainerListener
+ *
  * @author Michael Rimov
  * @author Joe Walnes
  * @author Aslak Helles&oslash;y
@@ -74,106 +68,92 @@
  * @author Paul Hammant
  * @author Mauro Talevi
  * @author Konstantin Pribluda
+ * @see org.nanocontainer.nanowar.NanoWarSessionListener
+ * @see org.nanocontainer.nanowar.ServletContainerListener
  */
 @SuppressWarnings("serial")
 public class NanoWarContextListener extends AbstractNanoWarListener implements ServletContextListener, KeyConstants {
 
-	/**
-	 * handle context initialisation.  we need to create container 
-	 * and store it into proper reference
-	 */
+    /**
+     * handle context initialisation.  we need to create container
+     * and store it into proper reference
+     */
     public void contextInitialized(ServletContextEvent event) {
         ServletContext context = event.getServletContext();
-            ContainerBuilder containerBuilder = createContainerBuilder(context);
-            ObjectReference<ContainerBuilder> builderRef = new ApplicationScopeReference<ContainerBuilder>(context, BUILDER);
-            builderRef.set(containerBuilder);
 
-            SimpleReference<PicoContainer> parentRef = new SimpleReference<PicoContainer>();
+        DefaultPicoContainer sessionContainer;
+        DefaultPicoContainer requestContainer;
 
-            // check whether we have to provide system roperties container
-            if(context.getInitParameter(SYSTEM_PROPERTIES_CONTAINER) != null) {
-            	parentRef.set(new SystemPropertiesPicoContainer());
-            }
-            
-            // maybe there are properties specified? 
-            String propertiesResource = context.getInitParameter(PROPERTIES_CONTAINER);
-            if(propertiesResource != null) {
-            	Properties properties = new Properties();
-                try {
-                    properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(propertiesResource));
-                } catch (IOException e) {
-                    event.getServletContext().log(e.getMessage(), e);
-                    throw new PicoCompositionException(e);
-                }
-                parentRef.set(new PropertiesPicoContainer(properties,parentRef.get()));
-            }
-            
-            ObjectReference containerRef = new ApplicationScopeReference(context, APPLICATION_CONTAINER);
-            containerBuilder.buildContainer(containerRef, parentRef, context, false);
+        Storing sessionStoring = new Storing();
+        Storing requestStoring = new Storing();
+
+        DefaultPicoContainer appContainer = new DefaultPicoContainer(new Caching());
+        appContainer.setName("application");
+        String builderClassName = context.getInitParameter("container-builder-class") ;
+        populateContainer(appResources, new ApplicationContainerHolder(appContainer), null, builderClassName);
+
+        context.setAttribute(ApplicationContainerHolder.class.getName(), new ApplicationContainerHolder(appContainer));
+
+        sessionStoring = new Storing();
+        sessionContainer = new DefaultPicoContainer(sessionStoring, appContainer);
+        sessionContainer.setName("session");
+        LifecycleState sessionStateModel = new ThreadLocalLifecycleState();
+        sessionContainer.setLifecycleState(sessionStateModel);
+        populateContainer(sessionResources, sessionContainer, appContainer, builderClassName);
+
+        context.setAttribute(SessionContainerHolder.class.getName(), new SessionContainerHolder(sessionContainer, sessionStoring, sessionStateModel));
+
+        requestStoring = new Storing();
+        requestContainer = new DefaultPicoContainer(requestStoring, sessionContainer);
+        requestContainer.setName("request");
+        LifecycleState requestStateModel = new ThreadLocalLifecycleState();
+        requestContainer.setLifecycleState(requestStateModel);
+        populateContainer(requestResources, requestContainer, sessionContainer, builderClassName);
+
+        context.setAttribute(RequestContainerHolder.class.getName(), new RequestContainerHolder(requestContainer, requestStoring, requestStateModel));
+
     }
 
-    /**
-     * TODO: this is kind of scary and has   big confusion  potential ( i.e.: collision with properties specification  )
-     * @param context
-     * @return
-     */
-    private ContainerBuilder createContainerBuilder(ServletContext context) {
-        Enumeration initParameters = context.getInitParameterNames();
-        while (initParameters.hasMoreElements()) {
-            String initParameter = (String) initParameters.nextElement();
-            if (initParameter.startsWith(NANOCONTAINER_PREFIX)) {
-                String builderClassName = getBuilderClassName(initParameter);
-                String script = context.getInitParameter(initParameter);
-                Reader scriptReader;
-                if (script.trim().startsWith("/") && !(script.trim().startsWith("//") || script.trim().startsWith("/*"))) {
-                    // the script isn't inlined, but in a separate file.
-                    scriptReader = new InputStreamReader(context.getResourceAsStream(script));
-                } else {
-                    scriptReader = new StringReader(script);
-                }
-                ScriptedContainerBuilderFactory scriptedContainerBuilderFactory = new ScriptedContainerBuilderFactory(scriptReader, builderClassName, Thread.currentThread().getContextClassLoader());
-                return scriptedContainerBuilderFactory.getContainerBuilder();
-            }
-            if (initParameter.equals(CONTAINER_COMPOSER)) {
-                ContainerComposer containerComposer = createContainerComposer(context);
-                return new DefaultContainerBuilder(containerComposer);
-            }
-        }
-        throw new PicoCompositionException("Couldn't create a builder from context parameters in web.xml");
+    public void contextDestroyed(ServletContextEvent event) {
+        ServletContext context = event.getServletContext();
+        ApplicationContainerHolder ach = (ApplicationContainerHolder) context.getAttribute(ApplicationContainerHolder.class.getName());
+        ach.getContainer().stop();
+        ach.getContainer().dispose();
     }
 
-    private String getBuilderClassName(String scriptName){
-        String extension = scriptName.substring(scriptName.lastIndexOf('.'));
-        ScriptBuilderResolver resolver = new ScriptBuilderResolver();
-        return resolver.getBuilderClassName(extension);
+    private void populateContainer(String resources, MutablePicoContainer container, MutablePicoContainer parent, String containerBuilderClassName) {
+        String[] resourcePaths = toCSV(resources);
+        for (String resourcePath : resourcePaths) {
+            ContainerPopulator populator = createContainerPopulator(getResource(resourcePath), parent, containerBuilderClassName);
+            populator.populateContainer(container);
+        }
     }
 
-    private ContainerComposer createContainerComposer(ServletContext context) {
-        String containerComposerClassName = context.getInitParameter(CONTAINER_COMPOSER);
-        // disposable container used to instantiate the ContainerComposer
-        NanoContainer nanoContainer = new DefaultNanoContainer(Thread.currentThread().getContextClassLoader());
-        String script = context.getInitParameter(CONTAINER_COMPOSER_CONFIGURATION);
-        PicoContainer picoConfiguration = null;
-        if ( script != null ){
-            Reader scriptReader = new InputStreamReader(context.getResourceAsStream(script));
-            String builderClassName = getBuilderClassName(script);
-            ScriptedContainerBuilderFactory scriptedContainerBuilderFactory = new ScriptedContainerBuilderFactory(scriptReader, builderClassName, Thread.currentThread().getContextClassLoader());
-            picoConfiguration = buildContainer(scriptedContainerBuilderFactory.getContainerBuilder());
+    private static final String COMMA = ",";
+
+    private String[] toCSV(String resources) {
+        StringTokenizer st = new StringTokenizer(resources, COMMA);
+        List<String> tokens = new ArrayList<String>();
+        while (st.hasMoreTokens()) {
+            tokens.add(st.nextToken().trim());
         }
-        ComponentAdapter componentAdapter;
-        if ( picoConfiguration != null ){
-            componentAdapter = nanoContainer.addComponent(containerComposerClassName, new ClassName(containerComposerClassName), new ConstantParameter(picoConfiguration)).getComponentAdapter(containerComposerClassName);
-        } else {
-            ClassName className = new ClassName(containerComposerClassName);
-            MutablePicoContainer mutablePicoContainer = nanoContainer.addComponent(className);
-            componentAdapter = mutablePicoContainer.getComponentAdapter(className);
-        }
-        return (ContainerComposer) componentAdapter.getComponentInstance(nanoContainer);
+        return tokens.toArray(new String[tokens.size()]);
     }
 
-    public void contextDestroyed(ServletContextEvent event) {
-        ServletContext context = event.getServletContext();
-        ObjectReference containerRef = new ApplicationScopeReference(context, APPLICATION_CONTAINER);
-        killContainer(containerRef);
+    private Reader getResource(String resource) {
+        return new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource));
     }
+
+    private ContainerPopulator createContainerPopulator(Reader reader, MutablePicoContainer parent, String containerBuilderClassName) {
+        NanoContainer nano = new DefaultNanoContainer(Thread.currentThread().getContextClassLoader());
+        nano.addComponent(containerBuilderClassName,
+                new ClassName(containerBuilderClassName), new ConstantParameter(reader),
+                new ConstantParameter(Thread.currentThread().getContextClassLoader()));
+        ContainerBuilder containerBuilder = (ContainerBuilder) nano
+                .getComponent(containerBuilderClassName);
+        ObjectReference parentRef = new SimpleReference();
+        parentRef.set(parent);
+        containerBuilder.buildContainer(new SimpleReference(), parentRef, null, false);
+        return (ContainerPopulator) containerBuilder;
+    }
 }
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionContainerHolder.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionContainerHolder.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionContainerHolder.java	(revision 0)
@@ -0,0 +1,30 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.DefaultPicoContainer;
+import org.picocontainer.lifecycle.LifecycleState;
+import org.picocontainer.behaviors.Storing;
+
+public class SessionContainerHolder {
+
+    private final DefaultPicoContainer container;
+    private final Storing storing;
+    private final ThreadLocalLifecycleState lifecycleState;
+
+    public SessionContainerHolder(DefaultPicoContainer container, Storing storing, ThreadLocalLifecycleState lifecycleState) {
+        this.container = container;
+        this.storing = storing;
+        this.lifecycleState = lifecycleState;
+    }
+
+    DefaultPicoContainer getContainer() {
+        return container;
+    }
+
+    Storing getStoring() {
+        return storing;
+    }
+
+    ThreadLocalLifecycleState getLifecycleStateModel() {
+        return lifecycleState;
+    }
+}
\ No newline at end of file
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/RequestContainerHolder.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/RequestContainerHolder.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/RequestContainerHolder.java	(revision 0)
@@ -0,0 +1,30 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.DefaultPicoContainer;
+import org.picocontainer.lifecycle.LifecycleState;
+import org.picocontainer.behaviors.Storing;
+
+public class RequestContainerHolder {
+
+    private final DefaultPicoContainer container;
+    private final Storing storing;
+    private final ThreadLocalLifecycleState lifecycleState;
+
+    public RequestContainerHolder(DefaultPicoContainer container, Storing storing, ThreadLocalLifecycleState lifecycleState) {
+        this.container = container;
+        this.storing = storing;
+        this.lifecycleState = lifecycleState;
+    }
+
+    DefaultPicoContainer getContainer() {
+        return container;
+    }
+
+    Storing getStoring() {
+        return storing;
+    }
+
+    ThreadLocalLifecycleState getLifecycleStateModel() {
+        return lifecycleState;
+    }
+}
\ No newline at end of file
Index: nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionStoreHolder.java
===================================================================
--- nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionStoreHolder.java	(revision 0)
+++ nanoextras/nanowar/nanowar/src/java/org/nanocontainer/nanowar/SessionStoreHolder.java	(revision 0)
@@ -0,0 +1,24 @@
+package org.nanocontainer.nanowar;
+
+import org.picocontainer.behaviors.Storing;
+import org.picocontainer.lifecycle.DefaultLifecycleState;
+
+public class SessionStoreHolder {
+    private final Storing.StoreWrapper storeWrapper;
+    private final DefaultLifecycleState defaultLifecycleState;
+
+    public SessionStoreHolder(Storing.StoreWrapper storeWrapper,
+                              DefaultLifecycleState defaultLifecycleState) {
+
+        this.storeWrapper = storeWrapper;
+        this.defaultLifecycleState = defaultLifecycleState;
+    }
+
+    Storing.StoreWrapper getStoreWrapper() {
+        return storeWrapper;
+    }
+
+    DefaultLifecycleState getDefaultLifecycleState() {
+        return defaultLifecycleState;
+    }
+}
Index: nanoextras/nanowar/pom.xml
===================================================================
--- nanoextras/nanowar/pom.xml	(revision 4422)
+++ nanoextras/nanowar/pom.xml	(working copy)
@@ -95,7 +95,7 @@
             <dependency>
                 <groupId>org.picocontainer</groupId>
                 <artifactId>picocontainer-gems</artifactId>
-                <version>2.0-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
                 <optional>true</optional>
             </dependency>
             <dependency>
@@ -120,7 +120,7 @@
             <dependency>
                 <groupId>org.picocontainer</groupId>
                 <artifactId>picocontainer-tck</artifactId>
-                <version>2.0-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
                 <scope>test</scope>
             </dependency>
             <dependency>
Index: nanoextras/struts2/picocontainer-struts2/pom.xml
===================================================================
--- nanoextras/struts2/picocontainer-struts2/pom.xml	(revision 4422)
+++ nanoextras/struts2/picocontainer-struts2/pom.xml	(working copy)
@@ -17,7 +17,7 @@
     <dependency>
       <groupId>org.picocontainer</groupId>
       <artifactId>picocontainer</artifactId>
-      <version>2.3-SNAPSHOT</version>
+      <version>2.4-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>javax.servlet</groupId>
Index: nanoextras/pom.xml
===================================================================
--- nanoextras/pom.xml	(revision 4422)
+++ nanoextras/pom.xml	(working copy)
@@ -8,10 +8,7 @@
     <url>http://www.nanocontainer.org</url>
 
     <modules>
-        <module>nanosar</module>
         <module>nanowar</module>
-        <module>remoting</module>
-        <module>persistence</module>
     </modules>
 
     <organization>
@@ -113,17 +110,17 @@
             <dependency>
                 <groupId>org.picocontainer</groupId>
                 <artifactId>picocontainer</artifactId>
-                <version>2.0-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.picocontainer</groupId>
                 <artifactId>picocontainer-gems</artifactId>
-                <version>2.0-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.picocontainer</groupId>
                 <artifactId>picocontainer-tck</artifactId>
-                <version>2.0-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>${pom.groupId}</groupId>
Index: pico/container/src/test/org/picocontainer/lifecycle/DefaultLifecycleStateTestCase.java
===================================================================
--- pico/container/src/test/org/picocontainer/lifecycle/DefaultLifecycleStateTestCase.java	(revision 0)
+++ pico/container/src/test/org/picocontainer/lifecycle/DefaultLifecycleStateTestCase.java	(revision 0)
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (C) PicoContainer Organization. All rights reserved.            *
+ * ------------------------------------------------------------------------- *
+ * The software in this package is published under the terms of the BSD      *
+ * style license a copy of which has been included with this distribution in *
+ * the LICENSE.txt file.                                                     *
+ *****************************************************************************/
+package org.picocontainer.lifecycle;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.picocontainer.lifecycle.DefaultLifecycleState.State.CONSTRUCTED;
+import static org.picocontainer.lifecycle.DefaultLifecycleState.State.DISPOSED;
+import static org.picocontainer.lifecycle.DefaultLifecycleState.State.STARTED;
+import static org.picocontainer.lifecycle.DefaultLifecycleState.State.STOPPED;
+
+import org.junit.Test;
+
+/**
+ * @author Michael Rimov
+ */
+public class DefaultLifecycleStateTestCase {
+
+	@Test public void testIsStartAllowedOptions() {
+		assertTrue(CONSTRUCTED.isStartAllowed());
+		assertFalse(STARTED.isStartAllowed());
+		assertTrue(STOPPED.isStartAllowed());
+		assertFalse(DISPOSED.isStartAllowed());
+	}
+
+	@Test public void testIsStopAllowedOptions() {
+		assertFalse(CONSTRUCTED.isStopAllowed());
+		assertTrue(STARTED.isStopAllowed());
+		assertFalse(STOPPED.isStopAllowed());
+		assertFalse(DISPOSED.isStopAllowed());
+	}
+
+	@Test public void testIsDisposeAllowedOptions() {
+		assertTrue(CONSTRUCTED.isDisposedAllowed());
+		assertFalse(STARTED.isDisposedAllowed());
+		assertTrue(STOPPED.isDisposedAllowed());
+		assertFalse(DISPOSED.isDisposedAllowed());
+	}
+	
+}
Index: pico/container/src/test/org/picocontainer/lifecycle/LifecycleStateTestCase.java
===================================================================
--- pico/container/src/test/org/picocontainer/lifecycle/LifecycleStateTestCase.java	(revision 4422)
+++ pico/container/src/test/org/picocontainer/lifecycle/LifecycleStateTestCase.java	(working copy)
@@ -1,45 +0,0 @@
-/*****************************************************************************
- * Copyright (C) PicoContainer Organization. All rights reserved.            *
- * ------------------------------------------------------------------------- *
- * The software in this package is published under the terms of the BSD      *
- * style license a copy of which has been included with this distribution in *
- * the LICENSE.txt file.                                                     *
- *****************************************************************************/
-package org.picocontainer.lifecycle;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.picocontainer.lifecycle.LifecycleState.CONSTRUCTED;
-import static org.picocontainer.lifecycle.LifecycleState.DISPOSED;
-import static org.picocontainer.lifecycle.LifecycleState.STARTED;
-import static org.picocontainer.lifecycle.LifecycleState.STOPPED;
-
-import org.junit.Test;
-
-/**
- * @author Michael Rimov
- */
-public class LifecycleStateTestCase {
-
-	@Test public void testIsStartAllowedOptions() {
-		assertTrue(CONSTRUCTED.isStartAllowed());
-		assertFalse(STARTED.isStartAllowed());
-		assertTrue(STOPPED.isStartAllowed());
-		assertFalse(DISPOSED.isStartAllowed());
-	}
-
-	@Test public void testIsStopAllowedOptions() {
-		assertFalse(CONSTRUCTED.isStopAllowed());
-		assertTrue(STARTED.isStopAllowed());
-		assertFalse(STOPPED.isStopAllowed());
-		assertFalse(DISPOSED.isStopAllowed());
-	}
-
-	@Test public void testIsDisposeAllowedOptions() {
-		assertTrue(CONSTRUCTED.isDisposedAllowed());
-		assertFalse(STARTED.isDisposedAllowed());
-		assertTrue(STOPPED.isDisposedAllowed());
-		assertFalse(DISPOSED.isDisposedAllowed());
-	}
-	
-}
Index: pico/container/src/java/org/picocontainer/lifecycle/LifecycleState.java
===================================================================
--- pico/container/src/java/org/picocontainer/lifecycle/LifecycleState.java	(revision 4422)
+++ pico/container/src/java/org/picocontainer/lifecycle/LifecycleState.java	(working copy)
@@ -12,72 +12,19 @@
  * Current lifecycle state of the container.
  * @author Michael Rimov
  */
-public enum LifecycleState {
+public interface LifecycleState {
 
-	/**
-	 * Default state of a container once it has been built.
-	 */
-	CONSTRUCTED,
-	
-	/**
-	 * 'Start' Lifecycle has been called.
-	 */
-	STARTED,
-	
-	/**
-	 * 'Stop' lifecycle has been called.
-	 */
-	STOPPED,
-	
-	/**
-	 * 'Dispose' lifecycle has been called.
-	 */
-	DISPOSED;
-	
-	
-	/**
-	 * Start is normally allowed if the object is constructed or
-	 * already stopped.  It is not allowed if the system is already
-	 * started or disposed.
-	 * @return true if start lifecycle methods should be allowed.
-	 */
-	public boolean isStartAllowed() {
-		if (this.equals(CONSTRUCTED) || this.equals(STOPPED)) {
-			return true;
-		}
-		
-		return false;
-	}
-	
-	/**
-	 * Returns true if stop is normally allowed in the container
-	 * lifecycle.  Stop is normally only allowed while the current
-	 * container state is STARTED.
-	 * @return true if stop is allowed.
-	 */
-	public boolean isStopAllowed() {
-		if (this.equals(STARTED)) {
-			return true;
-		}
-		
-		return false;
-	}
-	
-	public boolean isStarted() {
-		return this.equals(STARTED);
-	}
-	
-	/**
-	 * Returns true if the dispose lifecycle method is normally called.
-	 * Dispose is normally only allowed if the object has not been already
-	 * disposed, and it is not started.
-	 * @return
-	 */
-	public boolean isDisposedAllowed() {
-		if (this.equals(STOPPED) || this.equals(CONSTRUCTED)) {
-			return true;
-		}
-		
-		return false;
-	}
+    void removingComponent();
+
+    void starting();
+
+    void stopping();
+
+    void stopped();
+
+    boolean isStarted();
+
+    void disposing();
+
+    void disposed();
 }
Index: pico/container/src/java/org/picocontainer/lifecycle/DefaultLifecycleState.java
===================================================================
--- pico/container/src/java/org/picocontainer/lifecycle/DefaultLifecycleState.java	(revision 0)
+++ pico/container/src/java/org/picocontainer/lifecycle/DefaultLifecycleState.java	(revision 0)
@@ -0,0 +1,125 @@
+package org.picocontainer.lifecycle;
+
+import org.picocontainer.PicoCompositionException;
+
+import java.io.Serializable;
+
+public class DefaultLifecycleState implements LifecycleState, Serializable {
+
+    private State state = State.CONSTRUCTED;
+
+    public void removingComponent() {
+        if (state == State.STARTED) {
+            throw new PicoCompositionException("Cannot remove components after the container has started");
+        }
+
+        if (state == State.DISPOSED) {
+            throw new PicoCompositionException("Cannot remove components after the container has been disposed");
+        }
+    }
+
+    public void starting() {
+        if (!state.isStartAllowed()) {
+			throw new IllegalStateException("Cannot start.  Current container state was: " + state);
+    	}
+
+    	state = State.STARTED;
+
+    }
+
+    public void stopping() {
+        if (!state.isStopAllowed()) {
+            throw new IllegalStateException("Cannot stop.  Current container state was: " + state);
+        }
+    }
+
+    public void stopped() {
+        state = State.STOPPED;
+    }
+
+    public boolean isStarted() {
+        return state == State.STARTED;
+    }
+
+    public void disposing() {
+        if (!state.isDisposedAllowed()) {
+            throw new IllegalStateException("Cannot dispose.  Current lifecycle state is: " + state);
+        }
+
+    }
+
+    public void disposed() {
+        state = State.DISPOSED;
+    }
+
+    public enum State {
+
+	/**
+	 * Default state of a container once it has been built.
+	 */
+	CONSTRUCTED,
+
+	/**
+	 * 'Start' Lifecycle has been called.
+	 */
+	STARTED,
+
+	/**
+	 * 'Stop' lifecycle has been called.
+	 */
+	STOPPED,
+
+	/**
+	 * 'Dispose' lifecycle has been called.
+	 */
+	DISPOSED;
+
+
+	/**
+	 * Start is normally allowed if the object is constructed or
+	 * already stopped.  It is not allowed if the system is already
+	 * started or disposed.
+	 * @return true if start lifecycle methods should be allowed.
+	 */
+	public boolean isStartAllowed() {
+		if (this.equals(CONSTRUCTED) || this.equals(STOPPED)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns true if stop is normally allowed in the container
+	 * lifecycle.  Stop is normally only allowed while the current
+	 * container state is STARTED.
+	 * @return true if stop is allowed.
+	 */
+	public boolean isStopAllowed() {
+		if (this.equals(STARTED)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	public boolean isStarted() {
+		return this.equals(STARTED);
+	}
+
+	/**
+	 * Returns true if the dispose lifecycle method is normally called.
+	 * Dispose is normally only allowed if the object has not been already
+	 * disposed, and it is not started.
+	 * @return
+	 */
+	public boolean isDisposedAllowed() {
+		if (this.equals(STOPPED) || this.equals(CONSTRUCTED)) {
+			return true;
+		}
+
+		return false;
+	}
+}
+
+}
Index: pico/container/src/java/org/picocontainer/DefaultPicoContainer.java
===================================================================
--- pico/container/src/java/org/picocontainer/DefaultPicoContainer.java	(revision 4422)
+++ pico/container/src/java/org/picocontainer/DefaultPicoContainer.java	(working copy)
@@ -20,8 +20,8 @@
 import org.picocontainer.injectors.AbstractInjector;
 import org.picocontainer.injectors.AdaptingInjection;
 import org.picocontainer.lifecycle.LifecycleState;
-import static org.picocontainer.lifecycle.LifecycleState.*;
 import org.picocontainer.lifecycle.StartableLifecycleStrategy;
+import org.picocontainer.lifecycle.DefaultLifecycleState;
 import org.picocontainer.monitors.NullComponentMonitor;
 
 import java.io.Serializable;
@@ -96,9 +96,9 @@
     /**
      * Current state of the container.
      */
-    private LifecycleState lifecycleState = CONSTRUCTED;
-    
-    /** 
+    private LifecycleState lifecycleState = new DefaultLifecycleState();
+
+    /**
      * Keeps track of child containers started status.
      */
     private final Set<WeakReference<PicoContainer>> childrenStarted = new HashSet<WeakReference<PicoContainer>>();
@@ -384,14 +384,8 @@
 
     /** {@inheritDoc} **/
     public <T> ComponentAdapter<T> removeComponent(final Object componentKey) {
-        if (lifecycleState == STARTED) {
-            throw new PicoCompositionException("Cannot remove components after the container has started");
-        }
-        
-        if (lifecycleState == DISPOSED) {
-            throw new PicoCompositionException("Cannot remove components after the container has been disposed");        	
-        }
-        
+        lifecycleState.removingComponent();
+
         ComponentAdapter<T> adapter = (ComponentAdapter<T>) getComponentKeyToAdapterCache().remove(componentKey);
         getModifiableComponentAdapterList().remove(adapter);
         getOrderedComponentAdapters().remove(adapter);    	
@@ -632,12 +626,8 @@
      * @see #removeChildContainer(PicoContainer)
      */
     public void start() {
-    	
-    	if (!lifecycleState.isStartAllowed()) {
-			throw new IllegalStateException("Cannot start.  Current container state was: " + lifecycleState);    		
-    	}
 
-    	lifecycleState = STARTED;
+        lifecycleState.starting();
 
         startAdapters();
         childrenStarted.clear();
@@ -665,11 +655,10 @@
      * @see #removeChildContainer(PicoContainer)
      */
     public void stop() {
-    	if (!lifecycleState.isStopAllowed()) {
-			throw new IllegalStateException("Cannot stop.  Current container state was: " + lifecycleState);    		
-    	}
 
-    	for (PicoContainer child : children) {
+        lifecycleState.stopping();
+
+        for (PicoContainer child : children) {
             if (childStarted(child)) {
                 if (child instanceof Startable) {
                     ((Startable)child).stop();
@@ -677,7 +666,7 @@
             }
         }
         stopAdapters();
-        lifecycleState = STOPPED;
+        lifecycleState.stopped();
     }
 
     /**
@@ -719,20 +708,23 @@
     	if (lifecycleState.isStarted()) {
     		stop();
     	}
-    	
-    	if (!lifecycleState.isDisposedAllowed()) {
-			throw new IllegalStateException("Cannot dispose.  Current lifecycle state is: " + lifecycleState);    		
-    	}
 
+        lifecycleState.disposing();
+
         for (PicoContainer child : children) {
             if (child instanceof MutablePicoContainer) {
                 ((Disposable)child).dispose();
             }
         }
         disposeAdapters();
-        lifecycleState = DISPOSED;
+
+        lifecycleState.disposed();
     }
 
+    public void setLifecycleState(LifecycleState lifecycleState) {
+        this.lifecycleState = lifecycleState;
+    }
+
     public MutablePicoContainer makeChildContainer() {
         DefaultPicoContainer pc = new DefaultPicoContainer(componentFactory, lifecycleStrategy, this);
         addChildContainer(pc);
@@ -775,7 +767,7 @@
     	checkCircularChildDependencies(child);
     	if (children.add(child)) {
             // @todo Should only be added if child container has also be started
-            if (lifecycleState == STARTED) {
+            if (lifecycleState.isStarted()) {
                 childrenStarted.add(new WeakReference<PicoContainer>(child));
             }
         }
Index: nano/pom.xml
===================================================================
--- nano/pom.xml	(revision 4422)
+++ nano/pom.xml	(working copy)
@@ -122,17 +122,17 @@
       <dependency>
         <groupId>org.picocontainer</groupId>
         <artifactId>picocontainer</artifactId>
-        <version>2.3-SNAPSHOT</version>
+        <version>2.4-SNAPSHOT</version>
       </dependency>
       <dependency>
         <groupId>org.picocontainer</groupId>
         <artifactId>picocontainer-gems</artifactId>
-        <version>2.3-SNAPSHOT</version>
+        <version>2.4-SNAPSHOT</version>
       </dependency>
       <dependency>
         <groupId>org.picocontainer</groupId>
         <artifactId>picocontainer-tck</artifactId>
-        <version>2.3-SNAPSHOT</version>
+        <version>2.4-SNAPSHOT</version>
       </dependency>
       <dependency>
         <groupId>${pom.groupId}</groupId>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.