All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.struts.config.FormBeanConfig Maven / Gradle / Ivy

/*
 * $Id: FormBeanConfig.java 472728 2006-11-09 01:10:58Z niallp $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.struts.config;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.MutableDynaClass;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.DynaActionFormClass;
import org.apache.struts.chain.commands.util.ClassUtils;
import org.apache.struts.chain.contexts.ActionContext;
import org.apache.struts.chain.contexts.ServletActionContext;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.validator.BeanValidatorForm;

import java.lang.reflect.InvocationTargetException;

import java.util.HashMap;

/**
 * 

A JavaBean representing the configuration information of a * <form-bean> element in a Struts configuration file.

* * @version $Rev: 472728 $ $Date: 2006-01-17 07:26:20 -0500 (Tue, 17 Jan 2006) * $ * @since Struts 1.1 */ public class FormBeanConfig extends BaseConfig { private static final Log log = LogFactory.getLog(FormBeanConfig.class); // ----------------------------------------------------- Instance Variables /** * The set of FormProperty elements defining dynamic form properties for * this form bean, keyed by property name. */ protected HashMap formProperties = new HashMap(); /** *

The lockable object we can synchronize on when creating * DynaActionFormClass.

*/ protected String lock = ""; // ------------------------------------------------------------- Properties /** * The DynaActionFormClass associated with a DynaActionForm. */ protected transient DynaActionFormClass dynaActionFormClass; /** * Is the form bean class an instance of DynaActionForm with dynamic * properties? */ protected boolean dynamic = false; /** * The name of the FormBeanConfig that this config inherits configuration * information from. */ protected String inherit = null; /** * Have the inheritance values for this class been applied? */ protected boolean extensionProcessed = false; /** * The unique identifier of this form bean, which is used to reference * this bean in ActionMapping instances as well as for the * name of the request or session attribute under which the corresponding * form bean instance is created or accessed. */ protected String name = null; /** * The fully qualified Java class name of the implementation class to be * used or generated. */ protected String type = null; /** * Is this DynaClass currently restricted (for DynaBeans with a * MutableDynaClass). */ protected boolean restricted = false; /** *

Return the DynaActionFormClass associated with a * DynaActionForm.

* * @throws IllegalArgumentException if the ActionForm is not dynamic */ public DynaActionFormClass getDynaActionFormClass() { if (dynamic == false) { throw new IllegalArgumentException("ActionForm is not dynamic"); } synchronized (lock) { if (dynaActionFormClass == null) { dynaActionFormClass = new DynaActionFormClass(this); } } return dynaActionFormClass; } public boolean getDynamic() { return (this.dynamic); } public String getExtends() { return (this.inherit); } public void setExtends(String extend) { throwIfConfigured(); this.inherit = extend; } public boolean isExtensionProcessed() { return extensionProcessed; } public String getName() { return (this.name); } public void setName(String name) { throwIfConfigured(); this.name = name; } public String getType() { return (this.type); } public void setType(String type) { throwIfConfigured(); this.type = type; Class dynaBeanClass = DynaActionForm.class; Class formBeanClass = formBeanClass(); if (formBeanClass != null) { if (dynaBeanClass.isAssignableFrom(formBeanClass)) { this.dynamic = true; } else { this.dynamic = false; } } else { this.dynamic = false; } } /** *

Indicates whether a MutableDynaClass is currently restricted.

*

If so, no changes to the existing registration of property names, * data types, readability, or writeability are allowed.

*/ public boolean isRestricted() { return restricted; } /** *

Set whether a MutableDynaClass is currently restricted.

If * so, no changes to the existing registration of property names, data * types, readability, or writeability are allowed.

*/ public void setRestricted(boolean restricted) { this.restricted = restricted; } // ------------------------------------------------------ Protected Methods /** *

Traces the hierarchy of this object to check if any of the ancestors * is extending this instance.

* * @param moduleConfig The configuration for the module being configured. * @return true if circular inheritance was detected. */ protected boolean checkCircularInheritance(ModuleConfig moduleConfig) { String ancestorName = getExtends(); while (ancestorName != null) { // check if we have the same name as an ancestor if (getName().equals(ancestorName)) { return true; } // get our ancestor's ancestor FormBeanConfig ancestor = moduleConfig.findFormBeanConfig(ancestorName); ancestorName = ancestor.getExtends(); } return false; } /** *

Compare the form properties of this bean with that of the given and * copy those that are not present.

* * @param config The form bean config to copy properties from. * @see #inheritFrom(FormBeanConfig) */ protected void inheritFormProperties(FormBeanConfig config) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { throwIfConfigured(); // Inherit form property configs FormPropertyConfig[] baseFpcs = config.findFormPropertyConfigs(); for (int i = 0; i < baseFpcs.length; i++) { FormPropertyConfig baseFpc = baseFpcs[i]; // Do we have this prop? FormPropertyConfig prop = this.findFormPropertyConfig(baseFpc.getName()); if (prop == null) { // We don't have this, so let's copy it prop = (FormPropertyConfig) RequestUtils.applicationInstance(baseFpc.getClass() .getName()); BeanUtils.copyProperties(prop, baseFpc); this.addFormPropertyConfig(prop); prop.setProperties(baseFpc.copyProperties()); } } } // --------------------------------------------------------- Public Methods /** *

Create and return an ActionForm instance appropriate to * the information in this FormBeanConfig.

* *

Although this method is not formally deprecated yet, where possible, * the form which accepts an ActionContext as an argument is * preferred, to help sever direct dependencies on the Servlet API. As * the ActionContext becomes more familiar in Struts, this method will * almost certainly be deprecated.

* * @param servlet The action servlet * @return ActionForm instance * @throws IllegalAccessException if the Class or the appropriate * constructor is not accessible * @throws 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 ActionForm createActionForm(ActionServlet servlet) throws IllegalAccessException, InstantiationException { Object obj = null; // Create a new form bean instance if (getDynamic()) { obj = getDynaActionFormClass().newInstance(); } else { obj = formBeanClass().newInstance(); } ActionForm form = null; if (obj instanceof ActionForm) { form = (ActionForm) obj; } else { form = new BeanValidatorForm(obj); } form.setServlet(servlet); if (form instanceof DynaBean && ((DynaBean) form).getDynaClass() instanceof MutableDynaClass) { DynaBean dynaBean = (DynaBean) form; MutableDynaClass dynaClass = (MutableDynaClass) dynaBean.getDynaClass(); // Add properties dynaClass.setRestricted(false); FormPropertyConfig[] props = findFormPropertyConfigs(); for (int i = 0; i < props.length; i++) { dynaClass.add(props[i].getName(), props[i].getTypeClass()); dynaBean.set(props[i].getName(), props[i].initial()); } dynaClass.setRestricted(isRestricted()); } if (form instanceof BeanValidatorForm) { ((BeanValidatorForm)form).initialize(this); } return form; } /** *

Create and return an ActionForm instance appropriate to * the information in this FormBeanConfig.

*

NOTE: If the given ActionContext is not of type * ServletActionContext (or a subclass), then the form which * is returned will have a null servlet property. Some of * the subclasses of ActionForm included in Struts will later * throw a NullPointerException in this case.

TODO: * Find a way to control this direct dependency on the Servlet API.

* * @param context The ActionContext. * @return ActionForm instance * @throws IllegalAccessException if the Class or the appropriate * constructor is not accessible * @throws 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 ActionForm createActionForm(ActionContext context) throws IllegalAccessException, InstantiationException { ActionServlet actionServlet = null; if (context instanceof ServletActionContext) { ServletActionContext saContext = (ServletActionContext) context; actionServlet = saContext.getActionServlet(); } return createActionForm(actionServlet); } /** *

Checks if the given ActionForm instance is suitable for * use as an alternative to calling this FormBeanConfig * instance's createActionForm method.

* * @param form an existing form instance that may be reused. * @return true if the given form can be reused as the form for this * config. */ public boolean canReuse(ActionForm form) { if (form != null) { if (this.getDynamic()) { String className = ((DynaBean) form).getDynaClass().getName(); if (className.equals(this.getName())) { log.debug("Can reuse existing instance (dynamic)"); return (true); } } else { try { // check if the form's class is compatible with the class // we're configured for Class formClass = form.getClass(); if (form instanceof BeanValidatorForm) { BeanValidatorForm beanValidatorForm = (BeanValidatorForm) form; if (beanValidatorForm.getInstance() instanceof DynaBean) { String formName = beanValidatorForm.getStrutsConfigFormName(); if (getName().equals(formName)) { log.debug("Can reuse existing instance (BeanValidatorForm)"); return true; } else { return false; } } formClass = beanValidatorForm.getInstance().getClass(); } Class configClass = ClassUtils.getApplicationClass(this.getType()); if (configClass.isAssignableFrom(formClass)) { log.debug("Can reuse existing instance (non-dynamic)"); return (true); } } catch (Exception e) { log.debug("Error testing existing instance for reusability; just create a new instance", e); } } } return false; } /** * Add a new FormPropertyConfig instance to the set * associated with this module. * * @param config The new configuration instance to be added * @throws IllegalArgumentException if this property name has already been * defined */ public void addFormPropertyConfig(FormPropertyConfig config) { throwIfConfigured(); if (formProperties.containsKey(config.getName())) { throw new IllegalArgumentException("Property " + config.getName() + " already defined"); } formProperties.put(config.getName(), config); } /** * Return the form property configuration for the specified property name, * if any; otherwise return null. * * @param name Form property name to find a configuration for */ public FormPropertyConfig findFormPropertyConfig(String name) { return ((FormPropertyConfig) formProperties.get(name)); } /** * Return the form property configurations for this module. If there are * none, a zero-length array is returned. */ public FormPropertyConfig[] findFormPropertyConfigs() { FormPropertyConfig[] results = new FormPropertyConfig[formProperties.size()]; return ((FormPropertyConfig[]) formProperties.values().toArray(results)); } /** * Freeze the configuration of this component. */ public void freeze() { super.freeze(); FormPropertyConfig[] fpconfigs = findFormPropertyConfigs(); for (int i = 0; i < fpconfigs.length; i++) { fpconfigs[i].freeze(); } } /** *

Inherit values that have not been overridden from the provided * config object. Subclasses overriding this method should verify that * the given parameter is of a class that contains a property it is trying * to inherit:

* *
     * if (config instanceof MyCustomConfig) {
     *     MyCustomConfig myConfig =
     *         (MyCustomConfig) config;
     *
     *     if (getMyCustomProp() == null) {
     *         setMyCustomProp(myConfig.getMyCustomProp());
     *     }
     * }
     * 
* *

If the given config is extending another object, those * extensions should be resolved before it's used as a parameter to this * method.

* * @param config The object that this instance will be inheriting its * values from. * @see #processExtends(ModuleConfig) */ public void inheritFrom(FormBeanConfig config) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { throwIfConfigured(); // Inherit values that have not been overridden if (getName() == null) { setName(config.getName()); } if (!isRestricted()) { setRestricted(config.isRestricted()); } if (getType() == null) { setType(config.getType()); } inheritFormProperties(config); inheritProperties(config); } /** *

Inherit configuration information from the FormBeanConfig that this * instance is extending. This method verifies that any form bean config * object that it inherits from has also had its processExtends() method * called.

* * @param moduleConfig The {@link ModuleConfig} that this bean is from. * @see #inheritFrom(FormBeanConfig) */ public void processExtends(ModuleConfig moduleConfig) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { if (configured) { throw new IllegalStateException("Configuration is frozen"); } String ancestor = getExtends(); if ((!extensionProcessed) && (ancestor != null)) { FormBeanConfig baseConfig = moduleConfig.findFormBeanConfig(ancestor); if (baseConfig == null) { throw new NullPointerException("Unable to find " + "form bean '" + ancestor + "' to extend."); } // Check against circule inheritance and make sure the base config's // own extends have been processed already if (checkCircularInheritance(moduleConfig)) { throw new IllegalArgumentException( "Circular inheritance detected for form bean " + getName()); } // Make sure the ancestor's own extension has been processed. if (!baseConfig.isExtensionProcessed()) { baseConfig.processExtends(moduleConfig); } // Copy values from the base config inheritFrom(baseConfig); } extensionProcessed = true; } /** * Remove the specified form property configuration instance. * * @param config FormPropertyConfig instance to be removed */ public void removeFormPropertyConfig(FormPropertyConfig config) { if (configured) { throw new IllegalStateException("Configuration is frozen"); } formProperties.remove(config.getName()); } /** * Return a String representation of this object. */ public String toString() { StringBuffer sb = new StringBuffer("FormBeanConfig["); sb.append("name="); sb.append(this.name); sb.append(",type="); sb.append(this.type); sb.append(",extends="); sb.append(this.inherit); sb.append("]"); return (sb.toString()); } // ------------------------------------------------------ Protected Methods /** * Return the Class instance for the form bean implementation * configured by this FormBeanConfig instance. This method * uses the same algorithm as RequestUtils.applicationClass() * but is reproduced to avoid a runtime dependence. */ protected Class formBeanClass() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = this.getClass().getClassLoader(); } try { return (classLoader.loadClass(getType())); } catch (Exception e) { return (null); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy