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/error 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 * @see #handleError 053 */ 054 Object RESULT_NONE = new Object(); 055 056 /** 057 * Constant indicating that the response has been handled by this interceptor 058 * without a result and that no further interceptors are to be invoked. 059 * @see #handleTimeout 060 * @see #handleError 061 */ 062 Object RESPONSE_HANDLED = new Object(); 063 064 065 /** 066 * Invoked <em>before</em> the start of concurrent handling in the original 067 * thread in which the {@code Callable} is submitted for concurrent handling. 068 * <p>This is useful for capturing the state of the current thread just prior to 069 * invoking the {@link Callable}. Once the state is captured, it can then be 070 * transferred to the new {@link Thread} in 071 * {@link #preProcess(NativeWebRequest, Callable)}. Capturing the state of 072 * Spring Security's SecurityContextHolder and migrating it to the new Thread 073 * is a concrete example of where this is useful. 074 * <p>The default implementation is empty. 075 * @param request the current request 076 * @param task the task for the current async request 077 * @throws Exception in case of errors 078 */ 079 default <T> void beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) throws Exception { 080 } 081 082 /** 083 * Invoked <em>after</em> the start of concurrent handling in the async 084 * thread in which the {@code Callable} is executed and <em>before</em> the 085 * actual invocation of the {@code Callable}. 086 * <p>The default implementation is empty. 087 * @param request the current request 088 * @param task the task for the current async request 089 * @throws Exception in case of errors 090 */ 091 default <T> void preProcess(NativeWebRequest request, Callable<T> task) throws Exception { 092 } 093 094 /** 095 * Invoked <em>after</em> the {@code Callable} has produced a result in the 096 * async thread in which the {@code Callable} is executed. This method may 097 * be invoked later than {@code afterTimeout} or {@code afterCompletion} 098 * depending on when the {@code Callable} finishes processing. 099 * <p>The default implementation is empty. 100 * @param request the current request 101 * @param task the task for the current async request 102 * @param concurrentResult the result of concurrent processing, which could 103 * be a {@link Throwable} if the {@code Callable} raised an exception 104 * @throws Exception in case of errors 105 */ 106 default <T> void postProcess(NativeWebRequest request, Callable<T> task, 107 Object concurrentResult) throws Exception { 108 } 109 110 /** 111 * Invoked from a container thread when the async request times out before 112 * the {@code Callable} task completes. Implementations may return a value, 113 * including an {@link Exception}, to use instead of the value the 114 * {@link Callable} did not return in time. 115 * <p>The default implementation always returns {@link #RESULT_NONE}. 116 * @param request the current request 117 * @param task the task for the current async request 118 * @return a concurrent result value; if the value is anything other than 119 * {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing 120 * is resumed and subsequent interceptors are not invoked 121 * @throws Exception in case of errors 122 */ 123 default <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception { 124 return RESULT_NONE; 125 } 126 127 /** 128 * Invoked from a container thread when an error occurred while processing 129 * the async request before the {@code Callable} task completes. 130 * Implementations may return a value, including an {@link Exception}, to 131 * use instead of the value the {@link Callable} did not return in time. 132 * <p>The default implementation always returns {@link #RESULT_NONE}. 133 * @param request the current request 134 * @param task the task for the current async request 135 * @param t the error that occurred while request processing 136 * @return a concurrent result value; if the value is anything other than 137 * {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing 138 * is resumed and subsequent interceptors are not invoked 139 * @throws Exception in case of errors 140 * @since 5.0 141 */ 142 default <T> Object handleError(NativeWebRequest request, Callable<T> task, Throwable t) throws Exception { 143 return RESULT_NONE; 144 } 145 146 /** 147 * Invoked from a container thread when async processing completes for any 148 * reason including timeout or network error. 149 * <p>The default implementation is empty. 150 * @param request the current request 151 * @param task the task for the current async request 152 * @throws Exception in case of errors 153 */ 154 default <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception { 155 } 156 157}