View Javadoc
1   /*
2    * Copyright 2002-2014 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  
17  package org.springframework.web.servlet;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  
28  import org.springframework.util.CollectionUtils;
29  import org.springframework.util.ObjectUtils;
30  
31  /**
32   * Handler execution chain, consisting of handler object and any handler interceptors.
33   * Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
34   *
35   * @author Juergen Hoeller
36   * @since 20.06.2003
37   * @see HandlerInterceptor
38   */
39  public class HandlerExecutionChain {
40  
41  	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
42  
43  	private final Object handler;
44  
45  	private HandlerInterceptor[] interceptors;
46  
47  	private List<HandlerInterceptor> interceptorList;
48  
49  	private int interceptorIndex = -1;
50  
51  
52  	/**
53  	 * Create a new HandlerExecutionChain.
54  	 * @param handler the handler object to execute
55  	 */
56  	public HandlerExecutionChain(Object handler) {
57  		this(handler, (HandlerInterceptor[]) null);
58  	}
59  
60  	/**
61  	 * Create a new HandlerExecutionChain.
62  	 * @param handler the handler object to execute
63  	 * @param interceptors the array of interceptors to apply
64  	 * (in the given order) before the handler itself executes
65  	 */
66  	public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
67  		if (handler instanceof HandlerExecutionChain) {
68  			HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
69  			this.handler = originalChain.getHandler();
70  			this.interceptorList = new ArrayList<HandlerInterceptor>();
71  			CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
72  			CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
73  		}
74  		else {
75  			this.handler = handler;
76  			this.interceptors = interceptors;
77  		}
78  	}
79  
80  
81  	/**
82  	 * Return the handler object to execute.
83  	 * @return the handler object
84  	 */
85  	public Object getHandler() {
86  		return this.handler;
87  	}
88  
89  	public void addInterceptor(HandlerInterceptor interceptor) {
90  		initInterceptorList().add(interceptor);
91  	}
92  
93  	public void addInterceptors(HandlerInterceptor... interceptors) {
94  		if (!ObjectUtils.isEmpty(interceptors)) {
95  			initInterceptorList().addAll(Arrays.asList(interceptors));
96  		}
97  	}
98  
99  	private List<HandlerInterceptor> initInterceptorList() {
100 		if (this.interceptorList == null) {
101 			this.interceptorList = new ArrayList<HandlerInterceptor>();
102 			if (this.interceptors != null) {
103 				// An interceptor array specified through the constructor
104 				this.interceptorList.addAll(Arrays.asList(this.interceptors));
105 			}
106 		}
107 		this.interceptors = null;
108 		return this.interceptorList;
109 	}
110 
111 	/**
112 	 * Return the array of interceptors to apply (in the given order).
113 	 * @return the array of HandlerInterceptors instances (may be {@code null})
114 	 */
115 	public HandlerInterceptor[] getInterceptors() {
116 		if (this.interceptors == null && this.interceptorList != null) {
117 			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
118 		}
119 		return this.interceptors;
120 	}
121 
122 
123 	/**
124 	 * Apply preHandle methods of registered interceptors.
125 	 * @return {@code true} if the execution chain should proceed with the
126 	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
127 	 * that this interceptor has already dealt with the response itself.
128 	 */
129 	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
130 		HandlerInterceptor[] interceptors = getInterceptors();
131 		if (!ObjectUtils.isEmpty(interceptors)) {
132 			for (int i = 0; i < interceptors.length; i++) {
133 				HandlerInterceptor interceptor = interceptors[i];
134 				if (!interceptor.preHandle(request, response, this.handler)) {
135 					triggerAfterCompletion(request, response, null);
136 					return false;
137 				}
138 				this.interceptorIndex = i;
139 			}
140 		}
141 		return true;
142 	}
143 
144 	/**
145 	 * Apply postHandle methods of registered interceptors.
146 	 */
147 	void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
148 		HandlerInterceptor[] interceptors = getInterceptors();
149 		if (!ObjectUtils.isEmpty(interceptors)) {
150 			for (int i = interceptors.length - 1; i >= 0; i--) {
151 				HandlerInterceptor interceptor = interceptors[i];
152 				interceptor.postHandle(request, response, this.handler, mv);
153 			}
154 		}
155 	}
156 
157 	/**
158 	 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
159 	 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
160 	 * has successfully completed and returned true.
161 	 */
162 	void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
163 			throws Exception {
164 
165 		HandlerInterceptor[] interceptors = getInterceptors();
166 		if (!ObjectUtils.isEmpty(interceptors)) {
167 			for (int i = this.interceptorIndex; i >= 0; i--) {
168 				HandlerInterceptor interceptor = interceptors[i];
169 				try {
170 					interceptor.afterCompletion(request, response, this.handler, ex);
171 				}
172 				catch (Throwable ex2) {
173 					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
174 				}
175 			}
176 		}
177 	}
178 
179 	/**
180 	 * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
181 	 */
182 	void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
183 		HandlerInterceptor[] interceptors = getInterceptors();
184 		if (!ObjectUtils.isEmpty(interceptors)) {
185 			for (int i = interceptors.length - 1; i >= 0; i--) {
186 				if (interceptors[i] instanceof AsyncHandlerInterceptor) {
187 					try {
188 						AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
189 						asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
190 					}
191 					catch (Throwable ex) {
192 						logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
193 					}
194 				}
195 			}
196 		}
197 	}
198 
199 
200 	/**
201 	 * Delegates to the handler's {@code toString()}.
202 	 */
203 	@Override
204 	public String toString() {
205 		if (this.handler == null) {
206 			return "HandlerExecutionChain with no handler";
207 		}
208 		StringBuilder sb = new StringBuilder();
209 		sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]");
210 		if (!CollectionUtils.isEmpty(this.interceptorList)) {
211 			sb.append(" and ").append(this.interceptorList.size()).append(" interceptor");
212 			if (this.interceptorList.size() > 1) {
213 				sb.append("s");
214 			}
215 		}
216 		return sb.toString();
217 	}
218 
219 }