View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kns.web.ui;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.util.ClassLoaderUtils;
20  import org.kuali.rice.core.api.util.KeyValue;
21  import org.kuali.rice.core.web.format.Formatter;
22  import org.kuali.rice.kns.datadictionary.CollectionDefinitionI;
23  import org.kuali.rice.kns.datadictionary.FieldDefinition;
24  import org.kuali.rice.kns.datadictionary.FieldDefinitionI;
25  import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
26  import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
27  import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
28  import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
29  import org.kuali.rice.kns.lookup.LookupUtils;
30  import org.kuali.rice.kns.maintenance.Maintainable;
31  import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
32  import org.kuali.rice.kns.service.KNSServiceLocator;
33  import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
34  import org.kuali.rice.kns.util.FieldUtils;
35  import org.kuali.rice.kns.util.MaintenanceUtils;
36  import org.kuali.rice.kns.util.WebUtils;
37  import org.kuali.rice.krad.bo.BusinessObject;
38  import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
39  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
40  import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder;
41  import org.kuali.rice.krad.service.DataDictionaryService;
42  import org.kuali.rice.krad.service.KRADServiceLocator;
43  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
44  import org.kuali.rice.krad.service.PersistenceStructureService;
45  import org.kuali.rice.krad.util.KRADConstants;
46  import org.kuali.rice.krad.util.ObjectUtils;
47  
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.List;
51  import java.util.Set;
52  
53  /**
54   * @deprecated KNS Struts deprecated, use KRAD and the Spring MVC framework.
55   */
56  @Deprecated
57  public class FieldBridge {
58      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FieldBridge.class);
59      private static DataDictionaryService dataDictionaryService;
60      private static PersistenceStructureService persistenceStructureService;
61      private static BusinessObjectDictionaryService businessObjectDictionaryService;
62      private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
63  
64      /**
65       * Sets additional properties for MaintainableField(s)
66       *
67       * @param field The field to populate.
68       * @param definition The DD specification for the field.
69       */
70      public static final void setupField(Field field, FieldDefinitionI definition, Set<String> conditionallyRequiredMaintenanceFields) {
71          if (definition instanceof MaintainableFieldDefinition) {
72              MaintainableFieldDefinition maintainableFieldDefinition = ((MaintainableFieldDefinition) definition);
73              
74              field.setFieldRequired(maintainableFieldDefinition.isRequired());
75              field.setReadOnly(maintainableFieldDefinition.isUnconditionallyReadOnly());
76              if (maintainableFieldDefinition.isLookupReadOnly()) {
77              	field.setFieldType(Field.LOOKUP_READONLY);
78              }
79  
80              // set onblur and callback functions
81              if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldFunction())) {
82                  field.setWebOnBlurHandler(maintainableFieldDefinition.getWebUILeaveFieldFunction());
83              }
84  
85              if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction())) {
86                  field.setWebOnBlurHandlerCallback(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction());
87              }
88  
89              if (maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters()!=null) {
90                  field.setWebUILeaveFieldFunctionParameters(maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters());
91              }
92              
93  			if (StringUtils.isNotBlank(maintainableFieldDefinition.getAlternateDisplayAttributeName())) {
94  				field.setAlternateDisplayPropertyName(maintainableFieldDefinition.getAlternateDisplayAttributeName());
95  			}
96  
97  			if (StringUtils.isNotBlank(maintainableFieldDefinition.getAdditionalDisplayAttributeName())) {
98  				field.setAdditionalDisplayPropertyName(maintainableFieldDefinition.getAdditionalDisplayAttributeName());
99  			}
100             
101             if (conditionallyRequiredMaintenanceFields != null && conditionallyRequiredMaintenanceFields.contains(field.getPropertyName())) {
102             	field.setFieldRequired(true);
103             }
104             
105             if (((MaintainableFieldDefinition) definition).isTriggerOnChange()) {
106             	field.setTriggerOnChange(true);
107             }
108         }
109     }
110 
111     /**
112 	 * Uses reflection to populate the rows of the inquiry from the business
113 	 * object value. Also formats if needed.
114      *
115 	 * @param field
116 	 *            The Field to populate.
117 	 * @param bo
118 	 *            The BusinessObject from which the Field will be popualated.
119      */
120     public static final void populateFieldFromBusinessObject(Field field, BusinessObject bo) {
121         if (bo == null) {
122             throw new RuntimeException("Inquiry Business object is null.");
123         }
124 
125         field.setReadOnly(true); // inquiry fields are always read only
126 
127         Formatter formatter = field.getFormatter();
128         String propertyName = field.getPropertyName();
129 
130         // get the field type for the property
131 		ControlDefinition fieldControl = getDataDictionaryService().getAttributeControlDefinition(bo.getClass(),
132 				propertyName);
133         try {
134             Object prop = ObjectUtils.getPropertyValue(bo, field.getPropertyName());
135 
136 			// for select fields, display the associated label (unless we are
137 			// already display an additonal attribute)
138 			String propValue = KRADConstants.EMPTY_STRING;
139 			if (fieldControl != null && fieldControl.isSelect()
140 					&& StringUtils.isBlank(field.getAdditionalDisplayPropertyName())
141 					&& StringUtils.isBlank(field.getAlternateDisplayPropertyName())) {
142 				Class<? extends KeyValuesFinder> keyValuesFinderName = ClassLoaderUtils.getClass(fieldControl.getValuesFinderClass(), KeyValuesFinder.class);
143                 KeyValuesFinder finder = keyValuesFinderName.newInstance();
144                 if(formatter != null){
145                     prop = ObjectUtils.getFormattedPropertyValue(bo,propertyName,formatter);
146                 }
147                 propValue = lookupFinderValue(fieldControl, prop, finder);
148             } else {
149 				propValue = ObjectUtils.getFormattedPropertyValue(bo, field.getPropertyName(), formatter);
150                     }
151 			field.setPropertyValue(propValue);
152 			
153 			// set additional or alternate display property values if property
154 			// name is specified
155 			if (StringUtils.isNotBlank(field.getAlternateDisplayPropertyName())) {
156 				String alternatePropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
157 						.getAlternateDisplayPropertyName());
158 				field.setAlternateDisplayPropertyValue(alternatePropertyValue);
159                 }
160 
161 			if (StringUtils.isNotBlank(field.getAdditionalDisplayPropertyName())) {
162 				String additionalPropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
163 						.getAdditionalDisplayPropertyName());
164 				field.setAdditionalDisplayPropertyValue(additionalPropertyValue);
165             }
166 
167 			// for user fields, attempt to pull the principal ID and person's
168 			// name from the source object
169             if ( fieldControl != null && fieldControl.isKualiUser() ) {
170             	// this is supplemental, so catch and log any errors 
171             	try {
172             		if ( StringUtils.isNotBlank(field.getUniversalIdAttributeName()) ) {
173             			Object principalId = ObjectUtils.getNestedValue(bo, field.getUniversalIdAttributeName());
174             			if ( principalId != null ) {
175             				field.setUniversalIdValue(principalId.toString());
176             			}
177             		}
178             		if ( StringUtils.isNotBlank(field.getPersonNameAttributeName()) ) {
179             			Object personName = ObjectUtils.getNestedValue(bo, field.getPersonNameAttributeName());
180             			if ( personName != null ) {
181             				field.setPersonNameValue( personName.toString() );
182             			}
183             		}
184             	} catch ( Exception ex ) {
185             		LOG.warn( "Unable to get principal ID or person name property in FieldBridge.", ex );
186             	}
187             }
188             if (fieldControl != null && fieldControl.isFile()) {
189                 if (Field.FILE.equals(field.getFieldType())) {
190                     Object fileName = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_NAME);
191                     Object fileType = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_CONTENT_TYPE);
192                     field.setImageSrc(WebUtils.getAttachmentImageForUrl((String) fileType));
193                     field.setPropertyValue(fileName);
194                 }
195             }
196             FieldUtils.setInquiryURL(field, bo, propertyName);
197 		} catch (InstantiationException e) {
198             LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
199             throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
200 		} catch (ClassNotFoundException e) {
201 			LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
202             throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
203 		} catch (IllegalAccessException e) {
204             LOG.error("Unable to set columns: " + e.getMessage());
205             throw new RuntimeException("Unable to set columns: " + e.getMessage());
206         }
207 
208     }
209 
210     /**
211      * This method looks up a value in a finder class.
212      * @param fieldControl the type of web control that is associated with this field.
213      * @param prop the property to look up - either a property name as a String, or a referenced object
214      * @param finder finder to look the value up in
215      * @return the value that was returned from the lookup
216      */
217     private static String lookupFinderValue(ControlDefinition fieldControl, Object prop, KeyValuesFinder finder) {
218         String propValue = null;
219 
220         // KULRICE-1808 : PersistableBusinessObjectValuesFinder is not working for inquiries that have child objects with ValuesFinder populated select lists
221         if (finder instanceof PersistableBusinessObjectValuesFinder) {
222             ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass(ClassLoaderUtils.getClass(fieldControl.getBusinessObjectClass()));
223             ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName(fieldControl.getKeyAttribute());
224             ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName(fieldControl.getLabelAttribute());
225             if (fieldControl.getIncludeBlankRow() != null) {
226             	((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(fieldControl.getIncludeBlankRow());
227             }
228             ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(fieldControl.getIncludeKeyInLabel());
229         }
230         List<KeyValue> keyValues = finder.getKeyValues();
231         propValue = getPropertyValueFromList(prop, keyValues);
232         if(propValue==null) {
233 			propValue = lookupInactiveFinderValue(prop, finder);
234 		}
235         return propValue;
236     }
237     
238     private static String lookupInactiveFinderValue(Object property, KeyValuesFinder finder){
239     	List<KeyValue> keyValues = finder.getKeyValues(false);
240     	return getPropertyValueFromList(property, keyValues);
241     	
242     }
243     
244     private static String getPropertyValueFromList(Object property, List<KeyValue> keyValues){
245     	String propertyValue = null;
246         if (property != null) {
247             for (Object element2 : keyValues) {
248                 KeyValue element = (KeyValue) element2;
249                 if (element.getKey().toString().equals(property.toString())) {
250                     propertyValue = element.getValue();
251                     break;
252                 }
253             }
254         }
255         return propertyValue;
256     }
257     
258     /**
259      * Determines whether field level help is enabled for the field corresponding to the dataObjectClass and attribute name
260      *
261      * If this value is true, then the field level help will be enabled.
262      * If false, then whether a field is enabled is determined by the value returned by {@link #isMaintenanceFieldLevelHelpDisabled(Maintainable, MaintainableFieldDefinition)}
263      * and the system-wide parameter setting.  Note that if a field is read-only, that may cause field-level help to not be rendered.
264      *
265      * @param businessObjectClass the looked up class
266      * @param attributeName the attribute for the field
267      * @return true if field level help is enabled, false if the value of this method should NOT be used to determine whether this method's return value
268      * affects the enablement of field level help
269      */
270     protected static boolean isMaintenanceFieldLevelHelpEnabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
271         if ( fieldDefinition != null ) {
272             if ( fieldDefinition.isShowFieldLevelHelp() != null && fieldDefinition.isShowFieldLevelHelp() ) {
273                 return true;
274             }
275         }
276         return false;
277     }
278 
279     /**
280      * Determines whether field level help is disabled for the field corresponding to the dataObjectClass and attribute name
281      *
282      * If this value is true and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} returns false,
283      * then the field level help will not be rendered.  If both this and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} return false,
284      * then the system-wide setting will determine whether field level help is enabled.  Note that if a field is read-only, that may cause
285      * field-level help to not be rendered.
286      *
287      * @param businessObjectClass the looked up class
288      * @param attributeName the attribute for the field
289      * @return true if field level help is disabled, false if the value of this method should NOT be used to determine whether this method's return value
290      * affects the enablement of field level help
291      */
292     protected static boolean isMaintenanceFieldLevelHelpDisabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
293         if ( fieldDefinition != null ) {
294             if ( fieldDefinition.isShowFieldLevelHelp() != null && !fieldDefinition.isShowFieldLevelHelp() ) {
295                 return true;
296             }
297         }
298         return false;
299     }
300 
301     /**
302      * This method creates a Field for display on a Maintenance Document.
303      *
304      * @param id The DD definition for the Field (can be a Collection).
305      * @param sd The DD definition for the Section in which the field will be displayed.
306      * @param o The BusinessObject will be populated from this BO.
307      * @param m
308      * @param s The Section in which the Field will be displayed.
309      * @param autoFillDefaultValues Should default values be filled in?
310      * @param autoFillBlankRequiredValues Should values be filled in for fields that are required but which were left blank when submitting the form from the UI?
311      * @param displayedFieldNames What fields are being displayed on the form in the UI?
312      *
313      * @return
314      *
315      * @throws InstantiationException
316      * @throws IllegalAccessException
317      */
318     public static final Field toField(MaintainableItemDefinition id, MaintainableSectionDefinition sd, BusinessObject o, Maintainable m, Section s, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields) throws InstantiationException, IllegalAccessException {
319         Field field = new Field();
320 
321         // if FieldDefiniton, simply add a Field UI object
322         if (id instanceof MaintainableFieldDefinition) {
323             MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) id;
324             field = FieldUtils.getPropertyField(o.getClass(), maintainableFieldDefinition.getName(), false);
325 
326 			boolean translateCodes = getMaintenanceDocumentDictionaryService().translateCodes(o.getClass());
327 			if (translateCodes) {
328 				FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), field.getPropertyName(), field);
329 			}
330 
331             setupField(field, maintainableFieldDefinition, conditionallyRequiredMaintenanceFields);
332 
333             MaintenanceUtils.setFieldQuickfinder(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames, m);
334             MaintenanceUtils.setFieldDirectInquiry(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames);
335 
336             // set default value
337             //TODO St. Ailish says review this. A question was raised on 11-16-2006 Tuscon meeting as to why this is done here and not in the formatter.
338             /*if (autoFillDefaultValues) {
339                 Object defaultValue = maintainableFieldDefinition.getDefaultValue();
340                 if (defaultValue != null) {
341                     if (defaultValue.toString().equals("true")) {
342                         defaultValue = "Yes";
343                     }
344                     else if (defaultValue.toString().equals("false")) {
345                         defaultValue = "No";
346                     }
347                     field.setPropertyValue(defaultValue);
348                 }
349 
350                 Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
351                 if (defaultValueFinderClass != null) {
352                     field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
353                 }
354             }
355 
356             // if this flag is set, and the current field is required, and readonly, and blank, use the
357             // defaultValueFinder if one exists
358             if (autoFillBlankRequiredValues) {
359                 if ( maintainableFieldDefinition.isRequired() && maintainableFieldDefinition.isUnconditionallyReadOnly() ) {
360                     if ( StringUtils.isBlank( field.getPropertyValue() ) ) {
361                         Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
362                         if (defaultValueFinderClass != null) {
363                             field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
364                         }
365                     }
366                 }
367             }
368 			*/
369             field.setFieldLevelHelpEnabled(isMaintenanceFieldLevelHelpEnabled(m, maintainableFieldDefinition));
370             field.setFieldLevelHelpDisabled(isMaintenanceFieldLevelHelpDisabled(m, maintainableFieldDefinition));
371             field.setFieldLevelHelpUrl(maintainableFieldDefinition.getFieldLevelHelpUrl());
372         }
373 
374         return field;
375 
376     }
377 
378     /**
379      * This method will return a new form for adding in a BO for a collection.
380      * This should be customized in a subclass so the default behavior is to return nothing.
381      *
382      * @param collectionDefinition The DD definition for the Collection.
383      * @param o The BusinessObject form which the new Fields will be populated.
384      * @param document MaintenanceDocument instance which we ar building fields for
385      * @param m
386      * @param displayedFieldNames What Fields are being displayed on the form in the UI?
387      * @param containerRowErrorKey The error key for the Container/Collection used for displaying error messages.
388      * @param parents
389      * @param hideAdd Should the add line be hidden when displaying this Collection/Container in the UI?
390      * @param numberOfColumns How many columns the Fields in the Collection will be split into when displaying them in the UI.
391      *
392      * @return The List of new Fields.
393      */
394     public static final List<Field> getNewFormFields(CollectionDefinitionI collectionDefinition, BusinessObject o, Maintainable m, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields, StringBuffer containerRowErrorKey, String parents, boolean hideAdd, int numberOfColumns) {
395         LOG.debug( "getNewFormFields" );
396         String collName = collectionDefinition.getName();
397 
398         List<Field> collFields = new ArrayList<Field>();
399         Collection<? extends FieldDefinitionI> collectionFields;
400         //Class boClass = collectionDefinition.getDataObjectClass();
401         BusinessObject collBO = null;
402         try {
403             collectionFields = collectionDefinition.getFields();
404             collBO = m.getNewCollectionLine(parents + collName);
405 
406             if ( LOG.isDebugEnabled() ) {
407                 LOG.debug( "newBO for add line: " + collBO );
408             }
409 
410             for ( FieldDefinitionI fieldDefinition : collectionFields  ) {
411                 // construct Field UI object from definition
412                 Field collField = FieldUtils.getPropertyField(collectionDefinition.getBusinessObjectClass(), fieldDefinition.getName(), false);
413 
414                 if (fieldDefinition instanceof MaintainableFieldDefinition) {
415                     setupField(collField, fieldDefinition, conditionallyRequiredMaintenanceFields);
416                 }
417                 //generate the error key for the add row
418                 String[] nameParts = StringUtils.split(collField.getPropertyName(), ".");
419                 String fieldErrorKey = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + KRADConstants.ADD_PREFIX + ".";
420                 fieldErrorKey += collName + ".";
421                 for (int i = 0; i < nameParts.length; i++) {
422                     fieldErrorKey += nameParts[i];
423                     containerRowErrorKey.append(fieldErrorKey);
424                     if (i < nameParts.length) {
425                         fieldErrorKey += ".";
426                         containerRowErrorKey.append(",");
427                     }
428                 }
429 
430                 //  set the QuickFinderClass
431                 BusinessObject collectionBoInstance = collectionDefinition.getBusinessObjectClass().newInstance();
432                 FieldUtils.setInquiryURL(collField, collectionBoInstance, fieldDefinition.getName());
433                 if (collectionDefinition instanceof MaintainableCollectionDefinition) {
434                     MaintenanceUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m, (MaintainableFieldDefinition) fieldDefinition);
435                     MaintenanceUtils
436                             .setFieldDirectInquiry(collectionBoInstance, parents + collectionDefinition.getName(), true,
437                                     0, fieldDefinition.getName(), collField, displayedFieldNames, m,
438                                     (MaintainableFieldDefinition) fieldDefinition);
439                 }
440                 else {
441                     LookupUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m);
442                     LookupUtils.setFieldDirectInquiry(collectionBoInstance, fieldDefinition.getName(), collField);
443                 }
444 
445                 collFields.add(collField);
446             }
447 
448         } catch (InstantiationException e) {
449             LOG.error("Unable to create instance of object class" + e.getMessage());
450             throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
451         } catch (IllegalAccessException e) {
452             LOG.error("Unable to create instance of object class" + e.getMessage());
453             throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
454         }
455 
456         // populate field values from business object
457         collFields = FieldUtils.populateFieldsFromBusinessObject(collFields,collBO);
458 
459         // need to append the prefix afterwards since the population command (above)
460         // does not handle the prefixes on the property names
461         for ( Field field : collFields ) {
462             // prefix name for add line
463             field.setPropertyName(KRADConstants.MAINTENANCE_ADD_PREFIX + parents + collectionDefinition.getName() + "." + field.getPropertyName());
464         }
465         LOG.debug("Error Key for section " + collectionDefinition.getName() + " : " + containerRowErrorKey.toString());
466 
467         
468         collFields = constructContainerField(collectionDefinition, parents, o, hideAdd, numberOfColumns, collName, collFields);
469 
470         return collFields;
471     }
472 
473     /**
474      * 
475      * This method handles setting up a container field not including the add fields
476      * 
477      * @param collectionDefinition
478      * @param parents
479      * @param o
480      * @param hideAdd
481      * @param numberOfColumns
482      * @param collName
483      * @param collFields
484      * @return
485      */
486     public static List<Field> constructContainerField(CollectionDefinitionI collectionDefinition, String parents, BusinessObject o, boolean hideAdd, int numberOfColumns, String collName, List<Field> collFields) {
487         // get label for collection
488         String collectionLabel = getDataDictionaryService().getCollectionLabel(o.getClass(), collectionDefinition.getName());
489 
490         // retrieve the summary label either from the override or from the DD
491         String collectionElementLabel = collectionDefinition.getSummaryTitle();
492         if(StringUtils.isEmpty(collectionElementLabel)){
493             collectionElementLabel = getDataDictionaryService().getCollectionElementLabel(o.getClass().getName(), collectionDefinition.getName(),collectionDefinition.getBusinessObjectClass());
494         }
495 
496         // container field
497         Field containerField;
498         containerField = FieldUtils.constructContainerField(collName, collectionLabel, collFields, numberOfColumns);
499         if(StringUtils.isNotEmpty(collectionElementLabel)) {
500             containerField.setContainerElementName(collectionElementLabel);
501         }
502         collFields = new ArrayList();
503         collFields.add(containerField);
504 
505         // field button for adding lines
506         if(!hideAdd  && collectionDefinition.getIncludeAddLine()) {
507             Field field = new Field();
508 
509             String addButtonName = KRADConstants.DISPATCH_REQUEST_PARAMETER + "." + KRADConstants.ADD_LINE_METHOD + "." + parents + collectionDefinition.getName() + "." + KRADConstants.METHOD_TO_CALL_BOPARM_LEFT_DEL + collectionDefinition.getBusinessObjectClass().getName() + KRADConstants.METHOD_TO_CALL_BOPARM_RIGHT_DEL;
510             field.setPropertyName(addButtonName);
511             field.setFieldType(Field.IMAGE_SUBMIT);
512             field.setPropertyValue("images/tinybutton-add1.gif");
513             // collFields.add(field);
514             containerField.getContainerRows().add(new Row(field));
515         }
516 
517         if (collectionDefinition instanceof MaintainableCollectionDefinition) {
518             if (FieldUtils.isCollectionMultipleLookupEnabled((MaintainableCollectionDefinition) collectionDefinition)) {
519                 FieldUtils.modifyFieldToSupportMultipleValueLookups(containerField, parents, (MaintainableCollectionDefinition) collectionDefinition);
520             }
521         }
522 
523         return collFields;
524     }
525 
526     /**
527      * Call getNewFormFields with no parents.
528      *
529      * @see #getNewFormFields(org.kuali.rice.kns.datadictionary.CollectionDefinitionI, BusinessObject, Maintainable, List, StringBuffer, String, boolean, int)
530      */
531     public static final List<Field> getNewFormFields(MaintainableCollectionDefinition collectionDefinition, BusinessObject o, Maintainable m, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields, StringBuffer containerRowErrorKey, int numberOfColumns) {
532         String parent = "";
533         return getNewFormFields(collectionDefinition, o, m, displayedFieldNames, conditionallyRequiredMaintenanceFields, containerRowErrorKey, parent, false, numberOfColumns);
534     }
535 
536     /**
537      * Create a Field for display on an Inquiry screen.
538      *
539      * @param d The DD definition for the Field.
540      * @param o The BusinessObject from which the Field will be populated.
541      * @param s The Section in which the Field will be displayed.
542      *
543      * @return The populated Field.
544      */
545     public static Field toField(FieldDefinition d, BusinessObject o, Section s) {
546         Field field = FieldUtils.getPropertyField(o.getClass(), d.getAttributeName(), false);
547         
548         FieldUtils.setInquiryURL(field, o, field.getPropertyName());
549 
550 		String alternateDisplayPropertyName = getBusinessObjectDictionaryService()
551 				.getInquiryFieldAlternateDisplayAttributeName(o.getClass(), d.getAttributeName());
552 		if (StringUtils.isNotBlank(alternateDisplayPropertyName)) {
553 			field.setAlternateDisplayPropertyName(alternateDisplayPropertyName);
554 		}
555 
556 		String additionalDisplayPropertyName = getBusinessObjectDictionaryService()
557 				.getInquiryFieldAdditionalDisplayAttributeName(o.getClass(), d.getAttributeName());
558 		if (StringUtils.isNotBlank(additionalDisplayPropertyName)) {
559 			field.setAdditionalDisplayPropertyName(additionalDisplayPropertyName);
560 		}
561 		else {
562 			boolean translateCodes = getBusinessObjectDictionaryService().tranlateCodesInInquiry(o.getClass());
563 			if (translateCodes) {
564 				FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), d.getAttributeName(), field);
565 			}
566 		}
567 
568         populateFieldFromBusinessObject(field, o);
569 
570         return field;
571     }
572 
573 	public static DataDictionaryService getDataDictionaryService() {
574     	if (dataDictionaryService == null) {
575     		dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
576     	}
577 		return dataDictionaryService;
578 	}
579 
580 	public static PersistenceStructureService getPersistenceStructureService() {
581     	if (persistenceStructureService == null) {
582     		persistenceStructureService = KNSServiceLocator.getPersistenceStructureService();
583     	}
584 		return persistenceStructureService;
585 	}
586 
587 	public static BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
588     	if (businessObjectDictionaryService == null) {
589     		businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService();
590     	}
591 		return businessObjectDictionaryService; 
592 	}
593 	
594 	public static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
595     	if (maintenanceDocumentDictionaryService == null) {
596     		maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
597     	}
598 		return maintenanceDocumentDictionaryService; 
599 	}
600 
601 }
602