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...@apache.org on 2002/01/17 01:15:06 UTC

cvs commit: jakarta-struts/web/example/WEB-INF struts-config.xml

craigmcc    02/01/16 16:15:06

  Modified:    conf/share struts-config_1_1.dtd
               src/example/org/apache/struts/webapp/example
                        LogonAction.java
               src/share/org/apache/struts/action Action.java
                        ActionServlet.java RequestProcessor.java
               src/share/org/apache/struts/config ConfigRuleSet.java
                        FormBeanConfig.java FormPropertyConfig.java
               src/share/org/apache/struts/taglib/html FormTag.java
               src/share/org/apache/struts/util RequestUtils.java
               web/example/WEB-INF struts-config.xml
  Added:       src/share/org/apache/struts/action DynaActionForm.java
                        DynaActionFormClass.java
  Log:
  Initial check-in of dynamic ActionForm support (uses the new DynaBean
  support in the Commons version of BeanUtils).  Now, you have three choices
  for how to implement ActionForms:
  
  * Implement your own ActionForm subclass with standard JavaBean
    properties, as before.
  
  * Use the standard class "org.apache.struts.action.DynaActionForm",
    which will be populated with properties defined by <form-property>
    elements nested inside the <form-bean> element.  Note that you can
    also set initial values in the <form-property> element; these are
    used in the default implementation of reset().  Intelligent defaults
    take care of the most common cases.  Note that the default validate()
    method does NO checking, so you will need to do everything in your
    Action.
  
  * Implement a subclass of "org.apache.struts.action.DynaActionForm"
    if you need to customize just the reset() and/or validate() methods.
    In this case, you will need to tell Struts that you still want
    dynamic bean support:
      <form-bean name="logonForm" dynamic="true"
                 type="com.mycompany.mypackage.MyDynaActionForm">
        ... <form-property> elements ...
      </form-bean>
  
  Just as an illustration of how this is used, the logon form bean in the
  Struts example app has been replaced by a corresponding dynamic bean.
  Note that I had to adjust the Action to use PropertyUtils to read the
  properties, in order to make it not care about the actual implementation --
  this approach will be common when rapidly prototyping an applicaiton, and
  then going back and implementing specific ActionForm classes when needed
  later.  PropertyUtils knows how to handle either kind of ActionForm
  transparently, so no changes to the Action are required.
  
  Revision  Changes    Path
  1.10      +14 -1     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.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- struts-config_1_1.dtd	16 Jan 2002 17:42:40 -0000	1.9
  +++ struts-config_1_1.dtd	17 Jan 2002 00:15:05 -0000	1.10
  @@ -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.9 2002/01/16 17:42:40 craigmcc Exp $
  +     $Id: struts-config_1_1.dtd,v 1.10 2002/01/17 00:15:05 craigmcc Exp $
   -->
   
   
  @@ -194,6 +194,13 @@
                        bean, if you do not want to use the standard value.
                        [org.apache.struts.config.FormBeanConfig]
   
  +     dynamic         Is the class identified by the "type" attribute
  +                     a DynaActionForm with dynamic properties?  If the
  +                     type attribute is set to
  +                     "org.apache.struts.action.DynaActionForm", this
  +                     property defaults to true, otherwise it defaults
  +                     to false.
  +
        name            Unique identifier of this bean, used to reference it
                        in corresponding action mappings.
   
  @@ -203,6 +210,7 @@
   <!ELEMENT form-bean (icon?, display-name?, description?, set-property*, form-property*)>
   <!ATTLIST form-bean      id             ID              #IMPLIED>
   <!ATTLIST form-bean      className      %ClassName;     #IMPLIED>
  +<!ATTLIST form-bean      dynamic        %Boolean;       #IMPLIED>
   <!ATTLIST form-bean      name           %BeanName;      #REQUIRED>
   <!ATTLIST form-bean      type           %ClassName;     #REQUIRED>
   
  @@ -217,6 +225,10 @@
                        bean, if you do not want to use the standard value.
                        [org.apache.struts.config.FormPropertyConfig]
   
  +     initial         String representation of the initial value for
  +                     this property.  If not specified, primitives will
  +                     by initialized to zero and objects to null.
  +
        name            JavaBeans property name of the property being described
                        by this element.
   
  @@ -226,6 +238,7 @@
   -->
   <!ELEMENT form-property  (set-property*)>
   <!ATTLIST form-property  className      %ClassName;     #IMPLIED>
  +<!ATTLIST form-property  initial        CDATA           #IMPLIED>
   <!ATTLIST form-property  name           %PropName;      #REQUIRED>
   <!ATTLIST form-property  type           %ClassName;     #REQUIRED>
   
  
  
  
  1.4       +9 -6      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.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LogonAction.java	31 Dec 2001 01:14:36 -0000	1.3
  +++ LogonAction.java	17 Jan 2002 00:15:05 -0000	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $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 $
  + * $Header: /home/cvs/jakarta-struts/src/example/org/apache/struts/webapp/example/LogonAction.java,v 1.4 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -80,13 +80,14 @@
   import org.apache.struts.action.ActionServlet;
   import org.apache.struts.util.AppException;
   import org.apache.struts.util.MessageResources;
  +import org.apache.commons.beanutils.PropertyUtils;
   
   
   /**
    * Implementation of <strong>Action</strong> that validates a user logon.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.3 $ $Date: 2001/12/31 01:14:36 $
  + * @version $Revision: 1.4 $ $Date: 2002/01/17 00:15:05 $
    */
   
   public final class LogonAction extends Action {
  @@ -122,8 +123,10 @@
   
   	// Validate the request parameters specified by the user
   	ActionErrors errors = new ActionErrors();
  -	String username = ((LogonForm) form).getUsername();
  -	String password = ((LogonForm) form).getPassword();
  +	String username = (String)
  +            PropertyUtils.getSimpleProperty(form, "username");
  +        String password = (String)
  +            PropertyUtils.getSimpleProperty(form, "password");
   	Hashtable database = (Hashtable)
   	  servlet.getServletContext().getAttribute(Constants.DATABASE_KEY);
   	if (database == null)
  
  
  
  1.35      +12 -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.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- Action.java	13 Jan 2002 00:25:35 -0000	1.34
  +++ Action.java	17 Jan 2002 00:15:05 -0000	1.35
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.34 2002/01/13 00:25:35 craigmcc Exp $
  - * $Revision: 1.34 $
  - * $Date: 2002/01/13 00:25:35 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.35 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.35 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -109,13 +109,21 @@
    * by this Action.</p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.34 $ $Date: 2002/01/13 00:25:35 $
  + * @version $Revision: 1.35 $ $Date: 2002/01/17 00:15:05 $
    */
   
   public class Action {
   
   
       // ----------------------------------------------------- Manifest Constants
  +
  +
  +    /**
  +     * The context attributes key under which our <code>ActionServlet</code>
  +     * instance will be stored.
  +     */
  +    public static final String ACTION_SERVLET_KEY =
  +        "org.apache.struts.action.ACTION_SERVLET";
   
   
       /**
  
  
  
  1.87      +9 -6      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.86
  retrieving revision 1.87
  diff -u -r1.86 -r1.87
  --- ActionServlet.java	16 Jan 2002 17:42:40 -0000	1.86
  +++ ActionServlet.java	17 Jan 2002 00:15:05 -0000	1.87
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.86 2002/01/16 17:42:40 craigmcc Exp $
  - * $Revision: 1.86 $
  - * $Date: 2002/01/16 17:42:40 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.87 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.87 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -266,7 +266,7 @@
    *
    * @author Craig R. McClanahan
    * @author Ted Husted
  - * @version $Revision: 1.86 $ $Date: 2002/01/16 17:42:40 $
  + * @version $Revision: 1.87 $ $Date: 2002/01/17 00:15:05 $
    */
   
   public class ActionServlet
  @@ -376,12 +376,14 @@
        */
       public void destroy() {
   
  -    if (debug >= 1)
  -        log(internal.getMessage("finalizing"));
  +        if (debug >= 1) {
  +            log(internal.getMessage("finalizing"));
  +        }
   
           destroyDataSources();
           destroyApplications();
           destroyInternal();
  +        getServletContext().removeAttribute(Action.ACTION_SERVLET_KEY);
   
           // FIXME - destroy ApplicationConfig and message resource instances
   
  @@ -418,6 +420,7 @@
               initApplicationDataSources(ac);
           }
           destroyConfigDigester();
  +        getServletContext().setAttribute(Action.ACTION_SERVLET_KEY, this);
   
       }
   
  
  
  
  1.2       +13 -60    jakarta-struts/src/share/org/apache/struts/action/RequestProcessor.java
  
  Index: RequestProcessor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/RequestProcessor.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RequestProcessor.java	15 Jan 2002 03:00:17 -0000	1.1
  +++ RequestProcessor.java	17 Jan 2002 00:15:05 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/RequestProcessor.java,v 1.1 2002/01/15 03:00:17 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2002/01/15 03:00:17 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/RequestProcessor.java,v 1.2 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -92,7 +92,7 @@
    * interested in changing.</p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2002/01/15 03:00:17 $
  + * @version $Revision: 1.2 $ $Date: 2002/01/17 00:15:05 $
    * @since Struts 1.1
    */
   
  @@ -333,58 +333,10 @@
                                              HttpServletResponse response,
                                              ActionMapping mapping) {
   
  -        // Is there a form bean associated with this mapping?
  -        String attribute = mapping.getAttribute();
  -        if (attribute == null) {
  -            return (null);
  -        }
  -
  -        // Look up any existing form bean
  -        if (getDebug() >= 2) {
  -            log(" Looking for ActionForm bean instance in scope '" +
  -                mapping.getScope() + "' under attribute key '" +
  -                attribute + "'");
  -        }
  -        ActionForm instance = null;
  -        HttpSession session = null;
  -        if ("request".equals(mapping.getScope())) {
  -            instance = (ActionForm) request.getAttribute(attribute);
  -        } else {
  -            session = request.getSession();
  -            instance = (ActionForm) session.getAttribute(attribute);
  -        }
  -
  -        // Determine the form bean class we expect to use
  -        String name = mapping.getName();
  -        String className = null;
  -        FormBeanConfig config = appConfig.findFormBeanConfig(name);
  -        if (config != null) {
  -            className = config.getType();
  -        } else {
  -            return (null);
  -        }
  -
  -        // Can we recycle the existing form bean instance?
  -        if ((instance != null) &&
  -            className.equals(instance.getClass().getName())) {
  -            if (getDebug() >= 2) {
  -                log(" Recycling existing ActionForm bean instance of class '"
  -                    + className + "'");
  -            }
  -            return (instance);
  -        }
  -
  -        // Create a new form bean instance
  -        if (getDebug() >= 2) {
  -            log(" Creating new ActionForm bean instance of class '" +
  -                className + "'");
  -        }
  -        try {
  -            instance = null;
  -            Class clazz = Class.forName(className);
  -            instance = (ActionForm) clazz.newInstance();
  -        } catch (Throwable t) {
  -            log(getInternal().getMessage("formBean", className), t);
  +        // Create (if necessary a form bean to use
  +        ActionForm instance = RequestUtils.createActionForm
  +            (request, mapping, appConfig, servlet);
  +        if (instance == null) {
               return (null);
           }
   
  @@ -392,12 +344,13 @@
           if (getDebug() >= 2) {
               log(" Storing ActionForm bean instance in scope '" +
                   mapping.getScope() + "' under attribute key '" +
  -                attribute + "'");
  +                mapping.getAttribute() + "'");
           }
           if ("request".equals(mapping.getScope())) {
  -            request.setAttribute(attribute, instance);
  +            request.setAttribute(mapping.getAttribute(), instance);
           } else {
  -            session.setAttribute(attribute, instance);
  +            HttpSession session = request.getSession();
  +            session.setAttribute(mapping.getAttribute(), instance);
           }
           return (instance);
   
  @@ -1026,7 +979,7 @@
        * Return the debugging detail level that has been configured for our
        * controller servlet.
        */
  -    protected int getDebug() {
  +    public int getDebug() {
   
           return (servlet.getDebug());
   
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/action/DynaActionForm.java
  
  Index: DynaActionForm.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/DynaActionForm.java,v 1.1 2002/01/17 00:15:05 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2002/01/17 00:15:05 $
   *
   * ====================================================================
   *
   * 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 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.lang.reflect.Array;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import javax.servlet.ServletRequest;
  import javax.servlet.http.HttpServletRequest;
  import org.apache.commons.beanutils.ConversionException;
  import org.apache.commons.beanutils.DynaBean;
  import org.apache.commons.beanutils.DynaClass;
  import org.apache.commons.beanutils.DynaProperty;
  import org.apache.struts.config.FormBeanConfig;
  import org.apache.struts.config.FormPropertyConfig;
  
  
  /**
   * <p>Specialized subclass of <code>ActionForm</code> that allows the creation
   * of form beans with dynamic sets of properties, without requiring the
   * developer to create a Java class for each type of form bean.</p>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2002/01/17 00:15:05 $
   * @since Struts 1.1
   */
  
  public class DynaActionForm extends ActionForm implements DynaBean {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The DynaActionFormClass with which we are associated.
       */
      protected DynaActionFormClass dynaClass = null;
  
  
      /**
       * The set of property values for this DynaActionForm, keyed by
       * property name.
       */
      protected HashMap dynaValues = new HashMap();
  
  
      // ----------------------------------------------------- ActionForm 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 attempts to forward to the HTTP
       * version of this method.
       *
       * @param mapping The mapping used to select this instance
       * @param request The servlet request we are processing
       */
      public void reset(ActionMapping mapping, ServletRequest request) {
  
          try {
              reset(mapping, (HttpServletRequest) request);
          } catch (ClassCastException e) {
              ;
          }
  
      }
  
  
      /**
       * 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 uses the initial value specified in the
       * FormPropertyConfig element for each property.
       *
       * @param mapping The mapping used to select this instance
       * @param request The servlet request we are processing
       */
      public void reset(ActionMapping mapping, HttpServletRequest request) {
  
          String name = mapping.getName();
          if (name == null) {
              return;
          }
          FormBeanConfig config =
              mapping.getApplicationConfig().findFormBeanConfig(name);
          if (config == null) {
              return;
          }
          FormPropertyConfig props[] = config.findFormPropertyConfigs();
          for (int i = 0; i < props.length; i++) {
              set(props[i].getName(), props[i].initial());
          }
  
      }
  
  
      // ------------------------------------------------------- DynaBean Methods
  
  
      /**
       * Does the specified mapped property contain a value for the specified
       * key value?
       *
       * @param name Name of the property to check
       * @param key Name of the key to check
       *
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       */
      public boolean contains(String name, String key) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object value = dynaValues.get(name);
          if (value == null) {
              throw new NullPointerException
                  ("No mapped value for '" + name + "(" + key + ")'");
          } else if (value instanceof Map) {
              return (((Map) value).containsKey(key));
          } else {
              throw new IllegalArgumentException
                  ("Non-mapped property for '" + name + "(" + key + ")'");
          }
  
      }
  
  
      /**
       * Return the value of a simple property with the specified name.
       *
       * @param name Name of the property whose value is to be retrieved
       *
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       */
      public Object get(String name) {
  
          // Return any non-null value for the specified property
          Object value = dynaValues.get(name);
          if (value != null) {
              return (value);
          } 
  
          // Return a null value for a non-primitive property
          Class type = getDynaProperty(name).getType();
          if (!type.isPrimitive()) {
              return (value);
          }
  
          // Manufacture default values for primitive properties
          if (type == Boolean.TYPE) {
              return (Boolean.FALSE);
          } else if (type == Byte.TYPE) {
              return (new Byte((byte) 0));
          } else if (type == Character.TYPE) {
              return (new Character((char) 0));
          } else if (type == Double.TYPE) {
              return (new Double((double) 0.0));
          } else if (type == Float.TYPE) {
              return (new Float((float) 0.0));
          } else if (type == Integer.TYPE) {
              return (new Integer((int) 0));
          } else if (type == Long.TYPE) {
              return (new Long((int) 0));
          } else if (type == Short.TYPE) {
              return (new Short((short) 0));
          } else {
              return (null);
          }
  
      }
  
  
      /**
       * Return the value of an indexed property with the specified name.
       *
       * @param name Name of the property whose value is to be retrieved
       * @param index Index of the value to be retrieved
       *
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       * @exception IllegalArgumentException if the specified property
       *  exists, but is not indexed
       * @exception IndexOutOfBoundsException if the specified index
       *  is outside the range of the underlying property
       * @exception NullPointerException if no array or List has been
       *  initialized for this property
       */
      public Object get(String name, int index) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object value = dynaValues.get(name);
          if (value == null) {
              throw new NullPointerException
                  ("No indexed value for '" + name + "[" + index + "]'");
          } else if (value.getClass().isArray()) {
              return (Array.get(value, index));
          } else if (value instanceof List) {
              return ((List) value).get(index);
          } else {
              throw new IllegalArgumentException
                  ("Non-indexed property for '" + name + "[" + index + "]'");
          }
  
      }
  
  
      /**
       * Return the value of a mapped property with the specified name,
       * or <code>null</code> if there is no value for the specified key.
       *
       * @param name Name of the property whose value is to be retrieved
       * @param key Key of the value to be retrieved
       *
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       * @exception IllegalArgumentException if the specified property
       *  exists, but is not mapped
       */
      public Object get(String name, String key) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object value = dynaValues.get(name);
          if (value == null) {
              throw new NullPointerException
                  ("No mapped value for '" + name + "(" + key + ")'");
          } else if (value instanceof Map) {
              return (((Map) value).get(key));
          } else {
              throw new IllegalArgumentException
                  ("Non-mapped property for '" + name + "(" + key + ")'");
          }
  
      }
  
  
      /**
       * Return the <code>DynaClass</code> instance that describes the set of
       * properties available for this DynaBean.
       */
      public DynaClass getDynaClass() {
  
          return (this.dynaClass);
  
      }
  
  
      /**
       * Remove any existing value for the specified key on the
       * specified mapped property.
       *
       * @param name Name of the property for which a value is to
       *  be removed
       * @param key Key of the value to be removed
       *
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       */
      public void remove(String name, String key) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object value = dynaValues.get(name);
          if (value == null) {
              throw new NullPointerException
                  ("No mapped value for '" + name + "(" + key + ")'");
          } else if (value instanceof Map) {
              ((Map) value).remove(key);
          } else {
              throw new IllegalArgumentException
                  ("Non-mapped property for '" + name + "(" + key + ")'");
          }
  
      }
  
  
      /**
       * Set the value of a simple property with the specified name.
       *
       * @param name Name of the property whose value is to be set
       * @param value Value to which this property is to be set
       *
       * @exception ConversionException if the specified value cannot be
       *  converted to the type required for this property
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       * @exception NullPointerException if an attempt is made to set a
       *  primitive property to null
       */
      public void set(String name, Object value) {
  
          DynaProperty descriptor = getDynaProperty(name);
          if (value == null) {
              if (descriptor.getType().isPrimitive()) {
                  throw new NullPointerException
                      ("Primitive value for '" + name + "'");
              }
          } else if (!isDynaAssignable(descriptor.getType(), value.getClass())) {
              throw new ConversionException
                  ("Cannot assign value of type '" +
                   value.getClass().getName() +
                   "' to property '" + name + "' of type '" +
                   descriptor.getType().getName() + "'");
          }
          dynaValues.put(name, value);
  
      }
  
  
      /**
       * Set the value of an indexed property with the specified name.
       *
       * @param name Name of the property whose value is to be set
       * @param index Index of the property to be set
       * @param value Value to which this property is to be set
       *
       * @exception ConversionException if the specified value cannot be
       *  converted to the type required for this property
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       * @exception IllegalArgumentException if the specified property
       *  exists, but is not indexed
       * @exception IndexOutOfBoundsException if the specified index
       *  is outside the range of the underlying property
       */
      public void set(String name, int index, Object value) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object prop = dynaValues.get(name);
          if (prop == null) {
              throw new NullPointerException
                  ("No indexed value for '" + name + "[" + index + "]'");
          } else if (prop.getClass().isArray()) {
              Array.set(prop, index, value);
          } else if (prop instanceof List) {
              try {
                  ((List) prop).set(index, value);
              } catch (ClassCastException e) {
                  throw new ConversionException(e.getMessage());
              }
          } else {
              throw new IllegalArgumentException
                  ("Non-indexed property for '" + name + "[" + index + "]'");
          }
  
      }
  
  
      /**
       * Set the value of a mapped property with the specified name.
       *
       * @param name Name of the property whose value is to be set
       * @param key Key of the property to be set
       * @param value Value to which this property is to be set
       *
       * @exception ConversionException if the specified value cannot be
       *  converted to the type required for this property
       * @exception IllegalArgumentException if there is no property
       *  of the specified name
       * @exception IllegalArgumentException if the specified property
       *  exists, but is not mapped
       */
      public void set(String name, String key, Object value) {
  
          DynaProperty descriptor = getDynaProperty(name);
          Object prop = dynaValues.get(name);
          if (prop == null) {
              throw new NullPointerException
                  ("No mapped value for '" + name + "(" + key + ")'");
          } else if (prop instanceof Map) {
              ((Map) prop).put(key, value);
          } else {
              throw new IllegalArgumentException
                  ("Non-mapped property for '" + name + "(" + key + ")'");
          }
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Render a String representation of this object.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer("DynaActionForm[dynaClass=");
          sb.append(getDynaClass().getName());
          DynaProperty props[] = getDynaClass().getDynaProperties();
          if (props == null) {
              props = new DynaProperty[0];
          }
          for (int i = 0; i < props.length; i++) {
              sb.append(',');
              sb.append(props[i].getName());
              sb.append('=');
              sb.append(get(props[i].getName()));
          }
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Set the DynaActionFormClass instance that we are associated with.
       *
       * @param dynaClass The DynaActionFormClass instance for this bean
       */
      void setDynaActionFormClass(DynaActionFormClass dynaClass) {
  
          this.dynaClass = dynaClass;
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return the property descriptor for the specified property name.
       *
       * @param name Name of the property for which to retrieve the descriptor
       *
       * @exception IllegalArgumentException if this is not a valid property
       *  name for our DynaClass
       */
      protected DynaProperty getDynaProperty(String name) {
  
          DynaProperty descriptor = getDynaClass().getDynaProperty(name);
          if (descriptor == null) {
              throw new IllegalArgumentException
                  ("Invalid property name '" + name + "'");
          }
          return (descriptor);
  
      }
  
  
      /**
       * Is an object of the source class assignable to the destination class?
       *
       * @param dest Destination class
       * @param source Source class
       */
      protected boolean isDynaAssignable(Class dest, Class source) {
  
          if (dest.isAssignableFrom(source) ||
              ((dest == Boolean.TYPE) && (source == Boolean.class)) ||
              ((dest == Byte.TYPE) && (source == Byte.class)) ||
              ((dest == Character.TYPE) && (source == Character.class)) ||
              ((dest == Double.TYPE) && (source == Double.class)) ||
              ((dest == Float.TYPE) && (source == Float.class)) ||
              ((dest == Integer.TYPE) && (source == Integer.class)) ||
              ((dest == Long.TYPE) && (source == Long.class)) ||
              ((dest == Short.TYPE) && (source == Short.class))) {
              return (true);
          } else {
              return (false);
          }
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/action/DynaActionFormClass.java
  
  Index: DynaActionFormClass.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/DynaActionFormClass.java,v 1.1 2002/01/17 00:15:05 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2002/01/17 00:15:05 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2002 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 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.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import org.apache.commons.beanutils.DynaBean;
  import org.apache.commons.beanutils.DynaClass;
  import org.apache.commons.beanutils.DynaProperty;
  import org.apache.struts.config.FormBeanConfig;
  import org.apache.struts.config.FormPropertyConfig;
  
  
  /**
   * <p>Implementation of <code>DynaClass</code> for
   * <code>DynaActionForm</code> classes that allow developers to define
   * ActionForms without having to individually code all of the classes.
   * <strong>NOTE</strong> - This class is only used in the internal
   * implementation of dynamic action form beans.  Applications never need
   * to consult this documentation.</p>
   *
   * @author Craig McClanahan
   * @version $Revision: 1.1 $ $Date: 2002/01/17 00:15:05 $
   * @since Struts 1.1
   */
  
  public class DynaActionFormClass implements DynaClass {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new DynaActionFormClass for the specified form bean
       * configuration.  This constructor is private; DynaActionFormClass
       * instances will be created as needed via calls to the
       * static <code>createDynaActionFormClass()</code> method.
       *
       * @param config The FormBeanConfig instance describing the properties
       *  of the bean to be created
       *
       * @exception IllegalArgumentException if the bean implementation class
       *  specified in the configuration is not DynaActionForm (or a subclass
       *  of DynaActionForm)
       */
      private DynaActionFormClass(FormBeanConfig config) {
  
          introspect(config);
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The <code>DynaActionForm</code> implementation <code>Class</code> which
       * we will use to create new bean instances.
       */
      protected Class beanClass = null;
  
  
      /**
       * The "dynamic class name" for this <code>DynaClass</code>.
       */
      protected String name = null;
  
  
      /**
       * The set of dynamic properties that are part of this DynaClass.
       */
      protected DynaProperty properties[] = null;
  
  
      /**
       * The set of dynamic properties that are part of this DynaClass,
       * keyed by the property name.  Individual descriptor instances will
       * be the same instances as those in the <code>properties</code> list.
       */
      protected HashMap propertiesMap = new HashMap();
  
  
      // ------------------------------------------------------- Static Variables
  
  
      /**
       * The set of <code>DynaActionFormClass</code> instances that have
       * ever been created, keyed by the form bean name.
       */
      protected static HashMap dynaClasses = new HashMap();
  
  
      // ------------------------------------------------------ DynaClass Methods
  
  
      /**
       * Return the name of this DynaClass (analogous to the
       * <code>getName()</code> method of <code>java.lang.Class</code), which
       * allows the same <code>DynaClass</code> implementation class to support
       * different dynamic classes, with different sets of properties.
       */
      public String getName() {
  
          return (this.name);
  
      }
  
  
      /**
       * Return a property descriptor for the specified property, if it exists;
       * otherwise, return <code>null</code>.
       *
       * @param name Name of the dynamic property for which a descriptor
       *  is requested
       *
       * @exception IllegalArgumentException if no property name is specified
       */
      public DynaProperty getDynaProperty(String name) {
  
          if (name == null) {
              throw new IllegalArgumentException
                  ("No property name specified");
          }
          return ((DynaProperty) propertiesMap.get(name));
  
      }
  
  
      /**
       * <p>Return an array of <code>DynaProperty</code>s for the properties
       * currently defined in this DynaClass.  If no properties are defined, a
       * zero-length array will be returned.</p>
       *
       * <p><strong>FIXME</strong> - Should we really be implementing
       * <code>getBeanInfo()</code> instead, which returns property descriptors
       * and a bunch of other stuff?</p>
       */
      public DynaProperty[] getDynaProperties() {
  
          return (properties);
  
      }
  
  
      /**
       * <p>Instantiate and return a new DynaBean instance, associated
       * with this DynaClass.  <strong>NOTE</strong> - This operation is not
       * supported, and throws an exception.  You should create new
       * <code>WrapDynaBean</code> instances by calling its constructor:</p>
       * <pre>
       *   Object javaBean = ...;
       *   DynaBean wrapper = new WrapDynaBean(javaBean);
       * </pre>
       *
       * @exception IllegalAccessException if the Class or the appropriate
       *  constructor is not accessible
       * @exception InstantiationException if this Class represents an abstract
       *  class, an array class, a primitive type, or void; or if instantiation
       *  fails for some other reason
       */
      public DynaBean newInstance()
          throws IllegalAccessException, InstantiationException {
  
          DynaActionForm dynaBean = (DynaActionForm) beanClass.newInstance();
          dynaBean.setDynaActionFormClass(this);
          return (dynaBean);
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Render a String representation of this object.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer("DynaActionFormBean[name=");
          sb.append(name);
          DynaProperty props[] = getDynaProperties();
          if (props == null) {
              props = new DynaProperty[0];
          }
          for (int i = 0; i < props.length; i++) {
              sb.append(',');
              sb.append(props[i].getName());
              sb.append('/');
              sb.append(props[i].getType());
          }
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // --------------------------------------------------------- Static Methods
  
  
      /**
       * Clear our cache of DynaActionFormClass instances.
       */
      public static void clear() {
  
          synchronized (dynaClasses) {
              dynaClasses.clear();
          }
  
      }
  
  
      /**
       * Create (if necessary) and return a new <code>DynaActionFormClass</code>
       * instance for the specified form bean configuration instance.
       *
       * @param config The FormBeanConfig instance describing the properties
       *  of the bean to be created
       *
       * @exception IllegalArgumentException if the bean implementation class
       *  specified in the configuration is not DynaActionForm (or a subclass
       *  of DynaActionForm)
       */
      public static DynaActionFormClass
          createDynaActionFormClass(FormBeanConfig config) {
  
          synchronized (dynaClasses) {
              DynaActionFormClass dynaClass =
                  (DynaActionFormClass) dynaClasses.get(config.getName());
              if (dynaClass == null) {
                  dynaClass = new DynaActionFormClass(config);
                  dynaClasses.put(config.getName(), dynaClass);
              }
              return (dynaClass);
          }
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Introspect our form bean configuration to identify the supported
       * properties.
       *
       * @param config The FormBeanConfig instance describing the properties
       *  of the bean to be created
       *
       * @exception IllegalArgumentException if the bean implementation class
       *  specified in the configuration is not DynaActionForm (or a subclass
       *  of DynaActionForm)
       */
      protected void introspect(FormBeanConfig config) {
  
          // Validate the ActionFormBean implementation class
          try {
              // FIXME - Use thread context loader?
              beanClass = Class.forName(config.getType());
          } catch (Throwable t) {
              throw new IllegalArgumentException
                  ("Cannot instantiate ActionFormBean class '" +
                   config.getType() + "': " + t);
          }
          if (!beanClass.isAssignableFrom(DynaActionForm.class)) {
              throw new IllegalArgumentException
                  ("Class '" + config.getType() + "' is not a subclass of " +
                   "'org.apache.struts.action.DynaActionForm'");
          }
  
          // Set the name we will know ourselves by from the form bean name
          this.name = config.getName();
  
          // Look up the property descriptors for this bean class
          FormPropertyConfig descriptors[] = config.findFormPropertyConfigs();
          if (descriptors == null) {
              descriptors = new FormPropertyConfig[0];
          }
  
          // Create corresponding dynamic property definitions
          properties = new DynaProperty[descriptors.length];
          for (int i = 0; i < descriptors.length; i++) {
              // FIXME - special handling needed for arrays???
              Class clazz = null;
              try {
                  // FIXME - thread context class loader?
                  clazz = Class.forName(descriptors[i].getType());
              } catch (Throwable t) {
                  throw new IllegalArgumentException
                      ("Cannot instantiate property class '" +
                       descriptors[i].getType() + "' for property '" +
                       descriptors[i].getName() + "'");
              }
              properties[i] =
                  new DynaProperty(descriptors[i].getName(), clazz);
              propertiesMap.put(properties[i].getName(),
                                properties[i]);
          }
  
      }
  
  
  }
  
  
  
  1.6       +8 -4      jakarta-struts/src/share/org/apache/struts/config/ConfigRuleSet.java
  
  Index: ConfigRuleSet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/ConfigRuleSet.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ConfigRuleSet.java	16 Jan 2002 17:42:40 -0000	1.5
  +++ ConfigRuleSet.java	17 Jan 2002 00:15:05 -0000	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/ConfigRuleSet.java,v 1.5 2002/01/16 17:42:40 craigmcc Exp $
  - * $Revision: 1.5 $
  - * $Date: 2002/01/16 17:42:40 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/ConfigRuleSet.java,v 1.6 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.6 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -74,7 +74,7 @@
    * configuration file (<code>struts-config.xml</code>).</p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.5 $ $Date: 2002/01/16 17:42:40 $
  + * @version $Revision: 1.6 $ $Date: 2002/01/17 00:15:05 $
    * @since Struts 1.1
    */
   
  @@ -192,6 +192,10 @@
                "className");
           digester.addSetProperties
               ("struts-config/form-beans/form-bean/form-property");
  +        digester.addSetNext
  +            ("struts-config/form-beans/form-bean/form-property",
  +             "addFormPropertyConfig",
  +             "org.apache.struts.config.FormPropertyConfig");
   
           digester.addSetProperty
               ("struts-config/form-beans/form-bean/form-property/set-property",
  
  
  
  1.3       +22 -4     jakarta-struts/src/share/org/apache/struts/config/FormBeanConfig.java
  
  Index: FormBeanConfig.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormBeanConfig.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FormBeanConfig.java	15 Jan 2002 20:22:20 -0000	1.2
  +++ FormBeanConfig.java	17 Jan 2002 00:15:05 -0000	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormBeanConfig.java,v 1.2 2002/01/15 20:22:20 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2002/01/15 20:22:20 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormBeanConfig.java,v 1.3 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -73,7 +73,7 @@
    * configuration file.<p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2002/01/15 20:22:20 $
  + * @version $Revision: 1.3 $ $Date: 2002/01/17 00:15:05 $
    * @since Struts 1.1
    */
   
  @@ -94,6 +94,21 @@
   
   
       /**
  +     * Is the form bean class an instance of DynaActionForm with dynamic
  +     * properties?
  +     */
  +    protected boolean dynamic = false;
  +
  +    public boolean getDynamic() {
  +        return (this.dynamic);
  +    }
  +
  +    public void setDynamic(boolean dynamic) {
  +        this.dynamic = dynamic;
  +    }
  +
  +
  +    /**
        * The unique identifier of this form bean, which is used to reference this
        * bean in <code>ActionMapping</code> instances as well as for the name of
        * the request or session attribute under which the corresponding form bean
  @@ -122,6 +137,9 @@
   
       public void setType(String type) {
           this.type = type;
  +        if ("org.apache.struts.action.DynaActionForm".equals(type)) {
  +            this.dynamic = true;
  +        }
       }
   
   
  
  
  
  1.2       +77 -3     jakarta-struts/src/share/org/apache/struts/config/FormPropertyConfig.java
  
  Index: FormPropertyConfig.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormPropertyConfig.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FormPropertyConfig.java	15 Jan 2002 20:22:20 -0000	1.1
  +++ FormPropertyConfig.java	17 Jan 2002 00:15:05 -0000	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormPropertyConfig.java,v 1.1 2002/01/15 20:22:20 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2002/01/15 20:22:20 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/config/FormPropertyConfig.java,v 1.2 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -64,6 +64,7 @@
   
   
   import java.io.Serializable;
  +import org.apache.commons.beanutils.ConvertUtils;
   
   
   /**
  @@ -72,17 +73,46 @@
    * configuration file.<p>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2002/01/15 20:22:20 $
  + * @version $Revision: 1.2 $ $Date: 2002/01/17 00:15:05 $
    * @since Struts 1.1
    */
   
   public class FormPropertyConfig implements Serializable {
   
   
  +    // ----------------------------------------------------- Instance Variables
  +
  +
  +    /**
  +     * Have we calculated the initial value object yet?
  +     */
  +    protected transient boolean initialized = false;
  +
  +
  +    /**
  +     * The calculated initial value for this property.
  +     */
  +    protected transient Object initialValue = null;
  +
  +
       // ------------------------------------------------------------- Properties
   
   
       /**
  +     * String representation of the initial value for this property.
  +     */
  +    protected String initial = null;
  +
  +    public String getInitial() {
  +        return (this.initial);
  +    }
  +
  +    public void setInitial(String initial) {
  +        this.initial = initial;
  +    }
  +
  +
  +    /**
        * The JavaBean property name of the property described by this element.
        */
       protected String name = null;
  @@ -116,6 +146,48 @@
   
   
       /**
  +     * Return an object representing the initial value of this property.
  +     */
  +    public Object initial() {
  +
  +        // Don't bother synchronizing, a race is basically harmless
  +        if (!initialized) {
  +            try {
  +                if (initial == null) {
  +                    if ("boolean".equals(type)) {
  +                        initialValue = Boolean.FALSE;
  +                    } else if ("byte".equals(type)) {
  +                        initialValue = new Byte((byte) 0);
  +                    } else if ("char".equals(type)) {
  +                        initialValue = new Character((char) 0);
  +                    } else if ("double".equals(type)) {
  +                        initialValue = new Double((double) 0.0);
  +                    } else if ("float".equals(type)) {
  +                        initialValue = new Float((float) 0.0);
  +                    } else if ("int".equals(type)) {
  +                        initialValue = new Integer(0);
  +                    } else if ("long".equals(type)) {
  +                        initialValue = new Long((long) 0);
  +                    } else if ("short".equals(type)) {
  +                        initialValue = new Short((short) 0);
  +                    } else {
  +                        initialValue = null;
  +                    }
  +                } else {
  +                    Class clazz = Class.forName(type);
  +                    initialValue = ConvertUtils.convert(initial, clazz);
  +                }
  +            } catch (Throwable t) {
  +                initialValue = null;
  +            }
  +            initialized = true;
  +        }
  +        return (initialValue);
  +
  +    }
  +
  +
  +    /**
        * Return a String representation of this object.
        */
       public String toString() {
  @@ -125,6 +197,8 @@
           sb.append(this.name);
           sb.append(",type=");
           sb.append(this.type);
  +        sb.append(",initial=");
  +        sb.append(this.initial);
           sb.append("]");
           return (sb.toString());
   
  
  
  
  1.17      +53 -58    jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java
  
  Index: FormTag.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- FormTag.java	13 Jan 2002 00:25:37 -0000	1.16
  +++ FormTag.java	17 Jan 2002 00:15:05 -0000	1.17
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v 1.16 2002/01/13 00:25:37 craigmcc Exp $
  - * $Revision: 1.16 $
  - * $Date: 2002/01/13 00:25:37 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/taglib/html/FormTag.java,v 1.17 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.17 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -74,11 +74,12 @@
   import javax.servlet.jsp.tagext.TagSupport;
   import org.apache.struts.action.Action;
   import org.apache.struts.action.ActionForm;
  -import org.apache.struts.action.ActionFormBean;
   import org.apache.struts.action.ActionMapping;
   import org.apache.struts.action.ActionServlet;
   import org.apache.struts.config.ApplicationConfig;
  +import org.apache.struts.config.FormBeanConfig;
   import org.apache.struts.util.MessageResources;
  +import org.apache.struts.util.RequestUtils;
   import org.apache.struts.util.ResponseUtils;
   
   
  @@ -87,7 +88,7 @@
    * properties correspond to the various fields of the form.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.16 $ $Date: 2002/01/13 00:25:37 $
  + * @version $Revision: 1.17 $ $Date: 2002/01/17 00:15:05 $
    */
   
   public class FormTag extends TagSupport {
  @@ -103,6 +104,12 @@
   
   
       /**
  +     * The application configuration for our sub-application.
  +     */
  +    protected ApplicationConfig appConfig = null;
  +
  +
  +    /**
        * The content encoding to be used on a POST submit.
        */
       protected String enctype = null;
  @@ -123,6 +130,12 @@
   
   
       /**
  +     * The ActionMapping defining where we will be submitting this form
  +     */
  +    protected ActionMapping mapping = null;
  +
  +
  +    /**
        * The message resources for this package.
        */
       protected static MessageResources messages =
  @@ -555,34 +568,15 @@
   	    scope = PageContext.REQUEST_SCOPE;
   	Object bean = pageContext.getAttribute(name, scope);
   	if (bean == null) {
  -	    if (type == null)
  -	        throw new JspException
  -		    (messages.getMessage("getter.bean", name));
  -	    try {
  -		Class clazz = Class.forName(type);
  -		bean = clazz.newInstance();
  -                if (bean instanceof ActionForm) {
  -                    ActionForm form = (ActionForm)bean;
  -                    ApplicationConfig config = (ApplicationConfig)
  -                        pageContext.getRequest().getAttribute
  -                          (Action.APPLICATION_KEY);
  -                    if (config == null) { // Backwards compatibility hack
  -                        config = (ApplicationConfig)
  -                            pageContext.getServletContext().getAttribute
  -                              (Action.APPLICATION_KEY);
  -                    }
  -                    form.setServlet(servlet);
  -                    form.reset((ActionMapping)
  -                               config.findActionConfig(getActionMappingName()),
  -                               pageContext.getRequest());
  -                }
  -	    } catch (Exception e) {
  -		throw new JspException
  -		    (messages.getMessage("formTag.create", type,
  -					 e.toString()));
  -	    }
  -	    pageContext.setAttribute(name, bean, scope);
  -	}
  +            bean = RequestUtils.createActionForm
  +                ((HttpServletRequest) pageContext.getRequest(),
  +                 mapping, appConfig, servlet);
  +            if (bean == null) {
  +                throw new JspException
  +                    (messages.getMessage("formTag.create", type));
  +            }
  +            pageContext.setAttribute(name, bean, scope);
  +        }
   	pageContext.setAttribute(Constants.BEAN_KEY, bean,
                                    PageContext.REQUEST_SCOPE);
   
  @@ -658,8 +652,10 @@
   
   	super.release();
   	action = null;
  +        appConfig = null;
   	enctype = null;
   	focus = null;
  +        mapping = null;
   	method = "POST";
   	name = null;
   	onreset = null;
  @@ -768,39 +764,25 @@
        */
       protected void lookup() throws JspException {
   
  -        // Were the required values already specified?
  -        if (name != null) {
  -            if (scope == null)
  -                scope = "session";
  -            if (type == null) {
  -                JspException e = new JspException
  -                    (messages.getMessage("formTag.nameType"));
  -                pageContext.setAttribute(Action.EXCEPTION_KEY, e,
  -                                         PageContext.REQUEST_SCOPE);
  -                throw e;
  -            }
  -            return;
  -        }
  -
           // Look up the application configuration information we need
  -        ApplicationConfig config = (ApplicationConfig)
  +        appConfig = (ApplicationConfig)
               pageContext.getRequest().getAttribute(Action.APPLICATION_KEY);
  -        if (config == null) { // Backwards compatibility hack
  -            config = (ApplicationConfig)
  +        if (appConfig == null) { // Backwards compatibility hack
  +            appConfig = (ApplicationConfig)
                   pageContext.getServletContext().getAttribute(Action.APPLICATION_KEY);
           }
  -        if (config == null) {
  +        if (appConfig == null) {
               JspException e = new JspException
                   (messages.getMessage("formTag.collections"));
               pageContext.setAttribute(Action.EXCEPTION_KEY, e,
                                        PageContext.REQUEST_SCOPE);
               throw e;
           }
  +        servlet = appConfig.getServlet();
   
           // Look up the action mapping we will be submitting to
           String mappingName = getActionMappingName();
  -        ActionMapping mapping = (ActionMapping)
  -            config.findActionConfig(mappingName);
  +        mapping = (ActionMapping) appConfig.findActionConfig(mappingName);
           if (mapping == null) {
               JspException e = new JspException
                   (messages.getMessage("formTag.mapping", mappingName));
  @@ -809,10 +791,24 @@
               throw e;
           }
   
  +        // Were the required values already specified?
  +        if (name != null) {
  +            if (scope == null)
  +                scope = "session";
  +            if (type == null) {
  +                JspException e = new JspException
  +                    (messages.getMessage("formTag.nameType"));
  +                pageContext.setAttribute(Action.EXCEPTION_KEY, e,
  +                                         PageContext.REQUEST_SCOPE);
  +                throw e;
  +            }
  +            return;
  +        }
  +
           // Look up the form bean definition
  -        ActionFormBean formBean = (ActionFormBean)
  -            config.findFormBeanConfig(mapping.getName());
  -        if (formBean == null) {
  +        FormBeanConfig formBeanConfig =
  +            appConfig.findFormBeanConfig(mapping.getName());
  +        if (formBeanConfig == null) {
               JspException e = new JspException
                   (messages.getMessage("formTag.formBean", mapping.getName()));
               pageContext.setAttribute(Action.EXCEPTION_KEY, e,
  @@ -823,8 +819,7 @@
           // Calculate the required values
           name = mapping.getName();
           scope = mapping.getScope();
  -        servlet = config.getServlet();
  -        type = formBean.getType();
  +        type = formBeanConfig.getType();
   
       }
   }
  
  
  
  1.28      +107 -5    jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java
  
  Index: RequestUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v
  retrieving revision 1.27
  retrieving revision 1.28
  diff -u -r1.27 -r1.28
  --- RequestUtils.java	13 Jan 2002 00:25:37 -0000	1.27
  +++ RequestUtils.java	17 Jan 2002 00:15:05 -0000	1.28
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v 1.27 2002/01/13 00:25:37 craigmcc Exp $
  - * $Revision: 1.27 $
  - * $Date: 2002/01/13 00:25:37 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v 1.28 2002/01/17 00:15:05 craigmcc Exp $
  + * $Revision: 1.28 $
  + * $Date: 2002/01/17 00:15:05 $
    *
    * ====================================================================
    *
  @@ -82,6 +82,7 @@
   import javax.servlet.jsp.JspException;
   import javax.servlet.jsp.PageContext;
   import org.apache.commons.beanutils.BeanUtils;
  +import org.apache.commons.beanutils.DynaBean;
   import org.apache.commons.beanutils.PropertyUtils;
   import org.apache.struts.action.Action;
   import org.apache.struts.action.ActionError;
  @@ -91,8 +92,11 @@
   import org.apache.struts.action.ActionMapping;
   import org.apache.struts.action.ActionMessage;
   import org.apache.struts.action.ActionMessages;
  +import org.apache.struts.action.ActionServlet;
   import org.apache.struts.action.ActionServletWrapper;
  +import org.apache.struts.action.DynaActionFormClass;
   import org.apache.struts.config.ApplicationConfig;
  +import org.apache.struts.config.FormBeanConfig;
   import org.apache.struts.taglib.html.Constants;
   import org.apache.struts.upload.FormFile;
   import org.apache.struts.upload.MultipartRequestHandler;
  @@ -104,7 +108,7 @@
    *
    * @author Craig R. McClanahan
    * @author Ted Husted
  - * @version $Revision: 1.27 $ $Date: 2002/01/13 00:25:37 $
  + * @version $Revision: 1.28 $ $Date: 2002/01/17 00:15:05 $
    */
   
   public class RequestUtils {
  @@ -464,6 +468,104 @@
   
   
       /**
  +     * Create (if necessary) and return an ActionForm instance appropriate
  +     * for this request.  If no ActionForm instance is required, return
  +     * <code>null</code>.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param mapping The action mapping for this request
  +     * @param appConfig The application configuration for this sub-application
  +     */
  +    public static ActionForm createActionForm(HttpServletRequest request,
  +                                              ActionMapping mapping,
  +                                              ApplicationConfig appConfig,
  +                                              ActionServlet servlet) {
  +
  +        // Is there a form bean associated with this mapping?
  +        String attribute = mapping.getAttribute();
  +        if (attribute == null) {
  +            return (null);
  +        }
  +
  +        // Look up the form bean configuration information to use
  +        String name = mapping.getName();
  +        FormBeanConfig config = appConfig.findFormBeanConfig(name);
  +        if (config == null) {
  +            return (null);
  +        }
  +
  +        // Look up any existing form bean instance
  +        if (appConfig.getControllerConfig().getDebug() >= 2) {
  +            servlet.log(" Looking for ActionForm bean instance in scope '" +
  +                        mapping.getScope() + "' under attribute key '" +
  +                        attribute + "'");
  +        }
  +        ActionForm instance = null;
  +        HttpSession session = null;
  +        if ("request".equals(mapping.getScope())) {
  +            instance = (ActionForm) request.getAttribute(attribute);
  +        } else {
  +            session = request.getSession();
  +            instance = (ActionForm) session.getAttribute(attribute);
  +        }
  +
  +        // Can we recycle the existing form bean instance (if there is one)?
  +        if (instance != null) {
  +            if (config.getDynamic()) {
  +                String className =
  +                    ((DynaBean) instance).getDynaClass().getName();
  +                if (className.equals(config.getName())) {
  +                    if (appConfig.getControllerConfig().getDebug() >= 2) {
  +                        servlet.log
  +                            (" Recycling existing DynaActionForm instance " +
  +                            "of type '" + className + "'");
  +                    }
  +                    return (instance);
  +                }
  +            } else {
  +                String className =
  +                    instance.getClass().getName();
  +                if (className.equals(config.getType())) {
  +                    if (appConfig.getControllerConfig().getDebug() >= 2) {
  +                        servlet.log
  +                            (" Recycling existing ActionForm instance " +
  +                            "of class '" + className + "'");
  +                    }
  +                    return (instance);
  +                }
  +            }
  +        }
  +
  +        // Create and return a new form bean instance
  +        if (config.getDynamic()) {
  +            try {
  +                DynaActionFormClass dynaClass =
  +                    DynaActionFormClass.createDynaActionFormClass(config);
  +                instance = (ActionForm) dynaClass.newInstance();
  +            } catch (Throwable t) {
  +                servlet.log(servlet.getInternal().getMessage
  +                            ("formBean", config.getName()), t);
  +                return (null);
  +            }
  +        } else {
  +            try {
  +                // FIXME - thread context class loader?
  +                Class clazz = Class.forName(config.getType());
  +                instance = (ActionForm) clazz.newInstance();
  +            } catch (Throwable t) {
  +                servlet.log(servlet.getInternal().getMessage
  +                            ("formBean", config.getType()), t);
  +                return (null);
  +            }
  +        }
  +        instance.setServlet(servlet);
  +        instance.reset(mapping, request);
  +        return (instance);
  +
  +    }
  +
  +
  +    /**
        * Locate and return the specified bean, from an optionally specified
        * scope, in the specified page context.  If no such bean is found,
        * return <code>null</code> instead.  If an exception is thrown, it will
  @@ -478,7 +580,7 @@
        *  is requested
        */
       public static Object lookup(PageContext pageContext, String name,
  -    String scope) throws JspException {
  +                                String scope) throws JspException {
   
           Object bean = null;
           if (scope == null)
  
  
  
  1.15      +8 -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.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- struts-config.xml	31 Dec 2001 01:14:36 -0000	1.14
  +++ struts-config.xml	17 Jan 2002 00:15:05 -0000	1.15
  @@ -47,8 +47,16 @@
     <form-beans>
   
       <!-- Logon form bean -->
  +<!--
       <form-bean      name="logonForm"
                       type="org.apache.struts.webapp.example.LogonForm"/>
  +-->
  +    <form-bean      name="logonForm"
  +                    type="org.apache.struts.action.DynaActionForm">
  +      <form-property name="username" type="java.lang.String"/>
  +      <form-property name="password" type="java.lang.String"/>
  +    </form-bean>
  +
   
       <!-- Registration form bean -->
       <form-bean      name="registrationForm"
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>