craigmcc 01/12/30 17:14:36 Modified: conf/share struts-config_1_1.dtd src/example/org/apache/struts/webapp/example ApplicationResources.properties LogonAction.java src/share/org/apache/struts/action Action.java ActionMapping.java ActionServlet.java web/example/WEB-INF struts-config.xml Added: src/example/org/apache/struts/webapp/example ExpiredPasswordException.java src/share/org/apache/struts/action ActionException.java ActionExceptions.java ExceptionHandler.java src/share/org/apache/struts/util AppException.java web/example changePassword.jsp Log: Initial checkin of the "Declarative Exception Handling" feature (sorry this took so long). I've incorporated it as presented, based on the original configuration mechanism, to get it in play as quickly as possible. It will next be integrated into the new ApplicationConfig approach so that it works in sub-applications as well. Submitted by: Laine Donlan <[EMAIL PROTECTED]>, Dmitri Valdin <[EMAIL PROTECTED]> Revision Changes Path 1.4 +46 -3 jakarta-struts/conf/share/struts-config_1_1.dtd Index: struts-config_1_1.dtd =================================================================== RCS file: /home/cvs/jakarta-struts/conf/share/struts-config_1_1.dtd,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- struts-config_1_1.dtd 27 Dec 2001 16:20:59 -0000 1.3 +++ struts-config_1_1.dtd 31 Dec 2001 01:14:36 -0000 1.4 @@ -11,7 +11,7 @@ "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd"> - $Id: struts-config_1_1.dtd,v 1.3 2001/12/27 16:20:59 cedric Exp $ + $Id: struts-config_1_1.dtd,v 1.4 2001/12/31 01:14:36 craigmcc Exp $ --> @@ -79,7 +79,7 @@ hierarchy, and contains nested elements for all of the other configuration settings. --> -<!ELEMENT struts-config (data-sources?, form-beans?, global-forwards?, action-mappings?, controller?, message-resources?)> +<!ELEMENT struts-config (data-sources?, form-beans?, global-exceptions?, global-forwards?, action-mappings?, controller?, message-resources?)> <!ATTLIST struts-config id ID #IMPLIED> @@ -157,6 +157,49 @@ <!ATTLIST data-source user CDATA #IMPLIED> +<!-- The "global-exceptions" element configures the global handling of + exceptions thrown by Actions to mappable resources (identified by + context-relative URI paths). A global "exception" handler for a + particular exception class can be locally overridden by defining an + "exception" element with the same "type" attribute. +--> +<!ELEMENT global-exceptions (exception*)> +<!ATTLIST global-exceptions id ID #IMPLIED> + + +<!-- The "exception" element describes a mapping of an exception that may + occur during Action delegation and should be handled by the + ActionServlet. + + handler Fully qualified Java class name of the exception handler + which should handle this exception. + + hierarchical Determines if the exception's class hierarchy should be + used to determine the correct handler. + + key Resource bundle key specifying the error message + associated with this exception. + + path The context-relative path of the resource to + forward to if this exception occurs. + + scope Identifier of the scope ("request" or "session") + within which the resulting ActionError will be + made accessible + + type Fully qualified Java class name of the exception + that is to be handled. +--> +<!ELEMENT exception (icon?, display-name?, description?, set-property*)> +<!ATTLIST exception id ID #IMPLIED> +<!ATTLIST exception handler %ClassName; "org.apache.struts.action.ExceptionHandler"> +<!ATTLIST exception hierarchical %Boolean; #IMPLIED> +<!ATTLIST exception key CDATA #IMPLIED> +<!ATTLIST exception path %RequestPath; #IMPLIED> +<!ATTLIST exception scope CDATA #IMPLIED> +<!ATTLIST exception type %ClassName; #REQUIRED> + + <!-- The "form-beans" element is the root of the set of form bean descriptors for this application. The following attributes are defined: @@ -327,7 +370,7 @@ should be called prior to calling this action, or set to "false" if you do not want validation performed. --> -<!ELEMENT action (icon?, display-name?, description?, set-property*, forward*)> +<!ELEMENT action (icon?, display-name?, description?, set-property*, exception*, forward*)> <!ATTLIST action id ID #IMPLIED> <!ATTLIST action attribute %BeanName; #IMPLIED> <!ATTLIST action className %ClassName; #IMPLIED> 1.3 +3 -0 jakarta-struts/src/example/org/apache/struts/webapp/example/ApplicationResources.properties Index: ApplicationResources.properties =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/ApplicationResources.properties,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ApplicationResources.properties 23 Jun 2001 17:51:35 -0000 1.2 +++ ApplicationResources.properties 31 Dec 2001 01:14:36 -0000 1.3 @@ -2,6 +2,9 @@ button.confirm=Confirm button.reset=Reset button.save=Save +change.message=Your password has expired. Please ask the system administrator to change it. +change.try=Try Again +change.title=Password Has Expired database.load=Cannot load database from {0} error.database.missing=<li>User database is missing, cannot validate logon credentials</li> error.fromAddress.format=<li>Invalid format for From Address</li> 1.3 +41 -9 jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java Index: LogonAction.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- LogonAction.java 14 Apr 2001 12:53:08 -0000 1.2 +++ LogonAction.java 31 Dec 2001 01:14:36 -0000 1.3 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v 1.2 2001/04/14 12:53:08 rleland Exp $ - * $Revision: 1.2 $ - * $Date: 2001/04/14 12:53:08 $ + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v 1.3 2001/12/31 01:14:36 craigmcc Exp $ + * $Revision: 1.3 $ + * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * @@ -78,6 +78,7 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionServlet; +import org.apache.struts.util.AppException; import org.apache.struts.util.MessageResources; @@ -85,7 +86,7 @@ * Implementation of <strong>Action</strong> that validates a user logon. * * @author Craig R. McClanahan - * @version $Revision: 1.2 $ $Date: 2001/04/14 12:53:08 $ + * @version $Revision: 1.3 $ $Date: 2001/12/31 01:14:36 $ */ public final class LogonAction extends Action { @@ -106,14 +107,13 @@ * @param request The HTTP request we are processing * @param response The HTTP response we are creating * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs + * @exception Exception if business logic throws an exception */ - public ActionForward perform(ActionMapping mapping, + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + throws Exception { // Extract attributes we will need Locale locale = getLocale(request); @@ -130,7 +130,7 @@ errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.database.missing")); else { - user = (User) database.get(username); + user = getUser(database, username, password); if ((user != null) && !user.getPassword().equals(password)) user = null; if (user == null) @@ -161,6 +161,38 @@ // Forward control to the specified success URI return (mapping.findForward("success")); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Look up the user, throwing an exception to simulate business logic + * rule exceptions. + * + * @param database Database in which to look up the user + * @param username Username specified on the logon form + * @param password Password specified on the logon form + * + * @exception AppException if a business logic rule is violated + */ + public User getUser(Hashtable database, String username, String password) + throws AppException { + + // Force an ArithmeticException which can be handled explicitly + if ("arithmetic".equals(username)) { + int a = 10 / 0; + } + + // Force an application-specific exception which can be handled + if ("expired".equals(username)) { + throw new ExpiredPasswordException(username); + } + + // Look up and return the specified user + return ((User) database.get(username)); } 1.1 jakarta-struts/src/example/org/apache/struts/webapp/example/ExpiredPasswordException.java Index: ExpiredPasswordException.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/ExpiredPasswordException.java,v 1.1 2001/12/31 01:14:36 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.webapp.example; import org.apache.struts.util.AppException; /** * Example of an application-specific exception for which a handler * can be configured. */ public class ExpiredPasswordException extends AppException { /** * Construct a new instance of this exception for the specified username. * * @param username Username whose password has expired */ public ExpiredPasswordException(String username) { super("error.password.expired", username); } } 1.33 +33 -4 jakarta-struts/src/share/org/apache/struts/action/Action.java Index: Action.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v retrieving revision 1.32 retrieving revision 1.33 diff -u -r1.32 -r1.33 --- Action.java 29 Dec 2001 19:37:28 -0000 1.32 +++ Action.java 31 Dec 2001 01:14:36 -0000 1.33 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.32 2001/12/29 19:37:28 craigmcc Exp $ - * $Revision: 1.32 $ - * $Date: 2001/12/29 19:37:28 $ + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.33 2001/12/31 01:14:36 craigmcc Exp $ + * $Revision: 1.33 $ + * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * @@ -108,7 +108,7 @@ * by this Action. * * @author Craig R. McClanahan - * @version $Revision: 1.32 $ $Date: 2001/12/29 19:37:28 $ + * @version $Revision: 1.33 $ $Date: 2001/12/31 01:14:36 $ */ public class Action { @@ -320,6 +320,8 @@ * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs + * + * @deprecated Use the <code>execute()</code> method instead */ public ActionForward perform(ActionMapping mapping, ActionForm form, @@ -352,6 +354,8 @@ * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet exception occurs + * + * @deprecated Use the <code>execute()</code> method instead */ public ActionForward perform(ActionMapping mapping, ActionForm form, @@ -360,6 +364,31 @@ throws IOException, ServletException { return (null); // Override this method to provide functionality + + } + + + /** + * Process the specified HTTP request, and create the corresponding HTTP + * response (or forward to another web component that will create it), + * with provision for handling exceptions thrown by the business logic. + * + * @param mapping The ActionMapping used to select this instance + * @param form The optional ActionForm bean for this request (if any) + * @param request The HTTP request we are processing + * @param response The HTTP response we are creating + * + * @exception Exception if the application business logic throws + * an exception + */ + public ActionForward execute(ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws Exception { + + // Call the deprecated method + return (perform(mapping, form, request, response)); } 1.21 +51 -4 jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java Index: ActionMapping.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- ActionMapping.java 4 Nov 2001 07:42:21 -0000 1.20 +++ ActionMapping.java 31 Dec 2001 01:14:36 -0000 1.21 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java,v 1.20 2001/11/04 07:42:21 martinc Exp $ - * $Revision: 1.20 $ - * $Date: 2001/11/04 07:42:21 $ + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java,v 1.21 2001/12/31 01:14:36 craigmcc Exp $ + * $Revision: 1.21 $ + * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * @@ -130,7 +130,7 @@ * </ul> * * @author Craig R. McClanahan - * @version $Revision: 1.20 $ $Date: 2001/11/04 07:42:21 $ + * @version $Revision: 1.21 $ $Date: 2001/12/31 01:14:36 $ */ public class ActionMapping implements Serializable { @@ -147,6 +147,12 @@ /** + * The set of ActionException objects associated with this mapping. + */ + protected ActionExceptions exceptions = new ActionExceptions(); + + + /** * The context relative path of the servlet or JSP resource (to be called * via <code>RequestDispatcher.forward()</code>) that will process this * request, rather than instantiating and calling the Action class that is @@ -595,6 +601,18 @@ /** + * Add a new <code>ActionException</code> associated with this mapping. + * + * @param exception The ActionException to be added + */ + public void addException(ActionException exception) { + + exceptions.addException(exception); + + } + + + /** * Add a new <code>ActionForward</code> associated with this mapping. * * @param forward The ActionForward to be added @@ -602,6 +620,35 @@ public void addForward(ActionForward forward) { forwards.addForward(forward); + + } + + + /** + * Return the <code>ActionException</code> handler for exceptions of the + * specified type. + * + * @param type Exception class for which to find a handler + */ + public ActionException findException(Class type) { + + // First, check our locally defined exceptions + ActionException ex = exceptions.findException(type); + if (ex != null) { + return (ex); + } + + // Second, check the globally defined exceptions + ActionMappings mappings = getMappings(); + if (mappings == null) { + return (null); + } + ActionServlet servlet = mappings.getServlet(); + if (servlet == null) { + return (null); + } else { + return (servlet.findException(type)); + } } 1.82 +136 -7 jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java Index: ActionServlet.java =================================================================== RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v retrieving revision 1.81 retrieving revision 1.82 diff -u -r1.81 -r1.82 --- ActionServlet.java 29 Dec 2001 19:35:32 -0000 1.81 +++ ActionServlet.java 31 Dec 2001 01:14:36 -0000 1.82 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.81 2001/12/29 19:35:32 craigmcc Exp $ - * $Revision: 1.81 $ - * $Date: 2001/12/29 19:35:32 $ + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.82 2001/12/31 01:14:36 craigmcc Exp $ + * $Revision: 1.82 $ + * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * @@ -238,7 +238,7 @@ * * @author Craig R. McClanahan * @author Ted Husted - * @version $Revision: 1.81 $ $Date: 2001/12/29 19:35:32 $ + * @version $Revision: 1.82 $ $Date: 2001/12/31 01:14:36 $ */ public class ActionServlet @@ -308,6 +308,20 @@ /** + * The Java class name of the <code>ActionException</code> implementation + * class to use. + */ + protected String exceptionClass = + "org.apache.struts.action.ActionException"; + + + /** + * The global exceptions registered with this handler. + */ + protected ActionExceptions exceptions = new ActionExceptions(); + + + /** * The Java class name of the <code>MessageResourcesFactory</code> * class for the application message resources bundle. */ @@ -568,6 +582,20 @@ /** + * Add a global exception to the set configured for this servlet. + * + * @param exception The exception to be added + * + * @deprecated Will no longer be required with multi-application support + */ + public void addException(ActionException exception) { + + exceptions.addException(exception); + + } + + + /** * Register a form bean definition to the set configured for this servlet. * * @param formBean The form bean definition to be added @@ -679,6 +707,21 @@ /** + * Return the exception handler for an exception of the specified + * class, if any; otherwise return <code>null</code>. + * + * @param ex Exception class for which to find a handler + * + * @deprecated Will no longer be required with multi-application support + */ + public ActionException findException(Class ex) { + + return (exceptions.findException(ex)); + + } + + + /** * Return the forwarding associated with the specified logical name, * if any; otherwise return <code>null</code>. * @@ -1575,6 +1618,16 @@ "addForward", "org.apache.struts.action.ActionForward"); + digester.addObjectCreate + ("struts-config/action-mappings/action/exception", + exceptionClass, "className"); + digester.addSetProperties + ("struts-config/action-mappings/action/exception"); + digester.addSetNext + ("struts-config/action-mappings/action/exception", + "addException", + "org.apache.struts.action.ActionException"); + digester.addSetProperty ("struts-config/action-mappings/action/forward/set-property", "property", "value"); @@ -1590,6 +1643,17 @@ ("struts-config/form-beans/form-bean/set-property", "property", "value"); + digester.addObjectCreate("struts-config/global-exceptions/exception", + exceptionClass, "className"); + digester.addSetProperties("struts-config/global-exceptions/exception"); + digester.addSetNext("struts-config/global-exceptions/exception", + "addException", + "org.apache.struts.action.ActionException"); + + digester.addSetProperty + ("struts-config/global-exceptions/exception/set-property", + "property", "value"); + digester.addObjectCreate("struts-config/global-forwards/forward", forwardClass, "className"); digester.addSetProperties("struts-config/global-forwards/forward"); @@ -2160,9 +2224,24 @@ HttpServletResponse response) throws IOException, ServletException { - ActionForward forward = - action.perform(mapping, formInstance, request, response); - return (forward); + // ActionForward forward = + // action.perform(mapping, formInstance, request, response); + // return (forward); + + ActionError error = null; + Throwable cause = null; + try { + ActionForward forward = + action.execute(mapping, formInstance, request, response); + return (forward); + } catch (Exception ex) { + if (debug >= 1) { + log("Exception occurred", ex); + } + return (processException(ex, mapping, formInstance, + request, response)); + } + } @@ -2180,6 +2259,56 @@ response.setContentType(content); } + + + /** + * Ask our exception handler to handle the exception. Return the + * <code>ActionForward</code> instance (if any) returned by the called + * <code>ExceptionHandler</code>. + * + * @param ex The exception to handle + * @param maping The ActionMapping we are processing + * @param form The ActionForm we are processing (if any) + * @param request The servlet request we are processing + * @param response The servlet response we are processing + * + * @exception ServletException if a servlet exception occurs + */ + protected ActionForward processException(Exception ex, + ActionMapping mapping, + ActionForm form, + HttpServletRequest request, + HttpServletResponse response) + throws ServletException { + + // Look for an exception mapping + ActionException ae = mapping.findException(ex.getClass()); + + // If one is found, place it in the scope defined + if (ae != null) { + Class handlerClass = ae.getHandlerClass(); + try { + // Ask handler to handle the exception + ExceptionHandler handler = (ExceptionHandler) + handlerClass.newInstance(); + return (handler.execute(ex, ae, mapping, form, + request, response)); + } catch (Exception e) { + // Yuck - the exception handler thew an exception + throw new ServletException(e); + } + } else { + if (debug >= 1) { + log(internal.getMessage("unhandledException", ex.getClass())); + } + if (ex instanceof ServletException) { + throw (ServletException) ex; + } + throw new ServletException(ex); + } + + } + /** 1.1 jakarta-struts/src/share/org/apache/struts/action/ActionException.java Index: ActionException.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionException.java,v 1.1 2001/12/31 01:14:36 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.action; import java.io.Serializable; /** * An <strong>ActionException</strong> represents a potential exception * that may occur during delegation to an Action class. * Instances of this class may be configured in association * with an <code>ActionMapping</code> instance for named lookup of potentially * multiple destinations for a particular mapping instance. * <p> * An <code>ActionException</code> has the following minimal set of properties. * Additional properties can be provided as needed by subclassses. * <ul> * <li><strong>type</strong> - The fully qualified class name of the * exception to be associated to a particular <code>ActionMapping</code>. * <li><strong>key</strong> - (Optional) Message key associated with the particular * exception. * <li><strong>path</strong> - (Optional) Context releative URI that should * be redirected to as a result of the exception occuring. Will overide the * input form of the associated ActionMapping if one is provided. * <li><strong>scope</strong> - (Optional) The scope to store the exception in * if a problem should occur - defaults to 'request'. Valid values are * 'request' and 'session'. * <li><strong>hierarchical</strong> - (Optional) Defines whether or not the * Exception hierarchy should be used when determining if an occuring * exception can be assigned to a mapping instance. Default is true. * <li><strong>handler</strong> - (Optional) The fully qualified class name * of the handler, which is responsible to handle this exception. * Default is 'org.apache.struts.action.ExceptionHandler'. * </ul> * * @author ldonlan * @version $Revision: 1.1 $ $Date: 2001/12/31 01:14:36 $ */ public class ActionException implements Serializable { /** Holds value of property key. */ private String key; /** Holds value of property type. */ private String type; /** Holds value of property path. */ private String path; /** Holds value of property exClass. */ private Class exClass; /** Holds value of property hierachal. */ private boolean hierarchical = true; /** Holds value of property scope. */ private String scope = "request"; /** Holds value of handler. */ private String handler; /** Holds value of property handlerClass */ private Class handlerClass; /** Creates new ActionException */ public ActionException() { } /** * Returns the key associated with the exception. * @return Value of property key. */ public String getKey() { return key; } /** * Setter for property key. * @param key New value of property key. */ public void setKey(String key) { this.key = key; } /** * Returns the fully qualified type of the exception * @return Value of property type. */ public String getType() { return type; } /** * Setter for property type. * @param type New value of property type. * @todo Need to clean up this logging, but don't want to die if * an exception is mistyped, etc. */ public void setType(String type){ this.type = type; try{ exClass = Class.forName(type); }catch(ClassNotFoundException ex){ System.out.println("[ActionException] - Could not instantiate: " + ex.getClass() + " " + type); exClass = null; } } /** * Returns the path associated with the exception. * @return Value of property path. */ public String getPath() { return path; } /** * Setter for property path. * @param path New value of property path. */ public void setPath(String path) { this.path = path; } /** * Getter for property exClass. Will be null if the type could not * be used to create a class instance. * @return Value of property exClass. */ public Class getExClass() { return exClass; } /** Getter for property hierachal. * @return Value of property hierachal. */ public boolean isHierarchical() { return hierarchical; } /** Setter for property hierachal. * @param hierarchical */ public void setHierarchical(boolean hierarchical) { this.hierarchical = hierarchical; } /** Getter for property scope. * @return Value of property scope. */ public String getScope() { return scope; } /** Setter for property scope. * @param scope New value of property scope. */ public void setScope(String scope) { this.scope = scope; } /** * Returns the fully qualified type of the exception handler * @return Value of property handler. */ public String getHandler() { return handler; } /** * Setter for property handler. * @param type New value of property handler. * @todo Need to clean up this logging, but don't want to die if * an exception is mistyped, etc. */ public void setHandler(String handler){ this.handler = handler; try{ handlerClass = Class.forName(handler); }catch(ClassNotFoundException ex){ System.out.println("[ActionException] - Could not instantiate: " + ex.getClass() + " " + handler); handlerClass = null; } } /** * Getter for property handler. Will be null if the handler could not * be used to create a class instance. * @return Value of property handlerClass. */ public Class getHandlerClass() { return handlerClass; } /** *Returns an instance of an <b>ActionError</b> configured for *this exception. *@return ActionError */ public ActionError getError() { return new ActionError(this.key); } } 1.1 jakarta-struts/src/share/org/apache/struts/action/ActionExceptions.java Index: ActionExceptions.java =================================================================== /* * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionExceptions.java,v 1.1 2001/12/31 01:14:36 craigmcc Exp $ * $Revision: 1.1 $ * $Date: 2001/12/31 01:14:36 $ * * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.action; import java.io.*; import java.util.*; import org.apache.commons.collections.FastHashMap; /** * Encapsulate a collection of ActionException objects that can be * administered and searched, while hiding the internal implementation. * * @author ldonlan * @version $Revision: 1.1 $ $Date: 2001/12/31 01:14:36 $ */ public class ActionExceptions implements Serializable{ private static final String APP_EXCEPTION_KEY = "org.apache.struts.util.AppException"; private static final String APP_EXCEPTION_HANDLER_KEY = "org.apache.struts.action.ExceptionHandler"; /** Creates new ActionExceptions */ public ActionExceptions() { // Register an application exception. addAppException(); } // ----------------------------------------------------- Instance Variables /** * The collection of ActionForward instances, keyed by logical name. */ private FastHashMap exceptions = new FastHashMap(); // ------------------------------------------------------------- Properties /** * Return the "fast" mode flag. */ public boolean getFast() { return (exceptions.getFast()); } /** * Set the "fast" mode flag. * * @param fast The new fast mode flag */ public void setFast(boolean fast) { exceptions.setFast(fast); } /** * Register a logical exception that may occur processing the * maping. * * @param exception The exception to be added */ public void addException(ActionException ex){ exceptions.put(ex.getType(), ex); } /** * Return the ActionException associated with the specified class name, * if any; otherwise return <code>null</code>.<p> * The search will consist of first looking for a specific match on * the class provided. If one is not found, all <b>ActionException</b> * objects will be examined. For all objects with the hierarchacal * property set to true, a Class.isAssignableFrom() test will be performed. * The first match to be made will be returned. * * @param name class name of the exception */ public ActionException findException(Class type){ ActionException ex = null; ex = (ActionException)exceptions.get(type.getName()); //If no exact match was made if (ex == null){ //Look through all the A.E's Iterator it = exceptions.values().iterator(); ActionException current = null; while (it.hasNext()){ current = (ActionException)it.next(); //If there is a hierarchal match and the provided //exception is assignable from it, then return it if (current.isHierarchical()){ //Make sure that the class is not null - i.e the //type could not be used to create a class. if (current.getExClass() != null){ if (current.getExClass().isAssignableFrom(type)){ ex = current; break; } } } } } return ex; } /** *Removes the ActionException with the specified type from the *collection. * */ public ActionException remove(String type){ return (ActionException)exceptions.remove(type); } // -------------------------------------------------------- Private Methods /** * Register an application exception */ private void addAppException() { ActionException ae = new ActionException(); ae.setType(APP_EXCEPTION_KEY); ae.setHandler(APP_EXCEPTION_HANDLER_KEY); addException(ae); } } 1.1 jakarta-struts/src/share/org/apache/struts/action/ExceptionHandler.java Index: ExceptionHandler.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.action; import java.util.Locale; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionException; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.util.AppException; public class ExceptionHandler { /** * Handle the exception. * Return the <code>ActionForward</code> instance (if any) returned by * the called <code>ExceptionHandler</code>. * * @param ex The exception to handle * @param ae The ActionException corresponding to the exception * @param mapping The ActionMapping we are processing * @param formInstance The ActionForm we are processing * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception ServletException if a servlet exception occurs */ protected ActionForward execute(Exception ex, ActionException ae, ActionMapping mapping, ActionForm formInstance, HttpServletRequest request, HttpServletResponse response) throws ServletException { ActionForward forward = null; ActionError error = null; String property = null; String path; // Build the forward from the exception mapping if it exists // or from the form input if (ae.getPath() != null) { path = ae.getPath(); } else { path = mapping.getInput(); } // Generate the forward forward = new ActionForward(path); // Figure out the error if (ex instanceof AppException) { error = ((AppException) ex).getError(); property = ((AppException) ex).getProperty(); } else { error = ae.getError(); property = error.getKey(); } // Store the exception storeException(request, property, error, forward, ae.getScope()); return forward; } /** * Default implementation for handling an <b>ActionError</b> generated * from an Exception during <b>Action</b> delegation. The default * implementation is to set an attribute of the request or session, as * defined by the scope provided (the scope from the exception mapping). An * <b>ActionErrors</b> instance is created, the error is added to the collection * and the collection is set under the Action.ERROR_KEY. * * @param request * @param error - The error generated from the exception mapping * @param input - The forward generated from the input path (from the form or exception mapping) * @param scope - The scope of the exception mapping. * */ protected void storeException(HttpServletRequest request, String property, ActionError error, ActionForward forward, String scope) { ActionErrors errors = new ActionErrors(); errors.add(property, error); if ("request".equals(scope)){ request.setAttribute(Action.ERROR_KEY, errors); } else { request.getSession().setAttribute(Action.ERROR_KEY, errors); } } } 1.1 jakarta-struts/src/share/org/apache/struts/util/AppException.java Index: AppException.java =================================================================== /* * The Apache Software License, Version 1.1 * * Copyright (c) 1999-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Struts", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.struts.util; import java.util.Locale; import org.apache.struts.action.ActionError; public class AppException extends Exception { private String property = null; private ActionError error = null; // ----------------------------------------------------------- Constructors /** * Construct an application exception with no replacement values. * * @param key Message key for this error message */ public AppException(String key) { super(key); error = new ActionError(key); } /** * Construct an application exception with the specified replacement values. * * @param key Message key for this error message * @param value0 First replacement value */ public AppException(String key, Object value) { super(key); error = new ActionError(key, value); } /** * Construct an application exception with the specified replacement values. * * @param key Message key for this error message * @param value0 First replacement value * @param value1 Second replacement value */ public AppException(String key, Object value0, Object value1) { super(key); error = new ActionError(key, value0, value1); } /** * Construct an application exception with the specified replacement values. * * @param key Message key for this error message * @param value0 First replacement value * @param value1 Second replacement value * @param value2 Third replacement value */ public AppException(String key, Object value0, Object value1, Object value2) { super(key); error = new ActionError(key, value0, value1, value2); } /** * Construct an application exception with the specified replacement values. * * @param key Message key for this error message * @param value0 First replacement value * @param value1 Second replacement value * @param value2 Third replacement value * @param value3 Fourth replacement value */ public AppException(String key, Object value0, Object value1, Object value2, Object value3) { super(key); error = new ActionError(key, value0, value1, value2, value3); } // -------------------------------------------------------- Public Methods /** * Returns the property associated with the exception. * @return Value of property. */ public String getProperty() { return (property != null) ? property : error.getKey(); } /** * Set the property associated with the exception. * It can be a name of the edit field, which 'caused' the exception. */ public void setProperty(String property) { this.property = property; } /** * Returns the error associated with the exception. * @return Value of property error. */ public ActionError getError() { return error; } } 1.1 jakarta-struts/web/example/changePassword.jsp Index: changePassword.jsp =================================================================== <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <html:html locale="true"> <head> <title><bean:message key="change.title"/></title> <html:base/> </head> <body bgcolor="white"> <bean:message key="change.message"/> <html:link page="/logon.jsp"> <bean:message key="change.try"/> </html:link> </body> </html:html> 1.14 +3 -0 jakarta-struts/web/example/WEB-INF/struts-config.xml Index: struts-config.xml =================================================================== RCS file: /home/cvs/jakarta-struts/web/example/WEB-INF/struts-config.xml,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- struts-config.xml 8 Aug 2001 04:25:01 -0000 1.13 +++ struts-config.xml 31 Dec 2001 01:14:36 -0000 1.14 @@ -103,6 +103,9 @@ name="logonForm" scope="request" input="/logon.jsp"> + <exception + type="org.apache.struts.webapp.example.ExpiredPasswordException" + path="/changePassword.jsp"/> </action> <!-- Save user registration -->
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>