You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@locus.apache.org on 2000/10/12 23:51:11 UTC

cvs commit: jakarta-struts/src/share/org/apache/struts/action ActionError.java ActionErrors.java Action.java ActionForm.java ActionMapping.java ActionServlet.java ValidatingActionForm.java

craigmcc    00/10/12 14:51:10

  Modified:    src/share/org/apache/struts/action Action.java
                        ActionForm.java ActionMapping.java
                        ActionServlet.java ValidatingActionForm.java
  Added:       src/share/org/apache/struts/action ActionError.java
                        ActionErrors.java
  Log:
  Implement a series of interconnected changes:
  
  ActionError / ActionErrors
  --------------------------
  A new representation of error messages returned by validation methods that
  allows you to associate particular errors with particular field names, and
  stores up to for parameter replacement strings along with the message key,
  so you can use {0} type replacements.
  
  Action
  ------
  Use the new ActionErrors object instead of ErrorMessages.
  
  ActionMapping
  -------------
  Update the toString() representation.
  
  ActionServlet
  -------------
  Separate the functionality to populate ActionForm properties and the
  functionality to call the validation method into different protected
  methods that can be overridden separately if desired.
  
  ActionForm / ValidatingActionForm
  ---------------------------------
  Convert ActionForm from an interface to a base class, which includes
  default implementations of a validate() method.  The validate() method
  also takes the current mapping and request as arguments to provide more
  useful contextual information.
  
  NOTE:  DUE TO ONGOING DISCUSSIONS ON STRUTS-DEV, IT IS PREMATURE TO
  ASSUME THAT THIS CHANGE IS PERMANENT.
  
  Revision  Changes    Path
  1.6       +8 -9      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.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Action.java	2000/09/23 22:51:45	1.5
  +++ Action.java	2000/10/12 21:51:00	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.5 2000/09/23 22:51:45 craigmcc Exp $
  - * $Revision: 1.5 $
  - * $Date: 2000/09/23 22:51:45 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.6 2000/10/12 21:51:00 craigmcc Exp $
  + * $Revision: 1.6 $
  + * $Date: 2000/10/12 21:51:00 $
    *
    * ====================================================================
    *
  @@ -105,7 +105,7 @@
    * by this Action.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.5 $ $Date: 2000/09/23 22:51:45 $
  + * @version $Revision: 1.6 $ $Date: 2000/10/12 21:51:00 $
    */
   
   public class Action {
  @@ -348,20 +348,19 @@
        * created.
        *
        * @param request The servlet request we are processing
  -     * @param messages Vector containing message keys for looking
  -     *  up errors in the application resources
  +     * @param errors Error messages object
        */
       protected void saveErrors(HttpServletRequest request,
  -			      ErrorMessages messages) {
  +			      ActionErrors errors) {
   
   	// Remove any error messages attribute if none are required
  -	if ((messages == null) || (messages.getSize() == 0)) {
  +	if ((errors == null) || errors.empty()) {
   	    request.removeAttribute(ERROR_KEY);
   	    return;
   	}
   
   	// Save the error messages we need
  -	request.setAttribute(ERROR_KEY, messages.getErrors());
  +	request.setAttribute(ERROR_KEY, errors);
   
       }
   
  
  
  
  1.2       +125 -7    jakarta-struts/src/share/org/apache/struts/action/ActionForm.java
  
  Index: ActionForm.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionForm.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActionForm.java	2000/05/31 22:28:11	1.1
  +++ ActionForm.java	2000/10/12 21:51:01	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionForm.java,v 1.1 2000/05/31 22:28:11 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/05/31 22:28:11 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionForm.java,v 1.2 2000/10/12 21:51:01 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/12 21:51:01 $
    *
    * ====================================================================
    * 
  @@ -63,20 +63,138 @@
   package org.apache.struts.action;
   
   
  +import javax.servlet.ServletRequest;
  +import javax.servlet.http.HttpServletRequest;
  +
  +
   /**
  - * An <strong>ActionForm</strong> is a JavaBean optionally associated with
  - * a particular <code>ActionMapping</code>.  Such a bean will have had its
  + * <p>An <strong>ActionForm</strong> is a JavaBean optionally associated with
  + * one or more <code>ActionMappings</code>.  Such a bean will have had its
    * properties initialized from the corresponding request parameters before
  - * the action's <code>perform()</code> method is called.
  + * the corresonding action's <code>perform()</code> method is called.</p>
  + *
  + * <p>When the properties of this bean have been populated, but before the
  + * <code>perform()</code> method of the action is called, this bean's
  + * <code>validate()</code> method will be called, which gives the bean a chance
  + * to verify that the properties submitted by the user are correct and valid.
  + * If this method finds problems, it returns an error messages object that
  + * encapsulates those problems, and the controller servlet will return control
  + * to the corresponding input form.  Otherwise, the <code>validate()</code>
  + * method returns <code>null()</code>, indicating that everything is acceptable
  + * and the corresponding Action's <code>perform()</code> method should be
  + * called.</p>
  + *
  + * <p>This class must be subclassed in order to be instantiated.  Subclasses
  + * should provide property getter and setter methods for all of the bean
  + * properties they wish to expose, plus override any of the public or
  + * protected methods for which they wish to provide modified functionality.
  + * </p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/05/31 22:28:11 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/12 21:51:01 $
    */
  +
  +public abstract class ActionForm {
  +
  +
  +    // ----------------------------------------------------- Instance Variables
  +
  +
  +    /**
  +     * The controller servlet instance to which we are attached.
  +     */
  +    protected ActionServlet servlet = null;
  +
  +
  +    // ------------------------------------------------------------- Properties
  +
   
  -public interface ActionForm {
  +    /**
  +     * Return the controller servlet instance to which we are attached.
  +     */
  +    public ActionServlet getServlet() {
   
  +        return (this.servlet);
   
  +    }
  +
  +
  +    /**
  +     * Set the controller servlet instance to which we are attached (if
  +     * <code>servlet</code> is non-null), or release any allocated resources
  +     * (if <code>servlet</code> is null).
  +     *
  +     * @param servlet The new controller servlet, if any
  +     */
  +    public void setServlet(ActionServlet servlet) {
  +
  +        this.servlet = servlet;
  +
  +    }
  +
  +
       // --------------------------------------------------------- Public Methods
  +
  +
  +    /**
  +     * Reset all bean properties to their default state.  This method is
  +     * called before the properties are repopulated by the controller servlet.
  +     * <p>
  +     * The default implementation does nothing.  Subclasses should override
  +     * this method to reset all bean properties to default values.
  +     */
  +    public void reset() {
  +
  +        ;       // Default implementation does nothing
  +
  +    }
  +
  +
  +    /**
  +     * Validate the properties that have been set for this non-HTTP request,
  +     * and return an <code>ActionErrors</code> object that encapsulates any
  +     * validation errors that have been found.  If no errors are found, return
  +     * <code>null</code> or an <code>ActionErrors</code> object with no
  +     * recorded error messages.
  +     * <p>
  +     * The default implementation attempts to forward to the HTTP version of
  +     * this method.
  +     *
  +     * @param mapping The ActionMapping used to select this instance
  +     * @param request The non-HTTP request we are processing
  +     */
  +    public ActionErrors validate(ActionMapping mapping,
  +                                 ServletRequest request) {
  +
  +        try {
  +            return (validate(mapping, (HttpServletRequest) request));
  +        } catch (ClassCastException e) {
  +            return (null);
  +        }
  +
  +    }
  +
  +
  +    /**
  +     * Validate the properties that have been set for this HTTP request,
  +     * and return an <code>ActionErrors</code> object that encapsulates any
  +     * validation errors that have been found.  If no errors are found,
  +     * return <code>null</code> or an <code>ActionErrors</code> object with
  +     * no recorded error messages.
  +     * <p>
  +     * The default ipmlementation performs no validation and returns
  +     * <code>null</code>.  Subclasses must override this method to provide
  +     * any validation they wish to perform.
  +     *
  +     * @param mapping The ActionMapping used to select this instance
  +     * @param request The HTTP servlet request we are processing
  +     */
  +    public ActionErrors validate(ActionMapping mapping,
  +                                 HttpServletRequest request) {
  +
  +        return (null);
  +
  +    }
   
   
   }
  
  
  
  1.9       +15 -5     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.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ActionMapping.java	2000/09/23 22:51:46	1.8
  +++ ActionMapping.java	2000/10/12 21:51:02	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java,v 1.8 2000/09/23 22:51:46 craigmcc Exp $
  - * $Revision: 1.8 $
  - * $Date: 2000/09/23 22:51:46 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionMapping.java,v 1.9 2000/10/12 21:51:02 craigmcc Exp $
  + * $Revision: 1.9 $
  + * $Date: 2000/10/12 21:51:02 $
    *
    * ====================================================================
    *
  @@ -138,7 +138,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.8 $ $Date: 2000/09/23 22:51:46 $
  + * @version $Revision: 1.9 $ $Date: 2000/10/12 21:51:02 $
    */
   
   public class ActionMapping {
  @@ -654,6 +654,9 @@
       /**
        * Create and return an initialized instance of our form class.  If
        * instantiation fails for any reason, <code>null</code> is returned.
  +     *
  +     * @deprecated Creation of ActionForm instances is now the responsibility
  +     *  of the controller servlet
        */
       public ActionForm createFormInstance() {
   
  @@ -725,7 +728,14 @@
        */
       public String toString() {
   
  -	return ("ActionMapping[" + path + "]");
  +        StringBuffer sb = new StringBuffer("ActionMapping[path=");
  +        sb.append(path);
  +        if (type != null) {
  +            sb.append(", type=");
  +            sb.append(type);
  +        }
  +        sb.append("]");
  +        return (sb.toString());
   
       }
   
  
  
  
  1.29      +100 -67   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.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- ActionServlet.java	2000/10/07 22:55:13	1.28
  +++ ActionServlet.java	2000/10/12 21:51:03	1.29
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.28 2000/10/07 22:55:13 craigmcc Exp $
  - * $Revision: 1.28 $
  - * $Date: 2000/10/07 22:55:13 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.29 2000/10/12 21:51:03 craigmcc Exp $
  + * $Revision: 1.29 $
  + * $Date: 2000/10/12 21:51:03 $
    *
    * ====================================================================
    *
  @@ -197,7 +197,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.28 $ $Date: 2000/10/07 22:55:13 $
  + * @version $Revision: 1.29 $ $Date: 2000/10/12 21:51:03 $
    */
   
   public class ActionServlet
  @@ -1039,6 +1039,7 @@
   
   	// Process any ActionForm bean related to this request
   	ActionForm formInstance = processActionForm(mapping, request);
  +        processPopulate(formInstance, mapping, request);
   	if (!processValidate(mapping, formInstance, request, response))
   	    return;
   
  @@ -1069,7 +1070,7 @@
                                            HttpServletRequest request) {
   
           // Acquire the Action instance we will be using
  -        String actionClass = mapping.getActionClass();
  +        String actionClass = mapping.getType();
           Action actionInstance = (Action) actions.get(actionClass);
           if (actionInstance == null) {
               try {
  @@ -1090,56 +1091,66 @@
   
   
       /**
  -     * Process the <code>ActionForm</code> bean associated with this
  -     * mapping, if any.  Return the <code>ActionForm</code> instance if
  -     * we created or utilized one.
  +     * Retrieve and return the <code>ActionForm</code> bean associated with
  +     * this mapping, creating and stashing one if necessary.  If there is no
  +     * form bean associated with this mapping, return <code>null</code>.
        *
        * @param mapping The ActionMapping we are processing
        * @param request The servlet request we are processing
  -     *
  -     * @exception ServletException if thrown by BeanUtils.populate()
        */
       protected ActionForm processActionForm(ActionMapping mapping,
  -    					   HttpServletRequest request)
  -	throws ServletException {
  +    					   HttpServletRequest request) {
   
  +        // Is there a form bean associated with this mapping?
  +	String attribute = mapping.getAttribute();
  +        if (attribute == null)
  +            return (null);
  +
  +        // Look up the existing form bean, if any
  +        if (debug >= 1)
  +            log(" Looking for ActionForm bean under attribute '" +
  +                attribute + "'");
  +	ActionForm instance = null;
   	HttpSession session = null;
  -	ActionForm formInstance = null;
  -	String formAttribute = mapping.getFormAttribute();
  -	if (formAttribute != null) {
  -	    if (debug >= 1)
  -	        log(" Looking for ActionForm bean under attribute '" +
  -		    formAttribute + "'");
  -	    if ("request".equals(mapping.getFormScope())) {
  -		formInstance =
  -		    (ActionForm) request.getAttribute(formAttribute);
  -	    } else {
  -		session = request.getSession();
  -		formInstance =
  -		    (ActionForm) session.getAttribute(formAttribute);
  -	    }
  -	    if (formInstance == null) {
  -		if (debug >= 1)
  -		    log(" Creating new ActionForm instance");
  -		formInstance = mapping.createFormInstance();
  -		if (formInstance != null) {
  -		    if (debug >= 1)
  -		        log(" Storing instance under attribute '" +
  -			    formAttribute + "'");
  -		    if ("request".equals(mapping.getFormScope()))
  -			request.setAttribute(formAttribute, formInstance);
  -		    else
  -			session.setAttribute(formAttribute, formInstance);
  -	        }
  -	    }
  -	}
  -	if (formInstance != null) {
  -	    if (debug >= 1)
  -	        log(" Populating bean properties from this request");
  -	    BeanUtils.populate(formInstance, mapping.getFormPrefix(),
  -			       mapping.getFormSuffix(), request);
  +        if ("request".equals(mapping.getScope())) {
  +            instance = (ActionForm) request.getAttribute(attribute);
  +        } else {
  +            session = request.getSession();
  +            instance = (ActionForm) session.getAttribute(attribute);
  +        }
  +        if (instance != null)
  +            return (instance);
  +
  +        // Create a new form bean if we need to
  +        if (debug >= 1)
  +            log(" Creating new ActionForm instance");
  +        String name = mapping.getName();
  +        String className = null;
  +        ActionFormBean formBean = findFormBean(name);
  +        if (formBean != null)
  +            className = formBean.getType();
  +        if (className != null) {
  +            try {
  +                Class clazz = Class.forName(className);
  +                instance = (ActionForm) clazz.newInstance();
  +                instance.setServlet(this);
  +            } catch (Throwable t) {
  +                log("Error creating ActionForm instance of class '" +
  +                    className + "'", t);
  +            }
           }
  -	return (formInstance);
  +        if (instance == null)
  +            return (null);
  +
  +        // Store the newly created bean in the appropriate scope
  +        if (debug >= 1)
  +            log(" Storing instance under attribute '" +
  +                attribute + "'");
  +        if ("request".equals(mapping.getScope()))
  +            request.setAttribute(attribute, instance);
  +        else
  +            session.setAttribute(attribute, instance);
  +        return (instance);
   
       }
   
  @@ -1322,11 +1333,40 @@
   
   
       /**
  -     * If this form is a ValidatingActionForm, perform the required validation
  +     * Populate the properties of the specified ActionForm from the request
  +     * parameters included with this request.
  +     *
  +     * @param formInstance The ActionForm we are processing
  +     * @param mapping The ActionMapping we are processing
  +     * @param request The servlet request we are processing
  +     *
  +     * @exception ServletException if thrown by BeanUtils.populate()
  +     */
  +    protected void processPopulate(ActionForm formInstance,
  +                                   ActionMapping mapping,
  +                                   HttpServletRequest request)
  +	throws ServletException {
  +
  +        if (formInstance == null)
  +            return;
  +
  +        // Populate the bean properties of this ActionForm instance
  +        if (debug >= 1)
  +            log(" Populating bean properties from this request");
  +        formInstance.reset();
  +        BeanUtils.populate(formInstance, mapping.getPrefix(),
  +                           mapping.getSuffix(), request);
  +
  +    }
  +
  +
  +    /**
  +     * Call the <code>validate()</code> method of the specified ActionForm,
        * and forward back to the input form if there are any errors.  Return
  -     * <code>true</code> if we should continue processing (and call the Action
  -     * class perform() method), or <code>false</code> if have already forwarded
  -     * control back to the input form.
  +     * <code>true</code> if we should continue processing (and call the
  +     * <code>Action</code> class <code>perform()</code> method), or return
  +     * <code>false</code> if we have already forwarded control back to the
  +     * input form.
        *
        * @param mapping The ActionMapping we are processing
        * @param formInstance The ActionForm we are processing
  @@ -1341,25 +1381,18 @@
           HttpServletResponse response)
           throws IOException, ServletException {
   
  -	// Skip validation if it is not appropriate
  -	if (formInstance == null)
  -	    return (true);
  -	if (!(formInstance instanceof ValidatingActionForm))
  -	    return (true);
  -	if (mapping.getInputForm() == null)
  -	    return (true);
  -	if (request.getParameter(Constants.CANCEL_PROPERTY) != null)
  -	    return (true);
  +        if (formInstance == null)
  +            return (true);
   
  -	// Perform the requested validation
  -	if (debug >= 1)
  -	    log(" Validating bean properties");
  -	String errors[] = ((ValidatingActionForm) formInstance).validate();
  -	if ((errors == null) || (errors.length == 0))
  -	    return (true);
  +        // Call the validate() method of our ActionForm bean
  +        if (debug >= 1)
  +            log(" Calling form validation method");
  +        ActionErrors errors = formInstance.validate(mapping, request);
  +        if ((errors == null) || errors.empty())
  +            return (true);
   
   	// Save our error messages and return to the input form
  -	String uri = mapping.getInputForm();
  +	String uri = mapping.getInput();
   	if (debug >= 1)
   	    log(" Form validation error: redirecting to: " + uri);
   	request.setAttribute(Action.ERROR_KEY, errors);
  
  
  
  1.2       +20 -12    jakarta-struts/src/share/org/apache/struts/action/ValidatingActionForm.java
  
  Index: ValidatingActionForm.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ValidatingActionForm.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValidatingActionForm.java	2000/06/16 01:32:24	1.1
  +++ ValidatingActionForm.java	2000/10/12 21:51:04	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ValidatingActionForm.java,v 1.1 2000/06/16 01:32:24 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/06/16 01:32:24 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ValidatingActionForm.java,v 1.2 2000/10/12 21:51:04 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/10/12 21:51:04 $
    *
    * ====================================================================
    *
  @@ -64,16 +64,20 @@
   
   
   /**
  - * An <strong>ValidatingActionForm</strong> is a JavaBean optionally associated with
  - * a particular <code>ActionMapping</code>.  Such a bean will have had its
  - * properties initialized from the corresponding request parameters before
  - * the action's <code>perform()</code> method is called.
  + * <p>An <strong>ValidatingActionForm</strong> is a JavaBean optionally
  + * associated with one or more <code>ActionMappings</code>.  Such a bean will
  + * have had its properties initialized from the corresponding request
  + * parameters before the action's <code>perform()</code> method is called.</p>
  + *
  + * @deprecated Application ActionForm beans should now extend ActionForm
  + *  directly, and override the validate() method if they wish to provide
  + *  such services
    *
    * @author Jeff Hutchison
  - * @version $Revision: 1.1 $ $Date: 2000/06/16 01:32:24 $
  + * @version $Revision: 1.2 $ $Date: 2000/10/12 21:51:04 $
    */
   
  -public interface ValidatingActionForm extends ActionForm {
  +public class ValidatingActionForm extends ActionForm {
   
   
       // --------------------------------------------------------- Public Methods
  @@ -82,11 +86,15 @@
       /**
        * Perform validations on the form input values included in this form bean.
        * If validation errors occur, return a String array containing the message
  -     * keys of corresponding error messages (in our application MessageResources)
  -     * to be displayed.  If no validation errors occur, return <code>null</code>.
  +     * keys of corresponding error messages (in our application
  +     * MessageResources) to be displayed.  If no validation errors occur,
  +     * return <code>null</code>.
        */
  +    public String[] validate() {
   
  -    public String[] validate();
  +        return (null);
  +
  +    }
   
   
   }
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/action/ActionError.java
  
  Index: ActionError.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionError.java,v 1.1 2000/10/12 21:51:00 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/10/12 21:51:00 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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 apache@apache.org.
   *
   * 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;
  
  
  /**
   * An encapsulation of an individual error message returned by the
   * <code>validate()</code> method of an <code>ActionForm</code>, consisting
   * of a message key (to be used to look up message text in an appropriate
   * message resources database) plus up to four placeholder objects that can
   * be used for parametric replacement in the message text.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/10/12 21:51:00 $
   */
  
  public final class ActionError {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct an action error with no replacement values.
       *
       * @param key Message key for this error message
       */
      public ActionError(String key) {
  
          this(key, null, null, null, null);
  
      }
  
  
      /**
       * Construct an action error with the specified replacement values.
       *
       * @param key Message key for this error message
       * @param value0 First replacement value
       */
      public ActionError(String key, Object value0) {
  
          this(key, value0, null, null, null);
  
      }
  
  
      /**
       * Construct an action error with the specified replacement values.
       *
       * @param key Message key for this error message
       * @param value0 First replacement value
       * @param value1 Second replacement value
       */
      public ActionError(String key, Object value0, Object value1) {
  
          this(key, value0, value1, null, null);
  
      }
  
  
      /**
       * Construct an action error 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 ActionError(String key, Object value0, Object value1,
                         Object value2) {
  
          this(key, value0, value1, value2, null);
  
      }
  
  
      /**
       * Construct an action error 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 ActionError(String key, Object value0, Object value1,
                         Object value2, Object value3) {
  
          super();
          this.key = key;
          values[0] = value0;
          values[1] = value1;
          values[2] = value2;
          values[3] = value3;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The message key for this error message.
       */
      private String key = null;
  
  
      /**
       * The replacement values for this error mesasge.
       */
      private Object values[] = { null, null, null, null };
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Get the message key for this error message.
       */
      public String getKey() {
  
          return (this.key);
  
      }
  
  
      /**
       * Get the replacement values for this error message.
       */
      public Object[] getValues() {
  
          return (this.values);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/action/ActionErrors.java
  
  Index: ActionErrors.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionErrors.java,v 1.1 2000/10/12 21:51:00 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/10/12 21:51:00 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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 apache@apache.org.
   *
   * 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.ArrayList;
  import java.util.Iterator;
  import java.util.HashMap;
  
  
  /**
   * <p>A class that encapsulates the error messages being reported by
   * the <code>validate()</code> method of an <code>ActionForm</code>.
   * Validation errors are either global to the entire <code>ActionForm</code>
   * bean they are associated with, or they are specific to a particular
   * bean property (and, therefore, a particular input field on the corresponding
   * form).</p>
   *
   * <p>Each individual error is described by an <code>ActionError</code>
   * object, which contains a message key (to be looked up in an appropriate
   * message resources database), and up to four placeholder arguments used for
   * parametric substitution in the resulting message.</p>
   *
   * <p><strong>IMPLEMENTATION NOTE</strong> - It is assumed that these objects
   * are created and manipulated only within the context of a single thread.
   * Therefore, no synchronization is required for access to internal
   * collections.</p>
   *
   * @author David Geary
   * @author Craig R. McClanahan
   * @revision $Revision: 1.1 $ $Date: 2000/10/12 21:51:00 $
   */
  
  public class ActionErrors {
  
  
      // ----------------------------------------------------- Manifest Constants
  
  
      /**
       * The "property name" marker to use for global errors, as opposed to
       * those related to a specific property.
       */
      public static final String GLOBAL_ERROR =
          "org.apache.struts.action.GLOBAL_ERROR";
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * An empty collection to use for returning empty Iterators.  Do not add
       * any elements to this collection!
       */
      protected ArrayList empty = new ArrayList();
  
  
      /**
       * The accumulated set of <code>ActionError</code> objects (represented
       * as an ArrayList) for each property, keyed by property name.
       */
      protected HashMap errors = new HashMap();
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Add an error message to the set of errors for the specified property.
       *
       * @param property Property name (or ActionErrors.GLOBAL_ERROR)
       * @param error The error message to be added
       */
      public void add(String property, ActionError error) {
  
          ArrayList list = (ArrayList) errors.get(property);
          if (list == null) {
              list = new ArrayList();
              errors.put(property, list);
          }
          list.add(error);
  
      }
  
  
      /**
       * Clear all error messages recorded by this object.
       */
      public void clear() {
  
          errors.clear();
  
      }
  
  
      /**
       * Return <code>true</code> if there are no error messages recorded
       * in this collection, or <code>false</code> otherwise.
       */
      public boolean empty() {
  
          return (errors.size() == 0);
  
      }
  
  
      /**
       * Return the set of all recorded error messages, without distinction
       * by which property the messages are associated with.  If there are
       * no error messages recorded, an empty enumeration is returned.
       */
      public Iterator get() {
  
          if (errors.size() == 0)
              return (empty.iterator());
          ArrayList results = new ArrayList();
          Iterator props = errors.keySet().iterator();
          while (props.hasNext()) {
              String prop = (String) props.next();
              Iterator errors = ((ArrayList) this.errors.get(prop)).iterator();
              while (errors.hasNext())
                  results.add(errors.next());            
          }
          return (results.iterator());
  
      }
      
  
      /**
       * Return the set of error messages related to a specific property.
       * If there are no such errors, an empty enumeration is returned.
       *
       * @param property Property name (or ActionErrors.GLOBAL_ERROR)
       */
      public Iterator get(String property) {
  
          ArrayList list = (ArrayList) errors.get(property);
          if (list == null)
              return (empty.iterator());
          else
              return (list.iterator());
  
      }
  
  
      /**
       * Return the number of errors recorded for all properties (including
       * global errors).  <strong>NOTE</strong> - it is more efficient to call
       * <code>empty()</code> if all you care about is whether or not there are
       * any error messages at all.
       */
      public int size() {
  
          int total = 0;
          Iterator keys = errors.keySet().iterator();
          while (keys.hasNext()) {
              String key = (String) keys.next();
              ArrayList list = (ArrayList) errors.get(key);
              total += list.size();
          }
          return (total);
  
      }
  
  
      /**
       * Return the number of errors associated with the specified property.
       *
       * @param property Property name (or ActionErrors.GLOBAL_ERROR)
       */
      public int size(String property) {
  
          ArrayList list = (ArrayList) errors.get(property);
          if (list == null)
              return (0);
          else
              return (list.size());
  
      }
  
  
  }