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/08 15:40:31 UTC

[19/34] portals-pluto git commit: Added bug fixes and debugging code for async support

Added bug fixes and debugging code for async support


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

Branch: refs/heads/V3Prototype
Commit: 79160b5d6ce8dbbfd2c764f54a25f0ec9b0eca00
Parents: 1d62807
Author: Scott Nicklous <ms...@apache.org>
Authored: Wed Mar 30 18:18:58 2016 +0200
Committer: Scott Nicklous <ms...@apache.org>
Committed: Wed Mar 30 18:18:58 2016 +0200

----------------------------------------------------------------------
 .../apache/portals/samples/AsyncDialogBean.java |  22 ++-
 .../portals/samples/AsyncPortletResource.java   | 183 +++++++++++++++----
 .../src/main/webapp/WEB-INF/jsp/asyncOutput.jsp |   4 +-
 .../pluto/container/driver/PortletServlet3.java |  14 +-
 .../bean/processor/PortletInvoker.java          |   7 +-
 .../impl/PortletAsyncRequestWrapper.java        |  96 +++++++---
 .../container/PortletAsyncListener.java         |  94 +++++-----
 .../PortletResourceRequestContextImpl.java      |  86 ++++++++-
 8 files changed, 377 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/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 f0d76f9..a74af06 100644
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncDialogBean.java
@@ -180,15 +180,6 @@ public class AsyncDialogBean implements PortletSerializable {
       
       msg = null;
       
-      String strType = req.getActionParameters().getValue(PARAM_TYPE);
-      if (strType != null) {
-         try {
-            type = OutputType.valueOf(strType);
-         } catch (Exception e) {
-            msg = "try again. bad type: " + strType;
-         }
-      }
-      
       String strReps = req.getActionParameters().getValue(PARAM_REPS);
       if (strReps != null) {
          try {
@@ -208,6 +199,19 @@ public class AsyncDialogBean implements PortletSerializable {
             msg = "try again. bad delay.";
          }
       }
+      
+      String strType = req.getActionParameters().getValue(PARAM_TYPE);
+      if (strType != null) {
+         try {
+            type = OutputType.valueOf(strType);
+            if (type == OutputType.FWD && reps > 1) {
+               msg = "Repetitions cannot be > 1 for forwards.";
+               reps = 1;
+            }
+         } catch (Exception e) {
+            msg = "try again. bad type: " + strType;
+         }
+      }
 
       String auto = req.getActionParameters().getValue(PARAM_AUTO);
       if (auto != null) {

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/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 792601f..65fea26 100644
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
@@ -19,9 +19,12 @@
 package org.apache.portals.samples;
 
 import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
+import javax.portlet.PortletConfig;
 import javax.portlet.PortletException;
 import javax.portlet.PortletRequestDispatcher;
 import javax.portlet.ResourceRequest;
@@ -77,28 +80,69 @@ public class AsyncPortletResource {
             HttpServletRequest hreq = (HttpServletRequest) ctx.getRequest();
             HttpServletResponse hresp = (HttpServletResponse) ctx.getResponse();
             RequestDispatcher rd;
+            
+            {
+               List<String> attrNames = Collections.list(hreq.getAttributeNames());
+               StringBuilder txt = new StringBuilder(128);
+               txt.append("Runnable:");
+               txt.append("\nAttribute names: ").append(attrNames);
+               txt.append("\nasync_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.async.request_uri"));
+               txt.append("\nasync_context_path:      ").append((String) hreq.getAttribute("javax.servlet.async.context_path"));
+               txt.append("\nasync_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.async.servlet_path"));
+               txt.append("\nasync_path_info:      ").append((String) hreq.getAttribute("javax.servlet.async.path_info"));
+               txt.append("\nasync_query_string:      ").append((String) hreq.getAttribute("javax.servlet.async.query_string"));
+               txt.append("\nforward_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.forward.request_uri"));
+               txt.append("\nforward_context_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.context_path"));
+               txt.append("\nforward_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.servlet_path"));
+               txt.append("\nforward_path_info:      ").append((String) hreq.getAttribute("javax.servlet.forward.path_info"));
+               txt.append("\nforward_query_string:      ").append((String) hreq.getAttribute("javax.servlet.forward.query_string"));
+               txt.append("\ninclude_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.include.request_uri"));
+               txt.append("\ninclude_context_path:      ").append((String) hreq.getAttribute("javax.servlet.include.context_path"));
+               txt.append("\ninclude_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.include.servlet_path"));
+               txt.append("\ninclude_path_info:      ").append((String) hreq.getAttribute("javax.servlet.include.path_info"));
+               txt.append("\ninclude_query_string:      ").append((String) hreq.getAttribute("javax.servlet.include.query_string"));
+               txt.append("\nmethod_request_uri:      ").append(hreq.getRequestURI());
+               txt.append("\nmethod_context_path:      ").append(hreq.getContextPath());
+               txt.append("\nmethod_servlet_path:      ").append(hreq.getServletPath());
+               txt.append("\nmethod_path_info:      ").append(hreq.getPathInfo());
+               txt.append("\nmethod_query_string:      ").append(hreq.getQueryString());
+               LOGGER.fine(txt.toString());
+            }
+
+            
+            PortletConfig config = (PortletConfig) hreq.getAttribute("javax.portlet.config");
+            String portletName = "Could not get PortletConfig";
+            if (config != null) {
+               portletName = config.getPortletName();
+            }
 
             switch (type) {
             case TEXT:
                LOGGER.fine("Producing text output.");
                StringBuilder txt = new StringBuilder(128);
-               txt.append("<h5>Thread producing text output</h5>");
+               txt.append("<h5>Thread producing text output for portlet: " + portletName + "</h5>");
                txt.append("<p>dispatcher type: ").append(hreq.getDispatcherType().toString());
                txt.append("</p>");
                hresp.getWriter().write(txt.toString());
                if (done) {
                   ctx.complete();
+               } else {
+                  hresp.flushBuffer();
                }
                break;
             case AUTO:
-               LOGGER.fine("Dispatching to resource method.");
+               StringBuilder str = new StringBuilder(128);
+               str.append("Dispatching to resource method.");
+               str.append(" context path: ").append(hreq.getServletContext().getContextPath());
+               str.append(", Servlet patch: ").append(hreq.getServletPath());
+               LOGGER.fine(str.toString());
                hreq.setAttribute(ATTRIB_AUTO, new Boolean(true));
-               ctx.dispatch();
+               ctx.dispatch(hreq.getServletContext(), hreq.getServletPath());
                break;
             case DISPATCH:
                LOGGER.fine("Dispatching to JSP.");
                hreq.setAttribute(ATTRIB_TITLE, "Thread dispatching to JSP");
-               ctx.dispatch(JSP);
+               ctx.dispatch(hreq.getServletContext(), JSP);
                break;
             case FWD:
                LOGGER.fine("Doing request dispatcher forward to JSP.");
@@ -107,6 +151,8 @@ public class AsyncPortletResource {
                rd.forward(hreq, hresp);
                if (done) {
                   ctx.complete();
+               } else {
+                  hresp.flushBuffer();
                }
                break;
             case INC:
@@ -116,6 +162,8 @@ public class AsyncPortletResource {
                rd.include(hreq, hresp);
                if (done) {
                   ctx.complete();
+               } else {
+                  hresp.flushBuffer();
                }
                break;
             }
@@ -133,52 +181,111 @@ public class AsyncPortletResource {
    @ServeResourceMethod(portletNames = "AsyncPortlet", asyncSupported = true)
    public void getResource(ResourceRequest req, ResourceResponse resp) throws IOException, PortletException {
 
+      Boolean auto = (Boolean) req.getAttribute(ATTRIB_AUTO);
+      if (auto == null) {
+         auto = false;
+      }
+      req.removeAttribute(ATTRIB_AUTO);
+
       Integer reps = (Integer) req.getAttribute(ATTRIB_REPS);
+      boolean done = false;
       if (reps == null) {
          reps = adb.getReps();
       }
-
-      boolean done = false;
-      if (--reps <= 0 || !adb.isAutoDispatch()) {
+      if (reps <= 0) {
          done = true;
       }
-      req.setAttribute(ATTRIB_REPS, reps);
+      
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Resource method.");
+      txt.append(" delay: ").append(adb.getDelay());
+      txt.append(", type: ").append(adb.getType());
+      txt.append(", reps: ").append(reps);
+      txt.append(", total reps: ").append(adb.getReps());
+      txt.append(", auto: ").append(adb.isAutoDispatch());
+      txt.append(", auto-dispatch: ").append(auto);
+      txt.append(", done: ").append(done);
+      LOGGER.fine(txt.toString());
+      
+      AsyncContext ctx = null;
 
-      Boolean auto = (Boolean) req.getAttribute(ATTRIB_AUTO);
-      req.removeAttribute(ATTRIB_AUTO);
+      if (!done) {
+         reps--;
+         req.setAttribute(ATTRIB_REPS, reps);
+         
+         ctx = req.startAsync();
+         ctx.setTimeout(4000);
+      }
 
-      if ((adb.getDelay() <= 0) || (auto != null)) {
+      if (auto || (adb.getDelay() <= 0)) {
+         
+         // produce output if dispatched from work thread or if there is no delay requested
          
          PortletRequestDispatcher rd;
-         AsyncContext ctx = null;
-         try {
-            ctx = req.getAsyncContext();
-         } catch (Exception e) {}
          
-         StringBuilder txt = new StringBuilder(128);
-         txt.append("Producing output.");
-         txt.append(" delay: ").append(adb.getDelay());
-         txt.append(", type: ").append(adb.getType());
-         txt.append(", reps: ").append(reps);
-         txt.append(", total reps: ").append(adb.getReps());
-         txt.append(", recursive: ").append(adb.isAutoDispatch());
-         txt.append(", dispatched from work thread: ").append(auto);
-         txt.append(", asyncContext: ").append((ctx == null) ? "null" : "not null");
-         LOGGER.fine(txt.toString());
+         if (ctx == null) {
+            // last iteration of auto-dispatch
+            try {
+               ctx = req.getAsyncContext();
+            } catch (Exception e) {
+               txt.setLength(0);
+               txt.append("Could not get AsyncContext. Exception: ").append(e.toString());
+               LOGGER.warning(txt.toString());
+               resp.getWriter().write(txt.toString());
+               return;
+            }
+         }
+
+         HttpServletRequest hreq = (HttpServletRequest) req.getAttribute("javax.portlet.debug.ServletRequest");
+         
+         {
+            List<String> attrNames = Collections.list(hreq.getAttributeNames());
+            StringBuilder txt2 = new StringBuilder(128);
+            txt2.append("During content generation:");
+            txt2.append("\nAttribute names: ").append(attrNames);
+            txt2.append("\nasync_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.async.request_uri"));
+            txt2.append("\nasync_context_path:      ").append((String) hreq.getAttribute("javax.servlet.async.context_path"));
+            txt2.append("\nasync_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.async.servlet_path"));
+            txt2.append("\nasync_path_info:      ").append((String) hreq.getAttribute("javax.servlet.async.path_info"));
+            txt2.append("\nasync_query_string:      ").append((String) hreq.getAttribute("javax.servlet.async.query_string"));
+            txt2.append("\nforward_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.forward.request_uri"));
+            txt2.append("\nforward_context_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.context_path"));
+            txt2.append("\nforward_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.servlet_path"));
+            txt2.append("\nforward_path_info:      ").append((String) hreq.getAttribute("javax.servlet.forward.path_info"));
+            txt2.append("\nforward_query_string:      ").append((String) hreq.getAttribute("javax.servlet.forward.query_string"));
+            txt2.append("\ninclude_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.include.request_uri"));
+            txt2.append("\ninclude_context_path:      ").append((String) hreq.getAttribute("javax.servlet.include.context_path"));
+            txt2.append("\ninclude_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.include.servlet_path"));
+            txt2.append("\ninclude_path_info:      ").append((String) hreq.getAttribute("javax.servlet.include.path_info"));
+            txt2.append("\ninclude_query_string:      ").append((String) hreq.getAttribute("javax.servlet.include.query_string"));
+            txt2.append("\nmethod_request_uri:      ").append(hreq.getRequestURI());
+            txt2.append("\nmethod_context_path:      ").append(hreq.getContextPath());
+            txt2.append("\nmethod_servlet_path:      ").append(hreq.getServletPath());
+            txt2.append("\nmethod_path_info:      ").append(hreq.getPathInfo());
+            txt2.append("\nmethod_query_string:      ").append(hreq.getQueryString());
+            LOGGER.fine(txt2.toString());
+         }
+
+         
+         // HttpServletRequest hreq = (HttpServletRequest) ctx.getRequest();
+         PortletConfig config = (PortletConfig) req.getAttribute("javax.portlet.config");
+         String portletName = "Could not get PortletConfig";
+         if (config != null) {
+            portletName = config.getPortletName();
+         }
 
          switch (adb.getType()) {
          case DISPATCH:
             LOGGER.fine("Dispatching to JSP.");
-            if (ctx != null) {
-               ctx.dispatch(JSP);
-            }
+            ctx.dispatch(JSP);
             break;
          case FWD:
             LOGGER.fine("Doing request dispatcher forward to JSP.");
             req.setAttribute(ATTRIB_TITLE, "Resource Method forwarding to JSP");
             rd = req.getPortletContext().getRequestDispatcher(JSP);
             rd.forward(req, resp);
-            if (done && ctx != null) {
+            resp.flushBuffer();
+            if (!auto) {
                ctx.complete();
             }
             break;
@@ -187,32 +294,36 @@ public class AsyncPortletResource {
             req.setAttribute(ATTRIB_TITLE, "Resource Method including JSP");
             rd = req.getPortletContext().getRequestDispatcher(JSP);
             rd.include(req, resp);
-            if (done && ctx != null) {
+            resp.flushBuffer();
+            if (!auto) {
                ctx.complete();
             }
             break;
          default:
             LOGGER.fine("Producing text output.");
             txt.setLength(0);
-            txt.append("<h5>Async portlet resource method producing text output</h5>");
+            txt.append("<h5>Async portlet resource method producing text output for portlet: " + portletName + "</h5>");
             txt.append("<p>dispatcher type: ").append(req.getDispatcherType().toString());
             txt.append("</p>");
             resp.getWriter().write(txt.toString());
-            if (done && ctx != null) {
+            resp.flushBuffer();
+            if (!auto) {
                ctx.complete();
             }
             break;
          }
       }
       
-      if (adb.getDelay() > 0 && (!done || auto == null)) {
-         AsyncContext ctx = req.startAsync();
-         ctx.setTimeout(4000);
+      if (adb.getDelay() > 0 && req.isAsyncStarted()) {
+         
+         // now start the executor thread 
+         
          OutputType type = adb.getType();
          if (adb.isAutoDispatch()) {
             type = OutputType.AUTO;
          }
-         AsyncRunnable ar = new AsyncRunnable(ctx, adb.getDelay(), type, done);
+
+         AsyncRunnable ar = new AsyncRunnable(ctx, adb.getDelay(), type, (reps<=0));
          ctx.start(ar);
       }
 

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/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 a939991..9297b6b 100644
--- a/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
+++ b/PortletV3AnnotatedDemo/src/main/webapp/WEB-INF/jsp/asyncOutput.jsp
@@ -1,9 +1,11 @@
 <%@ page session="false" %>
 <%@ page isELIgnored ="false" %> 
+<%@ taglib uri="http://xmlns.jcp.org/portlet_3_0"  prefix="portlet" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
 
+<portlet:defineObjects />
 
-<h5><%=request.getAttribute("title") %></h5>
+<h5><%=request.getAttribute("title") %> for portlet: <%=portletConfig.getPortletName() %></h5>
 <p>Dispatch type: <%=request.getDispatcherType() %></p>
 <hr>

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/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 d835746..7aed69d 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
@@ -244,6 +244,13 @@ public class PortletServlet3 extends HttpServlet {
     * @throws IOException
     */
    private void dispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+      if (LOG.isDebugEnabled()) {
+         StringBuilder txt = new StringBuilder();
+         txt.append("Processing request.");
+         txt.append(" Dispatcher type: ").append(request.getDispatcherType());
+         txt.append(", request URI: ").append(request.getRequestURI());
+         LOG.debug(txt.toString());
+      }
       if (invoker == null) {
          throw new javax.servlet.UnavailableException("Portlet " + portletName + " unavailable");
       }
@@ -265,8 +272,11 @@ public class PortletServlet3 extends HttpServlet {
       final FilterManager filterManager = 
             (FilterManager) request.getAttribute(PortletInvokerService.FILTER_MANAGER);
 
-      requestContext.init(portletConfig, getServletContext(), request, response);
-      responseContext.init(request, response);
+      if (request.getDispatcherType() != DispatcherType.ASYNC) {
+         // the contexts are already initialized if this is part of a resource request async sequence
+         requestContext.init(portletConfig, getServletContext(), request, response);
+         responseContext.init(request, response);
+      }
 
       PortletWindow window = requestContext.getPortletWindow();
 

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletInvoker.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletInvoker.java b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletInvoker.java
index f9a592b..fd090da 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletInvoker.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/bean/processor/PortletInvoker.java
@@ -268,15 +268,10 @@ public class PortletInvoker implements Portlet, ResourceServingPortlet, EventPor
          
          // Handle AsyncContest#dispatch() case
          
-         MethodIdentifier ami = (MethodIdentifier) req.getAttribute(PortletInvokerService.ASYNC_METHOD);
-         AnnotatedMethod meth = null;
-         if (ami != null) {
-            meth = acb.getMethodStore().getMethod(mi);
-         }
+         AnnotatedMethod meth = (AnnotatedMethod) req.getAttribute(PortletInvokerService.ASYNC_METHOD);;
          if (meth == null) {
             StringBuilder txt = new StringBuilder(128);
             txt.append("Async processing error. ServeResource method not found for method identifier: ");
-            txt.append((ami == null) ? "null" : ami.toString());
             LOG.warn(txt.toString());
             return;
          }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAsyncRequestWrapper.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAsyncRequestWrapper.java b/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAsyncRequestWrapper.java
index dd259c9..57bdee6 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAsyncRequestWrapper.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAsyncRequestWrapper.java
@@ -19,6 +19,8 @@
 
 package org.apache.pluto.container.impl;
 
+import java.util.Enumeration;
+
 import javax.portlet.PortletRequest;
 import javax.servlet.AsyncContext;
 import javax.servlet.DispatcherType;
@@ -26,50 +28,90 @@ import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpSession;
 
 /**
  * @author Scott Nicklous
  *
  */
-public class PortletAsyncRequestWrapper extends HttpServletPortletRequestWrapper {
+public class PortletAsyncRequestWrapper extends HttpServletRequestWrapper {
+   
+   private final PortletRequest preq;
 
-   /**
-    * Modifies the behavior of the underlying wrapper to allow access to the
-    * async methods.
-    * 
-    * @param request
-    * @param servletContext
-    * @param session
-    * @param portletRequest
-    */
-   public PortletAsyncRequestWrapper(HttpServletRequest request, ServletContext servletContext, HttpSession session,
-         PortletRequest portletRequest) {
-      super(request, servletContext, session, portletRequest, false, false);
-      
+   public PortletAsyncRequestWrapper(HttpServletRequest hreq, PortletRequest preq) {
+      super(hreq);
+      this.preq = preq;
    }
    
-
-
+   
+   
    @Override
-   public AsyncContext startAsync() throws IllegalStateException {
-      return getRequest().startAsync();
+   public Object getAttribute(String name) {
+      return preq.getAttribute(name);
    }
-
+   
    @Override
-   public AsyncContext startAsync(ServletRequest request, ServletResponse response) throws IllegalStateException {
-      return getRequest().startAsync(request, response);
+   public Enumeration<String> getAttributeNames() {
+      return preq.getAttributeNames();
    }
-
+   
    @Override
-   public boolean isAsyncStarted() {
-      return getRequest().isAsyncStarted();
+   public void setAttribute(String name, Object o) {
+      preq.setAttribute(name, o);
    }
-
+   
    @Override
-   public boolean isAsyncSupported() {
-      return getRequest().isAsyncSupported();
+   public void removeAttribute(String name) {
+      preq.removeAttribute(name);
    }
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   // saved methods below.
 
+//    /**
+//     * Modifies the behavior of the underlying wrapper to allow access to the
+//     * async methods.
+//     * 
+//     * @param request
+//     * @param servletContext
+//     * @param session
+//     * @param portletRequest
+//     */
+//    public PortletAsyncRequestWrapper(HttpServletRequest request, ServletContext servletContext, HttpSession session,
+//          PortletRequest portletRequest) {
+//       super(request, servletContext, session, portletRequest, false, false);
+//       
+//    }
+//    
+// 
+// 
+//    @Override
+//    public AsyncContext startAsync() throws IllegalStateException {
+//       return getRequest().startAsync();
+//    }
+// 
+//    @Override
+//    public AsyncContext startAsync(ServletRequest request, ServletResponse response) throws IllegalStateException {
+//       return getRequest().startAsync(request, response);
+//    }
+// 
+//    @Override
+//    public boolean isAsyncStarted() {
+//       return getRequest().isAsyncStarted();
+//    }
+// 
+//    @Override
+//    public boolean isAsyncSupported() {
+//       return getRequest().isAsyncSupported();
+//    }
+// 
 
 }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/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 9474a10..d645aae 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
@@ -16,35 +16,33 @@
  *  under the License.
  */
 
-
 package org.apache.pluto.driver.services.container;
 
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.util.logging.Logger;
 
 import javax.portlet.ResourceRequest;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.pluto.container.PortletInvokerService;
-import org.apache.pluto.container.PortletResourceRequestContext;
 import org.apache.pluto.container.PortletResourceResponseContext;
 
 /**
  * Releases portal resources when the async request completes.
- *  
+ * 
  * @author Scott Nicklous
  */
 public class PortletAsyncListener implements AsyncListener {
    private static final Logger LOGGER = Logger.getLogger(PortletAsyncListener.class.getName());
 
-   private long start = System.currentTimeMillis();
-   
-   /* (non-Javadoc)
+   private long                start  = System.currentTimeMillis();
+
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncListener#onComplete(javax.servlet.AsyncEvent)
     */
    @Override
@@ -53,44 +51,50 @@ public class PortletAsyncListener implements AsyncListener {
       StringBuilder txt = new StringBuilder(128);
       txt.append("Completed. Execution time: ").append(delta).append(" milliseconds.");
       txt.append(" Releasing: ");
-      
-      // remove portlet-scoped barnacles
-      
-      AsyncContext ctx = evt.getAsyncContext();
-      HttpServletRequest hreq = (HttpServletRequest) ctx.getRequest();
-      ResourceRequest rreq = (ResourceRequest) hreq.getAttribute(PortletInvokerService.PORTLET_REQUEST);
-      if (rreq != null) {
-         txt.append("portlet-scoped attributes; ");
-         rreq.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
-         rreq.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
-         rreq.removeAttribute(PortletInvokerService.PORTLET_CONFIG);
-         rreq.removeAttribute(PortletInvokerService.ASYNC_METHOD);
-         
-         PortletResourceResponseContext respctx = (PortletResourceResponseContext)
-               rreq.getAttribute(PortletInvokerService.RESPONSE_CONTEXT);
-         if (respctx != null) {
-            txt.append("response context resources; ");
-            respctx.close();
-            respctx.release();
+
+      HttpServletRequest hreq = (HttpServletRequest) evt.getSuppliedRequest();
+      if (hreq != null) {
+         ResourceRequest rreq = (ResourceRequest) hreq.getAttribute(PortletInvokerService.PORTLET_REQUEST);
+         if (rreq != null) {
+
+            // remove portlet-scoped barnacles
+
+            txt.append("portlet-scoped attributes; ");
+            rreq.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
+            rreq.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
+            rreq.removeAttribute(PortletInvokerService.PORTLET_CONFIG);
+            rreq.removeAttribute(PortletInvokerService.ASYNC_METHOD);
+
+            PortletResourceResponseContext respctx = (PortletResourceResponseContext) rreq
+                  .getAttribute(PortletInvokerService.RESPONSE_CONTEXT);
+            if (respctx != null) {
+               txt.append("response context resources; ");
+               respctx.close();
+               respctx.release();
+            }
+         } else {
+            txt.append("... no resource request stuff. Couldn't get resource request; ");
          }
-      }
-      
-      // Release and remove container request attributes
-      
-      HttpServletRequest containerRequest = (HttpServletRequest) evt.getSuppliedRequest();
-      if (containerRequest != null) {
+         
+         // remove container-scoped attributes
+
          txt.append("container-scoped attributes; ");
-         containerRequest.removeAttribute(PortletInvokerService.METHOD_ID);
-         containerRequest.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
-         containerRequest.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
-         containerRequest.removeAttribute(PortletInvokerService.FILTER_MANAGER);
+         hreq.removeAttribute(PortletInvokerService.METHOD_ID);
+         hreq.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
+         hreq.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
+         hreq.removeAttribute(PortletInvokerService.FILTER_MANAGER);
+
+      } else {
+         txt.append("... nothing. Couldn't get servlet request.");
       }
-      
+
       LOGGER.fine(txt.toString());
 
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncListener#onError(javax.servlet.AsyncEvent)
     */
    @Override
@@ -102,7 +106,9 @@ public class PortletAsyncListener implements AsyncListener {
       LOGGER.fine(txt.toString());
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncListener#onStartAsync(javax.servlet.AsyncEvent)
     */
    @Override
@@ -111,14 +117,16 @@ public class PortletAsyncListener implements AsyncListener {
       StringBuilder txt = new StringBuilder(128);
       txt.append("Async started again after ").append(delta).append(" milliseconds.");
       LOGGER.fine(txt.toString());
-      
+
       // need to add this listener again so it gets called when finally complete.
-      
+
       AsyncContext ctx = evt.getAsyncContext();
       ctx.addListener(this);
    }
 
-   /* (non-Javadoc)
+   /*
+    * (non-Javadoc)
+    * 
     * @see javax.servlet.AsyncListener#onTimeout(javax.servlet.AsyncEvent)
     */
    @Override

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/79160b5d/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletResourceRequestContextImpl.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletResourceRequestContextImpl.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletResourceRequestContextImpl.java
index c361dcd..a441c29 100644
--- a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletResourceRequestContextImpl.java
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletResourceRequestContextImpl.java
@@ -16,6 +16,8 @@
  */
 package org.apache.pluto.driver.services.container;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import javax.portlet.PortletConfig;
@@ -38,6 +40,8 @@ import org.apache.pluto.container.impl.HttpServletPortletResponseWrapper;
 import org.apache.pluto.container.impl.PortletAsyncRequestWrapper;
 import org.apache.pluto.container.impl.ResourceParametersImpl;
 import org.apache.pluto.container.impl.ServletPortletSessionProxy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * @version $Id$
@@ -46,8 +50,16 @@ import org.apache.pluto.container.impl.ServletPortletSessionProxy;
 public class PortletResourceRequestContextImpl extends PortletRequestContextImpl implements
                 PortletResourceRequestContext
 {
+   
+   /** Logger. */
+   private static final Logger LOG = LoggerFactory.getLogger(PortletResourceRequestContextImpl.class);
+   private static final boolean isDebug = LOG.isDebugEnabled();
+   private static final boolean isTrace = LOG.isTraceEnabled();
+   
+   
    private String pageState;
    private ResourceResponse response;
+   private AsyncContext actx = null;
    
    
     public PortletResourceRequestContextImpl(PortletContainer container, HttpServletRequest containerRequest,
@@ -121,6 +133,35 @@ public class PortletResourceRequestContextImpl extends PortletRequestContextImpl
        ServletContext ctx = getServletContext();
        HttpSession sess = getSession();
        PortletConfig cfg = getPortletConfig(); 
+       
+       if (isDebug) {
+          List<String> attrNames = Collections.list(hreq.getAttributeNames());
+          StringBuilder txt = new StringBuilder(128);
+          txt.append("Start async before:");
+          txt.append("\nAttribute names: ").append(attrNames);
+          txt.append("\nasync_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.async.request_uri"));
+          txt.append("\nasync_context_path:      ").append((String) hreq.getAttribute("javax.servlet.async.context_path"));
+          txt.append("\nasync_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.async.servlet_path"));
+          txt.append("\nasync_path_info:      ").append((String) hreq.getAttribute("javax.servlet.async.path_info"));
+          txt.append("\nasync_query_string:      ").append((String) hreq.getAttribute("javax.servlet.async.query_string"));
+          txt.append("\nforward_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.forward.request_uri"));
+          txt.append("\nforward_context_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.context_path"));
+          txt.append("\nforward_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.servlet_path"));
+          txt.append("\nforward_path_info:      ").append((String) hreq.getAttribute("javax.servlet.forward.path_info"));
+          txt.append("\nforward_query_string:      ").append((String) hreq.getAttribute("javax.servlet.forward.query_string"));
+          txt.append("\ninclude_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.include.request_uri"));
+          txt.append("\ninclude_context_path:      ").append((String) hreq.getAttribute("javax.servlet.include.context_path"));
+          txt.append("\ninclude_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.include.servlet_path"));
+          txt.append("\ninclude_path_info:      ").append((String) hreq.getAttribute("javax.servlet.include.path_info"));
+          txt.append("\ninclude_query_string:      ").append((String) hreq.getAttribute("javax.servlet.include.query_string"));
+          txt.append("\nmethod_request_uri:      ").append(hreq.getRequestURI());
+          txt.append("\nmethod_context_path:      ").append(hreq.getContextPath());
+          txt.append("\nmethod_servlet_path:      ").append(hreq.getServletPath());
+          txt.append("\nmethod_path_info:      ").append(hreq.getPathInfo());
+          txt.append("\nmethod_query_string:      ").append(hreq.getQueryString());
+          LOG.debug(txt.toString());
+       }
+
 
        // Set portlet-scoped attributes directly on resource request
        
@@ -130,7 +171,7 @@ public class PortletResourceRequestContextImpl extends PortletRequestContextImpl
 
        // Wrap http req & response. 
        
-       HttpServletRequest wreq = new PortletAsyncRequestWrapper(hreq, ctx, sess, request);
+       HttpServletRequest wreq = new PortletAsyncRequestWrapper(hreq, request);
        HttpServletResponse wresp = new HttpServletPortletResponseWrapper(hresp, request, response, false);
 
        // get the original container req & resp to pass to listener for resource releasing
@@ -138,11 +179,46 @@ public class PortletResourceRequestContextImpl extends PortletRequestContextImpl
        HttpServletRequest creq = getContainerRequest();     
        HttpServletResponse cresp = getContainerResponse();
 
-       // Attach listener to release resources upon async complete.
+       // Start async, add listener to release resources upon async complete only once.
        
-       AsyncContext actx = hreq.startAsync(wreq, wresp);
-       PortletAsyncListener pal = new PortletAsyncListener();
-       actx.addListener(pal, creq, cresp);
+       if (actx == null) {
+          actx = hreq.startAsync(wreq, wresp);
+//          actx = hreq.startAsync(hreq, hresp);
+          PortletAsyncListener pal = new PortletAsyncListener();
+          actx.addListener(pal, creq, cresp);
+       } else {
+//          actx = hreq.startAsync(hreq, hresp);
+          actx = hreq.startAsync(wreq, wresp);
+       }
+
+       
+       if (isDebug) {
+          List<String> attrNames = Collections.list(hreq.getAttributeNames());
+          StringBuilder txt = new StringBuilder(128);
+          txt.append("Start async after:");
+          txt.append("\nAttribute names: ").append(attrNames);
+          txt.append("\nasync_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.async.request_uri"));
+          txt.append("\nasync_context_path:      ").append((String) hreq.getAttribute("javax.servlet.async.context_path"));
+          txt.append("\nasync_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.async.servlet_path"));
+          txt.append("\nasync_path_info:      ").append((String) hreq.getAttribute("javax.servlet.async.path_info"));
+          txt.append("\nasync_query_string:      ").append((String) hreq.getAttribute("javax.servlet.async.query_string"));
+          txt.append("\nforward_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.forward.request_uri"));
+          txt.append("\nforward_context_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.context_path"));
+          txt.append("\nforward_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.forward.servlet_path"));
+          txt.append("\nforward_path_info:      ").append((String) hreq.getAttribute("javax.servlet.forward.path_info"));
+          txt.append("\nforward_query_string:      ").append((String) hreq.getAttribute("javax.servlet.forward.query_string"));
+          txt.append("\ninclude_request_uri:      ").append((String) hreq.getAttribute("javax.servlet.include.request_uri"));
+          txt.append("\ninclude_context_path:      ").append((String) hreq.getAttribute("javax.servlet.include.context_path"));
+          txt.append("\ninclude_servlet_path:      ").append((String) hreq.getAttribute("javax.servlet.include.servlet_path"));
+          txt.append("\ninclude_path_info:      ").append((String) hreq.getAttribute("javax.servlet.include.path_info"));
+          txt.append("\ninclude_query_string:      ").append((String) hreq.getAttribute("javax.servlet.include.query_string"));
+          txt.append("\nmethod_request_uri:      ").append(hreq.getRequestURI());
+          txt.append("\nmethod_context_path:      ").append(hreq.getContextPath());
+          txt.append("\nmethod_servlet_path:      ").append(hreq.getServletPath());
+          txt.append("\nmethod_path_info:      ").append(hreq.getPathInfo());
+          txt.append("\nmethod_query_string:      ").append(hreq.getQueryString());
+          LOG.debug(txt.toString());
+       }
 
        return actx;
     }