Browse Source

WebAsyncManager avoids concurrentResult.toString() and builds correct DeferredResultProcessingInterceptor keys

Issue: SPR-12253
pull/649/merge
Juergen Hoeller 12 years ago
parent
commit
bf99d6a3b5
  1. 61
      spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java

61
spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.web.context.request.async; package org.springframework.web.context.request.async;
import java.util.ArrayList; import java.util.ArrayList;
@ -20,11 +21,11 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -48,7 +49,6 @@ import org.springframework.web.util.UrlPathHelper;
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 3.2 * @since 3.2
*
* @see org.springframework.web.context.request.AsyncWebRequestInterceptor * @see org.springframework.web.context.request.AsyncWebRequestInterceptor
* @see org.springframework.web.servlet.AsyncHandlerInterceptor * @see org.springframework.web.servlet.AsyncHandlerInterceptor
* @see org.springframework.web.filter.OncePerRequestFilter#shouldNotFilterAsyncDispatch * @see org.springframework.web.filter.OncePerRequestFilter#shouldNotFilterAsyncDispatch
@ -85,13 +85,14 @@ public final class WebAsyncManager {
/** /**
* Package private constructor. * Package-private constructor.
* @see WebAsyncUtils#getAsyncManager(javax.servlet.ServletRequest) * @see WebAsyncUtils#getAsyncManager(javax.servlet.ServletRequest)
* @see WebAsyncUtils#getAsyncManager(org.springframework.web.context.request.WebRequest) * @see WebAsyncUtils#getAsyncManager(org.springframework.web.context.request.WebRequest)
*/ */
WebAsyncManager() { WebAsyncManager() {
} }
/** /**
* Configure the {@link AsyncWebRequest} to use. This property may be set * Configure the {@link AsyncWebRequest} to use. This property may be set
* more than once during a single request to accurately reflect the current * more than once during a single request to accurately reflect the current
@ -99,7 +100,6 @@ public final class WebAsyncManager {
* wrapping, etc). However, it should not be set while concurrent handling * wrapping, etc). However, it should not be set while concurrent handling
* is in progress, i.e. while {@link #isConcurrentHandlingStarted()} is * is in progress, i.e. while {@link #isConcurrentHandlingStarted()} is
* {@code true}. * {@code true}.
*
* @param asyncWebRequest the web request to use * @param asyncWebRequest the web request to use
*/ */
public void setAsyncWebRequest(final AsyncWebRequest asyncWebRequest) { public void setAsyncWebRequest(final AsyncWebRequest asyncWebRequest) {
@ -144,7 +144,6 @@ public final class WebAsyncManager {
/** /**
* Provides access to the result from concurrent handling. * Provides access to the result from concurrent handling.
*
* @return an Object, possibly an {@code Exception} or {@code Throwable} if * @return an Object, possibly an {@code Exception} or {@code Throwable} if
* concurrent handling raised one. * concurrent handling raised one.
* @see #clearConcurrentResult() * @see #clearConcurrentResult()
@ -156,7 +155,6 @@ public final class WebAsyncManager {
/** /**
* Provides access to additional processing context saved at the start of * Provides access to additional processing context saved at the start of
* concurrent handling. * concurrent handling.
*
* @see #clearConcurrentResult() * @see #clearConcurrentResult()
*/ */
public Object[] getConcurrentResultContext() { public Object[] getConcurrentResultContext() {
@ -217,14 +215,14 @@ public final class WebAsyncManager {
} }
/** /**
* Register a {@link DeferredResultProcessingInterceptor} without a key. * Register one or more {@link DeferredResultProcessingInterceptor}s without a specified key.
* The key is derived from the class name and hashcode. * The default key is derived from the interceptor class name and hash code.
* @param interceptors one or more interceptors to register * @param interceptors one or more interceptors to register
*/ */
public void registerDeferredResultInterceptors(DeferredResultProcessingInterceptor... interceptors) { public void registerDeferredResultInterceptors(DeferredResultProcessingInterceptor... interceptors) {
Assert.notNull(interceptors, "A DeferredResultProcessingInterceptor is required"); Assert.notNull(interceptors, "A DeferredResultProcessingInterceptor is required");
for (DeferredResultProcessingInterceptor interceptor : interceptors) { for (DeferredResultProcessingInterceptor interceptor : interceptors) {
String key = interceptors.getClass().getName() + ":" + interceptors.hashCode(); String key = interceptor.getClass().getName() + ":" + interceptor.hashCode();
this.deferredResultInterceptors.put(key, interceptor); this.deferredResultInterceptors.put(key, interceptor);
} }
} }
@ -244,12 +242,10 @@ public final class WebAsyncManager {
* from the task execution is saved and the request dispatched in order to * from the task execution is saved and the request dispatched in order to
* resume processing of that result. If the task raises an Exception then * resume processing of that result. If the task raises an Exception then
* the saved result will be the raised Exception. * the saved result will be the raised Exception.
*
* @param callable a unit of work to be executed asynchronously * @param callable a unit of work to be executed asynchronously
* @param processingContext additional context to save that can be accessed * @param processingContext additional context to save that can be accessed
* via {@link #getConcurrentResultContext()} * via {@link #getConcurrentResultContext()}
* @throws Exception If concurrent processing failed to start * @throws Exception if concurrent processing failed to start
*
* @see #getConcurrentResult() * @see #getConcurrentResult()
* @see #getConcurrentResultContext() * @see #getConcurrentResultContext()
*/ */
@ -263,11 +259,10 @@ public final class WebAsyncManager {
* Use the given {@link WebAsyncTask} to configure the task executor as well as * Use the given {@link WebAsyncTask} to configure the task executor as well as
* the timeout value of the {@code AsyncWebRequest} before delegating to * the timeout value of the {@code AsyncWebRequest} before delegating to
* {@link #startCallableProcessing(Callable, Object...)}. * {@link #startCallableProcessing(Callable, Object...)}.
*
* @param webAsyncTask a WebAsyncTask containing the target {@code Callable} * @param webAsyncTask a WebAsyncTask containing the target {@code Callable}
* @param processingContext additional context to save that can be accessed * @param processingContext additional context to save that can be accessed
* via {@link #getConcurrentResultContext()} * via {@link #getConcurrentResultContext()}
* @throws Exception If concurrent processing failed to start * @throws Exception if concurrent processing failed to start
*/ */
public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext) throws Exception { public void startCallableProcessing(final WebAsyncTask<?> webAsyncTask, Object... processingContext) throws Exception {
Assert.notNull(webAsyncTask, "WebAsyncTask must not be null"); Assert.notNull(webAsyncTask, "WebAsyncTask must not be null");
@ -309,8 +304,7 @@ public final class WebAsyncManager {
} }
}); });
interceptorChain.applyBeforeConcurrentHandling(asyncWebRequest, callable); interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, callable);
startAsyncProcessing(processingContext); startAsyncProcessing(processingContext);
this.taskExecutor.submit(new Runnable() { this.taskExecutor.submit(new Runnable() {
@ -321,8 +315,8 @@ public final class WebAsyncManager {
interceptorChain.applyPreProcess(asyncWebRequest, callable); interceptorChain.applyPreProcess(asyncWebRequest, callable);
result = callable.call(); result = callable.call();
} }
catch (Throwable t) { catch (Throwable ex) {
result = t; result = ex;
} }
finally { finally {
result = interceptorChain.applyPostProcess(asyncWebRequest, callable, result); result = interceptorChain.applyPostProcess(asyncWebRequest, callable, result);
@ -337,18 +331,20 @@ public final class WebAsyncManager {
if (hasConcurrentResult()) { if (hasConcurrentResult()) {
return; return;
} }
concurrentResult = result; this.concurrentResult = result;
} }
if (asyncWebRequest.isAsyncComplete()) { if (this.asyncWebRequest.isAsyncComplete()) {
logger.error("Could not complete async processing due to timeout or network error"); logger.error("Could not complete async processing due to timeout or network error");
return; return;
} }
logger.debug("Concurrent result value [" + concurrentResult + "]"); if (logger.isDebugEnabled()) {
logger.debug("Dispatching request to resume processing"); logger.debug("Concurrent result value [" + this.concurrentResult +
"] - dispatching request to resume processing");
}
asyncWebRequest.dispatch(); this.asyncWebRequest.dispatch();
} }
/** /**
@ -358,12 +354,10 @@ public final class WebAsyncManager {
* result. The {@code AsyncWebRequest} is also updated with a completion * result. The {@code AsyncWebRequest} is also updated with a completion
* handler that expires the {@code DeferredResult} and a timeout handler * handler that expires the {@code DeferredResult} and a timeout handler
* assuming the {@code DeferredResult} has a default timeout result. * assuming the {@code DeferredResult} has a default timeout result.
*
* @param deferredResult the DeferredResult instance to initialize * @param deferredResult the DeferredResult instance to initialize
* @param processingContext additional context to save that can be accessed * @param processingContext additional context to save that can be accessed
* via {@link #getConcurrentResultContext()} * via {@link #getConcurrentResultContext()}
* @throws Exception If concurrent processing failed to start * @throws Exception if concurrent processing failed to start
*
* @see #getConcurrentResult() * @see #getConcurrentResult()
* @see #getConcurrentResultContext() * @see #getConcurrentResultContext()
*/ */
@ -391,8 +385,8 @@ public final class WebAsyncManager {
try { try {
interceptorChain.triggerAfterTimeout(asyncWebRequest, deferredResult); interceptorChain.triggerAfterTimeout(asyncWebRequest, deferredResult);
} }
catch (Throwable t) { catch (Throwable ex) {
setConcurrentResultAndDispatch(t); setConcurrentResultAndDispatch(ex);
} }
} }
}); });
@ -404,8 +398,7 @@ public final class WebAsyncManager {
} }
}); });
interceptorChain.applyBeforeConcurrentHandling(asyncWebRequest, deferredResult); interceptorChain.applyBeforeConcurrentHandling(this.asyncWebRequest, deferredResult);
startAsyncProcessing(processingContext); startAsyncProcessing(processingContext);
try { try {
@ -418,16 +411,14 @@ public final class WebAsyncManager {
} }
}); });
} }
catch (Throwable t) { catch (Throwable ex) {
setConcurrentResultAndDispatch(t); setConcurrentResultAndDispatch(ex);
} }
} }
private void startAsyncProcessing(Object[] processingContext) { private void startAsyncProcessing(Object[] processingContext) {
clearConcurrentResult(); clearConcurrentResult();
this.concurrentResultContext = processingContext; this.concurrentResultContext = processingContext;
this.asyncWebRequest.startAsync(); this.asyncWebRequest.startAsync();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {

Loading…
Cancel
Save