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.portlet.handler; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.List; 22 import javax.portlet.PortletRequest; 23 24 import org.springframework.beans.BeansException; 25 import org.springframework.context.support.ApplicationObjectSupport; 26 import org.springframework.core.Ordered; 27 import org.springframework.web.context.request.WebRequestInterceptor; 28 import org.springframework.web.portlet.HandlerExecutionChain; 29 import org.springframework.web.portlet.HandlerInterceptor; 30 import org.springframework.web.portlet.HandlerMapping; 31 32 /** 33 * Abstract base class for {@link org.springframework.web.portlet.HandlerMapping} 34 * implementations. Supports ordering, a default handler, and handler interceptors. 35 * 36 * @author Juergen Hoeller 37 * @author John A. Lewis 38 * @since 2.0 39 * @see #getHandlerInternal 40 * @see #setDefaultHandler 41 * @see #setInterceptors 42 * @see org.springframework.web.portlet.HandlerInterceptor 43 */ 44 public abstract class AbstractHandlerMapping extends ApplicationObjectSupport implements HandlerMapping, Ordered { 45 46 private int order = Integer.MAX_VALUE; // default: same as non-Ordered 47 48 private Object defaultHandler; 49 50 private final List<Object> interceptors = new ArrayList<Object>(); 51 52 private boolean applyWebRequestInterceptorsToRenderPhaseOnly = true; 53 54 private HandlerInterceptor[] adaptedInterceptors; 55 56 57 /** 58 * Specify the order value for this HandlerMapping bean. 59 * <p>Default value is {@code Integer.MAX_VALUE}, meaning that it's non-ordered. 60 * @see org.springframework.core.Ordered#getOrder() 61 */ 62 public final void setOrder(int order) { 63 this.order = order; 64 } 65 66 @Override 67 public final int getOrder() { 68 return this.order; 69 } 70 71 /** 72 * Set the default handler for this handler mapping. 73 * This handler will be returned if no specific mapping was found. 74 * <p>Default is {@code null}, indicating no default handler. 75 */ 76 public void setDefaultHandler(Object defaultHandler) { 77 this.defaultHandler = defaultHandler; 78 } 79 80 /** 81 * Return the default handler for this handler mapping, 82 * or {@code null} if none. 83 */ 84 public Object getDefaultHandler() { 85 return this.defaultHandler; 86 } 87 88 /** 89 * Set the interceptors to apply for all handlers mapped by this handler mapping. 90 * <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor. 91 * Each given WebRequestInterceptor will be wrapped in a WebRequestHandlerInterceptorAdapter. 92 * @param interceptors array of handler interceptors, or {@code null} if none 93 * @see #adaptInterceptor 94 * @see org.springframework.web.portlet.HandlerInterceptor 95 * @see org.springframework.web.context.request.WebRequestInterceptor 96 */ 97 public void setInterceptors(Object[] interceptors) { 98 this.interceptors.addAll(Arrays.asList(interceptors)); 99 } 100 101 /** 102 * Specify whether to apply WebRequestInterceptors to the Portlet render phase 103 * only ("true", or whether to apply them to the Portlet action phase as well 104 * ("false"). 105 * <p>Default is "true", since WebRequestInterceptors are usually built for 106 * MVC-style handler execution plus rendering process (which is, for example, 107 * the primary target scenario for "Open Session in View" interceptors, 108 * offering lazy loading of persistent objects during view rendering). 109 * Set this to "false" to have WebRequestInterceptors apply to the action 110 * phase as well (for example, in case of an "Open Session in View" interceptor, 111 * to allow for lazy loading outside of a transaction during the action phase). 112 * @see #setInterceptors 113 * @see org.springframework.web.context.request.WebRequestInterceptor 114 * @see WebRequestHandlerInterceptorAdapter#WebRequestHandlerInterceptorAdapter(WebRequestInterceptor, boolean) 115 * @see org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor 116 */ 117 public void setApplyWebRequestInterceptorsToRenderPhaseOnly(boolean applyWebRequestInterceptorsToRenderPhaseOnly) { 118 this.applyWebRequestInterceptorsToRenderPhaseOnly = applyWebRequestInterceptorsToRenderPhaseOnly; 119 } 120 121 122 /** 123 * Initializes the interceptors. 124 * @see #extendInterceptors(java.util.List) 125 * @see #initInterceptors() 126 */ 127 @Override 128 protected void initApplicationContext() throws BeansException { 129 extendInterceptors(this.interceptors); 130 initInterceptors(); 131 } 132 133 /** 134 * Extension hook that subclasses can override to register additional interceptors, 135 * given the configured interceptors (see {@link #setInterceptors}). 136 * <p>Will be invoked before {@link #initInterceptors()} adapts the specified 137 * interceptors into {@link HandlerInterceptor} instances. 138 * <p>The default implementation is empty. 139 * @param interceptors the configured interceptor List (never {@code null}), 140 * allowing to add further interceptors before as well as after the existing 141 * interceptors 142 */ 143 protected void extendInterceptors(List<?> interceptors) { 144 } 145 146 /** 147 * Initialize the specified interceptors, adapting them where necessary. 148 * @see #setInterceptors 149 * @see #adaptInterceptor 150 */ 151 protected void initInterceptors() { 152 if (!this.interceptors.isEmpty()) { 153 this.adaptedInterceptors = new HandlerInterceptor[this.interceptors.size()]; 154 for (int i = 0; i < this.interceptors.size(); i++) { 155 Object interceptor = this.interceptors.get(i); 156 if (interceptor == null) { 157 throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); 158 } 159 this.adaptedInterceptors[i] = adaptInterceptor(interceptor); 160 } 161 } 162 } 163 164 /** 165 * Adapt the given interceptor object to the HandlerInterceptor interface. 166 * <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor. 167 * Each given WebRequestInterceptor will be wrapped in a WebRequestHandlerInterceptorAdapter. 168 * Can be overridden in subclasses. 169 * @param interceptor the specified interceptor object 170 * @return the interceptor wrapped as HandlerInterceptor 171 * @see #setApplyWebRequestInterceptorsToRenderPhaseOnly 172 * @see org.springframework.web.portlet.HandlerInterceptor 173 * @see org.springframework.web.context.request.WebRequestInterceptor 174 * @see WebRequestHandlerInterceptorAdapter 175 */ 176 protected HandlerInterceptor adaptInterceptor(Object interceptor) { 177 if (interceptor instanceof HandlerInterceptor) { 178 return (HandlerInterceptor) interceptor; 179 } 180 else if (interceptor instanceof WebRequestInterceptor) { 181 return new WebRequestHandlerInterceptorAdapter( 182 (WebRequestInterceptor) interceptor, this.applyWebRequestInterceptorsToRenderPhaseOnly); 183 } 184 else { 185 throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName()); 186 } 187 } 188 189 /** 190 * Return the adapted interceptors as HandlerInterceptor array. 191 * @return the array of HandlerInterceptors, or {@code null} if none 192 */ 193 protected final HandlerInterceptor[] getAdaptedInterceptors() { 194 return this.adaptedInterceptors; 195 } 196 197 198 /** 199 * Look up a handler for the given request, falling back to the default 200 * handler if no specific one is found. 201 * @param request current portlet request 202 * @return the corresponding handler instance, or the default handler 203 * @see #getHandlerInternal 204 */ 205 @Override 206 public final HandlerExecutionChain getHandler(PortletRequest request) throws Exception { 207 Object handler = getHandlerInternal(request); 208 if (handler == null) { 209 handler = getDefaultHandler(); 210 } 211 if (handler == null) { 212 return null; 213 } 214 // Bean name or resolved handler? 215 if (handler instanceof String) { 216 String handlerName = (String) handler; 217 handler = getApplicationContext().getBean(handlerName); 218 } 219 return getHandlerExecutionChain(handler, request); 220 } 221 222 /** 223 * Look up a handler for the given request, returning {@code null} if no 224 * specific one is found. This method is called by {@link #getHandler}; 225 * a {@code null} return value will lead to the default handler, if one is set. 226 * <p>Note: This method may also return a pre-built {@link HandlerExecutionChain}, 227 * combining a handler object with dynamically determined interceptors. 228 * Statically specified interceptors will get merged into such an existing chain. 229 * @param request current portlet request 230 * @return the corresponding handler instance, or {@code null} if none found 231 * @throws Exception if there is an internal error 232 * @see #getHandler 233 */ 234 protected abstract Object getHandlerInternal(PortletRequest request) throws Exception; 235 236 /** 237 * Build a HandlerExecutionChain for the given handler, including applicable interceptors. 238 * <p>The default implementation simply builds a standard HandlerExecutionChain with 239 * the given handler and this handler mapping's common interceptors. Subclasses may 240 * override this in order to extend/rearrange the list of interceptors. 241 * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built 242 * HandlerExecutionChain. This method should handle those two cases explicitly, 243 * either building a new HandlerExecutionChain or extending the existing chain. 244 * <p>For simply adding an interceptor, consider calling {@code super.getHandlerExecutionChain} 245 * and invoking {@link HandlerExecutionChain#addInterceptor} on the returned chain object. 246 * @param handler the resolved handler instance (never {@code null}) 247 * @param request current portlet request 248 * @return the HandlerExecutionChain (never {@code null}) 249 * @see #getAdaptedInterceptors() 250 */ 251 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, PortletRequest request) { 252 if (handler instanceof HandlerExecutionChain) { 253 HandlerExecutionChain chain = (HandlerExecutionChain) handler; 254 chain.addInterceptors(getAdaptedInterceptors()); 255 return chain; 256 } 257 else { 258 return new HandlerExecutionChain(handler, getAdaptedInterceptors()); 259 } 260 } 261 262 }