001: /*
002: * $Id: LazyValidatorForm.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.validator;
022:
023: import org.apache.commons.beanutils.DynaBean;
024: import org.apache.commons.beanutils.LazyDynaBean;
025:
026: import java.util.List;
027: import java.util.Map;
028:
029: /**
030: * <p>Struts <i>Lazy</i> <code>ActionForm</code> which <i>wraps</i> a
031: * <code>LazyDynaBean</code>.</p>
032: *
033: * <p>There isn't really that much to this implementation as most of the
034: * <i>lazy</i> behaviour is in <code>LazyDynaBean</code> and <i>wrapping</i>
035: * the <code>LazyDynaBean<code> is handled in the parent
036: * <code>BeanValidatorForm</code>. The only thing it really does is populate
037: * <i>indexed</i> properties which are a <code>List<code> type with a
038: * <code>LazyDynaBean<code> in the <code>get(name, index)</code> method.</p>
039: *
040: * <p><i>Lazy</i> DynaBeans provide several types of <i>lazy</i>
041: * behaviour:</p>
042: *
043: * <ul>
044: *
045: * <li><b><i>lazy</i> property addition</b> - properties which do not exist
046: * are automatically added.</li>
047: *
048: * <li><b><i>lazy</i> List facilities</b> - automatically <i>grows</i> a
049: * <code>List</code> or <code>Array</code> to accomodate the index value being
050: * set.</li>
051: *
052: * <li><b><i>lazy</i> List creation</b> - automatic creation of a
053: * <code>List</code> or <code>Array</code> for <i>indexed</i> properties, if
054: * it doesn't exist.</li> <li><b><i>lazy</i> Map creation</b> - automatic
055: * creation of a <code>Map</code> for <i>mapped</i> properties, if it doesn't
056: * exist.</li>
057: *
058: * </ul>
059: *
060: * <p>Using this <i>lazy</i> <code>ActionForm</code> means that you don't have
061: * to define the ActionForm's properties in the <code>struts-config.xml</code>.
062: * However, a word of warning, everything in the Request gets populated into
063: * this <code>ActionForm</code> circumventing the normal <i>firewall</i>
064: * function of Struts forms. Therefore you should only <i>take out</i> of this
065: * form properties you expect to be there rather than blindly populating all
066: * the properties into the business tier.</p>
067: *
068: * <p>Having said that it is not necessary to pre-define properties in the
069: * <code>struts-config.xml</code>, it is useful to sometimes do so for
070: * <i>mapped</i> or <i>indexed</i> properties. For example, if you want to use
071: * a different <code>Map<code> implementation from the default
072: * <code>HashMap</code> or an array for indexed properties, rather than the
073: * default <code>List</code> type:</p>
074: *
075: * <pre><code>
076: * <form-bean name="myForm" type="org.apache.struts.validator.LazyValidatorForm">
077: * <form-property name="myMap" type="java.util.TreeMap" />
078: * <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]"
079: * />
080: * </form-bean>
081: * </code></pre>
082: *
083: * <p>Another reason for defining <i>indexed</i> properties in the
084: * <code>struts-config.xml</code> is that if you are validating indexed
085: * properties using the Validator and none are submitted then the indexed
086: * property will be <code>null</code> which causes validator to fail.
087: * Pre-defining them in the <code>struts-config.xml</code> will result in a
088: * zero-length indexed property (array or List) being instantiated, avoiding
089: * an issue with validator in that circumstance.</p>
090: *
091: * <p>This implementation validates using the ActionForm <i>name</i>. If you
092: * require a version that validates according to the <i>path</i> then it can
093: * be easily created in the following manner:</p>
094: *
095: * <pre><code>
096: * public class MyLazyForm extends LazyValidatorForm {
097: *
098: * public MyLazyForm () {
099: * 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: 471754 $ $Date: 2005-05-07 12:11:38 -0400 (Sat, 07 May 2005)
120: * $
121: * @see <a href="http://jakarta.apache.org/commons/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: }
|