You are viewing a plain text version of this content. The canonical link for it is here.
Posted to pluto-scm@portals.apache.org by ms...@apache.org on 2016/04/14 14:29:23 UTC

[43/50] [abbrv] portals-pluto git commit: worked on contextual enablement in AsyncContext.start() thread.

worked on contextual enablement in AsyncContext.start() thread.


Project: http://git-wip-us.apache.org/repos/asf/portals-pluto/repo
Commit: http://git-wip-us.apache.org/repos/asf/portals-pluto/commit/27e17ae6
Tree: http://git-wip-us.apache.org/repos/asf/portals-pluto/tree/27e17ae6
Diff: http://git-wip-us.apache.org/repos/asf/portals-pluto/diff/27e17ae6

Branch: refs/heads/master
Commit: 27e17ae6445ec12d0d68517e08c379461a382371
Parents: aae89a3
Author: Scott Nicklous <ms...@apache.org>
Authored: Mon Apr 4 17:03:52 2016 +0200
Committer: Scott Nicklous <ms...@apache.org>
Committed: Mon Apr 4 17:03:52 2016 +0200

----------------------------------------------------------------------
 .../apache/portals/samples/AsyncDialogBean.java |  45 ++++-
 .../portals/samples/AsyncPortletResource.java   |  35 ++--
 .../samples/PortletRequestRandomNumberBean.java |   3 +-
 .../src/main/webapp/WEB-INF/jsp/asyncDialog.jsp |  14 +-
 .../src/main/webapp/WEB-INF/jsp/asyncOutput.jsp |   6 +-
 .../pluto/container/PortletAsyncContext.java    |  11 +-
 .../pluto/container/driver/PortletServlet3.java |  59 +++----
 .../PortletRequestScopedBeanHolder.java         |  25 ++-
 .../processor/PortletSessionBeanHolder.java     |  21 +++
 .../processor/PortletStateScopedBeanHolder.java |  25 ++-
 .../container/PortletAsyncContextImpl.java      | 167 +++++++++++++++----
 .../container/PortletAsyncContextualRunner.java |  68 ++++++++
 .../container/PortletAsyncListener.java         |  27 ++-
 13 files changed, 419 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
index 5fa7245..c5717bc 100644
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
@@ -30,7 +30,6 @@ import javax.portlet.annotations.ActionMethod;
 import javax.portlet.annotations.PortletSerializable;
 import javax.portlet.annotations.RenderMethod;
 import javax.portlet.annotations.RenderStateScoped;
-import javax.servlet.DispatcherType;
 
 /**
  * Render state scoped bean. The bean is stored as a render parameter, so it
@@ -41,9 +40,16 @@ import javax.servlet.DispatcherType;
 public class AsyncDialogBean implements PortletSerializable {
    private static final Logger LOGGER = Logger.getLogger(AsyncDialogBean.class.getName());
 
+   // defines how output is to be generated
    public enum OutputType {
       TEXT, INC, FWD, DISPATCH, AUTO
    }
+   
+   // defines how timeouts are to be handled by the listener
+   // Ignore, complete, or dispatch
+   public enum TimeoutType {
+      NOP, CPL, DIS;
+   }
 
    public static final String PARAM_MSG      = "msg";
    public static final String PARAM_DELAY    = "delay";
@@ -55,6 +61,10 @@ public class AsyncDialogBean implements PortletSerializable {
    public static final String PARAM_TYPE_INC = OutputType.INC.toString();
    public static final String PARAM_TYPE_FWD = OutputType.FWD.toString();
    public static final String PARAM_TYPE_DIS = OutputType.DISPATCH.toString();
+   public static final String PARAM_TO     = "toType";
+   public static final String PARAM_TO_NOP = TimeoutType.NOP.toString();
+   public static final String PARAM_TO_CPL = TimeoutType.CPL.toString();
+   public static final String PARAM_TO_DIS = TimeoutType.DIS.toString();
 
    private int                delay;
    private int                reps;
@@ -62,6 +72,7 @@ public class AsyncDialogBean implements PortletSerializable {
    private String             msg;
    private boolean            autoDispatch;
    private boolean            useFilter;
+   private TimeoutType        handleTimeout;
 
    /**
     * This method is called by the portlet container to initialize the bean at
@@ -70,12 +81,14 @@ public class AsyncDialogBean implements PortletSerializable {
    @Override
    public void deserialize(String[] state) {
       if (state.length == 0) {
+         // set default values
          delay = 1000;
          reps = 1;
          type = OutputType.TEXT;
          msg = null;
          autoDispatch = true;
          useFilter = false;
+         handleTimeout = TimeoutType.CPL;
       } else {
          delay = Integer.parseInt(state[0]);
          reps = Integer.parseInt(state[1]);
@@ -83,6 +96,7 @@ public class AsyncDialogBean implements PortletSerializable {
          msg = state[3];
          autoDispatch = Boolean.parseBoolean(state[4]);
          useFilter = Boolean.parseBoolean(state[5]);
+         handleTimeout = TimeoutType.valueOf(state[6]);
       }
       LOGGER.fine("deserialized: " + Arrays.asList(state).toString());
    }
@@ -93,7 +107,8 @@ public class AsyncDialogBean implements PortletSerializable {
     */
    @Override
    public String[] serialize() {
-      String[] state = { "" + delay, "" + reps, type.toString(), msg, ""+autoDispatch, ""+useFilter };
+      String[] state = { "" + delay, "" + reps, type.toString(), msg, 
+            ""+autoDispatch, ""+useFilter, handleTimeout.toString() };
       LOGGER.fine("serialized: " + Arrays.asList(state).toString());
       return state;
    }
