diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
index 1af4dc4d2f9..127924c7bd4 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
@@ -34,7 +34,7 @@ import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
-import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
+import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -195,13 +195,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
participate = true;
}
else {
- if (!isAsyncDispatch(request) || !asyncManager.applyAsyncThreadInitializer(key)) {
+ if (!isAsyncDispatch(request) || !asyncManager.initializeAsyncThread(key)) {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
- AsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
+ WebAsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
asyncManager.registerAsyncThreadInitializer(key, initializer);
}
}
@@ -240,10 +240,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
- private AsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
+ private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
- return new AsyncThreadInitializer() {
+ return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
index 5f7ca275490..22f49c2c0ab 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
@@ -28,7 +28,7 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
-import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
+import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
/**
* Spring web request interceptor that binds a Hibernate Session to the
@@ -147,7 +147,7 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
String participateAttributeName = getParticipateAttributeName();
if (asyncManager.hasConcurrentResult()) {
- if (asyncManager.applyAsyncThreadInitializer(participateAttributeName)) {
+ if (asyncManager.initializeAsyncThread(participateAttributeName)) {
return;
}
}
@@ -169,7 +169,7 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
- AsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
+ WebAsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
asyncManager.registerAsyncThreadInitializer(participateAttributeName, asyncThreadInitializer);
}
else {
@@ -261,8 +261,8 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
- private AsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
- return new AsyncThreadInitializer() {
+ private WebAsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
+ return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
index 329a4e4eca1..929af55bd42 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
@@ -34,7 +34,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
-import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
+import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -126,13 +126,13 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
participate = true;
}
else {
- if (!isAsyncDispatch(request) || !asyncManager.applyAsyncThreadInitializer(key)) {
+ if (!isAsyncDispatch(request) || !asyncManager.initializeAsyncThread(key)) {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
- AsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
+ WebAsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
asyncManager.registerAsyncThreadInitializer(key, initializer);
}
}
@@ -153,10 +153,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
- private AsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
+ private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
- return new AsyncThreadInitializer() {
+ return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
index 6132430c38a..2a2678bd6fc 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
@@ -32,7 +32,7 @@ import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
-import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
+import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
/**
* Spring web request interceptor that binds a Hibernate Session to the
@@ -109,7 +109,7 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
String participateAttributeName = getParticipateAttributeName();
if (asyncManager.hasConcurrentResult()) {
- if (asyncManager.applyAsyncThreadInitializer(participateAttributeName)) {
+ if (asyncManager.initializeAsyncThread(participateAttributeName)) {
return;
}
}
@@ -126,7 +126,7 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
- AsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
+ WebAsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
asyncManager.registerAsyncThreadInitializer(participateAttributeName, asyncThreadInitializer);
}
}
@@ -200,8 +200,8 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
- private AsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
- return new AsyncThreadInitializer() {
+ private WebAsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
+ return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
}
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncTask.java b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncTask.java
new file mode 100644
index 00000000000..453ac62b275
--- /dev/null
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncTask.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2002-2012 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.
+ * 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.springframework.web.context.request.async;
+
+import java.util.concurrent.Callable;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.util.Assert;
+
+/**
+ * Holder for a {@link Callable}, a timeout value, and a task executor.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.2
+ */
+public class AsyncTask {
+
+ private final Callable> callable;
+
+ private final Long timeout;
+
+ private final String executorName;
+
+ private final AsyncTaskExecutor executor;
+
+ private BeanFactory beanFactory;
+
+
+ /**
+ * Create an AsyncTask with a timeout value and a Callable.
+ * @param timeout timeout value in milliseconds
+ * @param callable the callable for concurrent handling
+ */
+ public AsyncTask(long timeout, Callable> callable) {
+ this(timeout, null, null, callable);
+ Assert.notNull(timeout, "Timeout must not be null");
+ }
+
+ /**
+ * Create an AsyncTask with a timeout value, an executor name, and a Callable.
+ * @param timeout timeout value in milliseconds; ignored if {@code null}
+ * @param callable the callable for concurrent handling
+ */
+ public AsyncTask(Long timeout, String executorName, Callable> callable) {
+ this(timeout, null, executorName, callable);
+ Assert.notNull(executor, "Executor name must not be null");
+ }
+
+ /**
+ * Create an AsyncTask with a timeout value, an executor instance, and a Callable.
+ * @param timeout timeout value in milliseconds; ignored if {@code null}
+ * @param callable the callable for concurrent handling
+ */
+ public AsyncTask(Long timeout, AsyncTaskExecutor executor, Callable> callable) {
+ this(timeout, executor, null, callable);
+ Assert.notNull(executor, "Executor must not be null");
+ }
+
+ private AsyncTask(Long timeout, AsyncTaskExecutor executor, String executorName, Callable> callable) {
+ Assert.notNull(callable, "Callable must not be null");
+ this.callable = callable;
+ this.timeout = timeout;
+ this.executor = executor;
+ this.executorName = executorName;
+ }
+
+
+ /**
+ * Return the {@link Callable} to use for concurrent handling, never {@code null}.
+ */
+ public Callable> getCallable() {
+ return this.callable;
+ }
+
+ /**
+ * Return the timeout value in milliseconds or {@code null} if not value is set.
+ */
+ public Long getTimeout() {
+ return this.timeout;
+ }
+
+ /**
+ * Return the AsyncTaskExecutor to use for concurrent handling, or {@code null}.
+ */
+ public AsyncTaskExecutor getExecutor() {
+ if (this.executor != null) {
+ return this.executor;
+ }
+ else if (this.executorName != null) {
+ Assert.state(this.beanFactory != null, "A BeanFactory is required to look up an task executor bean");
+ return this.beanFactory.getBean(this.executorName, AsyncTaskExecutor.class);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * A {@link BeanFactory} to use to resolve an executor name. Applications are
+ * not expected to have to set this property when AsyncTask is used in a
+ * Spring MVC controller.
+ */
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+}
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebRequest.java
index a4e6af0e4e4..bfadad785ae 100644
--- a/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebRequest.java
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebRequest.java
@@ -29,20 +29,18 @@ public interface AsyncWebRequest extends NativeWebRequest {
/**
* Set the time required for concurrent handling to complete.
- * @param timeout amount of time in milliseconds
+ * This property should not be set when concurrent handling is in progress,
+ * i.e. when {@link #isAsyncStarted()} is {@code true}.
+ * @param timeout amount of time in milliseconds; {@code null} means no
+ * timeout, i.e. rely on the default timeout of the container.
*/
void setTimeout(Long timeout);
/**
- * Provide a Runnable to invoke on timeout.
+ * Set a handler to be invoked if concurrent processing times out.
*/
void setTimeoutHandler(Runnable runnable);
- /**
- * Provide a Runnable to invoke at the end of asynchronous request processing.
- */
- void addCompletionHandler(Runnable runnable);
-
/**
* Mark the start of asynchronous request processing so that when the main
* processing thread exits, the response remains open for further processing
@@ -70,6 +68,11 @@ public interface AsyncWebRequest extends NativeWebRequest {
*/
boolean isDispatched();
+ /**
+ * Add a Runnable to be invoked when request processing completes.
+ */
+ void addCompletionHandler(Runnable runnable);
+
/**
* Whether asynchronous processing has completed.
*/
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebUtils.java b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebUtils.java
index 02f138c8ccb..be8e8ee4288 100644
--- a/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebUtils.java
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/AsyncWebUtils.java
@@ -15,8 +15,14 @@
*/
package org.springframework.web.context.request.async;
-import javax.servlet.ServletRequest;
+import java.lang.reflect.Constructor;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.ClassUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
@@ -57,4 +63,30 @@ public abstract class AsyncWebUtils {
return asyncManager;
}
+ /**
+ * Create an AsyncWebRequest instance.
+ *
By default an instance of {@link StandardServletAsyncWebRequest} is created
+ * if running in Servlet 3.0 (or higher) environment or as a fallback option an
+ * instance of {@link NoSupportAsyncWebRequest} is returned.
+ * @param request the current request
+ * @param response the current response
+ * @return an AsyncWebRequest instance, never {@code null}
+ */
+ public static AsyncWebRequest createAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
+ return ClassUtils.hasMethod(ServletRequest.class, "startAsync") ?
+ createStandardServletAsyncWebRequest(request, response) : new NoSupportAsyncWebRequest(request, response);
+ }
+
+ private static AsyncWebRequest createStandardServletAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ String className = "org.springframework.web.context.request.async.StandardServletAsyncWebRequest";
+ Class> clazz = ClassUtils.forName(className, AsyncWebUtils.class.getClassLoader());
+ Constructor> constructor = clazz.getConstructor(HttpServletRequest.class, HttpServletResponse.class);
+ return (AsyncWebRequest) BeanUtils.instantiateClass(constructor, request, response);
+ }
+ catch (Throwable t) {
+ throw new IllegalStateException("Failed to instantiate StandardServletAsyncWebRequest", t);
+ }
+ }
+
}
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/DeferredResult.java b/spring-web/src/main/java/org/springframework/web/context/request/async/DeferredResult.java
index 6ceb3da02d2..b0675c8f491 100644
--- a/spring-web/src/main/java/org/springframework/web/context/request/async/DeferredResult.java
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/DeferredResult.java
@@ -24,10 +24,10 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
- * {@code DeferredResult} provides an alternative to returning a {@link Callable}
- * for asynchronous request processing. While with a Callable, a thread is used
- * to execute it on behalf of the application, with a DeferredResult the application
- * sets the result whenever it needs to from a thread of its choice.
+ * {@code DeferredResult} provides an alternative to using a {@link Callable}
+ * for asynchronous request processing. While a Callable is executed concurrently
+ * on behalf of the application, with a DeferredResult the application can produce
+ * the result from a thread of its choice.
*
* @author Rossen Stoyanchev
* @since 3.2
@@ -38,32 +38,53 @@ public final class DeferredResult {
private static final Object RESULT_NONE = new Object();
- private Object result = RESULT_NONE;
private final Object timeoutResult;
- private final AtomicBoolean expired = new AtomicBoolean(false);
+ private final Long timeout;
private DeferredResultHandler resultHandler;
+ private Object result = RESULT_NONE;
+
+ private final AtomicBoolean expired = new AtomicBoolean(false);
+
private final Object lock = new Object();
private final CountDownLatch latch = new CountDownLatch(1);
/**
- * Create a DeferredResult instance.
+ * Create a DeferredResult.
*/
public DeferredResult() {
- this(RESULT_NONE);
+ this(null, RESULT_NONE);
}
/**
- * Create a DeferredResult with a default result to use in case of a timeout.
- * @param timeoutResult the result to use
+ * Create a DeferredResult with a timeout.
+ * @param timeout timeout value in milliseconds
*/
- public DeferredResult(Object timeoutResult) {
+ public DeferredResult(long timeout) {
+ this(timeout, RESULT_NONE);
+ }
+
+ /**
+ * Create a DeferredResult with a timeout and a default result to use on timeout.
+ * @param timeout timeout value in milliseconds; ignored if {@code null}
+ * @param timeoutResult the result to use, possibly {@code null}
+ */
+ public DeferredResult(Long timeout, Object timeoutResult) {
this.timeoutResult = timeoutResult;
+ this.timeout = timeout;
+ }
+
+
+ /**
+ * Return the configured timeout value in milliseconds.
+ */
+ public Long getTimeoutMilliseconds() {
+ return this.timeout;
}
/**
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java
index b8e18cf770a..593376ed7bc 100644
--- a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java
@@ -70,6 +70,7 @@ public class StandardServletAsyncWebRequest extends ServletWebRequest implements
*
The timeout period begins when the main processing thread has exited.
*/
public void setTimeout(Long timeout) {
+ Assert.state(!isAsyncStarted(), "Cannot change the timeout with concurrent handling in progress");
this.timeout = timeout;
}
@@ -145,6 +146,9 @@ public class StandardServletAsyncWebRequest extends ServletWebRequest implements
}
+ /**
+ * Sends a SERVICE_UNAVAILABLE (503).
+ */
private class DefaultTimeoutHandler implements Runnable {
public void run() {
diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java
index f440ca77668..08b3e5a0300 100644
--- a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java
+++ b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java
@@ -38,25 +38,16 @@ import org.springframework.web.util.UrlPathHelper;
* as an SPI and not typically used directly by application classes.
*
*
An async scenario starts with request processing as usual in a thread (T1).
- * When a handler decides to handle the request concurrently, it calls
+ * Concurrent request handling can be innitiated by calling
* {@linkplain #startCallableProcessing(Callable, Object...) startCallableProcessing} or
* {@linkplain #startDeferredResultProcessing(DeferredResult, Object...) startDeferredResultProcessing}
- * both of which will process in a separate thread (T2).
- * After the start of concurrent handling {@link #isConcurrentHandlingStarted()}
- * returns "true" and this can be used by classes involved in processing on the
- * main thread (T1) quickly and with very minimal processing.
+ * both of which produce a result in a separate thread (T2). The result is saved
+ * and the request dispatched to the container, to resume processing with the saved
+ * result in a third thread (T3). Within the dispatched thread (T3), the saved
+ * result can be accessed via {@link #getConcurrentResult()} or its presence
+ * detected via {@link #hasConcurrentResult()}.
*
- *
When the concurrent handling completes in a separate thread (T2), both
- * {@code startCallableProcessing} and {@code startDeferredResultProcessing}
- * save the results and dispatched to the container, essentially to the
- * same request URI as the one that started concurrent handling. This allows for
- * further processing of the concurrent results. Classes in the dispatched
- * thread (T3), can access the results via {@link #getConcurrentResult()} or
- * detect their presence via {@link #hasConcurrentResult()}. Also in the
- * dispatched thread {@link #isConcurrentHandlingStarted()} will return "false"
- * unless concurrent handling is started once again.
- *
- * TODO .. mention Servlet 3 configuration
+ *
TODO .. Servlet 3 config
*
* @author Rossen Stoyanchev
* @since 3.2
@@ -73,42 +64,38 @@ public final class WebAsyncManager {
private static final Log logger = LogFactory.getLog(WebAsyncManager.class);
+
private AsyncWebRequest asyncWebRequest;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(this.getClass().getSimpleName());
- private final Map