001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.context.request.async;
018
019import java.util.concurrent.Callable;
020
021import org.springframework.core.task.AsyncTaskExecutor;
022import org.springframework.web.context.request.NativeWebRequest;
023
024/**
025 * Intercepts concurrent request handling, where the concurrent result is
026 * obtained by executing a {@link Callable} on behalf of the application with
027 * an {@link AsyncTaskExecutor}.
028 *
029 * <p>A {@code CallableProcessingInterceptor} is invoked before and after the
030 * invocation of the {@code Callable} task in the asynchronous thread, as well
031 * as on timeout from a container thread, or after completing for any reason
032 * including a timeout or network error.
033 *
034 * <p>As a general rule exceptions raised by interceptor methods will cause
035 * async processing to resume by dispatching back to the container and using
036 * the Exception instance as the concurrent result. Such exceptions will then
037 * be processed through the {@code HandlerExceptionResolver} mechanism.
038 *
039 * <p>The {@link #handleTimeout(NativeWebRequest, Callable) handleTimeout} method
040 * can select a value to be used to resume processing.
041 *
042 * @author Rossen Stoyanchev
043 * @author Rob Winch
044 * @since 3.2
045 */
046public interface CallableProcessingInterceptor {
047
048        /**
049         * Constant indicating that no result has been determined by this
050         * interceptor, giving subsequent interceptors a chance.
051         * @see #handleTimeout
052         */
053        Object RESULT_NONE = new Object();
054
055        /**
056         * Constant indicating that the response has been handled by this interceptor
057         * without a result and that no further interceptors are to be invoked.
058         * @see #handleTimeout
059         */
060        Object RESPONSE_HANDLED = new Object();
061
062
063        /**
064         * Invoked <em>before</em> the start of concurrent handling in the original
065         * thread in which the {@code Callable} is submitted for concurrent handling.
066         * <p>This is useful for capturing the state of the current thread just prior to
067         * invoking the {@link Callable}. Once the state is captured, it can then be
068         * transferred to the new {@link Thread} in
069         * {@link #preProcess(NativeWebRequest, Callable)}. Capturing the state of
070         * Spring Security's SecurityContextHolder and migrating it to the new Thread
071         * is a concrete example of where this is useful.
072         * @param request the current request
073         * @param task the task for the current async request
074         * @throws Exception in case of errors
075         */
076        <T> void  beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) throws Exception;
077
078        /**
079         * Invoked <em>after</em> the start of concurrent handling in the async
080         * thread in which the {@code Callable} is executed and <em>before</em> the
081         * actual invocation of the {@code Callable}.
082         * @param request the current request
083         * @param task the task for the current async request
084         * @throws Exception in case of errors
085         */
086        <T> void preProcess(NativeWebRequest request, Callable<T> task) throws Exception;
087
088        /**
089         * Invoked <em>after</em> the {@code Callable} has produced a result in the
090         * async thread in which the {@code Callable} is executed. This method may
091         * be invoked later than {@code afterTimeout} or {@code afterCompletion}
092         * depending on when the {@code Callable} finishes processing.
093         * @param request the current request
094         * @param task the task for the current async request
095         * @param concurrentResult the result of concurrent processing, which could
096         * be a {@link Throwable} if the {@code Callable} raised an exception
097         * @throws Exception in case of errors
098         */
099        <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) throws Exception;
100
101        /**
102         * Invoked from a container thread when the async request times out before
103         * the {@code Callable} task completes. Implementations may return a value,
104         * including an {@link Exception}, to use instead of the value the
105         * {@link Callable} did not return in time.
106         * @param request the current request
107         * @param task the task for the current async request
108         * @return a concurrent result value; if the value is anything other than
109         * {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing
110         * is resumed and subsequent interceptors are not invoked
111         * @throws Exception in case of errors
112         */
113        <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception;
114
115        /**
116         * Invoked from a container thread when async processing completes for any
117         * reason including timeout or network error.
118         * @param request the current request
119         * @param task the task for the current async request
120         * @throws Exception in case of errors
121         */
122        <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception;
123
124}