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
65
66
67
68 package com.ivata.mask.web.field;
69 import java.beans.PropertyDescriptor;
70 import java.lang.reflect.InvocationTargetException;
71 import java.util.Collection;
72
73 import org.apache.commons.beanutils.PropertyUtils;
74
75 import com.ivata.mask.field.Field;
76 import com.ivata.mask.field.FieldValueConvertor;
77 import com.ivata.mask.field.date.DateFieldValueConvertor;
78 import com.ivata.mask.field.number.NumberFieldValueConvertor;
79 import com.ivata.mask.field.valueobject.ValueObjectFieldValueConvertor;
80 import com.ivata.mask.persistence.PersistenceManager;
81 import com.ivata.mask.persistence.PersistenceSession;
82 import com.ivata.mask.util.SystemException;
83 import com.ivata.mask.valueobject.ValueObject;
84 import com.ivata.mask.web.field.hidden.HiddenFieldWriter;
85 import com.ivata.mask.web.field.text.TextAreaFieldWriter;
86 import com.ivata.mask.web.field.text.TextFieldWriter;
87 import com.ivata.mask.web.field.valueobject.ValueObjectFieldWriter;
88 import com.ivata.mask.web.format.HTMLFormatter;
89 import com.ivata.mask.web.format.LineBreakFormat;
90 /***
91 * <p>
92 * Use this utility class to generate an appropriate field writer for a given
93 * mask and field.
94 * </p>
95 *
96 * @since ivata masks 0.1 (2004-05-14)
97 * @author Colin MacLeod
98 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
99 * @version $Revision: 1.9 $
100 */
101 public class DefaultFieldWriterFactory implements FieldWriterFactory {
102 /***
103 * Refer to {@link #getActionPage}.
104 */
105 private String actionPage;
106 /***
107 * <p>
108 * Formatter used to format all texts.
109 * </p>
110 */
111 private HTMLFormatter formatter = new HTMLFormatter();
112 /***
113 * <p>
114 * This object is used to retrieve lists for collection field writers.
115 * </p>
116 */
117 private PersistenceManager persistenceManager;
118 /***
119 * Construct a writer factory.
120 *
121 * @param persistenceManagerParam
122 * used to retrieve value objects for a value
123 * @param actionPageParam
124 * page of the action to which we'll link value objects to.
125 */
126 public DefaultFieldWriterFactory(
127 final PersistenceManager persistenceManagerParam,
128 final String actionPageParam) {
129 this.persistenceManager = persistenceManagerParam;
130 this.actionPage = actionPageParam;
131
132 LineBreakFormat lineBreakFormat = new LineBreakFormat();
133 lineBreakFormat.setConvertLineBreaks(true);
134 formatter.add(lineBreakFormat);
135 }
136 /***
137 * Page of the <strong>Struts </strong> action to which we'll link value
138 * objects to. This must be a full, webapp-relative link, starting with '/'.
139 *
140 * @return Returns the actionPage.
141 */
142 protected final String getActionPage() {
143 return actionPage;
144 }
145 /***
146 * <p>
147 * Get a field writer appropriate to the given field.
148 * </p>
149 *
150 * @param valueObjectParam
151 * Field for which to return an appropriate field writer.
152 * @param fieldParam
153 * Field for which to return an appropriate field writer.
154 * @param subFieldParam
155 * Sub-field within the main field, if the field is a value
156 * object.
157 * but the value stored in a hidden field.
158 * @param hidden
159 * If <code>true</code>, overrides the field definition, and gets a writer
160 * for a hidden field.
161 * @return valid field writer for the field provided.
162 * @throws SystemException
163 * thrown if the writer cannot be retrieved for any reason.
164 */
165 public final FieldWriter getFieldWriter(final ValueObject valueObjectParam,
166 final Field fieldParam, final Field subFieldParam,
167 final boolean hidden)
168 throws SystemException {
169 FieldWriter fieldWriter = null;
170 String propertyName;
171 Field writerField;
172 if (subFieldParam == null) {
173 writerField = fieldParam;
174 } else {
175 writerField = subFieldParam;
176 }
177 String type = writerField.getType();
178 propertyName = "valueObject." + writerField.getPath();
179 FieldValueConvertor fieldValueConvertor = null;
180 if (Field.TYPE_RADIO.equals(type)) {
181 throw new UnsupportedOperationException("ERROR: field type '"
182 + type + "' is not yet supported.");
183 } else if (Field.TYPE_SELECT.equals(type)) {
184 throw new UnsupportedOperationException("ERROR: field type '"
185 + type + "' is not yet supported.");
186 } else if (Field.TYPE_AMOUNT.equals(type)) {
187 fieldWriter = newTextFieldWriter(writerField,
188 new NumberFieldValueConvertor("###0.##"), formatter);
189 } else if (Field.TYPE_NUMBER.equals(type)) {
190 fieldWriter = newTextFieldWriter(writerField,
191 new NumberFieldValueConvertor("###0"), formatter);
192 } else if (Field.TYPE_DATE.equals(type)) {
193 fieldWriter = newTextFieldWriter(writerField,
194 new DateFieldValueConvertor("yyyy-MM-dd"), formatter);
195 } else if (Field.TYPE_STRING.equals(type)) {
196 fieldWriter = newTextFieldWriter(writerField,
197 new FieldValueConvertor(), formatter);
198 } else {
199
200
201 PropertyDescriptor descriptor;
202 try {
203 Class valueObjectClass;
204 if (subFieldParam == null) {
205 valueObjectClass = valueObjectParam.getClass();
206 } else {
207 if (fieldParam.getDOClass() != null) {
208 valueObjectClass = fieldParam.getDOClass();
209 } else {
210 descriptor = PropertyUtils.getPropertyDescriptor(
211 valueObjectParam, fieldParam.getPath());
212 valueObjectClass = descriptor.getPropertyType();
213
214
215 if (Collection.class
216 .isAssignableFrom(valueObjectClass)) {
217 throw new NullPointerException(
218 "ERROR: you must specify a data object "
219 + "class for collection '"
220 + fieldParam.getName() + "'.");
221 }
222 }
223 }
224 descriptor = getPropertyDescriptor(valueObjectClass,
225 writerField.getPath());
226 } catch (NoSuchMethodException e) {
227 throw new SystemException(e);
228 } catch (IllegalAccessException e) {
229 throw new SystemException(e);
230 } catch (InvocationTargetException e) {
231 throw new SystemException(e);
232 }
233
234 Class propertyType = descriptor.getPropertyType();
235 if (ValueObject.class.isAssignableFrom(propertyType)
236 || Collection.class.isAssignableFrom(
237 propertyType)) {
238
239
240 if (hidden || writerField.isHidden()) {
241 fieldValueConvertor = new ValueObjectFieldValueConvertor();
242 } else {
243
244
245 Class dOClass;
246 boolean multiple = Collection.class
247 .isAssignableFrom(propertyType);
248 if (writerField.getDOClass() != null) {
249 dOClass = writerField.getDOClass();
250 } else if (multiple) {
251 throw new SystemException(
252 "ERROR: for collection field '"
253 + writerField.getPath()
254 + "', you must specify attribute 'class' in the "
255 + "ivata masks configuration.");
256 } else {
257 dOClass = propertyType;
258 }
259 PersistenceSession persistenceSession = persistenceManager
260 .openSession();
261 try {
262 Collection allEntries = persistenceManager.findAll(
263 persistenceSession, dOClass);
264 int listHeight = 1;
265 if (multiple) {
266 listHeight =
267 FieldWriterConstants.MULTIPLE_LIST_HEIGHT;
268 }
269 fieldWriter = newValueObjectFieldWriter(writerField,
270 actionPage, allEntries, formatter, listHeight,
271 multiple);
272 } finally {
273 persistenceSession.close();
274 }
275 }
276 } else {
277
278 fieldValueConvertor = new FieldValueConvertor();
279 }
280
281
282
283
284
285 if (fieldValueConvertor != null) {
286 if (hidden || writerField.isHidden()) {
287 fieldWriter = newHiddenFieldWriter(writerField,
288 fieldValueConvertor, formatter);
289 } else if (Field.TYPE_TEXTAREA.equals(type)) {
290 fieldWriter = newTextAreaFieldWriter(writerField,
291 fieldValueConvertor, formatter);
292 } else {
293 fieldWriter = newTextFieldWriter(writerField,
294 fieldValueConvertor, formatter);
295 }
296 }
297 }
298 return fieldWriter;
299 }
300 /***
301 * <p>
302 * Find the descriptor for the class and id provided.
303 * </p>
304 *
305 * @param theClass
306 * class for which to find a descriptor.
307 * @param name
308 * name of the property for which to find a descriptor.
309 * @return valid property descriptor describing the property called
310 * <code>name</code> in class <code>theClass</code>.
311 */
312 private PropertyDescriptor getPropertyDescriptor(final Class theClass,
313 final String name) {
314 PropertyDescriptor[] allDescriptors = PropertyUtils
315 .getPropertyDescriptors(theClass);
316 PropertyDescriptor descriptor = null;
317
318 int dotIndex = name.indexOf('.');
319 String propertyName = null;
320 if (dotIndex == -1) {
321 propertyName = name;
322 } else {
323 propertyName = name.substring(0, dotIndex);
324 }
325 for (int i = 0; i < allDescriptors.length; i++) {
326 if (propertyName.equals(allDescriptors[i].getName())) {
327 descriptor = allDescriptors[i];
328 }
329 }
330
331 if (dotIndex == -1) {
332 return descriptor;
333 } else {
334 return getPropertyDescriptor(theClass, name.substring(++dotIndex));
335 }
336 }
337 /***
338 * Override this method if you need a different field writer for text areas.
339 *
340 * @param field
341 * Refer to {@link TextAreaFieldWriter#TextAreaFieldWriter}.
342 * @param convertor
343 * Refer to {@link TextAreaFieldWriter#TextAreaFieldWriter}.
344 * @param formatterParam
345 * Refer to {@link TextAreaFieldWriter#TextAreaFieldWriter}.
346 * @return valid text area field writer.
347 */
348 protected FieldWriter newTextAreaFieldWriter(final Field field,
349 final FieldValueConvertor convertor,
350 final HTMLFormatter formatterParam) {
351 return new TextAreaFieldWriter(field,
352 convertor, formatterParam);
353 }
354 /***
355 * Override this method if you need a different field writer for hidden
356 * fields.
357 *
358 * @param fieldParam
359 * Refer to {@link TextFieldWriter#TextFieldWriter}.
360 * @param convertorParam
361 * Refer to {@link TextFieldWriter#TextFieldWriter}.
362 * @param formatterParam
363 * Refer to {@link TextFieldWriter#TextFieldWriter}.
364 * @return valid text field writer.
365 */
366 protected FieldWriter newHiddenFieldWriter(final Field fieldParam,
367 final FieldValueConvertor convertorParam,
368 final HTMLFormatter formatterParam) {
369 return new HiddenFieldWriter(
370 fieldParam, convertorParam, formatterParam);
371 }
372 /***
373 * Override this method if you need a different field writer for text
374 * fields.
375 *
376 * @param fieldParam
377 * Refer to {@link TextFieldWriter#TextFieldWriter}.
378 * @param convertorParam
379 * Refer to {@link TextFieldWriter#TextFieldWriter}.
380 * @param formatterParam
381 * Refer to {@link TextFieldWriter#TextFieldWriter}.
382 * @return valid text field writer.
383 */
384 protected FieldWriter newTextFieldWriter(final Field fieldParam,
385 final FieldValueConvertor convertorParam,
386 final HTMLFormatter formatterParam) {
387 return new TextFieldWriter(
388 fieldParam, convertorParam, formatterParam);
389 }
390 /***
391 * Override this method if you need a different field writer for value
392 * objects.
393 *
394 * @param fieldParam
395 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
396 * @param actionPageParam
397 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
398 * @param allValueObjectsParam
399 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
400 * @param formatterParam
401 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
402 * @param listHeightParam
403 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
404 * @param multipleParam
405 * Refer to {@link ValueObjectFieldWriter#ValueObjectFieldWriter}.
406 * @return valid field writer.
407 */
408 protected FieldWriter newValueObjectFieldWriter(final Field fieldParam,
409 final String actionPageParam,
410 final Collection allValueObjectsParam,
411 final HTMLFormatter formatterParam, final int listHeightParam,
412 final boolean multipleParam) {
413 return new ValueObjectFieldWriter(
414 fieldParam, actionPageParam, allValueObjectsParam,
415 formatterParam, listHeightParam,
416 multipleParam);
417 }
418 }
419