Package org.g4studio.core.mvc.xstruts.action

Source Code of org.g4studio.core.mvc.xstruts.action.DynaActionForm

package org.g4studio.core.mvc.xstruts.action;

import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

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.g4studio.core.mvc.xstruts.config.FormBeanConfig;
import org.g4studio.core.mvc.xstruts.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>
*
* <p>
* <strong>USAGE NOTE</strong> - Since Struts 1.1, the <code>reset</code> method
* no longer initializes property values to those specified in
* <code>&lt;form-property&gt;</code> elements in the Struts module
* configuration file. If you wish to utilize that behavior, the simplest
* solution is to subclass <code>DynaActionForm</code> and call the
* <code>initialize</code> method inside it.
* </p>
*
* @version $Rev: 421119 $ $Date: 2005-11-12 11:52:08 -0500 (Sat, 12 Nov 2005) $
* @since Struts 1.1
*/
public class DynaActionForm extends ActionForm implements DynaBean {
  // ----------------------------------------------------- Instance Variables

  /**
   * <p>
   * The <code>DynaActionFormClass</code> with which we are associated.
   * </p>
   */
  protected DynaActionFormClass dynaClass = null;

  /**
   * <p>
   * The set of property values for this <code>DynaActionForm</code>, keyed by
   * property name.
   * </p>
   */
  protected HashMap dynaValues = new HashMap();

  // ----------------------------------------------------- ActionForm Methods

  /**
   * <p>
   * Initialize all bean properties to their initial values, as specified in
   * the {@link FormPropertyConfig} elements associated with the definition of
   * this <code>DynaActionForm</code>.
   * </p>
   *
   * @param mapping
   *            The mapping used to select this instance
   */
  public void initialize(ActionMapping mapping) {
    String name = mapping.getName();

    if (name == null) {
      return;
    }

    FormBeanConfig config = mapping.getModuleConfig().findFormBeanConfig(name);

    if (config == null) {
      return;
    }

    initialize(config);
  }

  /**
   * <p>
   * Initialize the specified form bean.
   * </p>
   *
   * @param config
   *            The configuration for the form bean to initialize.
   */
  public void initialize(FormBeanConfig config) {
    FormPropertyConfig[] props = config.findFormPropertyConfigs();

    for (int i = 0; i < props.length; i++) {
      set(props[i].getName(), props[i].initial());
    }
  }

  // :FIXME: Is there any point in retaining these reset methods
  // since they now simply replicate the superclass behavior?

  /**
   * <p>
   * Reset bean properties to their default state, as needed. This method is
   * called before the properties are repopulated by the controller.
   * </p>
   *
   * <p>
   * The default implementation attempts to forward to the HTTP version of
   * this method.
   * </p>
   *
   * @param mapping
   *            The mapping used to select this instance
   * @param request
   *            The servlet request we are processing
   */
  public void reset(ActionMapping mapping, ServletRequest request) {
    super.reset(mapping, request);
  }

