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:46 UTC

[34/34] portals-pluto git commit: Added new classes for asynchronous processing and improved async documentation. New classes: PortletAsyncListener, PortletAsyncContext, and PortletAsyncEvent. Modified the Pluto implmentation to use the new interfaces. M

Added new classes for asynchronous processing and improved async
documentation. New classes: PortletAsyncListener, PortletAsyncContext, and
PortletAsyncEvent. Modified the Pluto implmentation to use the new
interfaces. Modified AsyncPortlet to used the newly introduced classes and
methods.


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

Branch: refs/heads/V3Prototype
Commit: 0e71c8ab72fe1d57f20a3b1a3ec357bd328930da
Parents: 1cbbbc3
Author: Scott Nicklous <ms...@apache.org>
Authored: Wed Apr 6 15:16:53 2016 +0200
Committer: Scott Nicklous <ms...@apache.org>
Committed: Wed Apr 6 15:16:53 2016 +0200

----------------------------------------------------------------------
 .../org/apache/portals/samples/APFilter.java    |  82 +++++
 .../org/apache/portals/samples/APListener.java  | 172 ++++++++++
 .../apache/portals/samples/AsyncPortlet.java    | 304 +++++++++++++++++
 .../portals/samples/AsyncPortletFilter.java     |  82 -----
 .../portals/samples/AsyncPortletListener.java   | 171 ----------
 .../portals/samples/AsyncPortletResource.java   | 316 -----------------
 .../src/main/webapp/WEB-INF/jsp/asyncOutput.jsp |   2 +-
 .../pluto/container/PortletAsyncContext.java    |  15 -
 .../pluto/container/PortletAsyncManager.java    |  15 +
 .../PortletResourceRequestContext.java          |   2 +-
 .../pluto/container/driver/PortletServlet3.java |   4 +-
 .../impl/PortletAsyncRequestWrapper.java        |  56 +---
 .../container/impl/ResourceRequestImpl.java     |  14 +-
 .../fixtures/mocks/MockResourceRequest.java     |   8 +-
 .../services/container/FilterManagerImpl.java   |   3 +-
 .../container/PortletAsyncContextImpl.java      |  94 ++++--
 .../container/PortletAsyncContextListener.java  | 335 +++++++++++++++++++
 .../container/PortletAsyncContextualRunner.java |   6 +-
 .../container/PortletAsyncListener.java         | 299 -----------------
 .../PortletResourceRequestContextImpl.java      |  17 +-
 .../java/javax/portlet/PortletAsyncContext.java | 200 ++++++++---
 .../java/javax/portlet/PortletAsyncEvent.java   |  40 ++-
 .../javax/portlet/PortletAsyncListener.java     |  16 +-
 .../java/javax/portlet/ResourceRequest.java     |   7 +-
 .../filter/ClientDataRequestWrapper.java        |   1 -
 .../javax/portlet/filter/ResourceFilter.java    |   7 +-
 .../portlet/filter/ResourceRequestWrapper.java  |   8 +-
 portlet-api/src/main/javadoc/overview.html      |  13 +
 portlet-api/src/main/javadoc/portlet-api.css    |   6 +-
 29 files changed, 1252 insertions(+), 1043 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APFilter.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APFilter.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APFilter.java
