View Javadoc

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