/*
 * 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"; } }