KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > portlet > handler > SimpleMappingExceptionResolver


1 /*
2  * Copyright 2002-2007 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.Enumeration JavaDoc;
20 import java.util.Properties JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import javax.portlet.RenderRequest;
24 import javax.portlet.RenderResponse;
25 import javax.portlet.WindowState;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.springframework.core.Ordered;
31 import org.springframework.web.portlet.HandlerExceptionResolver;
32 import org.springframework.web.portlet.ModelAndView;
33
34 /**
35  * Exception resolver that allows for mapping exception class names to view names,
36  * either for a list of given handlers or for all handlers in the DispatcherPortlet.
37  *
38  * <p>Error views are analogous to error page JSPs, but can be used with any
39  * kind of exception including any checked one, with fine-granular mappings for
40  * specific handlers.
41  *
42  * @author Juergen Hoeller
43  * @author John A. Lewis
44  * @since 2.0
45  */

46 public class SimpleMappingExceptionResolver implements HandlerExceptionResolver, Ordered {
47
48     /**
49      * The default name of the exception attribute: "exception".
50      */

51     public static final String JavaDoc DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
52
53
54     /** Logger available to subclasses */
55     protected final Log logger = LogFactory.getLog(getClass());
56
57     private int order = Integer.MAX_VALUE; // default: same as non-Ordered
58

59     private Set JavaDoc mappedHandlers;
60
61     private boolean renderWhenMinimized = false;
62
63     private Log warnLogger;
64
65     private Properties JavaDoc exceptionMappings;
66
67     private String JavaDoc defaultErrorView;
68
69     private String JavaDoc exceptionAttribute = DEFAULT_EXCEPTION_ATTRIBUTE;
70
71
72     public void setOrder(int order) {
73         this.order = order;
74     }
75
76     public int getOrder() {
77         return this.order;
78     }
79
80     /**
81      * Specify the set of handlers that this exception resolver should map.
82      * The exception mappings and the default error view will only apply
83      * to the specified handlers.
84      * <p>If no handlers set, both the exception mappings and the default error
85      * view will apply to all handlers. This means that a specified default
86      * error view will be used as fallback for all exceptions; any further
87      * HandlerExceptionResolvers in the chain will be ignored in this case.
88      */

89     public void setMappedHandlers(Set JavaDoc mappedHandlers) {
90         this.mappedHandlers = mappedHandlers;
91     }
92
93     /**
94      * Set if the resolver should render a view when the portlet is in
95      * a minimized window. The default is "false".
96      * @see javax.portlet.RenderRequest#getWindowState()
97      * @see javax.portlet.WindowState#MINIMIZED
98      */

99     public void setRenderWhenMinimized(boolean renderWhenMinimized) {
100         this.renderWhenMinimized = renderWhenMinimized;
101     }
102
103     /**
104      * Set the log category for warn logging. The name will be passed to the
105      * underlying logger implementation through Commons Logging, getting
106      * interpreted as log category according to the logger's configuration.
107      * <p>Default is no warn logging. Specify this setting to activate
108      * warn logging into a specific category. Alternatively, override
109      * the {@link #logException} method for custom logging.
110      * @see org.apache.commons.logging.LogFactory#getLog(String)
111      * @see org.apache.log4j.Logger#getLogger(String)
112      * @see java.util.logging.Logger#getLogger(String)
113      */

114     public void setWarnLogCategory(String JavaDoc loggerName) {
115         this.warnLogger = LogFactory.getLog(loggerName);
116     }
117
118     /**
119      * Set the mappings between exception class names and error view names.
120      * The exception class name can be a substring, with no wildcard support
121      * at present. A value of "PortletException" would match
122      * <code>javax.portet.PortletException</code> and subclasses, for example.
123      * <p><b>NB:</b> Consider carefully how specific the pattern is, and whether
124      * to include package information (which isn't mandatory). For example,
125      * "Exception" will match nearly anything, and will probably hide other rules.
126      * "java.lang.Exception" would be correct if "Exception" was meant to define
127      * a rule for all checked exceptions. With more unusual exception names such
128      * as "BaseBusinessException" there's no need to use a FQN.
129      * <p>Follows the same matching algorithm as RuleBasedTransactionAttribute
130      * and RollbackRuleAttribute.
131      * @param mappings exception patterns (can also be fully qualified class names)
132      * as keys, and error view names as values
133      * @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
134      * @see org.springframework.transaction.interceptor.RollbackRuleAttribute
135      */

136     public void setExceptionMappings(Properties JavaDoc mappings) {
137         this.exceptionMappings = mappings;
138     }
139
140     /**
141      * Set the name of the default error view.
142      * This view will be returned if no specific mapping was found.
143      * <p>Default is none.
144      */

145     public void setDefaultErrorView(String JavaDoc defaultErrorView) {
146         this.defaultErrorView = defaultErrorView;
147     }
148
149     /**
150      * Set the name of the model attribute as which the exception should
151      * be exposed. Default is "exception".
152      * @see #DEFAULT_EXCEPTION_ATTRIBUTE
153      */

154     public void setExceptionAttribute(String JavaDoc exceptionAttribute) {
155         this.exceptionAttribute = exceptionAttribute;
156     }
157
158
159     public ModelAndView resolveException(RenderRequest request, RenderResponse response, Object JavaDoc handler, Exception JavaDoc ex) {
160         // Check whether we're supposed to apply to the given handler.
161
if (this.mappedHandlers != null && !this.mappedHandlers.contains(handler)) {
162             return null;
163         }
164
165         // If the portlet is minimized and we don't want to render then return null.
166
if (WindowState.MINIMIZED.equals(request.getWindowState()) && !this.renderWhenMinimized) {
167             return null;
168         }
169
170         // Log exception, both at debug log level and at warn level, if desired.
171
if (logger.isDebugEnabled()) {
172             logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
173         }
174         logException(ex, request);
175
176         // Expose ModelAndView for chosen error view.
177
String JavaDoc viewName = determineViewName(ex, request);
178         if (viewName != null) {
179             return getModelAndView(viewName, ex, request);
180         }
181         else {
182             return null;
183         }
184     }
185
186
187     /**
188      * Log the given exception at warn level, provided that warn logging has been
189      * activated through the {@link #setWarnLogCategory "warnLogCategory"} property.
190      * <p>Calls {@link #buildLogMessage} in order to determine the concrete message
191      * to log. Always passes the full exception to the logger.
192      * @param ex the exception that got thrown during handler execution
193      * @param request current portlet request (useful for obtaining metadata)
194      * @see #setWarnLogCategory
195      * @see #buildLogMessage
196      * @see org.apache.commons.logging.Log#warn(Object, Throwable)
197      */

198     protected void logException(Exception JavaDoc ex, RenderRequest request) {
199         if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
200             this.warnLogger.warn(buildLogMessage(ex, request), ex);
201         }
202     }
203
204     /**
205      * Build a log message for the given exception, occured during processing
206      * the given request.
207      * @param ex the exception that got thrown during handler execution
208      * @param request current portlet request (useful for obtaining metadata)
209      * @return the log message to use
210      */