new file mode 100644
index 0000000..cccc71b
--- /dev/null
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APFilter.java
@@ -0,0 +1,82 @@
+/*  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.portals.samples;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+import javax.portlet.PortletException;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+import javax.portlet.annotations.PortletRequestFilter;
+import javax.portlet.filter.FilterChain;
+import javax.portlet.filter.FilterConfig;
+import javax.portlet.filter.ResourceFilter;
+import javax.servlet.DispatcherType;
+
+/**
+ * Filter for the async portlet. logs the dispatcher type and sometimes
+ * generates output.
+ * 
+ * @author Scott Nicklous
+ *
+ */
+@PortletRequestFilter(portletNames="AsyncPortlet")
+public class APFilter implements ResourceFilter {
+   private static final Logger LOGGER = Logger.getLogger(APFilter.class.getName());
+   
+   @Inject private PortletRequestRandomNumberBean reqnum;
+   @Inject private AsyncDialogBean adb;
+
+   @Override
+   public void init(FilterConfig filterConfig) throws PortletException {
+   }
+
+   @Override
+   public void destroy() {
+   }
+
+   @Override
+   public void doFilter(ResourceRequest request, ResourceResponse response, FilterChain chain) throws IOException,
+         PortletException {
+      
+      DispatcherType type = request.getDispatcherType();
+      
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Entering request. Dispatcher type: ").append(type);
+      txt.append(", request #: ").append(reqnum.getRandomNumber());
+      LOGGER.fine(txt.toString());
+      
+      if (adb.isShowFilter()) {
+         txt.setLength(0);
+         txt.append("<div class='msgbox'>");
+         txt.append("Filter: Request number: ").append(reqnum.getRandomNumber());
+         txt.append(", dispatcher type: ").append(request.getDispatcherType());
+         txt.append("</div>");
+         response.getWriter().write(txt.toString());
+      }
+      
+      chain.doFilter(request, response);
+      
+      LOGGER.fine("Exiting request. Dispatcher type: " + request.getDispatcherType());
+      
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APListener.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APListener.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APListener.java
new file mode 100644
index 0000000..11847a9
--- /dev/null
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/APListener.java
@@ -0,0 +1,172 @@
+/*  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.portals.samples;
+
+import static org.apache.portals.samples.AsyncPortlet.ATTRIB_TIMEOUT;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+import javax.portlet.PortletAsyncContext;
+import javax.portlet.PortletAsyncEvent;
+import javax.portlet.PortletAsyncListener;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+
+import org.apache.portals.samples.AsyncDialogBean.TimeoutType;
+
+/**
+ * @author Scott Nicklous
+ * 
+ */
+public class APListener implements PortletAsyncListener {
+   private static final Logger            LOGGER = Logger.getLogger(APListener.class.getName());
+
+   private long                           start  = System.currentTimeMillis();
+
+   @Inject
+   private PortletRequestRandomNumberBean reqnum;
+   @Inject
+   private AsyncDialogBean                adb;
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onComplete(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onComplete(PortletAsyncEvent evt) throws IOException {
+      long delta = System.currentTimeMillis() - start;
+
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Listener: Completed. Execution time: ").append(delta).append(" milliseconds.");
+
+      LOGGER.fine(txt.toString());
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onError(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onError(PortletAsyncEvent evt) throws IOException {
+
+      // this doesn't seem to get called when an error occurs in the executor
+      // thread.
+
+      long delta = System.currentTimeMillis() - start;
+
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Listener: Error after ").append(delta).append(" milliseconds.");
+      txt.append(", Exception: ").append(evt.getThrowable().getMessage());
+
+      LOGGER.fine(txt.toString());
+      evt.getPortletAsyncContext().complete();
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onStartAsync(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onStartAsync(PortletAsyncEvent evt) throws IOException {
+      long delta = System.currentTimeMillis() - start;
+      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.
+
+      PortletAsyncContext ctx = evt.getPortletAsyncContext();
+      // ctx.addListener(this);
+
+      // Try to write some output.
+
+      try {
+         if (adb.isShowListener()) {
+            ResourceRequest req = ctx.getResourceRequest();
+            ResourceResponse resp = ctx.getResourceResponse();
+            txt.setLength(0);
+            txt.append("<div class='orangebox'>");
+            txt.append("Listener: restarting async.");
+            txt.append("<span style='margin-left: 2em;'>");
+            txt.append("Request number: ").append(reqnum.getRandomNumber());
+            txt.append("</span>");
+            txt.append("<span style='margin-left: 2em;'>");
+            txt.append("Dispatcher type: ").append(req.getDispatcherType());
+            txt.append("</span>");
+            txt.append("</div>");
+            resp.getWriter().write(txt.toString());
+         }
+      } catch (Exception e) {
+         StringWriter sw = new StringWriter();
+         PrintWriter pw = new PrintWriter(sw);
+         e.printStackTrace(pw);
+         pw.flush();
+         LOGGER.fine("Exception producing output: \n" + sw.toString());
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onTimeout(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onTimeout(PortletAsyncEvent evt) throws IOException {
+      long delta = System.currentTimeMillis() - start;
+
+      try {
+         ResourceRequest req = evt.getPortletAsyncContext().getResourceRequest();
+         if (adb.isShowListener()) {
+            StringBuilder txt = new StringBuilder(128);
+            txt.append("<div class='orangebox'>");
+            txt.append("APListener: Timeout after ").append(delta).append(" milliseconds.");
+            txt.append("<span style='margin-left: 2em;'>");
+            txt.append("Action: ").append(adb.getHandleTimeout().toString());
+            txt.append("</span>");
+            txt.append("<span style='margin-left: 2em;'>");
+            txt.append("Request number: ").append(reqnum.getRandomNumber());
+            txt.append("</span>");
+            txt.append("<span style='margin-left: 2em;'>");
+            txt.append("Dispatcher type: ").append(req.getDispatcherType());
+            txt.append("</span>");
+            txt.append("</div>");
+            PrintWriter writer = evt.getPortletAsyncContext().getResourceResponse().getWriter();
+            writer.println(txt.toString());
+         }
+         
+         if (adb.getHandleTimeout() == TimeoutType.CPL) {
+            evt.getPortletAsyncContext().complete();
+         } else if (adb.getHandleTimeout() == TimeoutType.DIS) {
+            req.setAttribute(ATTRIB_TIMEOUT, ATTRIB_TIMEOUT);
+            evt.getPortletAsyncContext().dispatch();
+         }
+      } catch (Exception e) {
+         LOGGER.warning(" Couldn't get response to generate output. Exception: " + e.toString());
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortlet.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortlet.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortlet.java
new file mode 100644
index 0000000..2ae2fae
--- /dev/null
+++ b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortlet.java
@@ -0,0 +1,304 @@
+/*  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.portals.samples;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+import javax.portlet.PortletAsyncContext;
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletException;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+import javax.portlet.annotations.ServeResourceMethod;
+
+import org.apache.portals.samples.AsyncDialogBean.OutputType;
+
+/**
+ * Implements the async resource method for the async portlet.
+ * 
+ * @author Scott Nicklous
+ * 
+ */
+public class AsyncPortlet {
+   private static final Logger LOGGER = Logger.getLogger(AsyncPortlet.class.getName());
+   private static final boolean isTrace = LOGGER.isLoggable(Level.FINEST);
+   
+   private final static String JSP         = "/WEB-INF/jsp/asyncOutput.jsp";
+   private final static String ATTRIB_REPS = "reps";
+   private final static String ATTRIB_AUTO = "auto";
+   public  final static String ATTRIB_TITLE = "title";
+   public  final static String ATTRIB_TIMEOUT = "timeout";
+
+   public static class AsyncRunnable implements Runnable {
+
+      private PortletAsyncContext ctx;
+      private int          delay;
+      private OutputType   type;
+      
+      @Inject private PortletRequestRandomNumberBean reqnum;
+
+      public void init(PortletAsyncContext ctx, int delay, OutputType type) {
+         this.ctx = ctx;
+         this.delay = delay;
+         this.type = type;
+         
+         StringBuilder txt = new StringBuilder(128);
+         txt.append("Initializing runnable.");
+         txt.append(" delay: ").append(delay);
+         txt.append(", type: ").append(type);
+         LOGGER.fine(txt.toString());
+      }
+
+      @Override
+      public void run() {
+         try {
+            Thread.sleep(delay);
+
+            ResourceRequest req = ctx.getResourceRequest();
+            ResourceResponse resp = ctx.getResourceResponse();
+            PortletRequestDispatcher rd = req.getPortletContext().getRequestDispatcher(JSP);
+            
+            AsyncPortlet.trace(req, "Runnable: ");
+            
+            PortletConfig config = (PortletConfig) req.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 for portlet: " + portletName + "</h5>");
+               txt.append("<p>Dispatcher type: ").append(req.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>");
+               resp.getWriter().write(txt.toString());
+               ctx.complete();
+               break;
+            case AUTO:
+               StringBuilder str = new StringBuilder(128);
+               str.append("Dispatching to resource method.");
+               str.append(" context path: ").append(req.getPortletContext().getContextPath());
+               LOGGER.fine(str.toString());
+               req.setAttribute(ATTRIB_AUTO, new Boolean(true));
+               ctx.dispatch();
+               break;
+            case DISPATCH:
+               LOGGER.fine("Dispatching to JSP.");
+               req.setAttribute(ATTRIB_TITLE, "Thread dispatching to JSP");
+               ctx.dispatch(JSP);
+               break;
+            case FWD:
+               LOGGER.fine("Doing request dispatcher forward to JSP: " + JSP);
+               req.setAttribute(ATTRIB_TITLE, "Thread forwarding to JSP");
+               rd.forward(req, resp);
+               LOGGER.fine("After request dispatcher forward to JSP.");
+               ctx.complete();
+               break;
+            case INC:
+               LOGGER.fine("Including JSP: " + JSP);
+               req.setAttribute(ATTRIB_TITLE, "Thread including JSP");
+               rd.include(req, resp);
+               ctx.complete();
+               break;
+            }
+
+         } catch (IllegalStateException e) {
+            LOGGER.warning("Request may have timed out before it could complete. Exception: " + e.toString());
+         } catch (Exception e) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            e.printStackTrace(pw);
+            pw.flush();
+            LOGGER.fine("Exception during runner execution: \n" + sw.toString());
+         }
+      }
+
+   }
+
+   @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 {
+      
+      if (req.getAttribute(ATTRIB_TIMEOUT) != null) {
+         StringBuilder txt = new StringBuilder(128);
+         txt.append("<p>Resource method: listener reports timout.");
+         txt.append("<span style='margin-left: 2em;'>Request #: ");
+         txt.append("dispatcher type: ").append(req.getDispatcherType().toString());
+         txt.append("</span>");
+         txt.append("<span style='margin-left: 2em;'>Request #: ");
+         txt.append(reqnum.getRandomNumber());
+         txt.append("</span></p><hr>");
+         resp.getWriter().write(txt.toString());
+         return;
+      }
+
+      Boolean auto = (Boolean) req.getAttribute(ATTRIB_AUTO);
+      if (auto == null) {
+         auto = false;
+      }
+      req.removeAttribute(ATTRIB_AUTO);
+
+      Integer reps = (Integer) req.getAttribute(ATTRIB_REPS);
+      if (reps == null) {
+         reps = adb.getReps();
+      }
+      
+      boolean done = (reps <= 0) || (adb.getDelay() <= 0);
+
+      reps--;
+      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);
+      LOGGER.fine(txt.toString());
+      
+      PortletAsyncContext ctx = req.startAsync();
+      ctx.setTimeout(4000);
+      try {
+         ctx.addListener(ctx.createPortletAsyncListener(APListener.class));
+      } catch (PortletException e) {
+         StringWriter sw = new StringWriter();
+         PrintWriter pw = new PrintWriter(sw);
+         e.printStackTrace(pw);
+         pw.flush();
+         LOGGER.fine("Exception adding listener: \n" + sw.toString());
+      }
+
+      if (auto || (adb.getDelay() <= 0)) {
+         
+         // produce output if dispatched from work thread or if there is no delay requested
+         
+         PortletRequestDispatcher rd;
+
+         trace(req, "Resource method: ");
+         
+         // 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.");
+            req.setAttribute(ATTRIB_TITLE, "Resource Method dispatching to 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);
+            resp.flushBuffer();
+            if (done) {
+               ctx.complete();
+            }
+            break;
+         case INC:
+            LOGGER.fine("Doing request dispatcher include of JSP.");
+            req.setAttribute(ATTRIB_TITLE, "Resource Method including JSP");
+            rd = req.getPortletContext().getRequestDispatcher(JSP);
+            rd.include(req, resp);
+            resp.flushBuffer();
+            if (done) {
+               ctx.complete();
+            }
+            break;
+         default:
+            LOGGER.fine("Producing text output.");
+            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("<span style='margin-left: 2em;'>Request #: ");
+            txt.append(reqnum.getRandomNumber());
+            txt.append("</span></p><hr>");
+            resp.getWriter().write(txt.toString());
+            resp.flushBuffer();
+            if (done) {
+               ctx.complete();
+            }
+            break;
+         }
+      }
+      
+      if (!done) {
+         
+         // now start the executor thread 
+         
+         OutputType type = adb.getType();
+         if (adb.isAutoDispatch()) {
+            type = OutputType.AUTO;
+         }
+
+         runner.init(ctx, adb.getDelay(), type);
+         ctx.start(runner);
+      }
+   }
+   
+   public static void trace(ResourceRequest req, String src) {
+      if (isTrace) {
+         List<String> attrNames = Collections.list(req.getAttributeNames());
+         StringBuilder txt = new StringBuilder(128);
+         txt.append(src);
+         txt.append("\nAttribute names: ").append(attrNames);
+         txt.append("\nasync_request_uri:      ").append((String) req.getAttribute("javax.servlet.async.request_uri"));
+         txt.append("\nasync_context_path:      ").append((String) req.getAttribute("javax.servlet.async.context_path"));
+         txt.append("\nasync_servlet_path:      ").append((String) req.getAttribute("javax.servlet.async.servlet_path"));
+         txt.append("\nasync_path_info:      ").append((String) req.getAttribute("javax.servlet.async.path_info"));
+         txt.append("\nasync_query_string:      ").append((String) req.getAttribute("javax.servlet.async.query_string"));
+         txt.append("\nforward_request_uri:      ").append((String) req.getAttribute("javax.servlet.forward.request_uri"));
+         txt.append("\nforward_context_path:      ").append((String) req.getAttribute("javax.servlet.forward.context_path"));
+         txt.append("\nforward_servlet_path:      ").append((String) req.getAttribute("javax.servlet.forward.servlet_path"));
+         txt.append("\nforward_path_info:      ").append((String) req.getAttribute("javax.servlet.forward.path_info"));
+         txt.append("\nforward_query_string:      ").append((String) req.getAttribute("javax.servlet.forward.query_string"));
+         txt.append("\ninclude_request_uri:      ").append((String) req.getAttribute("javax.servlet.include.request_uri"));
+         txt.append("\ninclude_context_path:      ").append((String) req.getAttribute("javax.servlet.include.context_path"));
+         txt.append("\ninclude_servlet_path:      ").append((String) req.getAttribute("javax.servlet.include.servlet_path"));
+         txt.append("\ninclude_path_info:      ").append((String) req.getAttribute("javax.servlet.include.path_info"));
+         txt.append("\ninclude_query_string:      ").append((String) req.getAttribute("javax.servlet.include.query_string"));
+         txt.append("\nmethod_context_path:      ").append(req.getContextPath());
+         LOGGER.fine(txt.toString());
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletFilter.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletFilter.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletFilter.java
deleted file mode 100644
index 09eff20..0000000
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletFilter.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*  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.portals.samples;
-
-import java.io.IOException;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-import javax.portlet.PortletException;
-import javax.portlet.ResourceRequest;
-import javax.portlet.ResourceResponse;
-import javax.portlet.annotations.PortletRequestFilter;
-import javax.portlet.filter.FilterChain;
-import javax.portlet.filter.FilterConfig;
-import javax.portlet.filter.ResourceFilter;
-import javax.servlet.DispatcherType;
-
-/**
- * Filter for the async portlet. logs the dispatcher type and sometimes
- * generates output.
- * 
- * @author Scott Nicklous
- *
- */
-@PortletRequestFilter(portletNames="AsyncPortlet")
-public class AsyncPortletFilter implements ResourceFilter {
-   private static final Logger LOGGER = Logger.getLogger(AsyncPortletFilter.class.getName());
-   
-   @Inject private PortletRequestRandomNumberBean reqnum;
-   @Inject private AsyncDialogBean adb;
-
-   @Override
-   public void init(FilterConfig filterConfig) throws PortletException {
-   }
-
-   @Override
-   public void destroy() {
-   }
-
-   @Override
-   public void doFilter(ResourceRequest request, ResourceResponse response, FilterChain chain) throws IOException,
-         PortletException {
-      
-      DispatcherType type = request.getDispatcherType();
-      
-      StringBuilder txt = new StringBuilder(128);
-      txt.append("Entering request. Dispatcher type: ").append(type);
-      txt.append(", request #: ").append(reqnum.getRandomNumber());
-      LOGGER.fine(txt.toString());
-      
-      if (adb.isShowFilter()) {
-         txt.setLength(0);
-         txt.append("<div class='msgbox'>");
-         txt.append("Filter: Request number: ").append(reqnum.getRandomNumber());
-         txt.append(", dispatcher type: ").append(request.getDispatcherType());
-         txt.append("</div>");
-         response.getWriter().write(txt.toString());
-      }
-      
-      chain.doFilter(request, response);
-      
-      LOGGER.fine("Exiting request. Dispatcher type: " + request.getDispatcherType());
-      
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletListener.java
----------------------------------------------------------------------
diff --git a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletListener.java b/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletListener.java
deleted file mode 100644
index d8fd5fb..0000000
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletListener.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*  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.portals.samples;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import static org.apache.portals.samples.AsyncDialogBean.TimeoutType;
-import static org.apache.portals.samples.AsyncPortletResource.*;
-
-/**
- * @author Scott Nicklous
- * 
- */
-public class AsyncPortletListener implements AsyncListener {
-   private static final Logger            LOGGER = Logger.getLogger(AsyncPortletListener.class.getName());
-
-   private long                           start  = System.currentTimeMillis();
-
-   @Inject
-   private PortletRequestRandomNumberBean reqnum;
-   @Inject
-   private AsyncDialogBean                adb;
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see javax.servlet.AsyncListener#onComplete(javax.servlet.AsyncEvent)
-    */
-   @Override
-   public void onComplete(AsyncEvent evt) throws IOException {
-      long delta = System.currentTimeMillis() - start;
-
-      StringBuilder txt = new StringBuilder(128);
-      txt.append("Listener: Completed. Execution time: ").append(delta).append(" milliseconds.");
-
-      LOGGER.fine(txt.toString());
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see javax.servlet.AsyncListener#onError(javax.servlet.AsyncEvent)
-    */
-   @Override
-   public void onError(AsyncEvent evt) throws IOException {
-
-      // this doesn't seem to get called when an error occurs in the executor
-      // thread.
-
-      long delta = System.currentTimeMillis() - start;
-
-      StringBuilder txt = new StringBuilder(128);
-      txt.append("Listener: Error after ").append(delta).append(" milliseconds.");
-      txt.append(", Exception: ").append(evt.getThrowable().getMessage());
-
-      LOGGER.fine(txt.toString());
-      evt.getAsyncContext().complete();
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see javax.servlet.AsyncListener#onStartAsync(javax.servlet.AsyncEvent)
-    */
-   @Override
-   public void onStartAsync(AsyncEvent evt) throws IOException {
-      long delta = System.currentTimeMillis() - start;
-      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);
-
-      // Try to write some output.
-
-      try {
-         if (adb.isShowListener()) {
-            HttpServletRequest req = (HttpServletRequest) ctx.getRequest();
-            HttpServletResponse resp = (HttpServletResponse) ctx.getResponse();
-            txt.setLength(0);
-            txt.append("<div class='orangebox'>");
-            txt.append("Listener: restarting async.");
-            txt.append("<span style='margin-left: 2em;'>");
-            txt.append("Request number: ").append(reqnum.getRandomNumber());
-            txt.append("</span>");
-            txt.append("<span style='margin-left: 2em;'>");
-            txt.append("Dispatcher type: ").append(req.getDispatcherType());
-            txt.append("</span>");
-            txt.append("</div>");
-            resp.getWriter().write(txt.toString());
-         }
-      } catch (Exception e) {
-         StringWriter sw = new StringWriter();
-         PrintWriter pw = new PrintWriter(sw);
-         e.printStackTrace(pw);
-         pw.flush();
-         LOGGER.fine("Exception producing output: \n" + sw.toString());
-      }
-   }
-
-   /*
-    * (non-Javadoc)
-    * 
-    * @see javax.servlet.AsyncListener#onTimeout(javax.servlet.AsyncEvent)
-    */
-   @Override
-   public void onTimeout(AsyncEvent evt) throws IOException {
-      long delta = System.currentTimeMillis() - start;
-
-      try {
-         HttpServletRequest req = (HttpServletRequest) evt.getAsyncContext().getRequest();
-         if (adb.isShowListener()) {
-            StringBuilder txt = new StringBuilder(128);
-            txt.append("<div class='orangebox'>");
-            txt.append("AsyncPortletListener: Timeout after ").append(delta).append(" milliseconds.");
-            txt.append("<span style='margin-left: 2em;'>");
-            txt.append("Action: ").append(adb.getHandleTimeout().toString());
-            txt.append("</span>");
-            txt.append("<span style='margin-left: 2em;'>");
-            txt.append("Request number: ").append(reqnum.getRandomNumber());
-            txt.append("</span>");
-            txt.append("<span style='margin-left: 2em;'>");
-            txt.append("Dispatcher type: ").append(req.getDispatcherType());
-            txt.append("</span>");
-            txt.append("</div>");
-            PrintWriter writer = evt.getAsyncContext().getResponse().getWriter();
-            writer.println(txt.toString());
-         }
-         
-         if (adb.getHandleTimeout() == TimeoutType.CPL) {
-            evt.getAsyncContext().complete();
-         } else if (adb.getHandleTimeout() == TimeoutType.DIS) {
-            req.setAttribute(ATTRIB_TIMEOUT, ATTRIB_TIMEOUT);
-            evt.getAsyncContext().dispatch();
-         }
-      } catch (Exception e) {
-         LOGGER.warning(" Couldn't get response to generate output. Exception: " + e.toString());
-      }
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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
deleted file mode 100644
index 1c25e61..0000000
--- a/PortletV3AnnotatedDemo/src/main/java/org/apache/portals/samples/AsyncPortletResource.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*  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.portals.samples;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Level;
-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;
-import javax.portlet.ResourceResponse;
-import javax.portlet.annotations.ServeResourceMethod;
-import javax.servlet.AsyncContext;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.portals.samples.AsyncDialogBean.OutputType;
-
-/**
- * Implements the async resource method for the async portlet.
- * 
- * @author Scott Nicklous
- * 
- */
-public class AsyncPortletResource {
-   private static final Logger LOGGER = Logger.getLogger(AsyncPortletResource.class.getName());
-   private static final boolean isTrace = LOGGER.isLoggable(Level.FINEST);
-   
-   private final static String JSP         = "/WEB-INF/jsp/asyncOutput.jsp";
-   private final static String ATTRIB_REPS = "reps";
-   private final static String ATTRIB_AUTO = "auto";
-   public  final static String ATTRIB_TITLE = "title";
-   public  final static String ATTRIB_TIMEOUT = "timeout";
-
-   public static class AsyncRunnable implements Runnable {
-
-      private AsyncContext ctx;
-      private int          delay;
-      private OutputType   type;
-      
-      @Inject private PortletRequestRandomNumberBean reqnum;
-
-      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("Initializing runnable.");
-         txt.append(" delay: ").append(delay);
-         txt.append(", type: ").append(type);
-         LOGGER.fine(txt.toString());
-      }
-
-      @Override
-      public void run() {
-         try {
-            Thread.sleep(delay);
-
-            HttpServletRequest hreq = (HttpServletRequest) ctx.getRequest();
-            HttpServletResponse hresp = (HttpServletResponse) ctx.getResponse();
-            RequestDispatcher rd;
-            
-            AsyncPortletResource.trace(hreq, "Runnable: ");
-            
-            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 for portlet: " + portletName + "</h5>");
-               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;
-            case AUTO:
-               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();
-               break;
-            case DISPATCH:
-               LOGGER.fine("Dispatching to JSP.");
-               hreq.setAttribute(ATTRIB_TITLE, "Thread dispatching to JSP");
-               ctx.dispatch(JSP);
-               break;
-            case FWD:
-               LOGGER.fine("Doing request dispatcher forward to JSP: " + JSP);
-               hreq.setAttribute(ATTRIB_TITLE, "Thread forwarding to JSP");
-               rd = hreq.getRequestDispatcher(JSP);
-               rd.forward(hreq, hresp);
-               LOGGER.fine("After request dispatcher forward to JSP.");
-               ctx.complete();
-               break;
-            case INC:
-               LOGGER.fine("Including JSP: " + JSP);
-               hreq.setAttribute(ATTRIB_TITLE, "Thread including JSP");
-               rd = hreq.getRequestDispatcher(JSP);
-               rd.include(hreq, hresp);
-               ctx.complete();
-               break;
-            }
-
-         } catch (IllegalStateException e) {
-            LOGGER.warning("Request may have timed out before it could complete. Exception: " + e.toString());
-         } catch (Exception e) {
-            LOGGER.warning("Exception during async processing: " + e.toString());
-         }
-      }
-
-   }
-
-   @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 {
-      
-      if (req.getAttribute(ATTRIB_TIMEOUT) != null) {
-         StringBuilder txt = new StringBuilder(128);
-         txt.append("<p>Resource method: listener reports timout.");
-         txt.append("<span style='margin-left: 2em;'>Request #: ");
-         txt.append("dispatcher type: ").append(req.getDispatcherType().toString());
-         txt.append("</span>");
-         txt.append("<span style='margin-left: 2em;'>Request #: ");
-         txt.append(reqnum.getRandomNumber());
-         txt.append("</span></p><hr>");
-         resp.getWriter().write(txt.toString());
-         return;
-      }
-
-      Boolean auto = (Boolean) req.getAttribute(ATTRIB_AUTO);
-      if (auto == null) {
-         auto = false;
-      }
-      req.removeAttribute(ATTRIB_AUTO);
-
-      Integer reps = (Integer) req.getAttribute(ATTRIB_REPS);
-      if (reps == null) {
-         reps = adb.getReps();
-      }
-      
-      boolean done = (reps <= 0) || (adb.getDelay() <= 0);
-
-      reps--;
-      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);
-      LOGGER.fine(txt.toString());
-      
-      AsyncContext ctx = req.startAsync();
-      ctx.setTimeout(4000);
-      try {
-         ctx.addListener(ctx.createListener(AsyncPortletListener.class));
-      } catch (ServletException e) {
-         StringWriter sw = new StringWriter();
-         PrintWriter pw = new PrintWriter(sw);
-         e.printStackTrace(pw);
-         pw.flush();
-         LOGGER.fine("Exception adding listener: \n" + sw.toString());
-      }
-
-      if (auto || (adb.getDelay() <= 0)) {
-         
-         // produce output if dispatched from work thread or if there is no delay requested
-         
-         PortletRequestDispatcher rd;
-
-         trace(req, "Resource method: ");
-         
-         // 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.");
-            req.setAttribute(ATTRIB_TITLE, "Resource Method dispatching to 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);
-            resp.flushBuffer();
-            if (done) {
-               ctx.complete();
-            }
-            break;
-         case INC:
-            LOGGER.fine("Doing request dispatcher include of JSP.");
-            req.setAttribute(ATTRIB_TITLE, "Resource Method including JSP");
-            rd = req.getPortletContext().getRequestDispatcher(JSP);
-            rd.include(req, resp);
-            resp.flushBuffer();
-            if (done) {
-               ctx.complete();
-            }
-            break;
-         default:
-            LOGGER.fine("Producing text output.");
-            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("<span style='margin-left: 2em;'>Request #: ");
-            txt.append(reqnum.getRandomNumber());
-            txt.append("</span></p><hr>");
-            resp.getWriter().write(txt.toString());
-            resp.flushBuffer();
-            if (done) {
-               ctx.complete();
-            }
-            break;
-         }
-      }
-      
-      if (!done) {
-         
-         // now start the executor thread 
-         
-         OutputType type = adb.getType();
-         if (adb.isAutoDispatch()) {
-            type = OutputType.AUTO;
-         }
-
-         runner.init(ctx, adb.getDelay(), type);
-         ctx.start(runner);
-      }
-   }
-   
-   public static void trace(ResourceRequest req, String src) {
-      HttpServletRequest hreq = (HttpServletRequest) req.getAttribute("javax.portlet.debug.ServletRequest");
-      trace(hreq, src);
-   }
-   
-   public static void trace(HttpServletRequest hreq, String src) {
-      if (isTrace) {
-         List<String> attrNames = Collections.list(hreq.getAttributeNames());
-         StringBuilder txt = new StringBuilder(128);
-         txt.append(src);
-         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());
-      }
-
-   }
-}

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

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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
deleted file mode 100644
index 0892139..0000000
--- a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncContext.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.apache.pluto.container;
-
-import javax.servlet.AsyncContext;
-
-public interface PortletAsyncContext extends AsyncContext {
-
-   void setWrapped(AsyncContext actx);
-   void registerContext(boolean isListener);
-   void deregisterContext(boolean isListener);
-   void removeContext();
-   void launchRunner();
-   boolean isComplete();
-   void setComplete(boolean complete);
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncManager.java
----------------------------------------------------------------------
diff --git a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncManager.java b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncManager.java
new file mode 100644
index 0000000..cf71a4c
--- /dev/null
+++ b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletAsyncManager.java
@@ -0,0 +1,15 @@
+package org.apache.pluto.container;
+
+import javax.servlet.AsyncContext;
+
+public interface PortletAsyncManager {
+
+   void setWrapped(AsyncContext actx);
+   void registerContext(boolean isListener);
+   void deregisterContext(boolean isListener);
+   void removeContext();
+   void launchRunner();
+   boolean isComplete();
+   void setComplete(boolean complete);
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-container-api/src/main/java/org/apache/pluto/container/PortletResourceRequestContext.java
----------------------------------------------------------------------
diff --git a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletResourceRequestContext.java b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletResourceRequestContext.java
index b999eee..c5ef832 100644
--- a/pluto-container-api/src/main/java/org/apache/pluto/container/PortletResourceRequestContext.java
+++ b/pluto-container-api/src/main/java/org/apache/pluto/container/PortletResourceRequestContext.java
@@ -75,7 +75,7 @@ public interface PortletResourceRequestContext extends PortletRequestContext
     HttpSession getSession();
     AsyncContext startAsync();
     AsyncContext startAsync(ServletRequest request, ServletResponse response);
-    PortletAsyncContext getPortletAsyncContext();
+    PortletAsyncManager getPortletAsyncContext();
     BeanManager getBeanManager();
     void setBeanManager(BeanManager beanmgr);
 }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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 3aef3e4..b690fb0 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
@@ -51,7 +51,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.pluto.container.FilterManager;
-import org.apache.pluto.container.PortletAsyncContext;
+import org.apache.pluto.container.PortletAsyncManager;
 import org.apache.pluto.container.PortletContainerException;
 import org.apache.pluto.container.PortletInvokerService;
 import org.apache.pluto.container.PortletRequestContext;
@@ -477,7 +477,7 @@ public class PortletServlet3 extends HttpServlet {
 
             if (requestContext instanceof PortletResourceRequestContext) {
                PortletResourceRequestContext resctx = (PortletResourceRequestContext)requestContext;
-               PortletAsyncContext pac = resctx.getPortletAsyncContext();
+               PortletAsyncManager pac = resctx.getPortletAsyncContext();
                if (pac != null) {
                   pac.deregisterContext(false);
                   pac.launchRunner();

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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 353b49f..cb32bc7 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
@@ -30,6 +30,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.pluto.container.NamespaceMapper;
+import org.apache.pluto.container.PortletAsyncManager;
 import org.apache.pluto.container.PortletResourceRequestContext;
 import org.apache.pluto.container.PortletWindowID;
 import org.slf4j.Logger;
@@ -99,6 +100,10 @@ public class PortletAsyncRequestWrapper extends HttpServletPortletRequestWrapper
    
    @Override
    public void setAttribute(String name, Object o) {
+      PortletAsyncManager actx = reqctx.getPortletAsyncContext();
+      if (actx != null && actx.isComplete()) {
+         return;
+      }
       boolean encoded = false;
       Object val = getRequest().getAttribute(mapper.encode(winId, name));
       if (val != null) {
@@ -119,6 +124,10 @@ public class PortletAsyncRequestWrapper extends HttpServletPortletRequestWrapper
    
    @Override
    public void removeAttribute(String name) {
+      PortletAsyncManager actx = reqctx.getPortletAsyncContext();
+      if (actx != null && actx.isComplete()) {
+         return;
+      }
       boolean encoded = false;
       Object val = getRequest().getAttribute(mapper.encode(winId, name));
       if (val != null) {
@@ -161,53 +170,6 @@ public class PortletAsyncRequestWrapper extends HttpServletPortletRequestWrapper
       return info;
    }
    
-   
-   
-   
-   
-   
-   
-   
-   
-   
-   
-//    @Override
-//    public RequestDispatcher getRequestDispatcher(String path) {
-//       RequestDispatcher rd = super.getRequestDispatcher(path);
-//       if (rd != null) {
-//          PortletRequestDispatcherImpl prd =  new PortletRequestDispatcherImpl(rd, false);
-//          prd.setPortletRequest(preq);
-//          prd.setPortletResponse(reqctx.getResponse());
-//          return prd;
-//       }
-//       return null;
-//    }
-   
-   
-   
-   
-   
-   
-   
-   // 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 reqctx.startAsync();

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-container/src/main/java/org/apache/pluto/container/impl/ResourceRequestImpl.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/main/java/org/apache/pluto/container/impl/ResourceRequestImpl.java b/pluto-container/src/main/java/org/apache/pluto/container/impl/ResourceRequestImpl.java
index fdd2145..1d79fa1 100644
--- a/pluto-container/src/main/java/org/apache/pluto/container/impl/ResourceRequestImpl.java
+++ b/pluto-container/src/main/java/org/apache/pluto/container/impl/ResourceRequestImpl.java
@@ -20,11 +20,11 @@ import java.util.Enumeration;
 import java.util.Map;
 
 import javax.portlet.CacheControl;
+import javax.portlet.PortletAsyncContext;
 import javax.portlet.PortletRequest;
 import javax.portlet.ResourceParameters;
 import javax.portlet.ResourceRequest;
 import javax.portlet.ResourceResponse;
-import javax.servlet.AsyncContext;
 import javax.servlet.DispatcherType;
 
 import org.apache.pluto.container.PortletResourceRequestContext;
@@ -119,13 +119,13 @@ public class ResourceRequestImpl extends ClientDataRequestImpl implements Resour
    }
 
    @Override
-   public AsyncContext startAsync() throws IllegalStateException {
-      return getRequestContext().startAsync(this);
+   public PortletAsyncContext startAsync() throws IllegalStateException {
+      return (PortletAsyncContext) getRequestContext().startAsync(this);
    }
 
    @Override
-   public AsyncContext startAsync(ResourceRequest request, ResourceResponse response) throws IllegalStateException {
-      return getRequestContext().startAsync(request, response);
+   public PortletAsyncContext startAsync(ResourceRequest request, ResourceResponse response) throws IllegalStateException {
+      return (PortletAsyncContext) getRequestContext().startAsync(request, response);
    }
 
    @Override
@@ -139,8 +139,8 @@ public class ResourceRequestImpl extends ClientDataRequestImpl implements Resour
    }
 
    @Override
-   public AsyncContext getAsyncContext() {
-      return getRequestContext().getAsyncContext();
+   public PortletAsyncContext getAsyncContext() {
+      return (PortletAsyncContext) getRequestContext().getAsyncContext();
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-container/src/test/java/org/apache/pluto/container/bean/processor/fixtures/mocks/MockResourceRequest.java
----------------------------------------------------------------------
diff --git a/pluto-container/src/test/java/org/apache/pluto/container/bean/processor/fixtures/mocks/MockResourceRequest.java b/pluto-container/src/test/java/org/apache/pluto/container/bean/processor/fixtures/mocks/MockResourceRequest.java
index 2b4d1a2..6db56e2 100644
--- a/pluto-container/src/test/java/org/apache/pluto/container/bean/processor/fixtures/mocks/MockResourceRequest.java
+++ b/pluto-container/src/test/java/org/apache/pluto/container/bean/processor/fixtures/mocks/MockResourceRequest.java
@@ -21,10 +21,10 @@ package org.apache.pluto.container.bean.processor.fixtures.mocks;
 
 import java.util.Map;
 
+import javax.portlet.PortletAsyncContext;
 import javax.portlet.ResourceParameters;
 import javax.portlet.ResourceRequest;
 import javax.portlet.ResourceResponse;
-import javax.servlet.AsyncContext;
 import javax.servlet.DispatcherType;
 
 /**
@@ -90,12 +90,12 @@ public class MockResourceRequest extends MockClientDataRequest implements Resour
    }
 
    @Override
-   public AsyncContext startAsync() throws IllegalStateException {
+   public PortletAsyncContext startAsync() throws IllegalStateException {
       return null;
    }
 
    @Override
-   public AsyncContext startAsync(ResourceRequest request, ResourceResponse response) throws IllegalStateException {
+   public PortletAsyncContext startAsync(ResourceRequest request, ResourceResponse response) throws IllegalStateException {
       return null;
    }
 
@@ -110,7 +110,7 @@ public class MockResourceRequest extends MockClientDataRequest implements Resour
    }
 
    @Override
-   public AsyncContext getAsyncContext() {
+   public PortletAsyncContext getAsyncContext() {
       return null;
    }
 

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/FilterManagerImpl.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/FilterManagerImpl.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/FilterManagerImpl.java
index 1b076a3..37d00f7 100644
--- a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/FilterManagerImpl.java
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/FilterManagerImpl.java
@@ -18,9 +18,7 @@ package org.apache.pluto.driver.services.container;
 
 import java.io.IOException;
 import java.util.List;
-import java.util.Set;
 
-import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
@@ -56,6 +54,7 @@ import org.slf4j.LoggerFactory;
  * @version 2.0
  */
 public class FilterManagerImpl implements FilterManager{
+   @SuppressWarnings("unused")
    private static final Logger LOG = LoggerFactory.getLogger(FilterManagerImpl.class);
    
     private FilterChainImpl filterchain;

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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 ce8e044..1ab34e4 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
@@ -22,7 +22,10 @@ import java.util.Set;
 
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
+import javax.portlet.PortletAsyncContext;
+import javax.portlet.PortletException;
 import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncListener;
 import javax.servlet.ServletContext;
@@ -32,7 +35,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.pluto.container.PortletAsyncContext;
+import org.apache.pluto.container.PortletAsyncManager;
 import org.apache.pluto.container.PortletResourceRequestContext;
 import org.apache.pluto.container.bean.processor.PortletArtifactProducer;
 import org.apache.pluto.container.bean.processor.PortletRequestScopedBeanHolder;
@@ -48,7 +51,7 @@ import org.slf4j.LoggerFactory;
  * @author Scott Nicklous
  * 
  */
-public class PortletAsyncContextImpl implements PortletAsyncContext {
+public class PortletAsyncContextImpl implements PortletAsyncManager, AsyncContext, PortletAsyncContext {
    private static final Logger LOG = LoggerFactory.getLogger(PortletAsyncContextImpl.class);
    private static final boolean isDebug = LOG.isDebugEnabled();
    @SuppressWarnings("unused")
@@ -57,7 +60,7 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
    private AsyncContext                   actx;
    
    private final HttpServletRequest       hreq;
-   private final PortletAsyncListener     pal;
+   private final PortletAsyncContextListener     pal;
    private final PortletResourceRequestContext  prctx;
 
    private ResourceRequest                resreq;
@@ -81,7 +84,7 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       HttpServletRequest creq = prctx.getContainerRequest();
       HttpServletResponse cresp = prctx.getContainerResponse();
 
-      pal = new PortletAsyncListener(this);
+      pal = new PortletAsyncContextListener(this);
       actx.addListener(pal, creq, cresp);
    }
 
@@ -237,27 +240,7 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
    @SuppressWarnings("unchecked")
    @Override
    public <T extends AsyncListener> T createListener(Class<T> cls) throws ServletException {
-      if (isDebug) {
-         StringBuilder txt = new StringBuilder();
-         txt.append("Creating listener.");
-         txt.append(" Bean manager: ").append(beanmgr);
-         txt.append(", listener class: ").append(cls.getCanonicalName());
-         LOG.debug(txt.toString());
-      }
-      T lis = null;
-      if (beanmgr != null) {
-         Set<Bean<?>> beans = beanmgr.getBeans(cls);
-         Bean<?> bean = beanmgr.resolve(beans);
-         if (bean != null) {
-            lis = (T) beanmgr.getReference(bean, bean.getBeanClass(), beanmgr.createCreationalContext(bean));
-         } else {
-            LOG.warn("Could not get bean reference for: " + cls.getCanonicalName());
-            lis = actx.createListener(cls);
-         }
-      } else {
-         lis = actx.createListener(cls);
-      }
-      return lis;
+      return (T) createInstance(cls);
    }
 
    /*
@@ -352,4 +335,65 @@ public class PortletAsyncContextImpl implements PortletAsyncContext {
       pendingRunner = run;
    }
 
+   @Override
+   public void addListener(javax.portlet.PortletAsyncListener listener) throws IllegalStateException {
+      pal.addListener(listener);
+   }
+
+   @Override
+   public void addListener(javax.portlet.PortletAsyncListener listener, ResourceRequest request,
+         ResourceResponse response) throws IllegalStateException {
+      pal.addListener(listener, request, response);
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <T extends javax.portlet.PortletAsyncListener> T createPortletAsyncListener(Class<T> cls)
+         throws PortletException {
+      return (T) createInstance(cls);
+   }
+
+   @Override
+   public ResourceRequest getResourceRequest() throws IllegalStateException {
+      return resreq;
+   }
+
+   @Override
+   public ResourceResponse getResourceResponse() throws IllegalStateException {
+      return prctx.getResponse();
+   }
+   
+   private Object createInstance(Class<?> cls) {
+      if (isDebug) {
+         StringBuilder txt = new StringBuilder();
+         txt.append("Creating listener.");
+         txt.append(" Bean manager: ").append(beanmgr);
+         txt.append(", listener class: ").append(cls.getCanonicalName());
+         LOG.debug(txt.toString());
+      }
+      
+      Object lis = null;
+      if (beanmgr != null) {
+         Set<Bean<?>> beans = beanmgr.getBeans(cls);
+         Bean<?> bean = beanmgr.resolve(beans);
+         if (bean != null) {
+            lis = beanmgr.getReference(bean, bean.getBeanClass(), beanmgr.createCreationalContext(bean));
+         } else {
+            LOG.warn("Could not get bean reference for: " + cls.getCanonicalName());
+         }
+      } 
+      
+      if (lis == null) {
+         LOG.debug("Instantiating class directly: " + cls.getCanonicalName());
+         try {
+            lis = cls.newInstance();
+         } catch (Exception e) {
+            LOG.warn("Could not instantiate class: " + cls.getCanonicalName());
+         }
+      }
+      
+      return lis;
+
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextListener.java
----------------------------------------------------------------------
diff --git a/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextListener.java b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextListener.java
new file mode 100644
index 0000000..4e85c36
--- /dev/null
+++ b/pluto-portal-driver-impl/src/main/java/org/apache/pluto/driver/services/container/PortletAsyncContextListener.java
@@ -0,0 +1,335 @@
+/*  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 java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.portlet.PortletAsyncEvent;
+import javax.portlet.PortletAsyncListener;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.pluto.container.PortletInvokerService;
+import org.apache.pluto.container.PortletResourceResponseContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the listeners registered by the application. Releases portal resources when 
+ * the async request completes and provides contextual services for the listeners. 
+ * 
+ * @author Scott Nicklous
+ */
+public class PortletAsyncContextListener implements AsyncListener {
+   
+   /** Logger. */
+   private static final Logger LOG = LoggerFactory.getLogger(PortletAsyncContextListener.class);
+   private static final boolean isDebug = LOG.isDebugEnabled();
+   @SuppressWarnings("unused")
+   private static final boolean isTrace = LOG.isTraceEnabled();
+   
+   
+   // Data for one listener
+   private class Entry {
+
+      public AsyncListener          hlis;
+      public ServletRequest         hreq;
+      public ServletResponse        hresp;
+      public PortletAsyncListener   plis;
+      public ResourceRequest        preq;
+      public ResourceResponse       presp;
+
+      public Entry(AsyncListener lis, ServletRequest req, ServletResponse resp) {
+         this.hlis  = lis;
+         this.hreq  = req;
+         this.hresp = resp;
+      }
+      
+      public Entry(PortletAsyncListener lis, ResourceRequest req, ResourceResponse resp) {
+         this.plis  = lis;
+         this.preq  = req;
+         this.presp = resp;
+      }
+   }
+   
+   // The registered listeners
+   List<Entry> listeners = new ArrayList<Entry>();
+   
+   private long start  = System.currentTimeMillis();
+   private final PortletAsyncContextImpl pactx;
+   
+ 
+   public PortletAsyncContextListener(PortletAsyncContextImpl pactx) {
+      this.pactx = pactx;
+   }
+   
+   public void addListener(AsyncListener l) {
+      listeners.add(new Entry(l, null, null));
+   }
+   
+   public void addListener(AsyncListener l, ServletRequest req, ServletResponse resp) {
+      listeners.add(new Entry(l, req, resp));
+   }
+   
+   public void addListener(PortletAsyncListener l) {
+      listeners.add(new Entry(l, null, null));
+   }
+   
+   public void addListener(PortletAsyncListener l, ResourceRequest req, ResourceResponse resp) {
+      listeners.add(new Entry(l, req, resp));
+   }
+   
+   private void trace (String meth) {
+      if (isDebug) {
+         StringBuilder txt = new StringBuilder();
+         txt.append("Firing ").append(meth).append(" event for ");
+         txt.append(listeners.size()).append(" listeners.");
+         int hcnt=0, pcnt=0;
+         for (Entry e : listeners) {
+            if (e.hlis != null) hcnt++;
+            if (e.plis != null) pcnt++;
+         }
+         txt.append(", # AsyncListeners: ").append(hcnt);
+         txt.append(", # PortletAsyncListeners: ").append(pcnt);
+         LOG.debug(txt.toString());
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onComplete(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onComplete(AsyncEvent evt) throws IOException {
+
+      trace("onComplete");
+      
+      pactx.registerContext(true);
+      for (Entry l : listeners) {
+         if (l.hlis != null) {
+            AsyncEvent lisevt = new AsyncEvent(pactx, l.hreq, l.hresp);
+            l.hlis.onComplete(lisevt);
+         } else {
+            PortletAsyncEvent lisevt = new PortletAsyncEvent(pactx, l.preq, l.presp);
+            l.plis.onComplete(lisevt);
+         }
+      }
+      pactx.deregisterContext(true);
+      pactx.setComplete(true);
+      
+      long delta = System.currentTimeMillis() - start;
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Completed. Execution time: ").append(delta).append(" milliseconds.");
+      txt.append(" Releasing: ");
+
+      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; ");
+         }
+         
+         // remove container-scoped attributes
+
+         txt.append("container-scoped attributes; ");
+         hreq.removeAttribute(PortletInvokerService.METHOD_ID);
+         hreq.removeAttribute(PortletInvokerService.PORTLET_REQUEST);
+         hreq.removeAttribute(PortletInvokerService.PORTLET_RESPONSE);
+         hreq.removeAttribute(PortletInvokerService.FILTER_MANAGER);
+
+      } else {
+         txt.append("... no servlet request stuff. Couldn't get servlet request.");
+      }
+      
+      txt.append(" Removing contextual info.");
+      pactx.removeContext();
+
+      if (isDebug) {
+         LOG.debug(txt.toString());
+      }
+
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onError(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onError(AsyncEvent evt) throws IOException {
+      
+      trace("onError");      
+      pactx.registerContext(true);
+      for (Entry l : listeners) {
+         if (l.hlis != null) {
+            AsyncEvent lisevt = new AsyncEvent(pactx, l.hreq, l.hresp);
+            l.hlis.onError(lisevt);
+         } else {
+            PortletAsyncEvent lisevt = new PortletAsyncEvent(pactx, l.preq, l.presp);
+            l.plis.onError(lisevt);
+         }
+      }
+      pactx.deregisterContext(true);
+      
+      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());
+      if (isDebug) {
+         LOG.debug(txt.toString());
+      }
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onStartAsync(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onStartAsync(AsyncEvent evt) throws IOException {
+
+      trace("onStartAsync");
+      
+      // copy & clear the original listener list. If a listener wants to be notified
+      // again, it will add itself again.
+      
+      ArrayList<Entry> entries = new ArrayList<Entry>(listeners);
+      listeners.clear();
+
+      pactx.registerContext(true);
+      for (Entry l : entries) {
+         if (l.hlis != null) {
+            AsyncEvent lisevt = new AsyncEvent(pactx, l.hreq, l.hresp);
+            l.hlis.onStartAsync(lisevt);
+         } else {
+            PortletAsyncEvent lisevt = new PortletAsyncEvent(pactx, l.preq, l.presp);
+            l.plis.onStartAsync(lisevt);
+         }
+      }
+      pactx.deregisterContext(true);
+      
+      long delta = System.currentTimeMillis() - start;
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Async started again after ").append(delta).append(" milliseconds.");
+      if (isDebug) {
+         LOG.debug(txt.toString());
+      }
+
+      // need to add this listener again so it gets called when finally complete.
+
+      AsyncContext ctx = evt.getAsyncContext();
+      ctx.addListener(this);
+   }
+
+   /*
+    * (non-Javadoc)
+    * 
+    * @see javax.servlet.AsyncListener#onTimeout(javax.servlet.AsyncEvent)
+    */
+   @Override
+   public void onTimeout(AsyncEvent evt) throws IOException {
+
+      trace("onTimeout");
+      
+      pactx.registerContext(true);
+      for (Entry l : listeners) {
+         if (l.hlis != null) {
+            AsyncEvent lisevt = new AsyncEvent(pactx, l.hreq, l.hresp);
+            l.hlis.onTimeout(lisevt);
+         } else {
+            PortletAsyncEvent lisevt = new PortletAsyncEvent(pactx, l.preq, l.presp);
+            l.plis.onTimeout(lisevt);
+         }
+      }
+      pactx.deregisterContext(true);
+      
+      long delta = System.currentTimeMillis() - start;
+      StringBuilder txt = new StringBuilder(128);
+      txt.append("Timeout after ").append(delta).append(" milliseconds.");
+      
+      // if the application has properly registered a listener and has not processed the 
+      // timeout by calling onComplete or dispatch, complete the request.
+      
+      boolean warn = false;
+      AsyncContext ctx = evt.getAsyncContext();
+      try {
+         ctx.getRequest();
+         
+         try {
+            ctx.complete();
+            txt.append(" Portlet container completed request processing on behalf of the application.");
+            warn = true;
+         } catch (IllegalStateException e) {
+            txt.append(" An earlier listener has dispatched again.");
+         } catch (Exception e) {
+            txt.append(" Exception occured while completing request: " + e.toString());
+         }
+         
+      } catch(Exception e) {
+         txt.append(" Async processing was completed by the application.");
+      }
+
+      if (warn) {
+         LOG.warn(txt.toString());
+      } else {
+         if (isDebug) {
+            LOG.debug(txt.toString());
+         }
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/portals-pluto/blob/0e71c8ab/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
index bfbfd34..c44c27f 100644
--- 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
@@ -19,7 +19,7 @@
 
 package org.apache.pluto.driver.services.container;
 
-import org.apache.pluto.container.PortletAsyncContext;
+import org.apache.pluto.container.PortletAsyncManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,13 +37,13 @@ public class PortletAsyncContextualRunner implements Runnable {
    private static final boolean isTrace = LOG.isTraceEnabled();
    
 
-   private PortletAsyncContext pactx;
+   private PortletAsyncManager pactx;
    private Runnable targetRunner; 
 
    public PortletAsyncContextualRunner() {
    }
    
-   public void init(PortletAsyncContext pactx, Runnable targetRunner) {
+   public void init(PortletAsyncManager pactx, Runnable targetRunner) {
       this.pactx = pactx;
       this.targetRunner = targetRunner;
    }