001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kns.web.ui;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.core.api.util.ClassLoaderUtils;
020    import org.kuali.rice.core.api.util.KeyValue;
021    import org.kuali.rice.core.web.format.Formatter;
022    import org.kuali.rice.kns.datadictionary.CollectionDefinitionI;
023    import org.kuali.rice.kns.datadictionary.FieldDefinition;
024    import org.kuali.rice.kns.datadictionary.FieldDefinitionI;
025    import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
026    import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
027    import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
028    import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
029    import org.kuali.rice.kns.lookup.LookupUtils;
030    import org.kuali.rice.kns.maintenance.Maintainable;
031    import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
032    import org.kuali.rice.kns.service.KNSServiceLocator;
033    import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
034    import org.kuali.rice.kns.util.FieldUtils;
035    import org.kuali.rice.kns.util.MaintenanceUtils;
036    import org.kuali.rice.kns.util.WebUtils;
037    import org.kuali.rice.krad.bo.BusinessObject;
038    import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
039    import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
040    import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder;
041    import org.kuali.rice.krad.service.DataDictionaryService;
042    import org.kuali.rice.krad.service.KRADServiceLocator;
043    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
044    import org.kuali.rice.krad.service.PersistenceStructureService;
045    import org.kuali.rice.krad.util.KRADConstants;
046    import org.kuali.rice.krad.util.ObjectUtils;
047    
048    import java.util.ArrayList;
049    import java.util.Collection;
050    import java.util.List;
051    import java.util.Set;
052    
053    @Deprecated
054    public class FieldBridge {
055        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FieldBridge.class);
056        private static DataDictionaryService dataDictionaryService;
057        private static PersistenceStructureService persistenceStructureService;
058        private static BusinessObjectDictionaryService businessObjectDictionaryService;
059        private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
060    
061        /**
062         * Sets additional properties for MaintainableField(s)
063         *
064         * @param field The field to populate.
065         * @param definition The DD specification for the field.
066         */
067        public static final void setupField(Field field, FieldDefinitionI definition, Set<String> conditionallyRequiredMaintenanceFields) {
068            if (definition instanceof MaintainableFieldDefinition) {
069                MaintainableFieldDefinition maintainableFieldDefinition = ((MaintainableFieldDefinition) definition);
070                
071                field.setFieldRequired(maintainableFieldDefinition.isRequired());
072                field.setReadOnly(maintainableFieldDefinition.isUnconditionallyReadOnly());
073                if (maintainableFieldDefinition.isLookupReadOnly()) {
074                    field.setFieldType(Field.LOOKUP_READONLY);
075                }
076    
077                // set onblur and callback functions
078                if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldFunction())) {
079                    field.setWebOnBlurHandler(maintainableFieldDefinition.getWebUILeaveFieldFunction());
080                }
081    
082                if (StringUtils.isNotBlank(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction())) {
083                    field.setWebOnBlurHandlerCallback(maintainableFieldDefinition.getWebUILeaveFieldCallbackFunction());
084                }
085    
086                if (maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters()!=null) {
087                    field.setWebUILeaveFieldFunctionParameters(maintainableFieldDefinition.getWebUILeaveFieldFunctionParameters());
088                }
089                
090                            if (StringUtils.isNotBlank(maintainableFieldDefinition.getAlternateDisplayAttributeName())) {
091                                    field.setAlternateDisplayPropertyName(maintainableFieldDefinition.getAlternateDisplayAttributeName());
092                            }
093    
094                            if (StringUtils.isNotBlank(maintainableFieldDefinition.getAdditionalDisplayAttributeName())) {
095                                    field.setAdditionalDisplayPropertyName(maintainableFieldDefinition.getAdditionalDisplayAttributeName());
096                            }
097                
098                if (conditionallyRequiredMaintenanceFields != null && conditionallyRequiredMaintenanceFields.contains(field.getPropertyName())) {
099                    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    
142                    propValue = lookupFinderValue(fieldControl, prop, finder);
143                } else {
144                                    propValue = ObjectUtils.getFormattedPropertyValue(bo, field.getPropertyName(), formatter);
145                        }
146                            field.setPropertyValue(propValue);
147                            
148                            // set additional or alternate display property values if property
149                            // name is specified
150                            if (StringUtils.isNotBlank(field.getAlternateDisplayPropertyName())) {
151                                    String alternatePropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
152                                                    .getAlternateDisplayPropertyName());
153                                    field.setAlternateDisplayPropertyValue(alternatePropertyValue);
154                    }
155    
156                            if (StringUtils.isNotBlank(field.getAdditionalDisplayPropertyName())) {
157                                    String additionalPropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, field
158                                                    .getAdditionalDisplayPropertyName());
159                                    field.setAdditionalDisplayPropertyValue(additionalPropertyValue);
160                }
161    
162                            // for user fields, attempt to pull the principal ID and person's
163                            // name from the source object
164                if ( fieldControl != null && fieldControl.isKualiUser() ) {
165                    // this is supplemental, so catch and log any errors 
166                    try {
167                            if ( StringUtils.isNotBlank(field.getUniversalIdAttributeName()) ) {
168                                    Object principalId = ObjectUtils.getNestedValue(bo, field.getUniversalIdAttributeName());
169                                    if ( principalId != null ) {
170                                            field.setUniversalIdValue(principalId.toString());
171                                    }
172                            }
173                            if ( StringUtils.isNotBlank(field.getPersonNameAttributeName()) ) {
174                                    Object personName = ObjectUtils.getNestedValue(bo, field.getPersonNameAttributeName());
175                                    if ( personName != null ) {
176                                            field.setPersonNameValue( personName.toString() );
177                                    }
178                            }
179                    } catch ( Exception ex ) {
180                            LOG.warn( "Unable to get principal ID or person name property in FieldBridge.", ex );
181                    }
182                }
183                if (fieldControl != null && fieldControl.isFile()) {
184                    if (Field.FILE.equals(field.getFieldType())) {
185                        Object fileName = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_NAME);
186                        Object fileType = ObjectUtils.getNestedValue(bo, KRADConstants.BO_ATTACHMENT_FILE_CONTENT_TYPE);
187                        field.setImageSrc(WebUtils.getAttachmentImageForUrl((String) fileType));
188                        field.setPropertyValue(fileName);
189                    }
190                }
191                FieldUtils.setInquiryURL(field, bo, propertyName);
192                    } catch (InstantiationException e) {
193                LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
194                throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
195                    } catch (ClassNotFoundException e) {
196                            LOG.error("Unable to get instance of KeyValuesFinder: " + e.getMessage());
197                throw new RuntimeException("Unable to get instance of KeyValuesFinder: " + e.getMessage());
198                    } catch (IllegalAccessException e) {
199                LOG.error("Unable to set columns: " + e.getMessage());
200                throw new RuntimeException("Unable to set columns: " + e.getMessage());
201            }
202    
203        }
204    
205        /**
206         * This method looks up a value in a finder class.
207         * @param fieldControl the type of web control that is associated with this field.
208         * @param prop the property to look up - either a property name as a String, or a referenced object
209         * @param finder finder to look the value up in
210         * @return the value that was returned from the lookup
211         */
212        private static String lookupFinderValue(ControlDefinition fieldControl, Object prop, KeyValuesFinder finder) {
213            String propValue = null;
214    
215            // KULRICE-1808 : PersistableBusinessObjectValuesFinder is not working for inquiries that have child objects with ValuesFinder populated select lists
216            if (finder instanceof PersistableBusinessObjectValuesFinder) {
217                ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass(ClassLoaderUtils.getClass(fieldControl.getBusinessObjectClass()));
218                ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName(fieldControl.getKeyAttribute());
219                ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName(fieldControl.getLabelAttribute());
220                if (fieldControl.getIncludeBlankRow() != null) {
221                    ((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(fieldControl.getIncludeBlankRow());
222                }
223                ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(fieldControl.getIncludeKeyInLabel());
224            }
225            List<KeyValue> keyValues = finder.getKeyValues();
226            propValue = getPropertyValueFromList(prop, keyValues);
227            if(propValue==null) {
228                            propValue = lookupInactiveFinderValue(prop, finder);
229                    }
230            return propValue;
231        }
232        
233        private static String lookupInactiveFinderValue(Object property, KeyValuesFinder finder){
234            List<KeyValue> keyValues = finder.getKeyValues(false);
235            return getPropertyValueFromList(property, keyValues);
236            
237        }
238        
239        private static String getPropertyValueFromList(Object property, List<KeyValue> keyValues){
240            String propertyValue = null;
241            if (property != null) {
242                for (Object element2 : keyValues) {
243                    KeyValue element = (KeyValue) element2;
244                    if (element.getKey().toString().equals(property.toString())) {
245                        propertyValue = element.getValue();
246                        break;
247                    }
248                }
249            }
250            return propertyValue;
251        }
252        
253        /**
254         * Determines whether field level help is enabled for the field corresponding to the dataObjectClass and attribute name
255         *
256         * If this value is true, then the field level help will be enabled.
257         * If false, then whether a field is enabled is determined by the value returned by {@link #isMaintenanceFieldLevelHelpDisabled(Maintainable, MaintainableFieldDefinition)}
258         * and the system-wide parameter setting.  Note that if a field is read-only, that may cause field-level help to not be rendered.
259         *
260         * @param businessObjectClass the looked up class
261         * @param attributeName the attribute for the field
262         * @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
263         * affects the enablement of field level help
264         */
265        protected static boolean isMaintenanceFieldLevelHelpEnabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
266            if ( fieldDefinition != null ) {
267                if ( fieldDefinition.isShowFieldLevelHelp() != null && fieldDefinition.isShowFieldLevelHelp() ) {
268                    return true;
269                }
270            }
271            return false;
272        }
273    
274        /**
275         * Determines whether field level help is disabled for the field corresponding to the dataObjectClass and attribute name
276         *
277         * If this value is true and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} returns false,
278         * then the field level help will not be rendered.  If both this and {@link #isMaintenanceFieldLevelHelpEnabled(Maintainable, MaintainableFieldDefinition)} return false,
279         * then the system-wide setting will determine whether field level help is enabled.  Note that if a field is read-only, that may cause
280         * field-level help to not be rendered.
281         *
282         * @param businessObjectClass the looked up class
283         * @param attributeName the attribute for the field
284         * @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
285         * affects the enablement of field level help
286         */
287        protected static boolean isMaintenanceFieldLevelHelpDisabled(Maintainable m, MaintainableFieldDefinition fieldDefinition) {
288            if ( fieldDefinition != null ) {
289                if ( fieldDefinition.isShowFieldLevelHelp() != null && !fieldDefinition.isShowFieldLevelHelp() ) {
290                    return true;
291                }
292            }
293            return false;
294        }
295    
296        /**
297         * This method creates a Field for display on a Maintenance Document.
298         *
299         * @param id The DD definition for the Field (can be a Collection).
300         * @param sd The DD definition for the Section in which the field will be displayed.
301         * @param o The BusinessObject will be populated from this BO.
302         * @param m
303         * @param s The Section in which the Field will be displayed.
304         * @param autoFillDefaultValues Should default values be filled in?
305         * @param autoFillBlankRequiredValues Should values be filled in for fields that are required but which were left blank when submitting the form from the UI?
306         * @param displayedFieldNames What fields are being displayed on the form in the UI?
307         *
308         * @return
309         *
310         * @throws InstantiationException
311         * @throws IllegalAccessException
312         */
313        public static final Field toField(MaintainableItemDefinition id, MaintainableSectionDefinition sd, BusinessObject o, Maintainable m, Section s, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields) throws InstantiationException, IllegalAccessException {
314            Field field = new Field();
315    
316            // if FieldDefiniton, simply add a Field UI object
317            if (id instanceof MaintainableFieldDefinition) {
318                MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) id;
319                field = FieldUtils.getPropertyField(o.getClass(), maintainableFieldDefinition.getName(), false);
320    
321                            boolean translateCodes = getMaintenanceDocumentDictionaryService().translateCodes(o.getClass());
322                            if (translateCodes) {
323                                    FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), field.getPropertyName(), field);
324                            }
325    
326                setupField(field, maintainableFieldDefinition, conditionallyRequiredMaintenanceFields);
327    
328                MaintenanceUtils.setFieldQuickfinder(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames, m);
329                MaintenanceUtils.setFieldDirectInquiry(o, field.getPropertyName(), maintainableFieldDefinition, field, displayedFieldNames);
330    
331                // set default value
332                //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.
333                /*if (autoFillDefaultValues) {
334                    Object defaultValue = maintainableFieldDefinition.getDefaultValue();
335                    if (defaultValue != null) {
336                        if (defaultValue.toString().equals("true")) {
337                            defaultValue = "Yes";
338                        }
339                        else if (defaultValue.toString().equals("false")) {
340                            defaultValue = "No";
341                        }
342                        field.setPropertyValue(defaultValue);
343                    }
344    
345                    Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
346                    if (defaultValueFinderClass != null) {
347                        field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
348                    }
349                }
350    
351                // if this flag is set, and the current field is required, and readonly, and blank, use the
352                // defaultValueFinder if one exists
353                if (autoFillBlankRequiredValues) {
354                    if ( maintainableFieldDefinition.isRequired() && maintainableFieldDefinition.isUnconditionallyReadOnly() ) {
355                        if ( StringUtils.isBlank( field.getPropertyValue() ) ) {
356                            Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
357                            if (defaultValueFinderClass != null) {
358                                field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
359                            }
360                        }
361                    }
362                }
363                            */
364                field.setFieldLevelHelpEnabled(isMaintenanceFieldLevelHelpEnabled(m, maintainableFieldDefinition));
365                field.setFieldLevelHelpDisabled(isMaintenanceFieldLevelHelpDisabled(m, maintainableFieldDefinition));
366                field.setFieldLevelHelpUrl(maintainableFieldDefinition.getFieldLevelHelpUrl());
367            }
368    
369            return field;
370    
371        }
372    
373        /**
374         * This method will return a new form for adding in a BO for a collection.
375         * This should be customized in a subclass so the default behavior is to return nothing.
376         *
377         * @param collectionDefinition The DD definition for the Collection.
378         * @param o The BusinessObject form which the new Fields will be populated.
379         * @param document MaintenanceDocument instance which we ar building fields for
380         * @param m
381         * @param displayedFieldNames What Fields are being displayed on the form in the UI?
382         * @param containerRowErrorKey The error key for the Container/Collection used for displaying error messages.
383         * @param parents
384         * @param hideAdd Should the add line be hidden when displaying this Collection/Container in the UI?
385         * @param numberOfColumns How many columns the Fields in the Collection will be split into when displaying them in the UI.
386         *
387         * @return The List of new Fields.
388         */
389        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) {
390            LOG.debug( "getNewFormFields" );
391            String collName = collectionDefinition.getName();
392    
393            List<Field> collFields = new ArrayList<Field>();
394            Collection<? extends FieldDefinitionI> collectionFields;
395            //Class boClass = collectionDefinition.getDataObjectClass();
396            BusinessObject collBO = null;
397            try {
398                collectionFields = collectionDefinition.getFields();
399                collBO = m.getNewCollectionLine(parents + collName);
400    
401                if ( LOG.isDebugEnabled() ) {
402                    LOG.debug( "newBO for add line: " + collBO );
403                }
404    
405                for ( FieldDefinitionI fieldDefinition : collectionFields  ) {
406                    // construct Field UI object from definition
407                    Field collField = FieldUtils.getPropertyField(collectionDefinition.getBusinessObjectClass(), fieldDefinition.getName(), false);
408    
409                    if (fieldDefinition instanceof MaintainableFieldDefinition) {
410                        setupField(collField, fieldDefinition, conditionallyRequiredMaintenanceFields);
411                    }
412                    //generate the error key for the add row
413                    String[] nameParts = StringUtils.split(collField.getPropertyName(), ".");
414                    String fieldErrorKey = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + KRADConstants.ADD_PREFIX + ".";
415                    fieldErrorKey += collName + ".";
416                    for (int i = 0; i < nameParts.length; i++) {
417                        fieldErrorKey += nameParts[i];
418                        containerRowErrorKey.append(fieldErrorKey);
419                        if (i < nameParts.length) {
420                            fieldErrorKey += ".";
421                            containerRowErrorKey.append(",");
422                        }
423                    }
424    
425                    //  set the QuickFinderClass
426                    BusinessObject collectionBoInstance = collectionDefinition.getBusinessObjectClass().newInstance();
427                    FieldUtils.setInquiryURL(collField, collectionBoInstance, fieldDefinition.getName());
428                    if (collectionDefinition instanceof MaintainableCollectionDefinition) {
429                        MaintenanceUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m, (MaintainableFieldDefinition) fieldDefinition);
430                        MaintenanceUtils
431                                .setFieldDirectInquiry(collectionBoInstance, parents + collectionDefinition.getName(), true,
432                                        0, fieldDefinition.getName(), collField, displayedFieldNames, m,
433                                        (MaintainableFieldDefinition) fieldDefinition);
434                    }
435                    else {
436                        LookupUtils.setFieldQuickfinder(collectionBoInstance, parents+collectionDefinition.getName(), true, 0, fieldDefinition.getName(), collField, displayedFieldNames, m);
437                        LookupUtils.setFieldDirectInquiry(collectionBoInstance, fieldDefinition.getName(), collField);
438                    }
439    
440                    collFields.add(collField);
441                }
442    
443            } catch (InstantiationException e) {
444                LOG.error("Unable to create instance of object class" + e.getMessage());
445                throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
446            } catch (IllegalAccessException e) {
447                LOG.error("Unable to create instance of object class" + e.getMessage());
448                throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
449            }
450    
451            // populate field values from business object
452            collFields = FieldUtils.populateFieldsFromBusinessObject(collFields,collBO);
453    
454            // need to append the prefix afterwards since the population command (above)
455            // does not handle the prefixes on the property names
456            for ( Field field : collFields ) {
457                // prefix name for add line
458                field.setPropertyName(KRADConstants.MAINTENANCE_ADD_PREFIX + parents + collectionDefinition.getName() + "." + field.getPropertyName());
459            }
460            LOG.debug("Error Key for section " + collectionDefinition.getName() + " : " + containerRowErrorKey.toString());
461    
462            
463            collFields = constructContainerField(collectionDefinition, parents, o, hideAdd, numberOfColumns, collName, collFields);
464    
465            return collFields;
466        }
467    
468        /**
469         * 
470         * This method handles setting up a container field not including the add fields
471         * 
472         * @param collectionDefinition
473         * @param parents
474         * @param o
475         * @param hideAdd
476         * @param numberOfColumns
477         * @param collName
478         * @param collFields
479         * @return
480         */
481        public static List<Field> constructContainerField(CollectionDefinitionI collectionDefinition, String parents, BusinessObject o, boolean hideAdd, int numberOfColumns, String collName, List<Field> collFields) {
482            // get label for collection
483            String collectionLabel = getDataDictionaryService().getCollectionLabel(o.getClass(), collectionDefinition.getName());
484    
485            // retrieve the summary label either from the override or from the DD
486            String collectionElementLabel = collectionDefinition.getSummaryTitle();
487            if(StringUtils.isEmpty(collectionElementLabel)){
488                collectionElementLabel = getDataDictionaryService().getCollectionElementLabel(o.getClass().getName(), collectionDefinition.getName(),collectionDefinition.getBusinessObjectClass());
489            }
490    
491            // container field
492            Field containerField;
493            containerField = FieldUtils.constructContainerField(collName, collectionLabel, collFields, numberOfColumns);
494            if(StringUtils.isNotEmpty(collectionElementLabel)) {
495                containerField.setContainerElementName(collectionElementLabel);
496            }
497            collFields = new ArrayList();
498            collFields.add(containerField);
499    
500            // field button for adding lines
501            if(!hideAdd  && collectionDefinition.getIncludeAddLine()) {
502                Field field = new Field();
503    
504                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;
505                field.setPropertyName(addButtonName);
506                field.setFieldType(Field.IMAGE_SUBMIT);
507                field.setPropertyValue("images/tinybutton-add1.gif");
508                // collFields.add(field);
509                containerField.getContainerRows().add(new Row(field));
510            }
511    
512            if (collectionDefinition instanceof MaintainableCollectionDefinition) {
513                if (FieldUtils.isCollectionMultipleLookupEnabled((MaintainableCollectionDefinition) collectionDefinition)) {
514                    FieldUtils.modifyFieldToSupportMultipleValueLookups(containerField, parents, (MaintainableCollectionDefinition) collectionDefinition);
515                }
516            }
517    
518            return collFields;
519        }
520    
521        /**
522         * Call getNewFormFields with no parents.
523         *
524         * @see #getNewFormFields(org.kuali.rice.kns.datadictionary.CollectionDefinitionI, BusinessObject, Maintainable, List, StringBuffer, String, boolean, int)
525         */
526        public static final List<Field> getNewFormFields(MaintainableCollectionDefinition collectionDefinition, BusinessObject o, Maintainable m, List<String> displayedFieldNames, Set<String> conditionallyRequiredMaintenanceFields, StringBuffer containerRowErrorKey, int numberOfColumns) {
527            String parent = "";
528            return getNewFormFields(collectionDefinition, o, m, displayedFieldNames, conditionallyRequiredMaintenanceFields, containerRowErrorKey, parent, false, numberOfColumns);
529        }
530    
531        /**
532         * Create a Field for display on an Inquiry screen.
533         *
534         * @param d The DD definition for the Field.
535         * @param o The BusinessObject from which the Field will be populated.
536         * @param s The Section in which the Field will be displayed.
537         *
538         * @return The populated Field.
539         */
540        public static Field toField(FieldDefinition d, BusinessObject o, Section s) {
541            Field field = FieldUtils.getPropertyField(o.getClass(), d.getAttributeName(), false);
542            
543            FieldUtils.setInquiryURL(field, o, field.getPropertyName());
544    
545                    String alternateDisplayPropertyName = getBusinessObjectDictionaryService()
546                                    .getInquiryFieldAlternateDisplayAttributeName(o.getClass(), d.getAttributeName());
547                    if (StringUtils.isNotBlank(alternateDisplayPropertyName)) {
548                            field.setAlternateDisplayPropertyName(alternateDisplayPropertyName);
549                    }
550    
551                    String additionalDisplayPropertyName = getBusinessObjectDictionaryService()
552                                    .getInquiryFieldAdditionalDisplayAttributeName(o.getClass(), d.getAttributeName());
553                    if (StringUtils.isNotBlank(additionalDisplayPropertyName)) {
554                            field.setAdditionalDisplayPropertyName(additionalDisplayPropertyName);
555                    }
556                    else {
557                            boolean translateCodes = getBusinessObjectDictionaryService().tranlateCodesInInquiry(o.getClass());
558                            if (translateCodes) {
559                                    FieldUtils.setAdditionalDisplayPropertyForCodes(o.getClass(), d.getAttributeName(), field);
560                            }
561                    }
562    
563            populateFieldFromBusinessObject(field, o);
564    
565            return field;
566        }
567    
568            public static DataDictionaryService getDataDictionaryService() {
569            if (dataDictionaryService == null) {
570                    dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
571            }
572                    return dataDictionaryService;
573            }
574    
575            public static PersistenceStructureService getPersistenceStructureService() {
576            if (persistenceStructureService == null) {
577                    persistenceStructureService = KRADServiceLocator.getPersistenceStructureService();
578            }
579                    return persistenceStructureService;
580            }
581    
582            public static BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
583            if (businessObjectDictionaryService == null) {
584                    businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService();
585            }
586                    return businessObjectDictionaryService; 
587            }
588            
589            public static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
590            if (maintenanceDocumentDictionaryService == null) {
591                    maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
592            }
593                    return maintenanceDocumentDictionaryService; 
594            }
595    
596    }
597