|
|
|
@ -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,11 +13,13 @@ |
|
|
|
* 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.concurrent.Callable; |
|
|
|
import java.util.concurrent.Callable; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.factory.BeanFactory; |
|
|
|
import org.springframework.beans.factory.BeanFactory; |
|
|
|
|
|
|
|
import org.springframework.beans.factory.BeanFactoryAware; |
|
|
|
import org.springframework.core.task.AsyncTaskExecutor; |
|
|
|
import org.springframework.core.task.AsyncTaskExecutor; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.web.context.request.NativeWebRequest; |
|
|
|
import org.springframework.web.context.request.NativeWebRequest; |
|
|
|
@ -26,94 +28,105 @@ import org.springframework.web.context.request.NativeWebRequest; |
|
|
|
* Holder for a {@link Callable}, a timeout value, and a task executor. |
|
|
|
* Holder for a {@link Callable}, a timeout value, and a task executor. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
|
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 3.2 |
|
|
|
* @since 3.2 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class WebAsyncTask<V> { |
|
|
|
public class WebAsyncTask<V> implements BeanFactoryAware { |
|
|
|
|
|
|
|
|
|
|
|
private final Callable<V> callable; |
|
|
|
private final Callable<V> callable; |
|
|
|
|
|
|
|
|
|
|
|
private final Long timeout; |
|
|
|
private Long timeout; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private AsyncTaskExecutor executor; |
|
|
|
|
|
|
|
|
|
|
|
private final String executorName; |
|
|
|
private String executorName; |
|
|
|
|
|
|
|
|
|
|
|
private final AsyncTaskExecutor executor; |
|
|
|
private BeanFactory beanFactory; |
|
|
|
|
|
|
|
|
|
|
|
private Callable<V> timeoutCallback; |
|
|
|
private Callable<V> timeoutCallback; |
|
|
|
|
|
|
|
|
|
|
|
private Runnable completionCallback; |
|
|
|
private Runnable completionCallback; |
|
|
|
|
|
|
|
|
|
|
|
private BeanFactory beanFactory; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a {@code WebAsyncTask} wrapping the given {@link Callable}. |
|
|
|
* Create a {@code WebAsyncTask} wrapping the given {@link Callable}. |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WebAsyncTask(Callable<V> callable) { |
|
|
|
public WebAsyncTask(Callable<V> callable) { |
|
|
|
this(null, null, null, callable); |
|
|
|
Assert.notNull(callable, "Callable must not be null"); |
|
|
|
|
|
|
|
this.callable = callable; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value and a {@link Callable}. |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value and a {@link Callable}. |
|
|
|
* @param timeout timeout value in milliseconds |
|
|
|
* @param timeout a timeout value in milliseconds |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WebAsyncTask(long timeout, Callable<V> callable) { |
|
|
|
public WebAsyncTask(long timeout, Callable<V> callable) { |
|
|
|
this(timeout, null, null, callable); |
|
|
|
this(callable); |
|
|
|
|
|
|
|
this.timeout = timeout; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value, an executor name, and a {@link Callable}. |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value, an executor name, and a {@link Callable}. |
|
|
|
* @param timeout timeout value in milliseconds; ignored if {@code null} |
|
|
|
* @param timeout timeout value in milliseconds; ignored if {@code null} |
|
|
|
|
|
|
|
* @param executorName the name of an executor bean to use |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WebAsyncTask(Long timeout, String executorName, Callable<V> callable) { |
|
|
|
public WebAsyncTask(Long timeout, String executorName, Callable<V> callable) { |
|
|
|
this(timeout, null, executorName, callable); |
|
|
|
this(callable); |
|
|
|
Assert.notNull(executor, "Executor name must not be null"); |
|
|
|
Assert.notNull(executorName, "Executor name must not be null"); |
|
|
|
|
|
|
|
this.executorName = executorName; |
|
|
|
|
|
|
|
this.timeout = timeout; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value, an executor instance, and a Callable. |
|
|
|
* Create a {@code WebAsyncTask} with a timeout value, an executor instance, and a Callable. |
|
|
|
* @param timeout timeout value in milliseconds; ignored if {@code null} |
|
|
|
* @param timeout timeout value in milliseconds; ignored if {@code null} |
|
|
|
|
|
|
|
* @param executor the executor to use |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
* @param callable the callable for concurrent handling |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WebAsyncTask(Long timeout, AsyncTaskExecutor executor, Callable<V> callable) { |
|
|
|
public WebAsyncTask(Long timeout, AsyncTaskExecutor executor, Callable<V> callable) { |
|
|
|
this(timeout, executor, null, callable); |
|
|
|
this(callable); |
|
|
|
Assert.notNull(executor, "Executor must not be null"); |
|
|
|
Assert.notNull(executor, "Executor must not be null"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private WebAsyncTask(Long timeout, AsyncTaskExecutor executor, String executorName, Callable<V> callable) { |
|
|
|
|
|
|
|
Assert.notNull(callable, "Callable must not be null"); |
|
|
|
|
|
|
|
this.callable = callable; |
|
|
|
|
|
|
|
this.timeout = timeout; |
|
|
|
|
|
|
|
this.executor = executor; |
|
|
|
this.executor = executor; |
|
|
|
this.executorName = executorName; |
|
|
|
this.timeout = timeout; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the {@link Callable} to use for concurrent handling, never {@code null}. |
|
|
|
* Return the {@link Callable} to use for concurrent handling (never {@code null}). |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Callable<?> getCallable() { |
|
|
|
public Callable<?> getCallable() { |
|
|
|
return this.callable; |
|
|
|
return this.callable; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the timeout value in milliseconds or {@code null} if not value is set. |
|
|
|
* Return the timeout value in milliseconds, or {@code null} if no timeout is set. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Long getTimeout() { |
|
|
|
public Long getTimeout() { |
|
|
|
return this.timeout; |
|
|
|
return this.timeout; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the AsyncTaskExecutor to use for concurrent handling, or {@code null}. |
|
|
|
* A {@link BeanFactory} to use for resolving an executor name. |
|
|
|
|
|
|
|
* <p>This factory reference will automatically be set when |
|
|
|
|
|
|
|
* {@code WebAsyncTask} is used within a Spring MVC controller. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void setBeanFactory(BeanFactory beanFactory) { |
|
|
|
|
|
|
|
this.beanFactory = beanFactory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return the AsyncTaskExecutor to use for concurrent handling, |
|
|
|
|
|
|
|
* or {@code null} if none specified. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public AsyncTaskExecutor getExecutor() { |
|
|
|
public AsyncTaskExecutor getExecutor() { |
|
|
|
if (this.executor != null) { |
|
|
|
if (this.executor != null) { |
|
|
|
return this.executor; |
|
|
|
return this.executor; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (this.executorName != null) { |
|
|
|
else if (this.executorName != null) { |
|
|
|
Assert.state(this.beanFactory != null, "A BeanFactory is required to look up a task executor bean"); |
|
|
|
Assert.state(this.beanFactory != null, "BeanFactory is required to look up an executor bean by name"); |
|
|
|
return this.beanFactory.getBean(this.executorName, AsyncTaskExecutor.class); |
|
|
|
return this.beanFactory.getBean(this.executorName, AsyncTaskExecutor.class); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
@ -121,22 +134,13 @@ public class WebAsyncTask<V> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* A {@link BeanFactory} to use to resolve an executor name. Applications are |
|
|
|
|
|
|
|
* not expected to have to set this property when {@code WebAsyncTask} is used in a |
|
|
|
|
|
|
|
* Spring MVC controller. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void setBeanFactory(BeanFactory beanFactory) { |
|
|
|
|
|
|
|
this.beanFactory = beanFactory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Register code to invoke when the async request times out. This method is |
|
|
|
* Register code to invoke when the async request times out. |
|
|
|
* called from a container thread when an async request times out before the |
|
|
|
* <p>This method is called from a container thread when an async request times |
|
|
|
* {@code Callable} has completed. The callback is executed in the same |
|
|
|
* out before the {@code Callable} has completed. The callback is executed in |
|
|
|
* thread and therefore should return without blocking. It may return an |
|
|
|
* the same thread and therefore should return without blocking. It may return |
|
|
|
* alternative value to use, including an {@link Exception} or return |
|
|
|
* an alternative value to use, including an {@link Exception} or return |
|
|
|
* {@link CallableProcessingInterceptor#RESULT_NONE RESULT_NONE}. |
|
|
|
* {@link CallableProcessingInterceptor#RESULT_NONE RESULT_NONE}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void onTimeout(Callable<V> callback) { |
|
|
|
public void onTimeout(Callable<V> callback) { |
|
|
|
@ -144,9 +148,9 @@ public class WebAsyncTask<V> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Register code to invoke when the async request completes. This method is |
|
|
|
* Register code to invoke when the async request completes. |
|
|
|
* called from a container thread when an async request completed for any |
|
|
|
* <p>This method is called from a container thread when an async request |
|
|
|
* reason including timeout and network error. |
|
|
|
* completed for any reason, including timeout and network error. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void onCompletion(Runnable callback) { |
|
|
|
public void onCompletion(Runnable callback) { |
|
|
|
this.completionCallback = callback; |
|
|
|
this.completionCallback = callback; |
|
|
|
@ -154,12 +158,10 @@ public class WebAsyncTask<V> { |
|
|
|
|
|
|
|
|
|
|
|
CallableProcessingInterceptor getInterceptor() { |
|
|
|
CallableProcessingInterceptor getInterceptor() { |
|
|
|
return new CallableProcessingInterceptorAdapter() { |
|
|
|
return new CallableProcessingInterceptorAdapter() { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception { |
|
|
|
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception { |
|
|
|
return (timeoutCallback != null) ? timeoutCallback.call() : CallableProcessingInterceptor.RESULT_NONE; |
|
|
|
return (timeoutCallback != null ? timeoutCallback.call() : CallableProcessingInterceptor.RESULT_NONE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception { |
|
|
|
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception { |
|
|
|
if (completionCallback != null) { |
|
|
|
if (completionCallback != null) { |
|
|
|
|