View Javadoc
1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.web.context.request.async;
17  
18  import java.util.concurrent.Callable;
19  
20  import org.springframework.core.task.AsyncTaskExecutor;
21  import org.springframework.web.context.request.NativeWebRequest;
22  
23  /**
24   * Intercepts concurrent request handling, where the concurrent result is
25   * obtained by executing a {@link Callable} on behalf of the application with
26   * an {@link AsyncTaskExecutor}.
27   *
28   * <p>A {@code CallableProcessingInterceptor} is invoked before and after the
29   * invocation of the {@code Callable} task in the asynchronous thread, as well
30   * as on timeout from a container thread, or after completing for any reason
31   * including a timeout or network error.
32   *
33   * <p>As a general rule exceptions raised by interceptor methods will cause
34   * async processing to resume by dispatching back to the container and using
35   * the Exception instance as the concurrent result. Such exceptions will then
36   * be processed through the {@code HandlerExceptionResolver} mechanism.
37   *
38   * <p>The {@link #handleTimeout(NativeWebRequest, Callable) afterTimeout} method
39   * can select a value to be used to resume processing.
40   *
41   * @author Rossen Stoyanchev
42   * @author Rob Winch
43   * @since 3.2
44   */
45  public interface CallableProcessingInterceptor {
46  
47  	static final Object RESULT_NONE = new Object();
48  
49  	static final Object RESPONSE_HANDLED = new Object();
50  
51  	/**
52  	 * Invoked <em>before</em> the start of concurrent handling in the original
53  	 * thread in which the {@code Callable} is submitted for concurrent handling.
54  	 *
55  	 * <p>
56  	 * This is useful for capturing the state of the current thread just prior to
57  	 * invoking the {@link Callable}. Once the state is captured, it can then be
58  	 * transferred to the new {@link Thread} in
59  	 * {@link #preProcess(NativeWebRequest, Callable)}. Capturing the state of
60  	 * Spring Security's SecurityContextHolder and migrating it to the new Thread
61  	 * is a concrete example of where this is useful.
62  	 * </p>
63  	 *
64  	 * @param request the current request
65  	 * @param task the task for the current async request
66  	 * @throws Exception in case of errors
67  	 */
68  	<T> void  beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) throws Exception;
69  
70  	/**
71  	 * Invoked <em>after</em> the start of concurrent handling in the async
72  	 * thread in which the {@code Callable} is executed and <em>before</em> the
73  	 * actual invocation of the {@code Callable}.
74  	 *
75  	 * @param request the current request
76  	 * @param task the task for the current async request
77  	 * @throws Exception in case of errors
78  	 */
79  	<T> void preProcess(NativeWebRequest request, Callable<T> task) throws Exception;
80  
81  	/**
82  	 * Invoked <em>after</em> the {@code Callable} has produced a result in the
83  	 * async thread in which the {@code Callable} is executed. This method may
84  	 * be invoked later than {@code afterTimeout} or {@code afterCompletion}
85  	 * depending on when the {@code Callable} finishes processing.
86  	 *
87  	 * @param request the current request
88  	 * @param task the task for the current async request
89  	 * @param concurrentResult the result of concurrent processing, which could
90  	 * be a {@link Throwable} if the {@code Callable} raised an exception
91  	 * @throws Exception in case of errors
92  	 */
93  	<T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) throws Exception;
94  
95  	/**
96  	 * Invoked from a container thread when the async request times out before
97  	 * the {@code Callable} task completes. Implementations may return a value,
98  	 * including an {@link Exception}, to use instead of the value the
99  	 * {@link Callable} did not return in time.
100 	 *
101 	 * @param request the current request
102 	 * @param task the task for the current async request
103 	 * @return a concurrent result value; if the value is anything other than
104 	 * {@link #RESULT_NONE} or {@link #RESPONSE_HANDLED}, concurrent processing
105 	 * is resumed and subsequent interceptors are not invoked
106 	 * @throws Exception in case of errors
107 	 */
108 	<T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception;
109 
110 	/**
111 	 * Invoked from a container thread when async processing completes for any
112 	 * reason including timeout or network error.
113 	 *
114 	 * @param request the current request
115 	 * @param task the task for the current async request
116 	 * @throws Exception in case of errors
117 	 */
118 	<T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception;
119 
120 }