001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.portlet.handler; 018 019import java.util.Set; 020import javax.portlet.MimeResponse; 021import javax.portlet.PortletRequest; 022import javax.portlet.RenderRequest; 023import javax.portlet.RenderResponse; 024import javax.portlet.ResourceRequest; 025import javax.portlet.ResourceResponse; 026import javax.portlet.WindowState; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030 031import org.springframework.core.Ordered; 032import org.springframework.web.portlet.HandlerExceptionResolver; 033import org.springframework.web.portlet.ModelAndView; 034 035/** 036 * Abstract base class for {@link HandlerExceptionResolver} implementations. 037 * 038 * <p>Provides a set of mapped handlers that the resolver should map to, 039 * and the {@link Ordered} implementation. 040 * 041 * @author Arjen Poutsma 042 * @author Juergen Hoeller 043 * @since 3.0 044 */ 045public abstract class AbstractHandlerExceptionResolver implements HandlerExceptionResolver, Ordered { 046 047 /** Logger available to subclasses */ 048 protected final Log logger = LogFactory.getLog(getClass()); 049 050 private int order = Ordered.LOWEST_PRECEDENCE; 051 052 private Set<?> mappedHandlers; 053 054 private Class<?>[] mappedHandlerClasses; 055 056 private Log warnLogger; 057 058 private boolean renderWhenMinimized = false; 059 060 061 public void setOrder(int order) { 062 this.order = order; 063 } 064 065 @Override 066 public int getOrder() { 067 return this.order; 068 } 069 070 /** 071 * Specify the set of handlers that this exception resolver should apply to. 072 * <p>The exception mappings and the default error view will only apply to the specified handlers. 073 * <p>If no handlers or handler classes are set, the exception mappings and the default error 074 * view will apply to all handlers. This means that a specified default error view will be used 075 * as a fallback for all exceptions; any further HandlerExceptionResolvers in the chain will be 076 * ignored in this case. 077 */ 078 public void setMappedHandlers(Set<?> mappedHandlers) { 079 this.mappedHandlers = mappedHandlers; 080 } 081 082 /** 083 * Specify the set of classes that this exception resolver should apply to. 084 * <p>The exception mappings and the default error view will only apply to handlers of the 085 * specified types; the specified types may be interfaces or superclasses of handlers as well. 086 * <p>If no handlers or handler classes are set, the exception mappings and the default error 087 * view will apply to all handlers. This means that a specified default error view will be used 088 * as a fallback for all exceptions; any further HandlerExceptionResolvers in the chain will be 089 * ignored in this case. 090 */ 091 public void setMappedHandlerClasses(Class<?>... mappedHandlerClasses) { 092 this.mappedHandlerClasses = mappedHandlerClasses; 093 } 094 095 /** 096 * Set the log category for warn logging. The name will be passed to the underlying logger 097 * implementation through Commons Logging, getting interpreted as a log category according 098 * to the logger's configuration. 099 * <p>Default is no warn logging. Specify this setting to activate warn logging into a specific 100 * category. Alternatively, override the {@link #logException} method for custom logging. 101 * @see org.apache.commons.logging.LogFactory#getLog(String) 102 * @see org.apache.log4j.Logger#getLogger(String) 103 * @see java.util.logging.Logger#getLogger(String) 104 */ 105 public void setWarnLogCategory(String loggerName) { 106 this.warnLogger = LogFactory.getLog(loggerName); 107 } 108 109 /** 110 * Set if the resolver should render a view when the portlet is in 111 * a minimized window. The default is "false". 112 * @see javax.portlet.RenderRequest#getWindowState() 113 * @see javax.portlet.WindowState#MINIMIZED 114 */ 115 public void setRenderWhenMinimized(boolean renderWhenMinimized) { 116 this.renderWhenMinimized = renderWhenMinimized; 117 } 118 119 120 /** 121 * Checks whether this resolver is supposed to apply (i.e. the handler 122 * matches in case of "mappedHandlers" having been specified), then 123 * delegates to the {@link #doResolveException} template method. 124 */ 125 @Override 126 public ModelAndView resolveException(RenderRequest request, RenderResponse response, Object handler, Exception ex) { 127 if (shouldApplyTo(request, handler)) { 128 return doResolveException(request, response, handler, ex); 129 } 130 else { 131 return null; 132 } 133 } 134 135 @Override 136 public ModelAndView resolveException(ResourceRequest request, ResourceResponse response, Object handler, Exception ex) { 137 if (shouldApplyTo(request, handler)) { 138 return doResolveException(request, response, handler, ex); 139 } 140 else { 141 return null; 142 } 143 } 144 145 /** 146 * Check whether this resolver is supposed to apply to the given handler. 147 * <p>The default implementation checks against the specified mapped handlers 148 * and handler classes, if any, and also checks the window state (according 149 * to the "renderWhenMinimize" property). 150 * @param request current portlet request 151 * @param handler the executed handler, or {@code null} if none chosen at the 152 * time of the exception (for example, if multipart resolution failed) 153 * @return whether this resolved should proceed with resolving the exception 154 * for the given request and handler 155 * @see #setMappedHandlers 156 * @see #setMappedHandlerClasses 157 */ 158 protected boolean shouldApplyTo(PortletRequest request, Object handler) { 159 // If the portlet is minimized and we don't want to render then return null. 160 if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) { 161 return false; 162 } 163 // Check mapped handlers... 164 if (handler != null) { 165 if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) { 166 return true; 167 } 168 if (this.mappedHandlerClasses != null) { 169 for (Class<?> mappedClass : this.mappedHandlerClasses) { 170 if (mappedClass.isInstance(handler)) { 171 return true; 172 } 173 } 174 } 175 } 176 // Else only apply if there are no explicit handler mappings. 177 return (this.mappedHandlers == null && this.mappedHandlerClasses == null); 178 } 179 180 /** 181 * Log the given exception at warn level, provided that warn logging has been 182 * activated through the {@link #setWarnLogCategory "warnLogCategory"} property. 183 * <p>Calls {@link #buildLogMessage} in order to determine the concrete message to log. 184 * @param ex the exception that got thrown during handler execution 185 * @param request current portlet request (useful for obtaining metadata) 186 * @see #setWarnLogCategory 187 * @see #buildLogMessage 188 * @see org.apache.commons.logging.Log#warn(Object, Throwable) 189 */ 190 protected void logException(Exception ex, PortletRequest request) { 191 if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) { 192 this.warnLogger.warn(buildLogMessage(ex, request)); 193 } 194 } 195 196 /** 197 * Build a log message for the given exception, occurred during processing the given request. 198 * @param ex the exception that got thrown during handler execution 199 * @param request current portlet request (useful for obtaining metadata) 200 * @return the log message to use 201 */ 202 protected String buildLogMessage(Exception ex, PortletRequest request) { 203 return "Handler execution resulted in exception: " + ex; 204 } 205 206 207 /** 208 * Actually resolve the given exception that got thrown during on handler execution, 209 * returning a ModelAndView that represents a specific error page if appropriate. 210 * <p>Must be overridden in subclasses, in order to apply specific exception checks. 211 * Note that this template method will be invoked <i>after</i> checking whether this 212 * resolved applies ("mappedHandlers" etc), so an implementation may simply proceed 213 * with its actual exception handling. 214 * @param request current portlet request 215 * @param response current portlet response 216 * @param handler the executed handler, or null if none chosen at the time of 217 * the exception (for example, if multipart resolution failed) 218 * @param ex the exception that got thrown during handler execution 219 * @return a corresponding ModelAndView to forward to, or null for default processing 220 */ 221 protected abstract ModelAndView doResolveException(PortletRequest request, MimeResponse response, 222 Object handler, Exception ex); 223 224}