org.springframework.web.context.request.async.CallableProcessingInterceptor Maven / Gradle / Ivy
/*
* Copyright 2002-2017 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
*
* https://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.core.task.AsyncTaskExecutor;
import org.springframework.web.context.request.NativeWebRequest;
/**
* Intercepts concurrent request handling, where the concurrent result is
* obtained by executing a {@link Callable} on behalf of the application with
* an {@link AsyncTaskExecutor}.
*
* A {@code CallableProcessingInterceptor} is invoked before and after the
* invocation of the {@code Callable} task in the asynchronous thread, as well
* as on timeout/error from a container thread, or after completing for any reason
* including a timeout or network error.
*
*
As a general rule exceptions raised by interceptor methods will cause
* async processing to resume by dispatching back to the container and using
* the Exception instance as the concurrent result. Such exceptions will then
* be processed through the {@code HandlerExceptionResolver} mechanism.
*
*
The {@link #handleTimeout(NativeWebRequest, Callable) handleTimeout} method
* can select a value to be used to resume processing.
*
* @author Rossen Stoyanchev
* @author Rob Winch
* @since 3.2
*/
public interface CallableProcessingInterceptor {
/**
* Constant indicating that no result has been determined by this
* interceptor, giving subsequent interceptors a chance.
* @see #handleTimeout
* @see #handleError
*/
Object RESULT_NONE = new Object();
/**
* Constant indicating that the response has been handled by this interceptor
* without a result and that no further interceptors are to be invoked.
* @see #handleTimeout
* @see #handleError
*/
Object RESPONSE_HANDLED = new Object();
/**
* Invoked before the start of concurrent handling in the original
* thread in which the {@code Callable} is submitted for concurrent handling.
*
This is useful for capturing the state of the current thread just prior to
* invoking the {@link Callable}. Once the state is captured, it can then be
* transferred to the new {@link Thread} in
* {@link #preProcess(NativeWebRequest, Callable)}. Capturing the state of
* Spring Security's SecurityContextHolder and migrating it to the new Thread
* is a concrete example of where this is useful.
*
The default implementation is empty.
* @param request the current request
* @param task the task for the current async request
* @throws Exception in case of errors
*/
default void beforeConcurrentHandling(NativeWebRequest request, Callable task) throws Exception {
}
/**
* Invoked after the start of concurrent handling in the async
* thread in which the {@code Callable} is executed and before the
* actual invocation of the {@code Callable}.
* The default implementation is empty.
* @param request the current request
* @param task the task for the current async request
* @throws Exception in case of errors
*/
default void preProcess(NativeWebRequest request, Callable task) throws Exception {
}
/**
* Invoked after the {@code Callable} has produced a result in the
* async thread in which the {@code Callable} is executed. This method may
* be invoked later than {@code afterTimeout} or {@code afterCompletion}
* depending on when the {@code Callable} finishes processing.
* The default implementation is empty.
* @param request the current request
* @param task the task for the current async request
* @param concurrentResult the result of concurrent processing, which could
* be a {@link Throwable} if the {@code Callable} raised an exception
* @throws Exception in case of errors
*/
default void postProcess(NativeWebRequest request, Callable task,
Object concurrentResult) throws Exception {
}
/**
* Invoked from a container thread when the async request times out before
* the {@code Callable} task completes. Implementations may return a value,
* including an {@link Exception}, to use instead of the value the
* {@link Callable} did not return in time.
* The default implementation always returns {@link #RESULT_NONE}.
* @param request the current request
* @param task the task for the current async request
* @return a concurrent result value; if the value is anything other than
* {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing
* is resumed and subsequent interceptors are not invoked
* @throws Exception in case of errors
*/
default Object handleTimeout(NativeWebRequest request, Callable task) throws Exception {
return RESULT_NONE;
}
/**
* Invoked from a container thread when an error occurred while processing
* the async request before the {@code Callable} task completes.
* Implementations may return a value, including an {@link Exception}, to
* use instead of the value the {@link Callable} did not return in time.
* The default implementation always returns {@link #RESULT_NONE}.
* @param request the current request
* @param task the task for the current async request
* @param t the error that occurred while request processing
* @return a concurrent result value; if the value is anything other than
* {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing
* is resumed and subsequent interceptors are not invoked
* @throws Exception in case of errors
* @since 5.0
*/
default Object handleError(NativeWebRequest request, Callable task, Throwable t) throws Exception {
return RESULT_NONE;
}
/**
* Invoked from a container thread when async processing completes for any
* reason including timeout or network error.
* The default implementation is empty.
* @param request the current request
* @param task the task for the current async request
* @throws Exception in case of errors
*/
default void afterCompletion(NativeWebRequest request, Callable task) throws Exception {
}
}