1 /* 2 * $Id: LazyValidatorForm.java 562121 2007-08-02 14:28:23Z niallp $ 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 package org.apache.struts.validator; 22 23 import org.apache.commons.beanutils.DynaBean; 24 import org.apache.commons.beanutils.LazyDynaBean; 25 26 import java.util.List; 27 import java.util.Map; 28 29 /** 30 * <p>Struts <i>Lazy</i> <code>ActionForm</code> which <i>wraps</i> a 31 * <code>LazyDynaBean</code>.</p> 32 * 33 * <p>There isn't really that much to this implementation as most of the 34 * <i>lazy</i> behaviour is in <code>LazyDynaBean</code> and <i>wrapping</i> 35 * the <code>LazyDynaBean<code> is handled in the parent 36 * <code>BeanValidatorForm</code>. The only thing it really does is populate 37 * <i>indexed</i> properties which are a <code>List<code> type with a 38 * <code>LazyDynaBean<code> in the <code>get(name, index)</code> method.</p> 39 * 40 * <p><i>Lazy</i> DynaBeans provide several types of <i>lazy</i> 41 * behaviour:</p> 42 * 43 * <ul> 44 * 45 * <li><b><i>lazy</i> property addition</b> - properties which do not exist 46 * are automatically added.</li> 47 * 48 * <li><b><i>lazy</i> List facilities</b> - automatically <i>grows</i> a 49 * <code>List</code> or <code>Array</code> to accomodate the index value being 50 * set.</li> 51 * 52 * <li><b><i>lazy</i> List creation</b> - automatic creation of a 53 * <code>List</code> or <code>Array</code> for <i>indexed</i> properties, if 54 * it doesn't exist.</li> <li><b><i>lazy</i> Map creation</b> - automatic 55 * creation of a <code>Map</code> for <i>mapped</i> properties, if it doesn't 56 * exist.</li> 57 * 58 * </ul> 59 * 60 * <p>Using this <i>lazy</i> <code>ActionForm</code> means that you don't have 61 * to define the ActionForm's properties in the <code>struts-config.xml</code>. 62 * However, a word of warning, everything in the Request gets populated into 63 * this <code>ActionForm</code> circumventing the normal <i>firewall</i> 64 * function of Struts forms. Therefore you should only <i>take out</i> of this 65 * form properties you expect to be there rather than blindly populating all 66 * the properties into the business tier.</p> 67 * 68 * <p>Having said that it is not necessary to pre-define properties in the 69 * <code>struts-config.xml</code>, it is useful to sometimes do so for 70 * <i>mapped</i> or <i>indexed</i> properties. For example, if you want to use 71 * a different <code>Map<code> implementation from the default 72 * <code>HashMap</code> or an array for indexed properties, rather than the 73 * default <code>List</code> type:</p> 74 * 75 * <pre><code> 76 * <form-bean name="myForm" type="org.apache.struts.validator.LazyValidatorForm"> 77 * <form-property name="myMap" type="java.util.TreeMap" /> 78 * <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]" 79 * /> 80 * </form-bean> 81 * </code></pre> 82 * 83 * <p>Another reason for defining <i>indexed</i> properties in the 84 * <code>struts-config.xml</code> is that if you are validating indexed 85 * properties using the Validator and none are submitted then the indexed 86 * property will be <code>null</code> which causes validator to fail. 87 * Pre-defining them in the <code>struts-config.xml</code> will result in a 88 * zero-length indexed property (array or List) being instantiated, avoiding 89 * an issue with validator in that circumstance.</p> 90 * 91 * <p>This implementation validates using the ActionForm <i>name</i>. If you 92 * require a version that validates according to the <i>path</i> then it can 93 * be easily created in the following manner:</p> 94 * 95 * <pre><code> 96 * public class MyLazyForm extends LazyValidatorForm { 97 * 98 * public MyLazyForm () { 99 * super(); 100 * setPathValidation(true); 101 * } 102 * 103 * } 104 * </code></pre> 105 * 106 * <p>Rather than using this class, another alternative is to either use a 107 * <code>LazyDynaBean</code> or custom version of <code>LazyDynaBean</code> 108 * directly. Struts now automatically <i>wraps</i> objects which are not 109 * <code>ActionForms</code> in a <code>BeanValidatorForm</code>. For 110 * example:</p> 111 * 112 * <pre><code> 113 * <form-bean name="myForm" type="org.apache.commons.beanutils.LazyDynaBean"> 114 * <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]" 115 * /> 116 * </form-bean> 117 * </code></pre> 118 * 119 * @version $Rev: 562121 $ $Date: 2005-05-07 12:11:38 -0400 (Sat, 07 May 2005) 120 * $ 121 * @see <a href="http://commons.apache.org/beanutils/apidocs/org/apache/commons/beanutils/package-summary.html#dynamic.lazy">Commons 122 * BeanUtils JavaDoc</a> 123 * @since Struts 1.2.6 124 */ 125 public class LazyValidatorForm extends BeanValidatorForm { 126 // ------------------- Constructors ---------------------------------- 127 128 /** 129 * Default Constructor which creates a <code>LazyDynaBean</code> to 130 * <i>back</i> this form. 131 */ 132 public LazyValidatorForm() { 133 super(new LazyDynaBean()); 134 } 135 136 /** 137 */ 138 public LazyValidatorForm(DynaBean bean) { 139 super(bean); 140 } 141 142 // ------------------- DynaBean methods ---------------------------------- 143 144 /** 145 * <p>Return an indexed property value.</p> 146 * 147 * <p>If the "indexed" property is a <code>List</code> type then any 148 * missing values are populated with a bean (created in the 149 * <code>newIndexedBean(name)</code> method - in this implementation this 150 * is a <code>LazyDynaBean</code> type.</p> 151 */ 152 public Object get(String name, int index) { 153 int size = size(name); 154 155 // Get the indexed property 156 Object value = dynaBean.get(name, index); 157 158 // Create missing beans for Lists 159 if (value == null) { 160 Object indexedValue = dynaBean.get(name); 161 162 if (List.class.isAssignableFrom(indexedValue.getClass())) { 163 for (int i = size; i <= index; i++) { 164 value = newIndexedBean(name); 165 set(name, i, value); 166 } 167 } 168 } 169 170 return value; 171 } 172 173 // ------------------- Public methods ---------------------------------- 174 175 /** 176 * <p>Return the <code>Map</code> containing the property values.</p> 177 * 178 * <p>Provided so that properties can be access using JSTL.</p> 179 */ 180 public Map getMap() { 181 return ((LazyDynaBean) dynaBean).getMap(); 182 } 183 184 // ------------------- Protected methods ---------------------------------- 185 186 /** 187 * <p>Creates new <code>DynaBean</code> instances to populate an 'indexed' 188 * property of beans - defaults to <code>LazyDynaBean</code> type.</p> 189 * 190 * <p>Override this method if you require a different type of 191 * <code>DynaBean</code>.</p> 192 */ 193 protected DynaBean newIndexedBean(String name) { 194 return new LazyDynaBean(); 195 } 196 }