@@ -188,6 +203,20 @@ public class AsyncDialogBean implements PortletSerializable {
    }
 
    /**
+    * @return the handleTimeout
+    */
+   public TimeoutType getHandleTimeout() {
+      return handleTimeout;
+   }
+
+   /**
+    * @param handleTimeout the handleTimeout to set
+    */
+   public void setHandleTimeout(TimeoutType handleTimeout) {
+      this.handleTimeout = handleTimeout;
+   }
+
+   /**
     * Displays the dialog
     * 
     * @return the action form as string
@@ -263,7 +292,17 @@ public class AsyncDialogBean implements PortletSerializable {
          useFilter = false;
       }
 
-      String[] state = { "" + delay, "" + reps, type.toString(), msg, "" + autoDispatch };
+      String strto = req.getActionParameters().getValue(PARAM_TO);
+      if (strto != null) {
+         try {
+            handleTimeout = TimeoutType.valueOf(strto);
+         } catch (Exception e) {
+            msg = "try again. bad timeout handling: " + strto;
+         }
+      }
+
+      String[] state = { "" + delay, "" + reps, type.toString(), msg, 
+            ""+autoDispatch, ""+useFilter, handleTimeout.toString() };
       LOGGER.fine("Resulting params: " + Arrays.asList(state).toString());
    }
 

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
index 6cad2fb..6cbaebc 100644
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
@@ -53,19 +53,21 @@ public class AsyncPortletResource {
    private final static String ATTRIB_AUTO = "auto";
    public  final static String ATTRIB_TITLE = "title";
 
-   private class AsyncRunnable implements Runnable {
+   public static class AsyncRunnable implements Runnable {
 
-      private final AsyncContext ctx;
-      private final int          delay;
-      private final OutputType   type;
+      private AsyncContext ctx;
+      private int          delay;
+      private OutputType   type;
+      
+      @Inject private PortletRequestRandomNumberBean reqnum;
 
-      public AsyncRunnable(AsyncContext ctx, int delay, OutputType type) {
+      public void init(AsyncContext ctx, int delay, OutputType type) {
          this.ctx = ctx;
          this.delay = delay;
          this.type = type;
          
          StringBuilder txt = new StringBuilder(128);
-         txt.append("Constructing runnable.");
+         txt.append("Initializing runnable.");
          txt.append(" delay: ").append(delay);
          txt.append(", type: ").append(type);
          LOGGER.fine(txt.toString());
@@ -93,8 +95,12 @@ public class AsyncPortletResource {
                LOGGER.fine("Producing text output.");
                StringBuilder txt = new StringBuilder(128);
                txt.append("<h5>Thread producing text output for portlet: " + portletName + "</h5>");
-               txt.append("<p>dispatcher type: ").append(hreq.getDispatcherType().toString());
-               txt.append("</p><hr>");
+               txt.append("<p>Dispatcher type: ").append(hreq.getDispatcherType().toString());
+               txt.append("<span style='margin-left: 2em;'>Request #: ");
+               try { // in case context not active
+                  txt.append(reqnum.getRandomNumber());
+               } catch (Exception e) {}
+               txt.append("</span></p><hr>");
                hresp.getWriter().write(txt.toString());
                ctx.complete();
                break;
@@ -138,8 +144,9 @@ public class AsyncPortletResource {
 
    }
 
-   @Inject
-   private AsyncDialogBean adb;
+   @Inject private AsyncDialogBean adb;
+   @Inject private PortletRequestRandomNumberBean reqnum;
+   @Inject private AsyncRunnable runner;
 
    @ServeResourceMethod(portletNames = "AsyncPortlet", asyncSupported = true)
    public void getResource(ResourceRequest req, ResourceResponse resp) throws IOException, PortletException {
@@ -221,7 +228,9 @@ public class AsyncPortletResource {
             txt.setLength(0);
             txt.append("<h5>Resource method producing text output for portlet: " + portletName + "</h5>");
             txt.append("<p>dispatcher type: ").append(req.getDispatcherType().toString());
-            txt.append("</p><hr>");
+            txt.append("<span style='margin-left: 2em;'>Request #: ");
+            txt.append(reqnum.getRandomNumber());
+            txt.append("</span></p><hr>");
             resp.getWriter().write(txt.toString());
             resp.flushBuffer();
             if (done) {
@@ -240,8 +249,8 @@ public class AsyncPortletResource {
             type = OutputType.AUTO;
          }
 
-         AsyncRunnable ar = new AsyncRunnable(ctx, adb.getDelay(), type);
-         ctx.start(ar);
+         runner.init(ctx, adb.getDelay(), type);
+         ctx.start(runner);
       }
    }
    

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/PortletRequestRandomNumberBean.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/PortletRequestRandomNumberBean.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/PortletRequestRandomNumberBean.java
index 407d561..4889827 100644
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/PortletRequestRandomNumberBean.java
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/PortletRequestRandomNumberBean.java
@@ -19,6 +19,7 @@
 
 package org.apache.portals.samples;
 
+import javax.inject.Named;
 import javax.portlet.annotations.PortletRequestScoped;
 
 /**
@@ -26,7 +27,7 @@ import javax.portlet.annotations.PortletRequestScoped;
  * @author Scott Nicklous
  *
  */
