1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 package com.ivata.mask.web.struts;
65
66 import java.beans.PropertyDescriptor;
67 import java.util.Collection;
68 import java.util.Iterator;
69 import java.util.List;
70 import java.util.Vector;
71
72 import javax.naming.OperationNotSupportedException;
73 import javax.servlet.http.HttpServletRequest;
74 import javax.servlet.http.HttpSession;
75
76 import org.apache.commons.beanutils.PropertyUtils;
77 import org.apache.log4j.Logger;
78 import org.apache.struts.action.ActionMapping;
79
80 import com.ivata.mask.Mask;
81 import com.ivata.mask.field.Field;
82 import com.ivata.mask.validation.ValidationError;
83 import com.ivata.mask.validation.ValidationErrors;
84 import com.ivata.mask.valueobject.ValueObject;
85 /***
86 * This form references a single value object to be displayed.
87 *
88 * @author Colin MacLeod
89 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
90 * @since ivata masks 0.1 (2004-05-09)
91 * @version $Revision: 1.7.2.1 $
92 */
93 public class InputMaskForm extends MaskForm {
94 /***
95 * <strong>Log4J </strong> logger to provide tracing information.
96 */
97 private static Logger log = Logger.getLogger(InputMaskForm.class);
98 /***
99 * <p>
100 * Request attribute under which name this form is stored.
101 * </p>
102 */
103 public static final String REQUEST_ATTRIBUTE = "InputMaskForm";
104 /***
105 * Refer to {@link #isApplyButtonHidden}.
106 */
107 private boolean applyButtonHidden = false;
108 /***
109 * Refer to {@link #isClearButtonHidden}.
110 */
111 private boolean clearButtonHidden = false;
112 /***
113 * Refer to {@link #isDeleteButtonHidden}.
114 */
115 private boolean deleteButtonHidden = false;
116 /***
117 * Refer to {@link #isDeleteWithoutWarn}.
118 */
119 private boolean deleteWithoutWarn = false;
120 /***
121 * Refer to {@link #isDisplayOnly}.
122 */
123 private boolean displayOnly = false;
124 /***
125 * Refer to {@link #isRefreshOpener}.
126 */
127 private boolean refreshOpener = false;
128 /***
129 * Refer to {@link #getResourceFieldPath}.
130 */
131 private String resourceFieldPath;
132 /***
133 * These are the names of properties which are not cleared, in the
134 * <code>clear</code> method.
135 */
136 private List savedProperties = new Vector();
137 /***
138 * Refer to {@link #getValueObject}.
139 */
140 private ValueObject valueObject;
141 /***
142 * <p>
143 * Create a new mask form for the given value object.
144 * </p>
145 *
146 * @param valueObjectParam
147 * value object to be displayed.
148 * @param maskParam
149 * mask containing all the fields definitions to be displayed.
150 * @param baseClassParam
151 * base class of all value objects to show in the list associated
152 * with this mask.
153 */
154 public InputMaskForm(final ValueObject valueObjectParam,
155 final Mask maskParam, final Class baseClassParam) {
156 super(maskParam, baseClassParam);
157 this.valueObject = valueObjectParam;
158
159
160 this.saveProperty("modified");
161 this.saveProperty("modifiedBy");
162 this.saveProperty("created");
163 this.saveProperty("createdBy");
164 }
165
166 /***
167 * <p>
168 * Clear all bean properties to their default state.The difference between
169 * this and <code>reset</code> is that all properties are changed,
170 * regardless of current request state.
171 * </p>
172 *
173 * @see com.ivata.mask.web.struts.MaskForm#clear()
174 * @throws OperationNotSupported if the value object does not have a default
175 * constructor.
176 */
177 protected void clear()
178 throws OperationNotSupportedException {
179 Class dOClass = valueObject.getClass();
180 try {
181 valueObject = (ValueObject) dOClass.newInstance();
182 } catch (InstantiationException e) {
183 throw new OperationNotSupportedException(
184 "You must override InputMask.clear to create a new "
185 + "value object of class '"
186 + dOClass.getName()
187 + "' ("
188 + e.getClass().getName()
189 + ": "
190 + e.getMessage()
191 + ")");
192 } catch (IllegalAccessException e) {
193 throw new OperationNotSupportedException(
194 "You must override InputMask.clear to create a new "
195 + "value object of class '"
196 + dOClass.getName()
197 + "' ("
198 + e.getClass().getName()
199 + ": "
200 + e.getMessage()
201 + ")");
202 }
203 }
204 /***
205 * <p>
206 * The resource field path is the "stem" - the first string before
207 * the dot separator (.) - in the application resources for the fields in
208 * this form.
209 * </p>
210 * <p>
211 * For example, in a form for editing group information this might be simply
212 * <b>"group"</b>, and the message resource key for the group
213 * parent field would then be specified in the
214 * <code>ApplicationResources.properties</code> file as
215 * <b>"group.field.parent"</b> (without the quotes).
216 * </p>
217 * @return Returns the path to application resources for this form.
218 */
219 public String getResourceFieldPath() {
220 return resourceFieldPath;
221 }
222 /***
223 * Value object whose values are to be displayed in the mask.
224 *
225 * @return Value object to be displayed.
226 */
227 public ValueObject getValueObject() {
228 return valueObject;
229 }
230 /***
231 * Should the 'apply' button be shown or hidden?
232 * @return <code>true</code> if the apply button should <u>NOT</u> be shown.
233 */
234 public boolean isApplyButtonHidden() {
235 return applyButtonHidden;
236 }
237 /***
238 * Should the 'new' button be shown or hidden?
239 * @return <code>true</code> if the new button should <u>NOT</u> be shown.
240 */
241 public boolean isClearButtonHidden() {
242 return clearButtonHidden;
243 }
244 /***
245 * Should the 'delete' button be shown or hidden?
246 * @return <code>true</code> if the delete button should <u>NOT</u> be
247 * shown.
248 */
249 public boolean isDeleteButtonHidden() {
250 return deleteButtonHidden;
251 }
252 /***
253 * Sets whether or not the dialog should warn before deleting a value
254 * object.
255 * @return <code>true</code> if a warning is displayed before deleting.
256 */
257 public boolean isDeleteWithoutWarn() {
258 return deleteWithoutWarn;
259 }
260 /***
261 * If the mask is marked display only, only the text values of the fields
262 * are show (i.e. display mode), and there are no fields for user input.
263 *
264 * @return <code>true</code> if only text field values should be shown.
265 */
266 public boolean isDisplayOnly() {
267 return displayOnly || getMask().isDisplayOnly();
268 }
269 /***
270 * For pop-up windows, it is often useful to refresh the page which opened
271 * the pop-up, after the pop-up has changed something.
272 *
273 * @return Returns <code>true</code> if the page which opened this one
274 * should be refreshed on delete or confirm.
275 */
276 public boolean isRefreshOpener() {
277 return refreshOpener;
278 }
279 /***
280 * Refer to {@link DialogForm#reset}.
281 *
282 * @param mapping
283 * Refer to {@link DialogForm#reset}.
284 * @param request
285 * Refer to {@link DialogForm#reset}.
286 * @see DialogForm#reset
287 */
288 public void reset(final ActionMapping mapping,
289 final HttpServletRequest request) {
290 PropertyDescriptor[] descriptors = PropertyUtils
291 .getPropertyDescriptors(valueObject.getClass());
292 for (int i = 0; i < descriptors.length; i++) {
293 PropertyDescriptor descriptor = descriptors[i];
294 try {
295 String propertyName = descriptor.getName();
296 if (!savedProperties.contains(propertyName)) {
297
298 if (Collection.class.isAssignableFrom(
299 descriptor.getPropertyType())) {
300 Collection collection = (Collection)
301 PropertyUtils.getProperty(
302 valueObject, descriptor.getName());
303 collection.clear();
304 } else {
305 PropertyUtils.setProperty(valueObject, descriptor.getName(),
306 null);
307 }
308 }
309 } catch (Exception e) {
310
311 if (log.isDebugEnabled()) {
312 log.debug("Exception in InputMaskForm.reset", e);
313 }
314 }
315 }
316 super.reset(mapping, request);
317 }
318
319 /***
320 * Mark a property to be saved. By default, the <code>clear</code> method
321 * (and hence the <code>reset</code> method)
322 * will set all property values to <code>null</code>. By adding your
323 * property to the list of those saved here, it will be ignored in the
324 * <code>clear</code> method.
325 *
326 * @param propertyNameParam name of the property to save.
327 */
328 protected final void saveProperty(final String propertyNameParam) {
329 savedProperties.add(propertyNameParam);
330 }
331 /***
332 * Refer to {@link #isApplyButtonHidden}.
333 * @param applyButtonHiddenParam Refer to {@link #isApplyButtonHidden}.
334 */
335 public final void setApplyButtonHidden(boolean applyButtonHiddenParam) {
336 if (log.isDebugEnabled()) {
337 log.debug("setApplyButtonHidden before: '" + applyButtonHidden
338 + "', after: '" + applyButtonHiddenParam + "'");
339 }
340
341 applyButtonHidden = applyButtonHiddenParam;
342 }
343 /***
344 * Refer to {@link #isClearButtonHidden}.
345 * @param clearButtonHiddenParam Refer to {@link #isClearButtonHidden}.
346 */
347 public final void setClearButtonHidden(boolean clearButtonHiddenParam) {
348 if (log.isDebugEnabled()) {
349 log.debug("setClearButtonHidden before: '" + clearButtonHidden
350 + "', after: '" + clearButtonHiddenParam + "'");
351 }
352
353 clearButtonHidden = clearButtonHiddenParam;
354 }
355 /***
356 * Refer to {@link #isDeleteButtonHidden}.
357 * @param deleteButtonHiddenParam Refer to {@link #isDeleteButtonHidden}.
358 */
359 public final void setDeleteButtonHidden(boolean deleteButtonHiddenParam) {
360 if (log.isDebugEnabled()) {
361 log.debug("setDeleteButtonHidden before: '" + deleteButtonHidden
362 + "', after: '" + deleteButtonHiddenParam + "'");
363 }
364
365 deleteButtonHidden = deleteButtonHiddenParam;
366 }
367 /***
368 * Refer to {@link #isDeleteWithoutWarn}.
369 * @param deleteWithoutWarnParam Refer to {@link #isDeleteWithoutWarn}.
370 */
371 public final void setDeleteWithoutWarn(boolean deleteWithoutWarnParam) {
372 if (log.isDebugEnabled()) {
373 log.debug("setDeleteWithoutWarn before: '" + deleteWithoutWarn
374 + "', after: '" + deleteWithoutWarnParam + "'");
375 }
376
377 deleteWithoutWarn = deleteWithoutWarnParam;
378 }
379 /***
380 * Refer to {@link #isDisplayOnly}.
381 *
382 * @param b
383 * Refer to {@link #isDisplayOnly}.
384 */
385 public final void setDisplayOnly(final boolean b) {
386 displayOnly = b;
387 }
388 /***
389 * Refer to {@link #isRefreshOpener}.
390 * @param refreshOpenerParam Refer to {@link #isRefreshOpener}.
391 */
392 public final void setRefreshOpener(boolean refreshOpenerParam) {
393 if (log.isDebugEnabled()) {
394 log.debug("setRefreshOpener before: '" + refreshOpener
395 + "', after: '" + refreshOpenerParam + "'");
396 }
397
398 refreshOpener = refreshOpenerParam;
399 }
400 /***
401 * Refer to {@link #getResourceFieldPath}.
402 * @param resourceFieldPathParam Refer to {@link #getResourceFieldPath}.
403 */
404 public void setResourceFieldPath(String resourceFieldPathParam) {
405 if (log.isDebugEnabled()) {
406 log.debug("setResourceFieldPath before: '" + resourceFieldPath
407 + "', after: '" + resourceFieldPathParam + "'");
408 }
409
410 resourceFieldPath = resourceFieldPathParam;
411 }
412 /***
413 * Overridden to check mandatory fields.
414 *
415 * @param requestParam {@inheritDoc}
416 * @param sessionParam {@inheritDoc} <copyDoc>Refer to {@link DialogForm#validate}.</copyDoc>
417 * @return errors from the super class, with any mandatory field errors
418 * added.
419 */
420 public ValidationErrors validate(final HttpServletRequest requestParam,
421 final HttpSession sessionParam) {
422 if (log.isDebugEnabled()) {
423 log.debug("validate(HttpServletRequest requestParam = "
424 + requestParam + ", HttpSession sessionParam = "
425 + sessionParam + ") - start");
426 }
427
428 ValidationErrors errors
429 = super.validate(requestParam, sessionParam);
430 Mask mask = getMask();
431 List fields = mask.getFields();
432 Iterator fieldIterator = fields.iterator();
433 while (fieldIterator.hasNext()) {
434 Field field = (Field) fieldIterator.next();
435 if (!field.isMandatory()) {
436 continue;
437 }
438 try {
439 Object value = PropertyUtils.getProperty(valueObject,
440 field.getName());
441 if ((value == null)
442 || "".equals(value)
443 || "0".equals(value.toString())
444 || ((value instanceof Collection)
445 && ((Collection) value).isEmpty())) {
446 errors.add(new ValidationError(
447 field.getName(),
448 field,
449 "errors.required"));
450 }
451 } catch (Exception e) {
452 throw new RuntimeException(e);
453 }
454 }
455
456 if (log.isDebugEnabled()) {
457 log.debug("validate - end - return value = "
458 + errors);
459 }
460 return errors;
461 }
462 }
463