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 package com.ivata.mask.web.struts;
68 import java.beans.PropertyDescriptor;
69 import java.io.IOException;
70 import java.io.StringReader;
71 import java.lang.reflect.Constructor;
72 import java.lang.reflect.InvocationTargetException;
73 import java.util.Arrays;
74 import java.util.Collection;
75 import java.util.Enumeration;
76 import java.util.HashMap;
77 import java.util.List;
78 import java.util.Map;
79
80 import javax.servlet.ServletException;
81 import javax.servlet.http.HttpServletRequest;
82 import javax.servlet.http.HttpServletResponse;
83
84 import org.apache.commons.beanutils.DynaProperty;
85 import org.apache.commons.beanutils.PropertyUtils;
86 import org.apache.log4j.Logger;
87 import org.apache.struts.Globals;
88 import org.apache.struts.action.Action;
89 import org.apache.struts.action.ActionForm;
90 import org.apache.struts.action.ActionMapping;
91 import org.apache.struts.action.ActionServlet;
92 import org.apache.struts.action.DynaActionForm;
93 import org.apache.struts.config.FormBeanConfig;
94 import org.apache.struts.config.ModuleConfig;
95 import org.apache.struts.taglib.html.Constants;
96 import org.dom4j.Document;
97 import org.dom4j.DocumentException;
98 import org.dom4j.Element;
99 import org.dom4j.Node;
100 import org.dom4j.io.SAXReader;
101
102 import com.ivata.mask.Mask;
103 import com.ivata.mask.MaskFactory;
104 import com.ivata.mask.field.DefaultFieldValueConvertorFactory;
105 import com.ivata.mask.field.Field;
106 import com.ivata.mask.field.FieldValueConvertor;
107 import com.ivata.mask.field.FieldValueConvertorConstants;
108 import com.ivata.mask.field.FieldValueConvertorFactory;
109 import com.ivata.mask.persistence.PersistenceException;
110 import com.ivata.mask.persistence.PersistenceManager;
111 import com.ivata.mask.persistence.PersistenceSession;
112 import com.ivata.mask.util.StringHandling;
113 import com.ivata.mask.util.SystemException;
114 import com.ivata.mask.validation.ValidationErrors;
115 import com.ivata.mask.valueobject.ValueObject;
116 /***
117 * <p>
118 * Mask request processor implementation - kept separate so we can share
119 * funcitonality between the regular ({@link MaskRequestProcessor}) and tiles (
120 * {@link MaskTilesRequestProcessor}) versions.
121 * </p>
122 *
123 * @since ivata masks 0.4 (2004-12-23)
124 * @author Colin MacLeod
125 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
126 * @version $Revision: 1.3 $
127 */
128 public class MaskRequestProcessorImplementation {
129 /***
130 * <p>
131 * Used to generate convertors to convert property types from strings.
132 * </p>
133 */
134 private FieldValueConvertorFactory fieldValueConvertorFactory;
135 /***
136 * <p>
137 * This log provides tracing and debugging information.
138 * </p>
139 */
140 private Logger log = Logger.getLogger(MaskRequestProcessorImplementation.class);
141 /***
142 * <p>
143 * This factory is needed to access the masks and groups of masks.
144 * </p>
145 */
146 private MaskFactory maskFactory;
147 /***
148 * <p>
149 * Used to locate the value objects by their shared base class.
150 * </p>
151 */
152 private PersistenceManager persistenceManager;
153 /***
154 * <p>
155 * Initializes the mask factory, the value object locator and the the
156 * standard field value convertors.
157 * </p>
158 *
159 * @param maskFactoryParam
160 * needed to access the masks and groups of masks.
161 * @param persistenceManagerParam
162 * used to locate the value objects by their shared base class.
163 */
164 public MaskRequestProcessorImplementation(final MaskFactory maskFactoryParam,
165 final PersistenceManager persistenceManagerParam,
166 final FieldValueConvertorFactory fieldValueConvertorFactoryParam) {
167 this.maskFactory = maskFactoryParam;
168 this.persistenceManager = persistenceManagerParam;
169 this.fieldValueConvertorFactory = fieldValueConvertorFactoryParam;
170 }
171 /***
172 * <p>
173 * Override this method to define how to create actions in your environment.
174 * This lets you use ivata masks with a standard framework.
175 * </p>
176 *
177 * <p>
178 * The default implementation looks for the action classes it knows about
179 * and initializes them directly. This is a simple starting point; in real
180 * life it is better to use a standard framework such as <a
181 * href="http://picocontainer.org">picocontainer </a>.
182 * </p>
183 *
184 *
185 * @param className
186 * full path and name of the action class to be created.
187 * @param request
188 * request for which we are creating an action.
189 * @param response
190 * response we are sending.
191 * @param mapping
192 * <strong>Struts </strong> mapping.
193 * @return valid action for the path, or <code>null</code> if the action
194 * can and should be created using the default <strong>Struts
195 * </strong> framework.
196 * @throws IOException
197 * if the action cannot be created.
198 */
199 protected Action createAction(final String className,
200 final HttpServletRequest request,
201 final HttpServletResponse response,
202 final ActionMapping mapping,
203 final Map actions,
204 final ActionServlet servlet)
205 throws IOException, SystemException {
206
207 if (!className.startsWith("com.ivata.mask.web.struts")) {
208 return null;
209 }
210
211 Action action = null;
212 MaskAuthenticator maskAuthenticator = new DefaultMaskAuthenticator();
213 if (className.endsWith("FindAction")) {
214 action = new FindAction(persistenceManager, maskFactory,
215 maskAuthenticator);
216 } else if (className.endsWith("InputMaskAction")) {
217 action = new InputMaskAction(maskFactory, persistenceManager,
218 maskAuthenticator);
219 } else if (className.endsWith("ListAction")) {
220 action = new ListAction(persistenceManager, maskFactory,
221 maskAuthenticator);
222 } else if (className.endsWith("NewAction")) {
223 action = new NewAction(maskFactory, maskAuthenticator);
224 } else {
225 throw new IOException("Unknow action '" + className + "'");
226 }
227 return action;
228 }
229 /***
230 * <p>
231 * Override this method to define how to create action forms in your
232 * environment. This lets you use ivata masks with a standard framework.
233 * </p>
234 *
235 * <p>
236 * The default implementation looks for the form classes it knows about and
237 * initializes them directly. This is a simple starting point; in real life
238 * it is better to use a standard framework such as <a
239 * href="http://picocontainer.org">picocontainer </a>.
240 * </p>
241 *
242 * @param formBeanConfig
243 * instance of <code>FormBeanConfig</code> defining the form to
244 * be created.
245 * @param request
246 * request for which we are creating an action.
247 * @param response
248 * response we are sending.
249 * @param mapping
250 * <strong>Struts </strong> mapping.
251 * @return valid action for the path, or <code>null</code> if the form can
252 * and should be created using the default <strong>Struts </strong>
253 * framework.
254 * @throws SystemException
255 * if the form cannot be created for any reason.
256 */
257 protected ActionForm createActionForm(final FormBeanConfig formBeanConfig,
258 final HttpServletRequest request,
259 final HttpServletResponse response,
260 final ActionMapping mapping) throws SystemException {
261 String className = formBeanConfig.getType();
262
263 if (!className.startsWith("com.ivata.mask.web.struts")) {
264 return null;
265 }
266 ActionForm form = null;
267 if (className.endsWith("InputMaskForm")) {
268 String baseClassName = request.getParameter("baseClass");
269 if (baseClassName == null) {
270 throw new NullPointerException(
271 "ERROR in MaskRequestProcessor: "
272 + "you must specify a request parameter called "
273 + "'baseClass'.");
274 }
275 Class baseClass;
276 try {
277 baseClass = Class.forName(baseClassName);
278 } catch (ClassNotFoundException e) {
279 throw new RuntimeException("ERROR in MaskRequestProcessor: no "
280 + "class called '" + baseClassName + "'");
281 }
282
283
284 String valueObjectClassName = request
285 .getParameter("valueObjectClass");
286 ValueObject valueObject;
287 if (valueObjectClassName == null) {
288 String idString = request.getParameter("idString");
289 if (idString == null) {
290 throw new NullPointerException(
291 "ERROR in MaskRequestProcessor: "
292 + "you must specify either a request parameter called "
293 + "'valueObjectClass', or one called 'idString'.");
294 }
295 PersistenceSession persistenceSession = persistenceManager
296 .openSession();
297 try {
298 valueObject = persistenceManager.findByPrimaryKey(
299 persistenceSession, baseClass, idString);
300 } finally {
301 persistenceSession.close();
302 }
303 if (valueObject == null) {
304 throw new NullPointerException(
305 "ERROR in MaskRequestProcessor: "
306 + "no value object with id '" + idString
307 + "' in class '" + baseClass + "'");
308 }
309 } else {
310 Class valueObjectClass;
311 try {
312 valueObjectClass = Class.forName(valueObjectClassName);
313 } catch (ClassNotFoundException e) {
314 throw new RuntimeException(
315 "ERROR in MaskRequestProcessor: no "
316 + "class called '" + valueObjectClassName
317 + "'");
318 }
319 try {
320 valueObject = (ValueObject) valueObjectClass.newInstance();
321 } catch (InstantiationException e) {
322 throw new RuntimeException("ERROR ("
323 + e.getClass().getName() + "): " + e.getMessage());
324 } catch (IllegalAccessException e) {
325 throw new RuntimeException("ERROR ("
326 + e.getClass().getName() + "): " + e.getMessage());
327 }
328 }
329 String inputMask = request.getParameter("inputMask");
330 if (inputMask == null) {
331 inputMask = maskFactory.getDefaultInputMask();
332 }
333 Mask mask = maskFactory.getMask(valueObject.getClass(), inputMask);
334 form = new InputMaskForm(valueObject, mask, baseClass);
335 }
336 return form;
337 }
338 /***
339 * Used to generate convertors to convert property types from strings.
340 * @return Returns the FieldValueConvertor factory.
341 */
342 public FieldValueConvertorFactory getFieldValueConvertorFactory() {
343 return fieldValueConvertorFactory;
344 }
345 /***
346 * Refer to {@link }.
347 *
348 * @param servletParam
349 * @param moduleConfigParam
350 * @throws javax.servlet.ServletException
351 * @see org.apache.struts.action.RequestProcessor#init(org.apache.struts.action.ActionServlet, org.apache.struts.config.ModuleConfig)
352 */
353 public void init(ActionServlet servletParam, ModuleConfig moduleConfigParam)
354 throws ServletException {
355 }
356 /***
357 * <p>
358 * Overridden to populate forms, and convert the string values of value
359 * object properties into the correct form for their class.
360 * </p>
361 *
362 * @param request
363 * servlet request we are processing.
364 * @param response
365 * servlet response we are creating.
366 * @param form
367 * form instance we are populating.
368 * @param mapping
369 * <strong>Struts </strong> mapping we are using.
370 *
371 * @exception ServletException
372 * if an exception is thrown while setting property values
373 * @see org.apache.struts.action.RequestProcessor#processPopulate
374 */
375 protected void processPopulate(final HttpServletRequest request,
376 final HttpServletResponse response,
377 final ActionForm form, final ActionMapping mapping)
378 throws ServletException {
379
380 if ((request.getParameter(Constants.CANCEL_PROPERTY) != null)
381 || (request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {
382 request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
383 return;
384 }
385 form.reset(mapping, request);
386 Enumeration parameterNames = request.getParameterNames();
387 Map properties = new HashMap();
388 ValidationErrors allErrors = new ValidationErrors();
389 while (parameterNames.hasMoreElements()) {
390 String parameterName = (String) parameterNames.nextElement();
391
392 if (!parameterName
393 .startsWith(FieldValueConvertorConstants
394 .PARAMETER_NAME_PREFIX)) {
395 setNonFieldProperty(form, parameterName, request);
396 continue;
397 }
398 setFieldProperty(form, parameterName, request, allErrors);
399 }
400 if (!allErrors.isEmpty()) {
401 request.setAttribute(
402 FieldValueConvertorConstants.ERROR_REQUEST_ATTRIBUTE,
403 allErrors);
404 }
405 }
406 /***
407 * <p>
408 * Set a target type of <code>Collection.</code>
409 * </p>
410 *
411 * @param request Refer to {@link #processPopulate}.
412 * @param parameterName name of the request parameter which evaluates to
413 * a collection.
414 * @param propertyType name of the concrete target class, a subclass of
415 * <code>Collection</code>.
416 * @param field field definition for the target.
417 * @param valueObject value object which contains the collection as a
418 * property.
419 * @param allErrors used to store all errors encountered.
420 * @throws ServletException if the collection cannot be set for any reason.
421 */
422 private void setCollection(final HttpServletRequest request,
423 final String parameterName,
424 final Class propertyType,
425 final Field field,
426 final ValueObject valueObject,
427 final ValidationErrors allErrors)
428 throws ServletException {
429 Collection collection;
430 try {
431 collection = (Collection) PropertyUtils.getProperty(valueObject,
432 field.getName());
433 } catch (IllegalAccessException e) {
434 throw new ServletException(e);
435 } catch (InvocationTargetException e) {
436 throw new ServletException(e);
437 } catch (NoSuchMethodException e) {
438 throw new ServletException(e);
439 }
440 Class dOClass = field.getDOClass();
441 if (dOClass == null) {
442 throw new NullPointerException(
443 "ERROR: for collection '"
444 + field.getName()
445 + "', you must specify a data object class (attribute 'class' "
446 + "in the ivata masks config).");
447 }
448 collection.clear();
449
450 if ("sublist".equals(field.getType())) {
451 setSubList(request, parameterName, propertyType, dOClass, field,
452 allErrors, collection);
453 } else {
454
455 setValueObjectList(request, parameterName, dOClass, collection);
456 }
457 }
458 /***
459 * <p>
460 * Use a value convertor to convert and set a single field value.
461 * </p>
462 *
463 * @param value string equivalent of the field's value.
464 * @param field field defition of the field to be set.
465 * @param descriptor property descriptor for this field in the value object.
466 * @param valueObject value object which contains the field as a
467 * property.
468 * @param allErrors stores all errors encountered processing the form.
469 * @throws ServletException Not thrown by this class. Use in subclasses, if
470 * you cannot set the field value for any reason.
471 */
472 private void setField(final String value,
473 final Field field,
474 final PropertyDescriptor descriptor,
475 final ValueObject valueObject,
476 final ValidationErrors allErrors) throws ServletException {
477
478 Class type = descriptor.getPropertyType();
479 if (type.isPrimitive()) {
480 try {
481 type = DefaultFieldValueConvertorFactory
482 .convertPrimitiveType(type);
483 } catch (SystemException e) {
484 throw new ServletException(e);
485 }
486 }
487 FieldValueConvertor convertor;
488 try {
489 convertor = fieldValueConvertorFactory.getFieldValueConvertorForClass(type);
490 } catch (SystemException e) {
491 throw new ServletException(e);
492 }
493 ValidationErrors theseErrors = convertor.setStringValue(valueObject,
494 field, value);
495 if (!theseErrors.isEmpty()) {
496 allErrors.addAll(theseErrors);
497 }
498 }
499 /***
500 * Set a property on a form which does represents an <strong>ivata
501 * masks</strong> field.
502 *
503 * @param form form instance we are populating.
504 * @param parameterName name of the parameter containing the field value.
505 * @param request servlet request we are processing.
506 * @param allErrors Any validation errors will be appended to this
507 * collection.
508 * @throws ServletException if the field value cannot be set.
509 */
510 private void setFieldProperty(ActionForm form, String parameterName,
511 HttpServletRequest request, ValidationErrors allErrors)
512 throws ServletException {
513 String fieldId = parameterName
514 .substring(FieldValueConvertorConstants.PARAMETER_NAME_PREFIX
515 .length());
516 if (fieldId.length() == 0) {
517 if (log.isDebugEnabled()) {
518 log.debug("Empty field found for '"
519 + parameterName
520 + "' on form '"
521 + form + "'");
522 }
523 return;
524 }
525 PropertyDescriptor descriptor;
526 try {
527 descriptor = PropertyUtils.getPropertyDescriptor(form,
528 parameterName);
529 } catch (IllegalAccessException e) {
530 throw new ServletException(e);
531 } catch (InvocationTargetException e) {
532 throw new ServletException(e);
533 } catch (IllegalArgumentException e) {
534 descriptor = null;
535 } catch (NoSuchMethodException e) {
536 descriptor = null;
537 }
538 if (descriptor == null) {
539 if (log.isDebugEnabled()) {
540 log.debug("Property descriptor is null for '"
541 + parameterName
542 + "' on form '"
543 + form + "'");
544 }
545 return;
546 }
547 InputMaskForm inputMaskForm;
548 Mask mask;
549 ValueObject valueObject;
550 if (form instanceof InputMaskForm) {
551 inputMaskForm = (InputMaskForm) form;
552 mask = inputMaskForm.getMask();
553 valueObject = inputMaskForm.getValueObject();
554 } else {
555 return;
556 }
557 Class propertyType = descriptor.getPropertyType();
558
559 Field field = mask.getField(fieldId);
560 if (field == null) {
561 if (log.isDebugEnabled()) {
562 log.debug("(Normally OK): no field found for '"
563 + parameterName
564 + "' on form '"
565 + form + "'");
566 }
567 return;
568 }
569
570 if (Collection.class.isAssignableFrom(propertyType)) {
571 setCollection(request, parameterName, propertyType, field,
572 valueObject, allErrors);
573
574 } else if (ValueObject.class.isAssignableFrom(propertyType)) {
575 setValueObject(valueObject, field, propertyType, request
576 .getParameter(parameterName));
577
578 } else {
579 setField(request.getParameter(parameterName), field,
580 descriptor, valueObject, allErrors);
581 }
582 }
583 /***
584 * Set a property on a form which does not represent an <strong>ivata
585 * masks</strong> field. This method uses {@link FieldValueConvertor}
586 * instances to convert to and from strings.
587 *
588 * @param form form instance we are populating.
589 * @param parameterName name of the parameter containing the field value.
590 * @param request servlet request we are processing.
591 * @throws ServletException if the field value cannot be set.
592 */
593 private void setNonFieldProperty(ActionForm form, String parameterName,
594 HttpServletRequest request) throws ServletException {
595 PropertyDescriptor descriptor;
596 try {
597 descriptor = PropertyUtils.getPropertyDescriptor(form,
598 parameterName);
599 } catch (IllegalAccessException e) {
600 throw new ServletException(e);
601 } catch (InvocationTargetException e) {
602 throw new ServletException(e);
603 } catch (NoSuchMethodException e) {
604
605 descriptor = null;
606 }
607 Class type = null;
608
609 if (descriptor != null) {
610 type = descriptor.getPropertyType();
611
612
613 } else if (form instanceof DynaActionForm) {
614 DynaActionForm dynaForm = (DynaActionForm) form;
615 DynaProperty dynaProperty = dynaForm.getDynaClass()
616 .getDynaProperty(parameterName);
617 if (dynaProperty != null) {
618 type = dynaProperty.getType();
619 }
620 }
621
622
623
624 if (type == null) {
625 if (log.isDebugEnabled()) {
626 log.debug("(Normally OK): no field found for '"
627 + parameterName
628 + "' on form '"
629 + form
630 + "'");
631 }
632 try {
633 PropertyUtils.setProperty(form, parameterName,
634 request.getParameter(parameterName));
635 } catch (IllegalAccessException e) {
636 if (log.isDebugEnabled()) {
637 log.debug("(Normally OK): "
638 + e.getClass().getName()
639 + " thrown setting property '"
640 + parameterName
641 + "' on form '"
642 + form
643 + "'", e);
644 }
645 } catch (InvocationTargetException e) {
646 if (log.isDebugEnabled()) {
647 log.debug("(Normally OK): "
648 + e.getClass().getName()
649 + " thrown setting property '"
650 + parameterName
651 + "' on form '"
652 + form
653 + "'", e);
654 }
655 } catch (NoSuchMethodException e) {
656 if (log.isDebugEnabled()) {
657 log.debug("(Normally OK): "
658 + e.getClass().getName()
659 + " thrown setting property '"
660 + parameterName
661 + "' on form '"
662 + form
663 + "'", e);
664 }
665 }
666 return;
667 }
668 Object value;
669
670
671
672 if (type.isAssignableFrom(String.class)) {
673 value = request.getParameter(parameterName);
674 } else if (Object[].class.isAssignableFrom(type)) {
675 value = request.getParameterValues(parameterName);
676 } else if (type.isAssignableFrom(List.class)) {
677 value = Arrays.asList(request.getParameterValues(parameterName));
678 } else {
679
680 FieldValueConvertor convertor;
681 try {
682 convertor = fieldValueConvertorFactory
683 .getFieldValueConvertorForClass(type);
684 } catch (SystemException e2) {
685 throw new ServletException(e2);
686 }
687 if (convertor == null) {
688 Constructor constructor;
689 try {
690 constructor = type.getConstructor(new Class[] {
691 String.class
692 });
693 value = constructor.newInstance(new Object[] {
694 request.getParameter(parameterName)
695 });
696 } catch (SecurityException e) {
697 throw new ServletException(e);
698 } catch (NoSuchMethodException e) {
699 if (log.isDebugEnabled()) {
700 log.debug("No constructor found of type '"
701 + type.getName()
702 + "' with a string constructor on form '"
703 + form
704 + "'");
705 }
706 return;
707 } catch (IllegalArgumentException e) {
708 throw new ServletException(e);
709 } catch (InstantiationException e) {
710 throw new ServletException(e);
711 } catch (IllegalAccessException e) {
712 throw new ServletException(e);
713 } catch (InvocationTargetException e) {
714 throw new ServletException(e);
715 }
716 } else {
717 value = convertor.convertFromString(type,
718 request.getParameter(parameterName));
719 }
720 }
721 try {
722 PropertyUtils.setProperty(form, parameterName,
723 value);
724 } catch (IllegalAccessException e1) {
725 throw new ServletException(e1);
726 } catch (InvocationTargetException e1) {
727 throw new ServletException(e1);
728 } catch (NoSuchMethodException e1) {
729
730 if (log.isDebugEnabled()) {
731 log.debug("(Normally OK): no setter for property' "
732 + parameterName
733 + "'", e1);
734 }
735 }
736 }
737 /***
738 * <p>
739 * Set all the elements of a value object sublist.
740 * </p>
741 *
742 * @param requestParam Refer to {@link #setCollection}.
743 * @param parameterNameParam Refer to {@link #setCollection}.
744 * @param propertyTypeParam Refer to {@link #setCollection}.
745 * @param dOClassParam Refer to {@link #setCollection}.
746 * @param fieldParam Refer to {@link #setCollection}.
747 * @param allErrorsParam Refer to {@link #setCollection}.
748 * @param collectionParam Refer to {@link #setCollection}.
749 * @throws ServletException Refer to {@link #setCollection}.
750 */
751 private void setSubList(final HttpServletRequest requestParam,
752 final String parameterNameParam,
753 final Class propertyTypeParam,
754 final Class dOClassParam,
755 final Field fieldParam,
756 final ValidationErrors allErrorsParam,
757 final Collection collectionParam)
758 throws ServletException {
759 SAXReader reader = new SAXReader();
760 Document document;
761 try {
762 document = reader.read(new StringReader(requestParam
763 .getParameter(parameterNameParam)));
764 } catch (DocumentException e1) {
765 throw new ServletException(e1);
766 }
767 Element rootElement = document.getRootElement();
768
769 if (!"sublist".equals(rootElement.getName())) {
770 throw new ServletException(
771 "Unexpected root element in sublist. Found '"
772 + rootElement.getName()
773 + "' , expected 'sublist'.");
774 }
775
776 for (int i = 0, rootSize = rootElement.nodeCount(); i < rootSize; ++i) {
777 Node node = rootElement.node(i);
778
779
780 if (!((node instanceof Element) && "valueObject"
781 .equals(((Element) node).getName()))) {
782 throw new ServletException(
783 "Unexpected value object element in sublist. Found '"
784 + node.asXML()
785 + "' , expected element called 'valueObject'.");
786 }
787 Element dOElement = (Element) node;
788 String id = dOElement.attributeValue("id");
789 String schema = dOElement.attributeValue("schema");
790
791 if ("true".equals(schema)) {
792 continue;
793 }
794
795
796 ValueObject subObject;
797 if (!StringHandling.isNullOrEmpty(id)) {
798 try {
799 PersistenceSession persistenceSession = persistenceManager
800 .openSession();
801 try {
802 subObject = persistenceManager.findByPrimaryKey(
803 persistenceSession, dOClassParam, id);
804 } finally {
805 persistenceSession.close();
806 }
807 } catch (PersistenceException e) {
808 throw new ServletException(e);
809 }
810 } else {
811
812
813
814
815 try {
816 subObject = (ValueObject) dOClassParam.getConstructor(null)
817 .newInstance(null);
818 } catch (IllegalArgumentException e) {
819 throw new ServletException(e);
820 } catch (SecurityException e) {
821 throw new ServletException(e);
822 } catch (InstantiationException e) {
823 throw new ServletException(e);
824 } catch (IllegalAccessException e) {
825 throw new ServletException(e);
826 } catch (InvocationTargetException e) {
827 throw new ServletException(e);
828 } catch (NoSuchMethodException e) {
829 throw new ServletException(e);
830 }
831 }
832 Mask subMask = fieldParam.getValueObjectMask();
833
834 for (int j = 0, dOSize = dOElement.nodeCount(); j < dOSize; ++j) {
835 node = dOElement.node(j);
836
837
838 if (!((node instanceof Element) && "field"
839 .equals(((Element) node).getName()))) {
840 String xML = null;
841 if (node != null) {
842 xML = node.asXML();
843 }
844 throw new ServletException(
845 "Unexpected field element in sublist. Found '"
846 + xML
847 + "' , expected element called 'field'.");
848 }
849 Element fieldElement = (Element) node;
850 String subFieldId = fieldElement.attributeValue("id");
851 Field subField = subMask.getField(subFieldId);
852 PropertyDescriptor subDescriptor;
853 try {
854 subDescriptor = PropertyUtils.getPropertyDescriptor(
855 subObject, subFieldId);
856 } catch (IllegalAccessException e) {
857 throw new ServletException(e);
858 } catch (InvocationTargetException e) {
859 throw new ServletException(e);
860 } catch (NoSuchMethodException e) {
861 throw new ServletException(e);
862 }
863 Class subPropertyType = subDescriptor.getPropertyType();
864 try {
865 FieldValueConvertor subConvertor =
866 fieldValueConvertorFactory
867 .getFieldValueConvertorForClass(subPropertyType);
868 } catch (SystemException e2) {
869 throw new ServletException(e2);
870 }
871
872 if (ValueObject.class.isAssignableFrom(subPropertyType)) {
873 setValueObject(subObject, subField, subPropertyType,
874 fieldElement.getText());
875
876 } else {
877 setField(fieldElement.getText(), subField, subDescriptor,
878 subObject, allErrorsParam);
879 }
880 }
881
882 try {
883 PersistenceSession persistenceSession = persistenceManager
884 .openSession();
885 try {
886 if (StringHandling.isNullOrEmpty(id)) {
887 subObject = persistenceManager.add(persistenceSession,
888 subObject);
889 } else {
890 persistenceManager.amend(persistenceSession, subObject);
891 }
892 } finally {
893 persistenceSession.close();
894 }
895 } catch (PersistenceException e) {
896 throw new ServletException(e);
897 }
898 collectionParam.add(subObject);
899 }
900 }
901 /***
902 * <p>
903 * Set an individual value object.
904 * </p>
905 *
906 * @param valueObject value object containing the value object to be set.
907 * <b>Note</b> this is the container, not the 'property' value object.
908 * @param field field definition of this value object.
909 * @param propertyType class of value object.
910 * @param id value object unique identifier.
911 * @throws ServletException if the value object cannot be set for any
912 * reason.
913 */
914 private void setValueObject(final ValueObject valueObject,
915 final Field field, final Class propertyType,
916 final String id)
917 throws ServletException {
918 ValueObject subObject;
919 if (StringHandling.isNullOrEmpty(id)) {
920 subObject = null;
921 } else {
922 try {
923 PersistenceSession persistenceSession = persistenceManager
924 .openSession();
925 try {
926 subObject = persistenceManager.findByPrimaryKey(
927 persistenceSession, propertyType, id);
928 } finally {
929 persistenceSession.close();
930 }
931 if (subObject == null) {
932 throw new NullPointerException(
933 "ERROR: unable to locate sub-value object of class '"
934 + propertyType + "', with id '" + id + "'");
935 }
936 } catch (PersistenceException e) {
937 throw new ServletException(e);
938 }
939 }
940 try {
941 PropertyUtils.setProperty(valueObject, field.getName(), subObject);
942 } catch (IllegalAccessException e) {
943 throw new ServletException(e);
944 } catch (InvocationTargetException e) {
945 throw new ServletException(e);
946 } catch (NoSuchMethodException e) {
947 throw new ServletException(e);
948 }
949 }
950 /***
951 * <p>
952 * Set a list of value objects, identified by their id values.
953 * </p>
954 *
955 * @param request current servlet request we are processing.
956 * @param parameterName name of the request parameter which contains the
957 * value object list details.
958 * @param dOClass data object class of the value objects in the list.
959 * @param collection collection to add the value objects to.
960 * @throws ServletException if the value objects cannot be set for any
961 * reason.
962 */
963 private void setValueObjectList(final HttpServletRequest request,
964 final String parameterName,
965 final Class dOClass,
966 final Collection collection)
967 throws ServletException {
968 String[] ids = request.getParameterValues(parameterName);
969 for (int i = 0; i < ids.length; i++) {
970 ValueObject subObject;
971 try {
972 PersistenceSession persistenceSession = persistenceManager
973 .openSession();
974 try {
975 subObject = persistenceManager.findByPrimaryKey(
976 persistenceSession, dOClass, ids[i]);
977 } finally {
978 persistenceSession.close();
979 }
980 } catch (PersistenceException e) {
981 throw new ServletException(e);
982 }
983 if (subObject == null) {
984 throw new NullPointerException(
985 "ERROR: unable to locate sub value object of class '"
986 + dOClass + "', with id '" + ids[i] + "'");
987 }
988 collection.add(subObject);
989 }
990 }
991 }
992