Revision: 1362 http://stripes.svn.sourceforge.net/stripes/?rev=1362&view=rev Author: bengunter Date: 2010-11-29 21:06:26 +0000 (Mon, 29 Nov 2010)
Log Message: ----------- Applied improved fix for STS-780 from 1.5.x branch. Modified Paths: -------------- trunk/stripes/src/net/sourceforge/stripes/action/ActionBeanContext.java trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java Added Paths: ----------- trunk/stripes/src/net/sourceforge/stripes/action/ValidationErrorReportResolution.java Modified: trunk/stripes/src/net/sourceforge/stripes/action/ActionBeanContext.java =================================================================== --- trunk/stripes/src/net/sourceforge/stripes/action/ActionBeanContext.java 2010-11-29 20:59:48 UTC (rev 1361) +++ trunk/stripes/src/net/sourceforge/stripes/action/ActionBeanContext.java 2010-11-29 21:06:26 UTC (rev 1362) @@ -14,12 +14,9 @@ */ package net.sourceforge.stripes.action; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -27,12 +24,8 @@ import net.sourceforge.stripes.controller.FlashScope; import net.sourceforge.stripes.controller.StripesConstants; -import net.sourceforge.stripes.controller.StripesFilter; import net.sourceforge.stripes.exception.SourcePageNotFoundException; -import net.sourceforge.stripes.tag.ErrorsTag; import net.sourceforge.stripes.util.CryptoUtil; -import net.sourceforge.stripes.util.Log; -import net.sourceforge.stripes.validation.ValidationError; import net.sourceforge.stripes.validation.ValidationErrors; /** @@ -226,10 +219,7 @@ public Resolution getSourcePageResolution() throws SourcePageNotFoundException { String sourcePage = getSourcePage(); if (sourcePage == null) { - if (StripesFilter.getConfiguration().isDebugMode()) - return new ValidationErrorReportResolution(this); - else - throw new SourcePageNotFoundException(this); + throw new SourcePageNotFoundException(this); } else { return new ForwardResolution(sourcePage); @@ -267,90 +257,3 @@ "}"; } } - -class ValidationErrorReportResolution implements Resolution { - private static final Log log = Log.getInstance(ValidationErrorReportResolution.class); - private ActionBeanContext context; - - /** Construct a new instance to report validation errors in the specified context. */ - protected ValidationErrorReportResolution(ActionBeanContext context) { - this.context = context; - } - - public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception { - // log an exception for the stack trace - SourcePageNotFoundException exception = new SourcePageNotFoundException(this.context); - log.error(exception); - - // start the HTML error report - response.setContentType("text/html"); - PrintWriter writer = response.getWriter(); - writer.println("<html>"); - writer.println("<head><title>Stripes validation error report</title></head>"); - writer.println("<body style=\"font-family: Arial, sans-serif; font-size: 10pt;\">"); - writer.println("<h1>Stripes validation error report</h1><p>"); - writer.println(exception.getMessage()); - writer.println("</p><h2>Validation errors</h2><p>"); - sendErrors(request, response); - writer.println("</p></body></html>"); - } - - protected void sendErrors(HttpServletRequest request, HttpServletResponse response) - throws Exception { - // Output all errors in a standard format - Locale locale = request.getLocale(); - ResourceBundle bundle = null; - - try { - bundle = StripesFilter.getConfiguration().getLocalizationBundleFactory() - .getErrorMessageBundle(locale); - } - catch (MissingResourceException mre) { - log.warn(getClass().getName(), " could not find the error messages resource bundle. ", - "As a result default headers/footers etc. will be used. Check that ", - "you have a StripesResources.properties in your classpath (unless ", - "of course you have configured a different bundle)."); - } - - // Fetch the header and footer - String header = getResource(bundle, "header", ErrorsTag.DEFAULT_HEADER); - String footer = getResource(bundle, "footer", ErrorsTag.DEFAULT_FOOTER); - String openElement = getResource(bundle, "beforeError", "<li>"); - String closeElement = getResource(bundle, "afterError", "</li>"); - - // Write out the error messages - PrintWriter writer = response.getWriter(); - writer.write(header); - - for (List<ValidationError> list : this.context.getValidationErrors().values()) { - for (ValidationError fieldError : list) { - writer.write(openElement); - writer.write(fieldError.getMessage(locale)); - writer.write(closeElement); - } - } - - writer.write(footer); - } - - /** - * Utility method that is used to lookup the resources used for the errors header, - * footer, and the strings that go before and after each error. - * - * @param bundle the bundle to look up the resource from - * @param name the name of the resource to lookup (prefixes will be added) - * @param fallback a value to return if no resource can be found - * @return the value to use for the named resource - */ - protected String getResource(ResourceBundle bundle, String name, String fallback) { - if (bundle == null) { - return fallback; - } - - String resource; - try { resource = bundle.getString("stripes.errors." + name); } - catch (MissingResourceException mre) { resource = fallback; } - - return resource; - } -} Added: trunk/stripes/src/net/sourceforge/stripes/action/ValidationErrorReportResolution.java =================================================================== --- trunk/stripes/src/net/sourceforge/stripes/action/ValidationErrorReportResolution.java (rev 0) +++ trunk/stripes/src/net/sourceforge/stripes/action/ValidationErrorReportResolution.java 2010-11-29 21:06:26 UTC (rev 1362) @@ -0,0 +1,141 @@ +/* Copyright 2010 Ben Gunter + * + * 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 + * + * http://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 net.sourceforge.stripes.action; + +import java.io.PrintWriter; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import net.sourceforge.stripes.controller.StripesFilter; +import net.sourceforge.stripes.exception.SourcePageNotFoundException; +import net.sourceforge.stripes.tag.ErrorsTag; +import net.sourceforge.stripes.util.Log; +import net.sourceforge.stripes.validation.ValidationError; + +/** + * A resolution that streams a simple HTML response to the client detailing the validation errors + * that apply for an {...@link ActionBeanContext}. + * + * @author Ben Gunter + * @since Stripes 1.5.5 + */ +public class ValidationErrorReportResolution implements Resolution { + private static final Log log = Log.getInstance(ValidationErrorReportResolution.class); + private ActionBeanContext context; + + /** Construct a new instance to report validation errors in the specified context. */ + public ValidationErrorReportResolution(ActionBeanContext context) { + this.context = context; + } + + /** Get the action bean context on which the validation errors occurred. */ + public ActionBeanContext getContext() { + return context; + } + + public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception { + // log an exception for the stack trace + SourcePageNotFoundException exception = new SourcePageNotFoundException(getContext()); + log.error(exception); + + // start the HTML error report + response.setContentType("text/html"); + PrintWriter writer = response.getWriter(); + writer.println("<html>"); + writer.println("<head><title>Stripes validation error report</title></head>"); + writer.println("<body style=\"font-family: Arial, sans-serif; font-size: 10pt;\">"); + writer.println("<h1>Stripes validation error report</h1><p>"); + writer.println(exception.getMessage()); + writer.println("</p><h2>Validation errors</h2><p>"); + sendErrors(request, response); + writer.println("</p></body></html>"); + } + + /** + * Called by {...@link #execute(HttpServletRequest, HttpServletResponse)} to write the actual + * validation errors to the client. The {...@code header}, {...@code footer}, {...@code beforeError} and + * {...@code afterError} resources are used by this method. + * + * @param request The servlet request. + * @param response The servlet response. + */ + protected void sendErrors(HttpServletRequest request, HttpServletResponse response) + throws Exception { + // Output all errors in a standard format + Locale locale = request.getLocale(); + ResourceBundle bundle = null; + + try { + bundle = StripesFilter.getConfiguration().getLocalizationBundleFactory() + .getErrorMessageBundle(locale); + } + catch (MissingResourceException mre) { + log.warn(getClass().getName(), " could not find the error messages resource bundle. ", + "As a result default headers/footers etc. will be used. Check that ", + "you have a StripesResources.properties in your classpath (unless ", + "of course you have configured a different bundle)."); + } + + // Fetch the header and footer + String header = getResource(bundle, "header", ErrorsTag.DEFAULT_HEADER); + String footer = getResource(bundle, "footer", ErrorsTag.DEFAULT_FOOTER); + String openElement = getResource(bundle, "beforeError", "<li>"); + String closeElement = getResource(bundle, "afterError", "</li>"); + + // Write out the error messages + PrintWriter writer = response.getWriter(); + writer.write(header); + + for (List<ValidationError> list : getContext().getValidationErrors().values()) { + for (ValidationError fieldError : list) { + writer.write(openElement); + writer.write(fieldError.getMessage(locale)); + writer.write(closeElement); + } + } + + writer.write(footer); + } + + /** + * Utility method that is used to lookup the resources used for the error header, footer, and + * the strings that go before and after each error. + * + * @param bundle the bundle to look up the resource from + * @param name the name of the resource to lookup (prefixes will be added) + * @param fallback a value to return if no resource can be found + * @return the value to use for the named resource + */ + protected String getResource(ResourceBundle bundle, String name, String fallback) { + if (bundle == null) { + return fallback; + } + + String resource; + try { + resource = bundle.getString("stripes.errors." + name); + } + catch (MissingResourceException mre) { + resource = fallback; + } + + return resource; + } +} Modified: trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java =================================================================== --- trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java 2010-11-29 20:59:48 UTC (rev 1361) +++ trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java 2010-11-29 21:06:26 UTC (rev 1362) @@ -33,6 +33,7 @@ import net.sourceforge.stripes.action.FileBean; import net.sourceforge.stripes.action.ForwardResolution; import net.sourceforge.stripes.action.Resolution; +import net.sourceforge.stripes.action.ValidationErrorReportResolution; import net.sourceforge.stripes.config.Configuration; import net.sourceforge.stripes.controller.DispatcherHelper; import net.sourceforge.stripes.controller.ExecutionContext; @@ -145,6 +146,12 @@ if (resolution != null) resolution.execute(request, response); } + else if (throwable instanceof SourcePageNotFoundException) { + Resolution resolution = handle((SourcePageNotFoundException) throwable, request, + response); + if (resolution != null) + resolution.execute(request, response); + } else { // If there's no sensible proxy, rethrow the original throwable, // NOT the unwrapped one since they may add extra information @@ -163,6 +170,33 @@ /** * <p> + * A default handler for {...@link SourcePageNotFoundException}. That exception is thrown when + * validation errors occur on a request but the source page cannot be determined from the + * request parameters. Such a condition generally arises during application development when, + * for example, a parameter is accidentally omitted from a generated hyperlink or AJAX request. + * </p> + * <p> + * In the past, it was very difficult to determine what validation errors triggered the + * exception. This method returns a {...@link ValidationErrorReportResolution}, which sends a + * simple HTML response to the client that very clearly details the validation errors. + * </p> + * <p> + * In production, most applications will provide their own handler for + * {...@link SourcePageNotFoundException} by extending this class and overriding this method. + * </p> + * + * @param exception The exception. + * @param request The servlet request. + * @param response The servlet response. + * @return A {...@link ValidationErrorReportResolution} + */ + protected Resolution handle(SourcePageNotFoundException exception, HttpServletRequest request, + HttpServletResponse response) throws Exception { + return new ValidationErrorReportResolution(exception.getActionBeanContext()); + } + + /** + * <p> * {...@link FileUploadLimitExceededException} is notoriously difficult to handle for several * reasons: * <ul> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Increase Visibility of Your 3D Game App & Earn a Chance To Win $500! Tap into the largest installed PC base & get more eyes on your game by optimizing for Intel(R) Graphics Technology. Get started today with the Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs. http://p.sf.net/sfu/intelisp-dev2dev _______________________________________________ Stripes-development mailing list Stripes-development@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/stripes-development