  /**
   * <p>
   * Reset the properties to their <code>initial</code> value if their
   * <code>reset</code> configuration is set to true or if <code>reset</code>
   * is set to a list of HTTP request methods that includes the method of
   * given <code>request</code> object.
   * </p>
   *
   * @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 = getDynaClass().getName();

    if (name == null) {
      return;
    }

    FormBeanConfig config = mapping.getModuleConfig().findFormBeanConfig(name);

    if (config == null) {
      return;
    }

    // look for properties we should reset
    FormPropertyConfig[] props = config.findFormPropertyConfigs();

    for (int i = 0; i < props.length; i++) {
      String resetValue = props[i].getReset();

      // skip this property if there's no reset value
      if ((resetValue == null) || (resetValue.length() <= 0)) {
        continue;
      }

      boolean reset = Boolean.valueOf(resetValue).booleanValue();

      if (!reset) {
        // check for the request method
        // use a StringTokenizer with the default delimiters + a comma
        StringTokenizer st = new StringTokenizer(resetValue, ", \t\n\r\f");

        while (st.hasMoreTokens()) {
          String token = st.nextToken();

          if (token.equalsIgnoreCase(request.getMethod())) {
            reset = true;

            break;
          }
        }
      }

      if (reset) {
        set(props[i].getName(), props[i].initial());
      }
    }
  }

  // ------------------------------------------------------- DynaBean Methods

  /**
   * <p>
   * Indicates if the specified mapped property contain a value for the
   * specified key value.
   * </p>
   *
   * @param name
   *            Name of the property to check
   * @param key
   *            Name of the key to check
   * @return <code>true</code> if the specified mapped property contains a
   *         value for the specified key value; <code>true</code> otherwise.
   * @throws NullPointerException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if there is no mapped property of the specified name
   */
  public boolean contains(String name, String key) {
    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 + ")'");
    }
  }

  /**
   * <p>
   * Return the value of a simple property with the specified name.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be retrieved
   * @return The value of a simple property with the specified name.
   * @throws IllegalArgumentException
   *             if there is no property of the specified name
   * @throws NullPointerException
   *             if the type specified for the property is invalid
   */
  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 == null) {
      throw new NullPointerException("The type for property " + name + " is invalid");
    }

    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(0.0));
    } else if (type == Float.TYPE) {
      return (new Float((float) 0.0));
    } else if (type == Integer.TYPE) {
      return (new Integer(0));
    } else if (type == Long.TYPE) {
      return (new Long(0));
    } else if (type == Short.TYPE) {
      return (new Short((short) 0));
    } else {
      return (null);
    }
  }

  /**
   * <p>
   * Return the value of an indexed property with the specified name.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be retrieved
   * @param index
   *            Index of the value to be retrieved
   * @return The value of an indexed property with the specified name.
   * @throws IllegalArgumentException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if the specified property exists, but is not indexed
   * @throws NullPointerException
   *             if no array or List has been initialized for this property
   */
  public Object get(String name, int index) {
    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 + "]'");
    }
  }

  /**
   * <p>
   * Return the value of a mapped property with the specified name, or
   * <code>null</code> if there is no value for the specified key.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be retrieved
   * @param key
   *            Key of the value to be retrieved
   * @return The value of a mapped property with the specified name, or
   *         <code>null</code> if there is no value for the specified key.
   * @throws NullPointerException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if the specified property exists, but is not mapped
   */
  public Object get(String name, String key) {
    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 + ")'");
    }
  }

  /**
   * <p>
   * Return the value of a <code>String</code> property with the specified
   * name. This is equivalent to calling <code>(String)
   * dynaForm.get(name)</code>.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be retrieved.
   * @return The value of a <code>String</code> property with the specified
   *         name.
   * @throws IllegalArgumentException
   *             if there is no property of the specified name
   * @throws NullPointerException
   *             if the type specified for the property is invalid
   * @throws ClassCastException
   *             if the property is not a String.
   * @since Struts 1.2
   */
  public String getString(String name) {
    return (String) this.get(name);
  }

  /**
   * <p>
   * Return the value of a <code>String[]</code> property with the specified
   * name. This is equivalent to calling <code>(String[])
   * dynaForm.get(name)</code>.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be retrieved.
   * @return The value of a <code>String[]</code> property with the specified
   *         name.
   * @throws IllegalArgumentException
   *             if there is no property of the specified name
   * @throws NullPointerException
   *             if the type specified for the property is invalid
   * @throws ClassCastException
   *             if the property is not a String[].
   * @since Struts 1.2
   */
  public String[] getStrings(String name) {
    return (String[]) this.get(name);
  }

  /**
   * <p>
   * Return the <code>DynaClass</code> instance that describes the set of
   * properties available for this <code>DynaBean</code>.
   * </p>
   *
   * @return The <code>DynaClass</code> instance that describes the set of
   *         properties available for this <code>DynaBean</code>.
   */
  public DynaClass getDynaClass() {
    return (this.dynaClass);
  }

  /**
   * <p>
   * Returns the <code>Map</code> containing the property values. This is done
   * mostly to facilitate accessing the <code>DynaActionForm</code> through
   * JavaBeans accessors, in order to use the JavaServer Pages Standard Tag
   * Library (JSTL).
   * </p>
   *
   * <p>
   * For instance, the normal JSTL EL syntax for accessing an
   * <code>ActionForm</code> would be something like this:
   *
   * <pre>
   *  ${formbean.prop}
   * </pre>
   *
   * The JSTL EL syntax for accessing a <code>DynaActionForm</code> looks
   * something like this (because of the presence of this
   * <code>getMap()</code> method):
   *
   * <pre>
   *  ${dynabean.map.prop}
   * </pre>
   *
   * </p>
   *
   * @return The <code>Map</code> containing the property values.
   */
  public Map getMap() {
    return (dynaValues);
  }

  /**
   * <p>
   * Remove any existing value for the specified key on the specified mapped
   * property.
   * </p>
   *
   * @param name
   *            Name of the property for which a value is to be removed
   * @param key
   *            Key of the value to be removed
   * @throws NullPointerException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if there is no mapped property of the specified name
   */
  public void remove(String name, String key) {
    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 + ")'");
    }
  }

  /**
   * <p>
   * Set the value of a simple property with the specified name.
   * </p>
   *
   * @param name
   *            Name of the property whose value is to be set
   * @param value
   *            Value to which this property is to be set
   * @throws ConversionException
   *             if the specified value cannot be converted to the type
   *             required for this property
   * @throws IllegalArgumentException
   *             if there is no property of the specified name
   * @throws NullPointerException
   *             if the type specified for the property is invalid
   * @throws 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 (descriptor.getType() == null) {
      throw new NullPointerException("The type for property " + name + " is invalid");
    }

    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);
  }

  /**
   * <p>
   * Set the value of an indexed property with the specified name.
   * </p>
   *
   * @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
   * @throws ConversionException
   *             if the specified value cannot be converted to the type
   *             required for this property
   * @throws NullPointerException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if the specified property exists, but is not indexed
   * @throws IndexOutOfBoundsException
   *             if the specified index is outside the range of the underlying
   *             property
   */
  public void set(String name, int index, Object value) {
    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 + "]'");
    }
  }

  /**
   * <p>
   * Set the value of a mapped property with the specified name.
   * </p>
   *
   * @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
   * @throws NullPointerException
   *             if there is no property of the specified name
   * @throws IllegalArgumentException
   *             if the specified property exists, but is not mapped
   */
  public void set(String name, String key, Object value) {
    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

  /**
   * <p>
   * Render a String representation of this object.
   * </p>
   *
   * @return A string representation of this object.
   */
  public String toString() {
    StringBuffer sb = new StringBuffer("DynaActionForm[dynaClass=");
    DynaClass dynaClass = getDynaClass();

    if (dynaClass == null) {
      return sb.append("null]").toString();
    }

    sb.append(dynaClass.getName());

    DynaProperty[] props = dynaClass.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('=');

      Object value = get(props[i].getName());

      if (value == null) {
        sb.append("<NULL>");
      } else if (value.getClass().isArray()) {
        int n = Array.getLength(value);

        sb.append("{");

        for (int j = 0; j < n; j++) {
          if (j > 0) {
            sb.append(',');
          }

          sb.append(Array.get(value, j));
        }

        sb.append("}");
      } else if (value instanceof List) {
        int n = ((List) value).size();

        sb.append("{");

        for (int j = 0; j < n; j++) {
          if (j > 0) {
            sb.append(',');
          }

          sb.append(((List) value).get(j));
        }

        sb.append("}");
      } else if (value instanceof Map) {
        int n = 0;
        Iterator keys = ((Map) value).keySet().iterator();

        sb.append("{");

        while (keys.hasNext()) {
          if (n > 0) {
            sb.append(',');
          }

          n++;

          Object key = keys.next();

          sb.append(key);
          sb.append('=');
          sb.append(((Map) value).get(key));
        }

        sb.append("}");
      } else {
        sb.append(value);
      }
    }

    sb.append("]");

    return (sb.toString());
  }

  // -------------------------------------------------------- Package Methods

  /**
   * <p>
   * Set the <code>DynaActionFormClass</code> instance with which we are
   * associated.
   * </p>
   *
   * @param dynaClass
   *            The DynaActionFormClass instance for this bean
   */
  void setDynaActionFormClass(DynaActionFormClass dynaClass) {
    this.dynaClass = dynaClass;
  }

  // ------------------------------------------------------ Protected Methods

  /**
   * <p>
   * Return the property descriptor for the specified property name.
   * </p>
   *
   * @param name
   *            Name of the property for which to retrieve the descriptor
   * @return The property descriptor for the specified property name.
   * @throws 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);
  }

  /**
   * <p>
   * Indicates if an object of the source class is assignable to the
   * destination class.
   * </p>
   *
   * @param dest
   *            Destination class
   * @param source
   *            Source class
   * @return <code>true</code> if the source is assignable to the destination;
   *         <code>false</code> otherwise.
   */
  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);
    }
  }
}
TOP

Related Classes of org.g4studio.core.mvc.xstruts.action.DynaActionForm

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.