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}