Author: remy.maucherat(a)jboss.com
Date: 2009-04-08 12:47:25 -0400 (Wed, 08 Apr 2009)
New Revision: 996
Modified:
trunk/java/org/apache/catalina/connector/Request.java
trunk/java/org/apache/catalina/core/ApplicationDispatcher.java
trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java
trunk/java/org/apache/catalina/core/StandardWrapperValve.java
trunk/java/org/apache/catalina/security/SecurityClassLoad.java
Log:
- Should implement async dispatch.
Modified: trunk/java/org/apache/catalina/connector/Request.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Request.java 2009-04-08 12:34:27 UTC (rev
995)
+++ trunk/java/org/apache/catalina/connector/Request.java 2009-04-08 16:47:25 UTC (rev
996)
@@ -130,6 +130,11 @@
||
Boolean.valueOf(System.getProperty("org.apache.catalina.connector.Request.WRAPPED_RESPONSE_IN_LOGIN",
"false")).booleanValue();
+ protected static final boolean CHECK_ASYNC =
+ Globals.STRICT_SERVLET_COMPLIANCE
+ ||
Boolean.valueOf(System.getProperty("org.apache.catalina.connector.Request.CHECK_ASYNC",
"true")).booleanValue();
+
+
// ----------------------------------------------------------- Constructors
@@ -2871,7 +2876,7 @@
}
public AsyncContext startAsync() throws IllegalStateException {
- return startAsync(getRequest(), response.getResponse());
+ return startAsync(null, null);
}
public AsyncContext startAsync(ServletRequest servletRequest,
@@ -2880,14 +2885,26 @@
if (timeout <= 0) {
timeout = Integer.MAX_VALUE;
}
- if (!isAsyncSupported()) {
+ if (CHECK_ASYNC && !isAsyncSupported()) {
throw new
IllegalStateException(sm.getString("coyoteRequest.noAsync"));
}
// FIXME: if (asyncContext != null && !processing) { throw ISE }
// FIXME: if (response.isClosed()) { throw ISE }
setTimeout(timeout);
- asyncContext = new AsyncContextImpl(servletRequest, servletResponse);
- eventMode = true;
+ if (asyncContext == null) {
+ asyncContext = new AsyncContextImpl
+ ((servletRequest == null) ? getRequest() : servletRequest,
+ (servletResponse == null) ? response.getResponse() : servletResponse);
+ eventMode = true;
+ } else {
+ if (servletRequest != null) {
+ asyncContext.setRequest(servletRequest);
+ }
+ if (servletResponse != null) {
+ asyncContext.setResponse(servletResponse);
+ }
+ asyncContext.reset();
+ }
return asyncContext;
}
@@ -2995,6 +3012,7 @@
protected String path = null;
protected Runnable runnable = null;
protected boolean useAttributes = false;
+ protected boolean ready = true;
public AsyncContextImpl(ServletRequest request, ServletResponse response) {
this.request = request;
@@ -3051,6 +3069,18 @@
resume();
}
+ public boolean isReady() {
+ return ready;
+ }
+
+ public void setRequest(ServletRequest request) {
+ this.request = request;
+ }
+
+ public void setResponse(ServletResponse response) {
+ this.response = response;
+ }
+
public ServletContext getServletContext() {
return servletContext;
}
@@ -3067,6 +3097,14 @@
return runnable;
}
+ public void reset() {
+ servletContext = null;
+ path = null;
+ runnable = null;
+ useAttributes = false;
+ ready = true;
+ }
+
public Map<AsyncEvent, AsyncListener> getAsyncListeners() {
return asyncListeners;
}
Modified: trunk/java/org/apache/catalina/core/ApplicationDispatcher.java
===================================================================
--- trunk/java/org/apache/catalina/core/ApplicationDispatcher.java 2009-04-08 12:34:27 UTC
(rev 995)
+++ trunk/java/org/apache/catalina/core/ApplicationDispatcher.java 2009-04-08 16:47:25 UTC
(rev 996)
@@ -24,6 +24,7 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import javax.servlet.AsyncContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
@@ -99,12 +100,31 @@
}
+ protected class PrivilegedAsync implements PrivilegedExceptionAction {
+ private ServletRequest request;
+ private ServletResponse response;
+ private boolean attributes;
+
+ PrivilegedAsync(ServletRequest request, ServletResponse response, boolean
attributes)
+ {
+ this.request = request;
+ this.response = response;
+ this.attributes = attributes;
+ }
+
+ public Object run() throws ServletException, IOException {
+ doAsync(request, response, attributes);
+ return null;
+ }
+ }
+
+
/**
* Used to pass state when the request dispatcher is used. Using instance
* variables causes threading issues and state is too complex to pass and
* return single ServletRequest or ServletResponse objects.
*/
- private class State {
+ private static class State {
State(ServletRequest request, ServletResponse response,
boolean including) {
this.outerRequest = request;
@@ -280,6 +300,86 @@
/**
+ * Async forward this request and response to another resource for processing.
+ * Any runtime exception, IOException, or ServletException thrown by the
+ * called servlet will be propogated to the caller.
+ *
+ * @param request The servlet request to be forwarded
+ * @param response The servlet response to be forwarded
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet exception occurs
+ */
+ public void async(ServletRequest request, ServletResponse response, boolean
attributes)
+ throws ServletException, IOException
+ {
+ if (Globals.IS_SECURITY_ENABLED) {
+ try {
+ AccessController.doPrivileged(new PrivilegedAsync(request, response,
attributes));
+ } catch (PrivilegedActionException pe) {
+ Exception e = pe.getException();
+ if (e instanceof ServletException)
+ throw (ServletException) e;
+ throw (IOException) e;
+ }
+ } else {
+ doAsync(request,response, attributes);
+ }
+ }
+
+ private void doAsync(ServletRequest request, ServletResponse response, boolean
attributes)
+ throws ServletException, IOException
+ {
+
+ // Set up to handle the specified request and response
+ State state = new State(request, response, false);
+
+ if (Globals.STRICT_SERVLET_COMPLIANCE) {
+ // Check SRV.8.2 / SRV.14.2.5.1 compliance
+ checkSameObjects(request, response);
+ }
+
+ if (attributes) {
+ wrapResponse(state);
+ ApplicationHttpRequest wrequest =
+ (ApplicationHttpRequest) wrapRequest(state);
+ String contextPath = context.getPath();
+ HttpServletRequest hrequest = state.hrequest;
+ if (hrequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI) == null) {
+ wrequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,
+ hrequest.getRequestURI());
+ wrequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,
+ hrequest.getContextPath());
+ wrequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,
+ hrequest.getServletPath());
+ wrequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,
+ hrequest.getPathInfo());
+ wrequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,
+ hrequest.getQueryString());
+ }
+
+ wrequest.setContextPath(contextPath);
+ wrequest.setRequestURI(requestURI);
+ wrequest.setServletPath(servletPath);
+ wrequest.setPathInfo(pathInfo);
+ if (queryString != null) {
+ wrequest.setQueryString(queryString);
+ wrequest.setQueryParams(queryString);
+ }
+ }
+
+ state.outerRequest.setAttribute
+ (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+ requestPath);
+ state.outerRequest.setAttribute
+ (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+ Integer.valueOf(ApplicationFilterFactory.ASYNC_INTEGER));
+ invoke(state.outerRequest, response, state);
+
+ }
+
+
+ /**
* Forward this request and response to another resource for processing.
* Any runtime exception, IOException, or ServletException thrown by the
* called servlet will be propogated to the caller.
@@ -447,7 +547,6 @@
}
-
/**
* Include the response from another resource in the current response.
* Any runtime exception, IOException, or ServletException thrown by the
@@ -828,14 +927,11 @@
// Instantiate a new wrapper at this point and insert it in the chain
ServletRequest wrapper = null;
if ((current instanceof ApplicationHttpRequest) ||
- (current instanceof Request) ||
(current instanceof HttpServletRequest)) {
// Compute a crossContext flag
HttpServletRequest hcurrent = (HttpServletRequest) current;
boolean crossContext = false;
- if ((state.outerRequest instanceof ApplicationHttpRequest) ||
- (state.outerRequest instanceof Request) ||
- (state.outerRequest instanceof HttpServletRequest)) {
+ if (state.outerRequest instanceof HttpServletRequest) {
HttpServletRequest houterRequest =
(HttpServletRequest) state.outerRequest;
Object contextPath = houterRequest.getAttribute
@@ -888,14 +984,13 @@
// Instantiate a new wrapper at this point and insert it in the chain
ServletResponse wrapper = null;
- if ((current instanceof ApplicationHttpResponse) ||
- (current instanceof Response) ||
- (current instanceof HttpServletResponse))
+ if (current instanceof HttpServletResponse) {
wrapper =
new ApplicationHttpResponse((HttpServletResponse) current,
state.including);
- else
+ } else {
wrapper = new ApplicationResponse(current, state.including);
+ }
if (previous == null)
state.outerResponse = wrapper;
else
Modified: trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java
===================================================================
--- trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java 2009-04-08 12:34:27
UTC (rev 995)
+++ trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java 2009-04-08 16:47:25
UTC (rev 996)
@@ -27,6 +27,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
+import javax.servlet.AsyncContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@@ -72,7 +73,10 @@
Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR,
Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR,
Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR,
- Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR };
+ Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR,
+ AsyncContext.ASYNC_REQUEST_URI, AsyncContext.ASYNC_CONTEXT_PATH,
+ AsyncContext.ASYNC_SERVLET_PATH, AsyncContext.ASYNC_PATH_INFO,
+ AsyncContext.ASYNC_QUERY_STRING };
/**
Modified: trunk/java/org/apache/catalina/core/StandardWrapperValve.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardWrapperValve.java 2009-04-08 12:34:27 UTC
(rev 995)
+++ trunk/java/org/apache/catalina/core/StandardWrapperValve.java 2009-04-08 16:47:25 UTC
(rev 996)
@@ -48,6 +48,7 @@
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.Iterator;
import javax.management.MalformedObjectNameException;
@@ -57,6 +58,7 @@
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletResponse;
@@ -65,6 +67,7 @@
import org.apache.catalina.connector.ClientAbortException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
+import org.apache.catalina.connector.ResponseFacade;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.log.SystemLogHandler;
@@ -439,11 +442,41 @@
}
ApplicationDispatcher dispatcher =
(ApplicationDispatcher)
servletContext.getRequestDispatcher(asyncContext.getPath());
- // FIXME: Add an async method to Application dispatcher
// Invoke the dispatcher async method with the attributes flag
- asyncContext.getUseAttributes();
+ try {
+ dispatcher.async(asyncContext.getRequest(),
asyncContext.getResponse(),
+ asyncContext.getUseAttributes());
+ } catch (Throwable e) {
+
container.getLogger().error(sm.getString("standardWrapper.async.dispatchError",
+ getContainer().getName()), e);
+ exception(request, response, e);
+ }
+ // If there is no new startAsync, then close the response
+ if (!asyncContext.isReady()) {
+ if (asyncContext.getResponse() instanceof ResponseFacade) {
+ response.setSuspended(true);
+ } else {
+ // Close anyway
+ try {
+ PrintWriter writer = response.getWriter();
+ writer.close();
+ } catch (IllegalStateException e) {
+ try {
+ ServletOutputStream stream = response.getOutputStream();
+ stream.close();
+ } catch (IllegalStateException f) {
+ ;
+ } catch (IOException f) {
+ ;
+ }
+ } catch (IOException e) {
+ ;
+ }
+ }
+ event.close();
+ }
} else {
- // FIXME: should not happen
+ throw new
IllegalStateException(sm.getString("standardWrapper.async.invalidContext"));
}
return;
}
Modified: trunk/java/org/apache/catalina/security/SecurityClassLoad.java
===================================================================
--- trunk/java/org/apache/catalina/security/SecurityClassLoad.java 2009-04-08 12:34:27 UTC
(rev 995)
+++ trunk/java/org/apache/catalina/security/SecurityClassLoad.java 2009-04-08 16:47:25 UTC
(rev 996)
@@ -55,6 +55,9 @@
"core.ApplicationContextFacade$1");
loader.loadClass
(basePackage +
+ "core.ApplicationDispatcher$PrivilegedAsync");
+ loader.loadClass
+ (basePackage +
"core.ApplicationDispatcher$PrivilegedForward");
loader.loadClass
(basePackage +