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 package com.ivata.mask.web.field.valueobject;
67 import com.ivata.mask.Mask;
68 import com.ivata.mask.field.Field;
69 import com.ivata.mask.util.StringHandling;
70 import com.ivata.mask.valueobject.ValueObject;
71 import com.ivata.mask.web.field.AttributesWriter;
72 import com.ivata.mask.web.field.FieldWriter;
73 import com.ivata.mask.web.format.HTMLFormatter;
74 import org.apache.commons.beanutils.PropertyUtils;
75 import org.apache.struts.taglib.TagUtils;
76 import org.dom4j.Document;
77 import org.dom4j.DocumentFactory;
78 import org.dom4j.Element;
79 import java.lang.reflect.InvocationTargetException;
80 import java.net.MalformedURLException;
81 import java.util.Collection;
82 import java.util.HashMap;
83 import java.util.Iterator;
84 import java.util.List;
85 import java.util.Map;
86 import java.util.Vector;
87 import javax.servlet.jsp.PageContext;
88 /***
89 * <p>
90 * This writer is used to display links to other value objects.
91 * </p>
92 *
93 * @since ivata masks 0.2 (2004-05-14)
94 * @author Colin MacLeod
95 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
96 * @version $Revision: 1.8 $
97 */
98 public class ValueObjectFieldWriter implements FieldWriter {
99 /***
100 * <p>
101 * This is the style class used for combo (single choice) lists.
102 * </p>
103 */
104 public static final String CSS_COMBO = "combo";
105 /***
106 * <p>
107 * This is the style class used for multiple choice lists.
108 * </p>
109 */
110 public static final String CSS_LIST = "list";
111 /***
112 * <p>
113 * This is the value which is output as a default. TODO: i18n
114 * </p>
115 */
116 public static final String DEFAULT_DISPLAY_VALUE = "[None]";
117 /***
118 * <p>
119 * This is the value which is output as a default. TODO: i18n
120 * </p>
121 */
122 public static final String DEFAULT_VALUE = "";
123 /***
124 * <p>
125 * This is the value which is output as a new entry. TODO: i18n
126 * </p>
127 */
128 public static final String NEW_DISPLAY_VALUE = "[New]";
129 /***
130 * <p>
131 * Local page of the action to which we'll link, for a read-only field.
132 * </p>
133 */
134 private String actionPage;
135 /***
136 * Refer to {@link #getAllValueObjects}.
137 */
138 private Collection allValueObjects;
139 /***
140 * <p>
141 * Stores all of the field's attributes and values, then writes them out
142 * later.
143 * </p>
144 */
145 private AttributesWriter attributesWriter;
146 /***
147 * <p>
148 * Field to be displayed.
149 * </p>
150 */
151 private Field field;
152 /***
153 * <p>
154 * Used to format the returned text.
155 * </p>
156 */
157 private HTMLFormatter formatter;
158 /***
159 * <p>
160 * Stores all of the hidden field's attributes and values, then writes them
161 * out later. This is used for a sublist.
162 * </p>
163 */
164 private AttributesWriter hiddenAttributesWriter;
165 /***
166 * <p>
167 * Construct a field writer.
168 * </p>
169 *
170 * @param fieldParam
171 * defines the field to be displayed.
172 * @param actionPageParam
173 * Refer to {@link DefaultFieldWriter#getActionPage}.
174 * @param allValueObjectsParam
175 * Refer to {@link #getAllValueObjects}.
176 * @param formatterParam
177 * Refer to {@link #getFormatter}.
178 * @param listHeightParam
179 * set as the size attribute in the field.
180 * @param multipleParam
181 * if <code>true</code>, then the user can make more than one
182 * selection.
183 */
184 public ValueObjectFieldWriter(final Field fieldParam,
185 final String actionPageParam,
186 final Collection allValueObjectsParam,
187 final HTMLFormatter formatterParam, final int listHeightParam,
188 final boolean multipleParam) {
189 super();
190 this.field = fieldParam;
191 this.actionPage = actionPageParam;
192 this.allValueObjects = allValueObjectsParam;
193 this.formatter = formatterParam;
194 boolean multiple = multipleParam;
195
196 String propertyNameSuffix;
197 if (isSublist()) {
198 propertyNameSuffix = "_sublist";
199
200 multiple = false;
201 } else {
202 propertyNameSuffix = "";
203 }
204 attributesWriter = new AttributesWriter(fieldParam, propertyNameSuffix);
205 attributesWriter
206 .setAttribute("size", Integer.toString(listHeightParam));
207 if (fieldParam.isMandatory()) {
208 attributesWriter.appendAttribute("class", "mandatory");
209 }
210 if (multiple) {
211 attributesWriter.setAttribute("multiple", "multiple");
212
213 if (StringHandling.isNullOrEmpty(fieldParam.getType())) {
214 attributesWriter.appendAttribute("class", CSS_LIST);
215 }
216 } else {
217 attributesWriter.remove("multiple");
218
219 if (StringHandling.isNullOrEmpty(fieldParam.getType())) {
220 attributesWriter.appendAttribute("class", CSS_COMBO);
221 }
222 }
223 }
224 /***
225 * All possible value objects to display in a list - for a choice. The user
226 * will be given the chance to choose from only these values.
227 *
228 * @return Returns the all value objects as a <code>Collection</code> of
229 * <code>ValueObject</code> instances.
230 */
231 protected final Collection getAllValueObjects() {
232 return allValueObjects;
233 }
234 /***
235 * <p>
236 * Access the attributes writer, which is responsible for converting the
237 * field attributes into text.
238 * </p>
239 *
240 * @return attributes writer.
241 */
242 protected final AttributesWriter getAttributesWriter() {
243 return attributesWriter;
244 }
245 /***
246 * <p>
247 * Access the field to be displayed.
248 * </p>
249 *
250 * @return field to be displayed.
251 */
252 protected final Field getField() {
253 return field;
254 }
255 /***
256 * Used to format the displayed, usually ensuring line breaks are converted
257 * into HTML.
258 *
259 * @return Returns the formatter.
260 */
261 protected final HTMLFormatter getFormatter() {
262 return formatter;
263 }
264 /***
265 * <p>
266 * Find out whether or not this field represents a sublist.
267 * </p>
268 *
269 * @return <code>true</code> if this is a sublist.
270 */
271 private boolean isSublist() {
272 return "sublist".equals(field.getType());
273 }
274 /***
275 * Refer to {@link FieldWriter#clearAttribute}.
276 *
277 * @param name Refer to {@link FieldWriter#clearAttribute}.
278 */
279 public void removeAttribute(final String name) {
280 attributesWriter.remove(name);
281 }
282 /***
283 * Refer to {@link FieldWriter#setAttribute}.
284 *
285 * @param name Refer to {@link FieldWriter#setAttribute}.
286 * @param value Refer to {@link FieldWriter#setAttribute}.
287 */
288 public void setAttribute(final String name, final String value) {
289 attributesWriter.setAttribute(name, value);
290 }
291 /***
292 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
293 *
294 * @param pageContextParam
295 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
296 * @param valueObjectParam
297 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
298 * @param displayOnlyParam
299 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
300 * @return Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
301 */
302 public final String write(final PageContext pageContextParam,
303 final ValueObject valueObjectParam,
304 final boolean displayOnlyParam) {
305 assert (pageContextParam != null);
306 assert (valueObjectParam != null);
307 Collection values;
308 Object object;
309 try {
310 object = PropertyUtils.getProperty(valueObjectParam, field
311 .getPath());
312
313
314 if (object != null) {
315 if (object instanceof ValueObject) {
316 values = new Vector();
317 values.add(object);
318 } else {
319
320
321 values = (Collection) object;
322 }
323 } else {
324 values = null;
325 }
326 } catch (IllegalAccessException e) {
327 throw new RuntimeException("ERROR (" + e.getClass().getName()
328 + ") in ValueObjectFieldWriter: " + e.getMessage());
329 } catch (InvocationTargetException e) {
330 throw new RuntimeException("ERROR (" + e.getClass().getName()
331 + ") in ValueObjectFieldWriter: " + e.getMessage());
332 } catch (NoSuchMethodException e) {
333
334 values = null;
335 }
336 if (displayOnlyParam) {
337 return writeDisplayOnly(pageContextParam, values);
338 } else {
339 return writeChoiceField(pageContextParam, values);
340 }
341 }
342 /***
343 * Display a field (which is not read-only).
344 *
345 * @param pageContextParam
346 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
347 * @param valuesParam
348 * contains all the possible values as strings.
349 * @return string representing the combo box.
350 */
351 public final String writeChoiceField(final PageContext pageContextParam,
352 final Collection valuesParam) {
353 List values = new Vector();
354 if (valuesParam != null) {
355 values.addAll(valuesParam);
356 }
357
358 if (allValueObjects.size() == 0) {
359 return DEFAULT_DISPLAY_VALUE;
360 }
361
362 if (values == null) {
363 values = new Vector();
364 values.add(DEFAULT_VALUE);
365 }
366
367 String stringValue;
368 StringBuffer buffer = new StringBuffer();
369
370
371 Iterator allValueIterator;
372 if (isSublist()) {
373 writeHiddenContents(buffer, field, values);
374
375 String onChangeSublist = "onChangeSublist(\""
376 + hiddenAttributesWriter.getAttribute("id")
377 + "\");return true";
378 attributesWriter.setAttribute("onchange", onChangeSublist);
379
380
381 allValueIterator = values.iterator();
382 } else {
383
384
385 allValueIterator = allValueObjects.iterator();
386 }
387 buffer.append("<select");
388 buffer.append(attributesWriter.toString());
389 buffer.append(">");
390
391 if (!isSublist() && !field.isMandatory()) {
392 buffer.append("\n<option value='");
393 buffer.append(DEFAULT_VALUE);
394 buffer.append("'>");
395 buffer.append(DEFAULT_DISPLAY_VALUE);
396 buffer.append("</option>");
397 }
398 while (allValueIterator.hasNext()) {
399 ValueObject thisObject = (ValueObject) allValueIterator.next();
400 buffer.append("\n<option value='");
401 buffer.append(thisObject.getIdString());
402
403 Iterator valueIterator = values.iterator();
404 while (valueIterator.hasNext()) {
405 Object value = valueIterator.next();
406 String idString;
407 if (value instanceof String) {
408 idString = (String) value;
409 } else {
410 idString = ((ValueObject) value).getIdString();
411 }
412
413 if (idString.equals(thisObject.getIdString()) && !isSublist()) {
414 buffer.append("' selected='selected");
415 break;
416 }
417 }
418 String displayValue;
419
420
421 if (isSublist()) {
422 Mask mask = field.getValueObjectMask();
423 Iterator fieldsIterator = mask.getFields().iterator();
424 StringBuffer displayValueBuffer = new StringBuffer();
425 while (fieldsIterator.hasNext()) {
426 if (displayValueBuffer.length() > 0) {
427 displayValueBuffer.append(" ");
428 }
429 Field subField = (Field) fieldsIterator.next();
430 String subDisplayValue;
431 Object subObject;
432 try {
433 subObject = PropertyUtils.getProperty(thisObject,
434 subField.getName());
435 } catch (IllegalAccessException e) {
436 throw new RuntimeException(e);
437 } catch (InvocationTargetException e) {
438 throw new RuntimeException(e);
439 } catch (NoSuchMethodException e) {
440 throw new RuntimeException(e);
441 }
442 if (subObject == null) {
443 subDisplayValue = DEFAULT_DISPLAY_VALUE;
444 } else if (subObject instanceof ValueObject) {
445 subDisplayValue = ((ValueObject) subObject)
446 .getDisplayValue();
447 } else {
448 subDisplayValue = subObject.toString();
449 }
450 displayValueBuffer.append(subDisplayValue);
451 }
452 displayValue = displayValueBuffer.toString();
453 } else {
454 displayValue = thisObject.getDisplayValue();
455 }
456 buffer.append("'>");
457 buffer.append(formatter.format(displayValue));
458 buffer.append("</option>");
459 }
460
461 if (isSublist()) {
462 buffer.append("\n<option value='");
463 buffer.append(DEFAULT_VALUE);
464 buffer.append("' selected='selected'>");
465 buffer.append(NEW_DISPLAY_VALUE);
466 buffer.append("</option>");
467 }
468 buffer.append("</select>");
469 stringValue = buffer.toString();
470 return stringValue;
471 }
472 /***
473 * Display the correct field value from the value object - for a read-only
474 * field.
475 *
476 * @param pageContextParam
477 * Refer to {@link com.ivata.mask.web.field.FieldWriter#write}.
478 * @param valuesParam
479 * Refer to {@link #writeChoiceField}.
480 * @return Refer to {@link #writeChoiceField}.
481 * @see com.ivata.mask.web.field.FieldWriter#write
482 */
483 public final String writeDisplayOnly(final PageContext pageContextParam,
484 final Collection valuesParam) {
485
486 if (valuesParam == null) {
487 return "";
488 }
489 Iterator valueIterator = valuesParam.iterator();
490 StringBuffer buffer = new StringBuffer();
491 String type = field.getType();
492 while (valueIterator.hasNext()) {
493 ValueObject valueObject = (ValueObject) valueIterator.next();
494
495 String stringValue = valueObject.getDisplayValue();
496 attributesWriter.setAttribute("value", stringValue);
497
498
499 if (!"sublist".equals(type)) {
500 buffer.append("<a href='");
501 try {
502 Map params = new HashMap();
503 params.put("baseClass", valueObject.getClass().getName());
504 params.put("idString", valueObject.getIdString());
505 params.put("displayOnly", "true");
506 String uRL = TagUtils.getInstance().computeURL(
507 pageContextParam, null, null, actionPage, null,
508 null, params, null, false);
509 buffer.append(uRL);
510 } catch (MalformedURLException e) {
511 throw new RuntimeException("ERROR ("
512 + e.getClass().getName()
513 + ") in ValueObjectFieldWriter: " + e.getMessage());
514 }
515 buffer.append("'>");
516 }
517 buffer.append(valueObject.getDisplayValue());
518 if (!"sublist".equals(type)) {
519 buffer.append("</a>");
520 }
521
522
523 if (valueIterator.hasNext()) {
524 buffer.append("<br/>\n");
525 }
526 }
527 return buffer.toString();
528 }
529 /***
530 * <p>
531 * If this is a sublist, we actually store the entries to submit in XML in a
532 * hidden field. This method generates that hidden field into the string
533 * buffer provided.
534 * </p>
535 *
536 * @param bufferParam
537 * String buffer into which we will write the results.
538 * @param fieldParam
539 * Field to be written out.
540 * @param valuesParam
541 * Refer to {@link #writeChoiceField}.
542 */
543 private void writeHiddenContents(final StringBuffer bufferParam,
544 final Field fieldParam, final Collection valuesParam) {
545 Document document = DocumentFactory.getInstance().createDocument();
546 Element rootElement = document.addElement("sublist");
547 Mask mask = fieldParam.getValueObjectMask();
548
549 Iterator valueIterator = valuesParam.iterator();
550 while (valueIterator.hasNext()) {
551 ValueObject valueObject = (ValueObject) valueIterator.next();
552 Element dOElement = rootElement.addElement("valueObject");
553 dOElement.addAttribute("id", valueObject.getIdString());
554
555 Iterator fieldIterator = mask.getFields().iterator();
556 while (fieldIterator.hasNext()) {
557 Field subField = (Field) fieldIterator.next();
558 Element fieldElement = dOElement.addElement("field");
559 fieldElement.addAttribute("id", subField.getName());
560 Object value;
561 try {
562 value = PropertyUtils.getProperty(valueObject, subField
563 .getName());
564 } catch (IllegalAccessException e) {
565 throw new RuntimeException("ERROR ("
566 + e.getClass().getName()
567 + ") in ValueObjectFieldWriter: " + e.getMessage(),
568 e);
569 } catch (InvocationTargetException e) {
570 throw new RuntimeException("ERROR ("
571 + e.getClass().getName()
572 + ") in ValueObjectFieldWriter: " + e.getMessage(),
573 e);
574 } catch (NoSuchMethodException e) {
575 throw new RuntimeException("ERROR ("
576 + e.getClass().getName()
577 + ") in ValueObjectFieldWriter: " + e.getMessage(),
578 e);
579 }
580 if (value != null) {
581
582 if (value instanceof ValueObject) {
583 fieldElement.setText(((ValueObject) value)
584 .getIdString());
585 } else {
586
587 fieldElement.setText(value.toString());
588 }
589 }
590 }
591 }
592
593
594 Iterator fieldIterator = mask.getFields().iterator();
595 Element dOElement = rootElement.addElement("valueObject");
596 dOElement.addAttribute("schema", "true");
597 while (fieldIterator.hasNext()) {
598 Field subField = (Field) fieldIterator.next();
599 Element fieldElement = dOElement.addElement("field");
600 fieldElement.addAttribute("id", subField.getName());
601 fieldElement.setText("");
602 }
603
604 hiddenAttributesWriter = new AttributesWriter(fieldParam);
605 hiddenAttributesWriter.setAttribute("type", "hidden");
606 hiddenAttributesWriter.setAttribute("value", document.asXML());
607 bufferParam.append("<input");
608 bufferParam.append(hiddenAttributesWriter.toString());
609 bufferParam.append("/>");
610
611 AttributesWriter idAttributesWriter = new AttributesWriter(fieldParam,
612 "_id");
613 idAttributesWriter.setAttribute("type", "hidden");
614 bufferParam.append("<input");
615 bufferParam.append(idAttributesWriter.toString());
616 bufferParam.append("/>");
617
618 AttributesWriter indexAttributesWriter = new AttributesWriter(
619 fieldParam, "_index");
620 indexAttributesWriter.setAttribute("type", "hidden");
621 bufferParam.append("<input");
622 bufferParam.append(indexAttributesWriter.toString());
623 bufferParam.append("/>");
624 }
625 }
626