/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
Handler execution chain, consisting of handler object and any handler interceptors. Returned by HandlerMapping's HandlerMapping.getHandler
method. Author: Juergen Hoeller See Also: Since: 20.06.2003
/**
* Handler execution chain, consisting of handler object and any handler interceptors.
* Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
*
* @author Juergen Hoeller
* @since 20.06.2003
* @see HandlerInterceptor
*/
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
private int interceptorIndex = -1;
Create a new HandlerExecutionChain.
Params: - handler – the handler object to execute
/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
*/
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
Create a new HandlerExecutionChain.
Params: - handler – the handler object to execute
- interceptors – the array of interceptors to apply
(in the given order) before the handler itself executes
/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
* @param interceptors the array of interceptors to apply
* (in the given order) before the handler itself executes
*/
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
this(handler, (interceptors != null ? Arrays.asList(interceptors) : Collections.emptyList()));
}
Create a new HandlerExecutionChain.
Params: - handler – the handler object to execute
- interceptorList – the list of interceptors to apply
(in the given order) before the handler itself executes
Since: 5.3
/**
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
* @param interceptorList the list of interceptors to apply
* (in the given order) before the handler itself executes
* @since 5.3
*/
public HandlerExecutionChain(Object handler, List<HandlerInterceptor> interceptorList) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList.addAll(originalChain.interceptorList);
}
else {
this.handler = handler;
}
this.interceptorList.addAll(interceptorList);
}
Return the handler object to execute.
/**
* Return the handler object to execute.
*/
public Object getHandler() {
return this.handler;
}
Add the given interceptor to the end of this chain.
/**
* Add the given interceptor to the end of this chain.
*/
public void addInterceptor(HandlerInterceptor interceptor) {
this.interceptorList.add(interceptor);
}
Add the given interceptor at the specified index of this chain.
Since: 5.2
/**
* Add the given interceptor at the specified index of this chain.
* @since 5.2
*/
public void addInterceptor(int index, HandlerInterceptor interceptor) {
this.interceptorList.add(index, interceptor);
}
Add the given interceptors to the end of this chain.
/**
* Add the given interceptors to the end of this chain.
*/
public void addInterceptors(HandlerInterceptor... interceptors) {
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
Return the array of interceptors to apply (in the given order).
Returns: the array of HandlerInterceptors instances (may be null
)
/**
* Return the array of interceptors to apply (in the given order).
* @return the array of HandlerInterceptors instances (may be {@code null})
*/
@Nullable
public HandlerInterceptor[] getInterceptors() {
return (!this.interceptorList.isEmpty() ? this.interceptorList.toArray(new HandlerInterceptor[0]) : null);
}
Return the list of interceptors to apply (in the given order).
Returns: the list of HandlerInterceptors instances (potentially empty) Since: 5.3
/**
* Return the list of interceptors to apply (in the given order).
* @return the list of HandlerInterceptors instances (potentially empty)
* @since 5.3
*/
public List<HandlerInterceptor> getInterceptorList() {
return (!this.interceptorList.isEmpty() ? Collections.unmodifiableList(this.interceptorList) :
Collections.emptyList());
}
Apply preHandle methods of registered interceptors.
Returns: true
if the execution chain should proceed with the next interceptor or the handler itself. Else, DispatcherServlet assumes that this interceptor has already dealt with the response itself.
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
Apply postHandle methods of registered interceptors.
/**
* Apply postHandle methods of registered interceptors.
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
Will just invoke afterCompletion for all interceptors whose preHandle invocation
has successfully completed and returned true.
/**
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
* has successfully completed and returned true.
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
/**
* Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
*/
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (interceptor instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptor;
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
}
catch (Throwable ex) {
if (logger.isErrorEnabled()) {
logger.error("Interceptor [" + interceptor + "] failed in afterConcurrentHandlingStarted", ex);
}
}
}
}
}
Delegates to the handler's toString()
implementation. /**
* Delegates to the handler's {@code toString()} implementation.
*/
@Override
public String toString() {
return "HandlerExecutionChain with [" + getHandler() + "] and " + this.interceptorList.size() + " interceptors";
}
}