-@PortletRequestScoped
+@PortletRequestScoped @Named("reqnum")
 public class PortletRequestRandomNumberBean {
    
    private int randomNumber;

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncDialog.jsp
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncDialog.jsp b/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncDialog.jsp
index fd7e941..355ce90 100644
--- a/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncDialog.jsp
+++ b/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncDialog.jsp
@@ -25,7 +25,6 @@ limitations under the License.
 
 <h3>Async Portlet</h3>
 <div class='parmbox'>
-${adb.getMsg()}
 <FORM  ACTION='<portlet:actionURL/>' id='<portlet:namespace/>-setParams' method='POST' enctype='application/x-www-form-urlencoded'>
    <table style='width:100%;'><tr><td align='left'>
 
@@ -40,6 +39,15 @@ ${adb.getMsg()}
    <input name='<%=PARAM_AUTO%>' value='<%=PARAM_AUTO%>' type='checkbox' ${adb.isAutoDispatch() ? "checked" : "" } > recursive
 
    </td></tr><tr><td>
+   Handle timeout:
+   </td><td>
+   <input type='radio' name='<%=PARAM_TO%>' value='<%=PARAM_TO_NOP%>' ${adb.getHandleTimeout() == "NOP" ? "checked" : "" } > ignore
+   </td><td>
+   <input type='radio' name='<%=PARAM_TO%>' value='<%=PARAM_TO_CPL%>' ${adb.getHandleTimeout() == "CPL" ? "checked" : "" } > complete
+   </td><td>
+   <input type='radio' name='<%=PARAM_TO%>' value='<%=PARAM_TO_DIS%>' ${adb.getHandleTimeout() == "DIS" ? "checked" : "" } > dispatch
+
+   </td></tr><tr><td>
    Output type:
    </td><td>
    <input type='radio' name='<%=PARAM_TYPE%>' value='<%=PARAM_TYPE_TXT%>' ${adb.getType() == "TEXT" ? "checked" : "" } > text
@@ -56,6 +64,10 @@ ${adb.getMsg()}
    <input name='<%=PARAM_FILTER%>' value='<%=PARAM_FILTER%>' type='checkbox' ${adb.isUseFilter() ? "checked" : "" } > show filter
    </td></tr></table>
 </FORM>
+<p>
+Request #: ${reqnum.getRandomNumber()}
+<span style='margin-left: 2em;'>${adb.getMsg()}</span>
+</p>
 </div>
 <div class='infobox' id='<portlet:namespace/>putResourceHere'></div>
 

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp b/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
index 9297b6b..1c7024e 100644
--- a/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
+++ b/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
@@ -7,5 +7,9 @@
 <portlet:defineObjects />
 
 <h5><%=request.getAttribute("title") %> for portlet: <%=portletConfig.getPortletName() %></h5>
-<p>Dispatch type: <%=request.getDispatcherType() %></p>
+<p>Dispatch type: <%=request.getDispatcherType() %>
+<c:catch var ="catchException">
+   <span style='margin-left: 2em;'>Request #: ${reqnum.getRandomNumber()}</span>
+</c:catch>
+</p>
 <hr>

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java
----------------------------------------------------------------------
diff --git a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java
index 709306e..c4c9966 100644
--- a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java
+++ b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java
@@ -1,14 +1,15 @@
 package org.apache.pluto.container;
 
+import javax.enterprise.inject.spi.BeanManager;
+import javax.portlet.ResourceRequest;
 import javax.servlet.AsyncContext;
 
 public interface PortletAsyncContext extends AsyncContext {
 
-   void init(PortletResourceRequestContext prctx);
-
-   /**
-    * @param actx the async context to set
-    */
+   void init(PortletResourceRequestContext prctx, ResourceRequest resreq, BeanManager beanmgr);
    void setWrapped(AsyncContext actx);
+   void registerContext();
+   void deregisterContext();
+   void removeContext();
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PortletServlet3.java
----------------------------------------------------------------------
diff --git a/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PortletServlet3.java b/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PortletServlet3.java
index c48ee4d..820ab14 100644
--- a/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PortletServlet3.java
+++ b/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PortletServlet3.java
@@ -326,7 +326,6 @@ public class PortletServlet3 extends HttpServlet {
             wreq = ((ServletRequestWrapper) wreq).getRequest();
          }
          
-         
          if (wreq instanceof PortletAsyncRequestWrapper) {
             
             HttpServletRequest hreq = (HttpServletRequest) ((PortletAsyncRequestWrapper) wreq).getRequest();
@@ -340,13 +339,20 @@ public class PortletServlet3 extends HttpServlet {
          } else {
             LOG.debug("Couldn't find the portlet async wrapper.");
          }
+
+         // enable contextual support for async
+         ((PortletResourceRequestContext)requestContext).getPortletAsyncContext().registerContext();
          
       } else {
          
-         // the contexts are already initialized if this is part of a resource request async sequence
+         // Not an async dispatch
+         
          requestContext.init(portletConfig, getServletContext(), request, response);
          requestContext.setExecutingRequestBody(true);
          responseContext.init(request, response);
+
+         // enable contextual support
+         beforeInvoke(portletRequest, portletResponse, portletConfig);
       
       }
 
@@ -356,8 +362,6 @@ public class PortletServlet3 extends HttpServlet {
       notify(event, true, null);
       
       try {
-
-         beforeInvoke(portletRequest, portletResponse, portletConfig);
          
          // The requested method is RENDER: call Portlet.render(..)
          if (methodId == PortletInvokerService.METHOD_RENDER) {
@@ -451,43 +455,40 @@ public class PortletServlet3 extends HttpServlet {
       } finally {
          
          requestContext.setExecutingRequestBody(false);
-         afterInvoke(portletResponse);
          
          // If an async request is running or has been dispatched, resources
          // will be released by the PortletAsyncListener. Otherwise release here.
          
-         if (!request.isAsyncStarted()) {
-            
-            LOG.debug("Async not started, releasing resources. executing req body: " + requestContext.isExecutingRequestBody());
-            
-            if (request.getDispatcherType() != DispatcherType.ASYNC) {
+         if (!request.isAsyncStarted() && (request.getDispatcherType() != DispatcherType.ASYNC)) {
 
-               request.removeAttribute(PortletInvokerService.METHOD_ID);
-               request.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
-               request.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
-               request.removeAttribute(PortletInvokerService.FILTER_MANAGER);
+            LOG.debug("Async not being processed, releasing resources. executing req body: " + requestContext.isExecutingRequestBody());
+
+            request.removeAttribute(PortletInvokerService.METHOD_ID);
+            request.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
+            request.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
+            request.removeAttribute(PortletInvokerService.FILTER_MANAGER);
+
+            afterInvoke(portletResponse);
 
-            }
          } else {
             LOG.debug("Async started, not releasing resources. executing req body: " + requestContext.isExecutingRequestBody());
 
-            // Initialize the async context after the request during which async is 
-            // first started.
-            
-            if (request.getDispatcherType() != DispatcherType.ASYNC) {
-               if (requestContext instanceof PortletResourceRequestContext) {
-                  PortletResourceRequestContext resctx = (PortletResourceRequestContext)requestContext;
-                  PortletAsyncContext pac = resctx.getPortletAsyncContext();
-                  if (pac != null) {
-                     pac.init(resctx);
-                  } else {
-                     LOG.warn("Couldn't get portlet async context.");
+            if (requestContext instanceof PortletResourceRequestContext) {
+               PortletResourceRequestContext resctx = (PortletResourceRequestContext)requestContext;
+               PortletAsyncContext pac = resctx.getPortletAsyncContext();
+               if (pac != null) {
+                  if (request.getDispatcherType() != DispatcherType.ASYNC) {
+                     // initialize only on the first time thru
+                     pac.init(resctx, (ResourceRequest) portletRequest, beanmgr);
                   }
+                  pac.deregisterContext();
                } else {
-                  LOG.warn("Wrong kind of request context: " + requestContext.getClass().getCanonicalName());
+                  LOG.warn("Couldn't get portlet async context.");
                }
-            }            
-            
+            } else {
+               LOG.warn("Wrong kind of request context: " + requestContext.getClass().getCanonicalName());
+            }
+
          }
       }
    }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletRequestScopedBeanHolder.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletRequestScopedBeanHolder.java b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletRequestScopedBeanHolder.java
index 468e1f0..34538b3 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletRequestScopedBeanHolder.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletRequestScopedBeanHolder.java
@@ -91,7 +91,9 @@ public class PortletRequestScopedBeanHolder implements Serializable {
    public static void removeBeanHolder() {
       
       PortletRequestScopedBeanHolder bh = getBeanHolder();
-      bh.removeAll();
+      if (bh != null) {
+         bh.removeAll();
+      }
       holders.remove();
 
       if (isTrace) {
@@ -110,6 +112,27 @@ public class PortletRequestScopedBeanHolder implements Serializable {
    public static PortletRequestScopedBeanHolder getBeanHolder() {
       return holders.get();
    }
+   
+   /**
+    * Removes the bean holder for the current thread and
+    * returns the removed instance to the caller.
+    * 
+    * @return  the removed bean holder
+    */
+   public static PortletRequestScopedBeanHolder deregister() {
+      PortletRequestScopedBeanHolder holder = holders.get();
+      holders.remove();
+      return holder;
+   }
+   
+   /**
+    * Registers the provided bean holder for the current thread.
+    * 
+    * @param holder the bean holder to register
+    */
+   public static void register(PortletRequestScopedBeanHolder holder) {
+      holders.set(holder);
+   }
 
    /**
     * Returns existing instance of object, or null if no instance exists.

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletSessionBeanHolder.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletSessionBeanHolder.java b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletSessionBeanHolder.java
index 6d97539..b8d5a23 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletSessionBeanHolder.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletSessionBeanHolder.java
@@ -120,6 +120,27 @@ public class PortletSessionBeanHolder implements Serializable {
    public static PortletSessionBeanHolder getBeanHolder() {
       return holders.get();
    }
+   
+   /**
+    * Removes the bean holder for the current thread and
+    * returns the removed instance to the caller.
+    * 
+    * @return  the removed bean holder
+    */
+   public static PortletSessionBeanHolder deregister() {
+      PortletSessionBeanHolder holder = holders.get();
+      holders.remove();
+      return holder;
+   }
+   
+   /**
+    * Registers the provided bean holder for the current thread.
+    * 
+    * @param holder the bean holder to register
+    */
+   public static void register(PortletSessionBeanHolder holder) {
+      holders.set(holder);
+   }
 
    /**
     * Returns an instance for the contextual type, or null if none available.

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletStateScopedBeanHolder.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletStateScopedBeanHolder.java b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletStateScopedBeanHolder.java
index d0ec561..24ca9ca 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletStateScopedBeanHolder.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletStateScopedBeanHolder.java
@@ -104,7 +104,9 @@ public class PortletStateScopedBeanHolder implements Serializable {
    public static void removeBeanHolder(StateAwareResponse resp) {
       
       PortletStateScopedBeanHolder bh = getBeanHolder();
-      bh.removeAll(resp);
+      if (bh != null) {
+         bh.removeAll(resp);
+      }
       holders.remove();
 
       if (isTrace) {
@@ -123,6 +125,27 @@ public class PortletStateScopedBeanHolder implements Serializable {
    public static PortletStateScopedBeanHolder getBeanHolder() {
       return holders.get();
    }
+   
+   /**
+    * Removes the bean holder for the current thread and
+    * returns the removed instance to the caller.
+    * 
+    * @return  the removed bean holder
+    */
+   public static PortletStateScopedBeanHolder deregister() {
+      PortletStateScopedBeanHolder holder = holders.get();
+      holders.remove();
+      return holder;
+   }
+   
+   /**
+    * Registers the provided bean holder for the current thread.
+    * 
+    * @param holder the bean holder to register
+    */
+   public static void register(PortletStateScopedBeanHolder holder) {
+      holders.set(holder);
+   }
 
    /**
     * Returns existing instance of object, or null if no instance exists.

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextImpl.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextImpl.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextImpl.java
index d638db1..2df6a2f 100644
--- a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextImpl.java
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextImpl.java
@@ -16,9 +16,13 @@
  *  under the License.
  */
 
-
 package org.apache.pluto.driver.services.container;
 
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.portlet.ResourceRequest;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncListener;
 import javax.servlet.ServletContext;
@@ -30,41 +34,121 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.pluto.container.PortletAsyncContext;
 import org.apache.pluto.container.PortletResourceRequestContext;
+import org.apache.pluto.container.bean.processor.PortletArtifactProducer;
+import org.apache.pluto.container.bean.processor.PortletRequestScopedBeanHolder;
+import org.apache.pluto.container.bean.processor.PortletSessionBeanHolder;
+import org.apache.pluto.container.bean.processor.PortletStateScopedBeanHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Wrapper class for the AsyncContext obtained from the servlet container. Provides
- * a couple of work-arounds for Tomcat async bugs as well as portlet-specific listener
- * support.
+ * Wrapper class for the AsyncContext obtained from the servlet container. Provides a couple of work-arounds for Tomcat
+ * async bugs as well as portlet-specific listener support.
  * 
  * @author Scott Nicklous
- *
+ * 
  */
 public class PortletAsyncContextImpl implements PortletAsyncContext {
+   private static final Logger LOG = LoggerFactory.getLogger(PortletAsyncContextImpl.class);
+   private static final boolean isDebug = LOG.isDebugEnabled();
+   private static final boolean isTrace = LOG.isTraceEnabled();
+   
+   
+
+   private AsyncContext                   actx;
+   private final HttpServletRequest       hreq;
 
-   private AsyncContext actx;
-   private final HttpServletRequest hreq;
+   private PortletResourceRequestContext  prctx;
+   private ResourceRequest                resreq;
+   private PortletSessionBeanHolder       sessbh;
+   private PortletStateScopedBeanHolder   statebh;
+   private PortletRequestScopedBeanHolder reqbh;
+   private BeanManager                    beanmgr;
+
+   private Runnable                       pendingRunner;
 
    public PortletAsyncContextImpl(AsyncContext actx, HttpServletRequest hreq) {
       this.actx = actx;
       this.hreq = hreq;
    }
 
-   /* (non-Javadoc)
-    * @see org.apache.pluto.driver.services.container.PortletAsyncContext#requestComplete(org.apache.pluto.container.PortletResourceRequestContext)
+   /*
+    * (non-Javadoc)
+    * 
+    * @see org.apache.pluto.driver.services.container.PortletAsyncContext#requestComplete(org.apache.pluto.container.
+    * PortletResourceRequestContext)
     */
    @Override
-   public void init(PortletResourceRequestContext prctx) {
+   public void init(PortletResourceRequestContext prctx, ResourceRequest resreq, BeanManager beanmgr) {
+      this.prctx = prctx;
+      this.resreq = resreq;
+      this.beanmgr = beanmgr;
 
       // get the original container req & resp to pass to listener for resource releasing
 
       HttpServletRequest creq = prctx.getContainerRequest();
       HttpServletResponse cresp = prctx.getContainerResponse();
 
-      PortletAsyncListener pal = new PortletAsyncListener();
+      PortletAsyncListener pal = new PortletAsyncListener(this);
       actx.addListener(pal, creq, cresp);
+
    }
-   
-   /* (non-Javadoc)
+
+   /**
+    * Called when a new thread begins running in order to set up contextual support
+    */
+   @Override
+   public void registerContext() {
+      PortletSessionBeanHolder.register(sessbh);
+      PortletStateScopedBeanHolder.register(statebh);
+      PortletRequestScopedBeanHolder.register(reqbh);
+      PortletArtifactProducer.setPrecursors(resreq, prctx.getResponse(), prctx.getPortletConfig());
+   }
+
+   /**
+    * Called when exiting portlet handling for this thread. The bean holders are deregistered from the thread but are
+    * saved rather than destroyed.
+    */
+   @Override
+   public void deregisterContext() {
+      this.sessbh = PortletSessionBeanHolder.deregister();
+      this.statebh = PortletStateScopedBeanHolder.deregister();
+      this.reqbh = PortletRequestScopedBeanHolder.deregister();
+      PortletArtifactProducer.remove();
+
+      // now if a runner is pending, initialize the contextual runnable and start it
+
+      if (pendingRunner != null) {
+         PortletAsyncContextualRunner runner = new PortletAsyncContextualRunner();
+
+         if (isDebug) {
+            StringBuilder txt = new StringBuilder();
+            txt.append("Executing Portlet Runnable: " + pendingRunner.getClass().getCanonicalName());
+            LOG.debug(txt.toString());
+         }
+
+         runner.init(this, pendingRunner);
+         pendingRunner = null;
+         actx.start(runner);
+      }
+
+   }
+
+   /**
+    * Called when exiting portlet handling for this thread. The bean holders are deregistered from the thread and any
+    * beans contained are destroyed.
+    */
+   @Override
+   public void removeContext() {
+      PortletSessionBeanHolder.removeBeanHolder();
+      PortletStateScopedBeanHolder.removeBeanHolder(null);
+      PortletRequestScopedBeanHolder.removeBeanHolder();
+      PortletArtifactProducer.remove();
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
     * @see org.apache.pluto.driver.services.container.PortletAsyncContext#setWrapped(javax.servlet.AsyncContext)
     */
    @Override
@@ -72,7 +156,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       this.actx = actx;
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#addListener(javax.servlet.AsyncListener)
     */
    @Override
@@ -80,15 +166,20 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.addListener(l);
    }
 
-   /* (non-Javadoc)
-    * @see javax.servlet.AsyncContext#addListener(javax.servlet.AsyncListener, javax.servlet.ServletRequest, javax.servlet.ServletResponse)
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncContext#addListener(javax.servlet.AsyncListener, javax.servlet.ServletRequest,
+    * javax.servlet.ServletResponse)
     */
    @Override
    public void addListener(AsyncListener l, ServletRequest req, ServletResponse resp) {
       actx.addListener(l, req, resp);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#complete()
     */
    @Override
@@ -96,7 +187,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.complete();
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#createListener(java.lang.Class)
     */
    @Override
@@ -104,7 +197,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       return actx.createListener(cls);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#dispatch()
     */
    @Override
@@ -113,7 +208,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.dispatch(hreq.getServletContext(), hreq.getServletPath());
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#dispatch(java.lang.String)
     */
    @Override
@@ -122,7 +219,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.dispatch(hreq.getServletContext(), path);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#dispatch(javax.servlet.ServletContext, java.lang.String)
     */
    @Override
@@ -130,7 +229,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.dispatch(sctx, path);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#getRequest()
     */
    @Override
@@ -138,7 +239,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       return actx.getRequest();
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#getResponse()
     */
    @Override
@@ -146,7 +249,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       return actx.getResponse();
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#getTimeout()
     */
    @Override
@@ -154,7 +259,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       return actx.getTimeout();
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#hasOriginalRequestAndResponse()
     */
    @Override
@@ -162,7 +269,9 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       return actx.hasOriginalRequestAndResponse();
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#setTimeout(long)
     */
    @Override
@@ -170,12 +279,14 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       actx.setTimeout(time);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncContext#start(java.lang.Runnable)
     */
    @Override
    public void start(Runnable run) {
-      actx.start(run);
+      pendingRunner = run;
    }
 
 }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextualRunner.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextualRunner.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextualRunner.java
new file mode 100644
index 0000000..6dcac04
--- /dev/null
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextualRunner.java
@@ -0,0 +1,68 @@
+/*  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+
+package org.apache.pluto.driver.services.container;
+
+import org.apache.pluto.container.PortletAsyncContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Runner that is launched in thread on behalf of the portlet application runnable 
+ * in order to initialize contextual information.
+ * 
+ * @author Scott Nicklous
+ *
+ */
+public class PortletAsyncContextualRunner implements Runnable {
+   private static final Logger LOG = LoggerFactory.getLogger(PortletAsyncContextualRunner.class);
+   private static final boolean isDebug = LOG.isDebugEnabled();
+   @SuppressWarnings("unused")
+   private static final boolean isTrace = LOG.isTraceEnabled();
+   
+
+   private PortletAsyncContext pactx;
+   private Runnable targetRunner; 
+
+   public PortletAsyncContextualRunner() {
+   }
+   
+   public void init(PortletAsyncContext pactx, Runnable targetRunner) {
+      this.pactx = pactx;
+      this.targetRunner = targetRunner;
+   }
+
+   @Override
+   public void run() {
+      if (isDebug) {
+         LOG.debug("Initializing contextual environment and launching runner in thread: " + Thread.currentThread().getId());
+      }
+
+      pactx.registerContext();
+      try {
+         targetRunner.run();
+      } finally {
+         if (isDebug) {
+            LOG.debug("Shutting down contextual environment for thread: " + Thread.currentThread().getId());
+         }
+         pactx.deregisterContext();
+      }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/27e17ae6/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncListener.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncListener.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncListener.java
index 97b77c6..d546986 100644
--- a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncListener.java
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncListener.java
@@ -25,10 +25,9 @@ import javax.portlet.ResourceRequest;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
-import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
+import org.apache.pluto.container.PortletAsyncContext;
 import org.apache.pluto.container.PortletInvokerService;
 import org.apache.pluto.container.PortletResourceResponseContext;
 
@@ -40,7 +39,12 @@ import org.apache.pluto.container.PortletResourceResponseContext;
 public class PortletAsyncListener implements AsyncListener {
    private static final Logger LOGGER = Logger.getLogger(PortletAsyncListener.class.getName());
 
-   private long                start  = System.currentTimeMillis();
+   private long start  = System.currentTimeMillis();
+   private final PortletAsyncContext pactx;
+ 
+   public PortletAsyncListener(PortletAsyncContext pactx) {
+      this.pactx = pactx;
+   }
 
    /*
     * (non-Javadoc)
@@ -87,8 +91,11 @@ public class PortletAsyncListener implements AsyncListener {
          hreq.removeAttribute(PortletInvokerService.FILTER_MANAGER);
 
       } else {
-         txt.append("... nothing. Couldn't get servlet request.");
+         txt.append("... no servlet request stuff. Couldn't get servlet request.");
       }
+      
+      txt.append(" Removing contextual info.");
+      pactx.removeContext();
 
       LOGGER.fine(txt.toString());
 
@@ -104,6 +111,18 @@ public class PortletAsyncListener implements AsyncListener {
       long delta = System.currentTimeMillis() - start;
       StringBuilder txt = new StringBuilder(128);
       txt.append("Error after ").append(delta).append(" milliseconds.");
+
+      // attempt to complete
+
+      try {
+         AsyncContext ctx = evt.getAsyncContext();
+         ctx.complete();
+         txt.append(" Portlet container completed request processing on behalf of the application.");
+      } catch (IllegalStateException e) {
+         txt.append(" An earlier listener has already dispatched or completed request.");
+      } catch (Exception e) {
+      }
+
       txt.append(", Exception: ").append(evt.getThrowable().getMessage());
       LOGGER.fine(txt.toString());
    }