211     protected String JavaDoc buildLogMessage(Exception JavaDoc ex, RenderRequest request) {
212         return "Handler execution resulted in exception";
213     }
214
215
216     /**
217      * Determine the view name for the given exception, searching the
218      * {@link #setExceptionMappings "exceptionMappings"}, using the
219      * {@link #setDefaultErrorView "defaultErrorView"} as fallback.
220      * @param ex the exception that got thrown during handler execution
221      * @param request current portlet request (useful for obtaining metadata)
222      * @return the resolved view name, or <code>null</code> if none found
223      */

224     protected String JavaDoc determineViewName(Exception JavaDoc ex, RenderRequest request) {
225         String JavaDoc viewName = null;
226         // Check for specific exception mappings.
227
if (this.exceptionMappings != null) {
228             viewName = findMatchingViewName(this.exceptionMappings, ex);
229         }
230         // Return default error view else, if defined.
231
if (viewName == null && this.defaultErrorView != null) {
232             if (logger.isDebugEnabled()) {
233                 logger.debug("Resolving to default view '" + this.defaultErrorView +
234                         "' for exception of type [" + ex.getClass().getName() + "]");
235             }
236             viewName = this.defaultErrorView;
237         }
238         return viewName;
239     }
240
241     /**
242      * Find a matching view name in the given exception mappings
243      * @param exceptionMappings mappings between exception class names and error view names
244      * @param ex the exception that got thrown during handler execution
245      * @return the view name, or <code>null</code> if none found
246      * @see #setExceptionMappings
247      */

