View Javadoc

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