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