248     protected String JavaDoc findMatchingViewName(Properties JavaDoc exceptionMappings, Exception JavaDoc ex) {
249         String JavaDoc viewName = null;
250         String JavaDoc dominantMapping = null;
251         int deepest = Integer.MAX_VALUE;
252         for (Enumeration JavaDoc names = exceptionMappings.propertyNames(); names.hasMoreElements();) {
253             String JavaDoc exceptionMapping = (String JavaDoc) names.nextElement();
254             int depth = getDepth(exceptionMapping, ex);
255             if (depth >= 0 && depth < deepest) {
256                 deepest = depth;
257                 dominantMapping = exceptionMapping;
258                 viewName = exceptionMappings.getProperty(exceptionMapping);
259             }
260         }
261         if (viewName != null && logger.isDebugEnabled()) {
262             logger.debug("Resolving to view '" + viewName + "' for exception of type [" + ex.getClass().getName() +
263                     "], based on exception mapping [" + dominantMapping + "]");
264         }
265         return viewName;
266     }
267
268     /**
269      * Return the depth to the superclass matching.
270      * <p>0 means ex matches exactly. Returns -1 if there's no match.
271      * Otherwise, returns depth. Lowest depth wins.
272      * <p>Follows the same algorithm as
273      * {@link org.springframework.transaction.interceptor.RollbackRuleAttribute}.
274      */

275     protected int getDepth(String JavaDoc exceptionMapping, Exception JavaDoc ex) {
276         return getDepth(exceptionMapping, ex.getClass(), 0);
277     }
278
279     private int getDepth(String JavaDoc exceptionMapping, Class JavaDoc exceptionClass, int depth) {
280         if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
281             // Found it!
282
return depth;
283         }
284         // If we've gone as far as we can go and haven't found it...
285
if (exceptionClass.equals(Throwable JavaDoc.class)) {
286             return -1;
287         }
288         return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
289     }
290
291
292     /**
293      * Return a ModelAndView for the given request, view name and exception.
294      * Default implementation delegates to <code>getModelAndView(viewName, ex)</code>.
295      * @param viewName the name of the error view
296      * @param ex the exception that got thrown during handler execution
297      * @param request current portlet request (useful for obtaining metadata)
298      * @return the ModelAndView instance
299      * @see #getModelAndView(String, Exception)
300      */

301     protected ModelAndView getModelAndView(String JavaDoc viewName, Exception JavaDoc ex, RenderRequest request) {
302         return getModelAndView(viewName, ex);
303     }
304
305     /**
306      * Return a ModelAndView for the given view name and exception.
307      * Default implementation adds the specified exception attribute.
308      * Can be overridden in subclasses.
309      * @param viewName the name of the error view
310      * @param ex the exception that got thrown during handler execution
311      * @return the ModelAndView instance
312      * @see #setExceptionAttribute
313      */

314     protected ModelAndView getModelAndView(String JavaDoc viewName, Exception JavaDoc ex) {
315         ModelAndView mv = new ModelAndView(viewName);
316         if (this.exceptionAttribute != null) {
317             if (logger.isDebugEnabled()) {
318                 logger.debug("Exposing Exception as model attribute '" + this.exceptionAttribute + "'");
319             }
320             mv.addObject(this.exceptionAttribute, ex);
321         }
322         return mv;
323     }
324
325 }
326
Popular Tags