Coverage Report - org.kuali.rice.kns.util.FieldUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
FieldUtils
0%
0/826
0%
0/508
6.321
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.util;
 17  
 
 18  
 import org.apache.commons.beanutils.PropertyUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 21  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 22  
 import org.kuali.rice.core.api.mo.common.active.MutableInactivatable;
 23  
 import org.kuali.rice.core.api.uif.AttributeLookupSettings;
 24  
 import org.kuali.rice.core.api.uif.Control;
 25  
 import org.kuali.rice.core.api.uif.DataType;
 26  
 import org.kuali.rice.core.api.uif.RemotableAbstractControl;
 27  
 import org.kuali.rice.core.api.uif.RemotableAbstractWidget;
 28  
 import org.kuali.rice.core.api.uif.RemotableAttributeField;
 29  
 import org.kuali.rice.core.api.uif.RemotableAttributeLookupSettings;
 30  
 import org.kuali.rice.core.api.uif.RemotableCheckboxGroup;
 31  
 import org.kuali.rice.core.api.uif.RemotableDatepicker;
 32  
 import org.kuali.rice.core.api.uif.RemotableHiddenInput;
 33  
 import org.kuali.rice.core.api.uif.RemotablePasswordInput;
 34  
 import org.kuali.rice.core.api.uif.RemotableQuickFinder;
 35  
 import org.kuali.rice.core.api.uif.RemotableRadioButtonGroup;
 36  
 import org.kuali.rice.core.api.uif.RemotableSelect;
 37  
 import org.kuali.rice.core.api.uif.RemotableTextExpand;
 38  
 import org.kuali.rice.core.api.uif.RemotableTextInput;
 39  
 import org.kuali.rice.core.api.uif.RemotableTextarea;
 40  
 import org.kuali.rice.core.api.util.ClassLoaderUtils;
 41  
 import org.kuali.rice.core.api.util.ConcreteKeyValue;
 42  
 import org.kuali.rice.core.api.util.KeyValue;
 43  
 import org.kuali.rice.core.web.format.FormatException;
 44  
 import org.kuali.rice.core.web.format.Formatter;
 45  
 import org.kuali.rice.kew.api.KewApiConstants;
 46  
 import org.kuali.rice.kim.api.identity.Person;
 47  
 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
 48  
 import org.kuali.rice.kns.datadictionary.FieldDefinition;
 49  
 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
 50  
 import org.kuali.rice.kns.datadictionary.control.ButtonControlDefinition;
 51  
 import org.kuali.rice.kns.datadictionary.control.CurrencyControlDefinition;
 52  
 import org.kuali.rice.kns.datadictionary.control.KualiUserControlDefinition;
 53  
 import org.kuali.rice.kns.datadictionary.control.LinkControlDefinition;
 54  
 import org.kuali.rice.kns.document.authorization.FieldRestriction;
 55  
 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions;
 56  
 import org.kuali.rice.kns.inquiry.Inquirable;
 57  
 import org.kuali.rice.kns.lookup.HtmlData;
 58  
 import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData;
 59  
 import org.kuali.rice.kns.lookup.LookupUtils;
 60  
 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
 61  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 62  
 import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
 63  
 import org.kuali.rice.kns.web.ui.Column;
 64  
 import org.kuali.rice.kns.web.ui.Field;
 65  
 import org.kuali.rice.kns.web.ui.PropertyRenderingConfigElement;
 66  
 import org.kuali.rice.kns.web.ui.Row;
 67  
 import org.kuali.rice.kns.web.ui.Section;
 68  
 import org.kuali.rice.krad.bo.BusinessObject;
 69  
 import org.kuali.rice.krad.bo.DataObjectRelationship;
 70  
 import org.kuali.rice.krad.bo.KualiCode;
 71  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 72  
 import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
 73  
 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
 74  
 import org.kuali.rice.krad.datadictionary.mask.MaskFormatter;
 75  
 import org.kuali.rice.krad.keyvalues.IndicatorValuesFinder;
 76  
 import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
 77  
 import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder;
 78  
 import org.kuali.rice.krad.service.BusinessObjectDictionaryService;
 79  
 import org.kuali.rice.krad.service.DataDictionaryService;
 80  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 81  
 import org.kuali.rice.krad.service.KualiModuleService;
 82  
 import org.kuali.rice.krad.service.ModuleService;
 83  
 import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils;
 84  
 import org.kuali.rice.krad.util.GlobalVariables;
 85  
 import org.kuali.rice.krad.util.KRADConstants;
 86  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 87  
 import org.kuali.rice.krad.util.MessageMap;
 88  
 import org.kuali.rice.krad.util.ObjectUtils;
 89  
 import org.kuali.rice.krad.valuefinder.ValueFinder;
 90  
 
 91  
 import java.lang.reflect.InvocationTargetException;
 92  
 import java.security.GeneralSecurityException;
 93  
 import java.util.ArrayList;
 94  
 import java.util.Collection;
 95  
 import java.util.Collections;
 96  
 import java.util.HashMap;
 97  
 import java.util.Iterator;
 98  
 import java.util.List;
 99  
 import java.util.Map;
 100  
 
 101  
 
 102  
 /**
 103  
  * This class is used to build Field objects from underlying data dictionary and general utility methods for handling fields.
 104  
  */
 105  
 public final class FieldUtils {
 106  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FieldUtils.class);
 107  0
     private static DataDictionaryService dataDictionaryService = null;
 108  0
     private static BusinessObjectMetaDataService businessObjectMetaDataService = null;
 109  0
     private static BusinessObjectDictionaryService businessObjectDictionaryService = null;
 110  0
     private static KualiModuleService kualiModuleService = null;
 111  
     
 112  0
         private FieldUtils() {
 113  0
                 throw new UnsupportedOperationException("do not call");
 114  
         }
 115  
 
 116  
     public static void setInquiryURL(Field field, BusinessObject bo, String propertyName) {
 117  0
         HtmlData inquiryHref = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
 118  
 
 119  0
         Boolean b = getBusinessObjectDictionaryService().noInquiryFieldInquiry(bo.getClass(), propertyName);
 120  0
         if (b == null || !b.booleanValue()) {
 121  0
             Class<Inquirable> inquirableClass = getBusinessObjectDictionaryService().getInquirableClass(bo.getClass());
 122  0
             Boolean b2 = getBusinessObjectDictionaryService().forceLookupResultFieldInquiry(bo.getClass(), propertyName);
 123  0
             Inquirable inq = null;
 124  
             try {
 125  0
                 if ( inquirableClass != null ) {
 126  0
                     inq = inquirableClass.newInstance();
 127  
                 } else {
 128  0
                     inq = KNSServiceLocator.getKualiInquirable();
 129  0
                     if ( LOG.isDebugEnabled() ) {
 130  0
                         LOG.debug( "Default Inquirable Class: " + inq.getClass() );
 131  
         }
 132  
                 }
 133  
 
 134  0
                 inquiryHref = inq.getInquiryUrl(bo, propertyName, null == b2 ? false : b2.booleanValue() );
 135  
 
 136  0
             } catch ( Exception ex ) {
 137  0
                 LOG.error("unable to create inquirable to get inquiry URL", ex );
 138  0
             }
 139  
         }
 140  
 
 141  0
         field.setInquiryURL(inquiryHref);
 142  0
     }
 143  
 
 144  
         /**
 145  
          * Sets the control on the field based on the data dictionary definition
 146  
          *
 147  
          * @param businessObjectClass
 148  
          *            - business object class for the field attribute
 149  
          * @param attributeName
 150  
          *            - name of the attribute whose {@link Field} is being set
 151  
          * @param convertForLookup
 152  
          *            - whether the field is being build for lookup search which impacts the control chosen
 153  
          * @param field
 154  
          *            - {@link Field} to set control on
 155  
          */
 156  
         public static void setFieldControl(Class businessObjectClass, String attributeName, boolean convertForLookup,
 157  
                         Field field) {
 158  0
                 ControlDefinition control = getDataDictionaryService().getAttributeControlDefinition(businessObjectClass,
 159  
                                 attributeName);
 160  0
                 String fieldType = Field.TEXT;
 161  
 
 162  0
                 if (control != null) {
 163  0
                         if (control.isSelect()) {
 164  0
                                 if (control.getScript() != null && control.getScript().length() > 0) {
 165  0
                                         fieldType = Field.DROPDOWN_SCRIPT;
 166  0
                                         field.setScript(control.getScript());
 167  
                                 } else {
 168  0
                                         fieldType = Field.DROPDOWN;
 169  
                                 }
 170  
                         }
 171  
 
 172  0
                         if (control.isMultiselect()) {
 173  0
                                 fieldType = Field.MULTISELECT;
 174  
                         }
 175  
 
 176  0
                         if (control.isCheckbox()) {
 177  0
                                 fieldType = Field.CHECKBOX;
 178  
                         }
 179  
 
 180  0
                         if (control.isRadio()) {
 181  0
                                 fieldType = Field.RADIO;
 182  
                         }
 183  
 
 184  0
                         if (control.isHidden()) {
 185  0
                                 fieldType = Field.HIDDEN;
 186  
                         }
 187  
 
 188  0
                         if (control.isKualiUser()) {
 189  0
                                 fieldType = Field.KUALIUSER;
 190  0
                                 KualiUserControlDefinition kualiUserControl = (KualiUserControlDefinition) control;
 191  0
                                 field.setUniversalIdAttributeName(kualiUserControl.getUniversalIdAttributeName());
 192  0
                                 field.setUserIdAttributeName(kualiUserControl.getUserIdAttributeName());
 193  0
                                 field.setPersonNameAttributeName(kualiUserControl.getPersonNameAttributeName());
 194  
                         }
 195  
 
 196  0
                         if (control.isWorkflowWorkgroup()) {
 197  0
                                 fieldType = Field.WORKFLOW_WORKGROUP;
 198  
                         }
 199  
 
 200  0
                         if (control.isFile()) {
 201  0
                                 fieldType = Field.FILE;
 202  
                         }
 203  
 
 204  0
                         if (control.isTextarea() && !convertForLookup) {
 205  0
                                 fieldType = Field.TEXT_AREA;
 206  
                         }
 207  
 
 208  0
                         if (control.isLookupHidden()) {
 209  0
                                 fieldType = Field.LOOKUP_HIDDEN;
 210  
                         }
 211  
 
 212  0
                         if (control.isLookupReadonly()) {
 213  0
                                 fieldType = Field.LOOKUP_READONLY;
 214  
                         }
 215  
 
 216  0
                         if (control.isCurrency()) {
 217  0
                                 fieldType = Field.CURRENCY;
 218  
                         }
 219  
 
 220  0
                         if (control.isButton()) {
 221  0
                                 fieldType = Field.BUTTON;
 222  
                         }
 223  
 
 224  0
                         if (control.isLink()) {
 225  0
                                 fieldType = Field.LINK;
 226  
                         }
 227  
 
 228  0
                         if (Field.CURRENCY.equals(fieldType) && control instanceof CurrencyControlDefinition) {
 229  0
                                 CurrencyControlDefinition currencyControl = (CurrencyControlDefinition) control;
 230  0
                                 field.setStyleClass("amount");
 231  0
                                 field.setSize(currencyControl.getSize());
 232  0
                                 field.setFormattedMaxLength(currencyControl.getFormattedMaxLength());
 233  
                         }
 234  
 
 235  
                         // for text controls, set size attribute
 236  0
                         if (Field.TEXT.equals(fieldType)) {
 237  0
                                 Integer size = control.getSize();
 238  0
                                 if (size != null) {
 239  0
                                         field.setSize(size.intValue());
 240  
                                 } else {
 241  0
                                         field.setSize(30);
 242  
                                 }
 243  0
                                 field.setDatePicker(control.isDatePicker());
 244  0
                                 field.setRanged(control.isRanged());
 245  
                         }
 246  
 
 247  0
                         if (Field.WORKFLOW_WORKGROUP.equals(fieldType)) {
 248  0
                                 Integer size = control.getSize();
 249  0
                                 if (size != null) {
 250  0
                                         field.setSize(size.intValue());
 251  
                                 } else {
 252  0
                                         field.setSize(30);
 253  
                                 }
 254  
                         }
 255  
 
 256  
                         // for text area controls, set rows and cols attributes
 257  0
                         if (Field.TEXT_AREA.equals(fieldType)) {
 258  0
                                 Integer rows = control.getRows();
 259  0
                                 if (rows != null) {
 260  0
                                         field.setRows(rows.intValue());
 261  
                                 } else {
 262  0
                                         field.setRows(3);
 263  
                                 }
 264  
 
 265  0
                                 Integer cols = control.getCols();
 266  0
                                 if (cols != null) {
 267  0
                                         field.setCols(cols.intValue());
 268  
                                 } else {
 269  0
                                         field.setCols(40);
 270  
                                 }
 271  0
                                 field.setExpandedTextArea(control.isExpandedTextArea());
 272  
                         }
 273  
 
 274  0
             if (Field.MULTISELECT.equals(fieldType)) {
 275  0
                 Integer size = control.getSize();
 276  0
                                 if (size != null) {
 277  0
                                         field.setSize(size.intValue());
 278  
                                 }
 279  
             }
 280  
 
 281  
                         // for dropdown and radio, get instance of specified KeyValuesFinder and set field values
 282  0
                         if (Field.DROPDOWN.equals(fieldType) || Field.RADIO.equals(fieldType)
 283  
                                         || Field.DROPDOWN_SCRIPT.equals(fieldType)
 284  
                                         || Field.MULTISELECT.equals(fieldType)) {
 285  0
                                 String keyFinderClassName = control.getValuesFinderClass();
 286  
 
 287  0
                                 if (StringUtils.isNotBlank(keyFinderClassName)) {
 288  
                                         try {
 289  0
                                                 Class keyFinderClass = ClassLoaderUtils.getClass(keyFinderClassName);
 290  0
                                                 KeyValuesFinder finder = (KeyValuesFinder) keyFinderClass.newInstance();
 291  
 
 292  0
                                                 if (finder != null) {
 293  0
                                                         if (finder instanceof PersistableBusinessObjectValuesFinder) {
 294  0
                                                                 ((PersistableBusinessObjectValuesFinder) finder)
 295  
                                                                                 .setBusinessObjectClass(ClassLoaderUtils.getClass(control
 296  
                                                 .getBusinessObjectClass()));
 297  0
                                                                 ((PersistableBusinessObjectValuesFinder) finder).setKeyAttributeName(control
 298  
                                         .getKeyAttribute());
 299  0
                                                                 ((PersistableBusinessObjectValuesFinder) finder).setLabelAttributeName(control
 300  
                                                                                 .getLabelAttribute());
 301  0
                                                                 if (control.getIncludeBlankRow() != null) {
 302  0
                                                                         ((PersistableBusinessObjectValuesFinder) finder).setIncludeBlankRow(control
 303  
                                                                                         .getIncludeBlankRow());
 304  
                                                                 }
 305  0
                                                                 ((PersistableBusinessObjectValuesFinder) finder).setIncludeKeyInDescription(control
 306  
                                         .getIncludeKeyInLabel());
 307  
                                                         }
 308  0
                                                         field.setFieldValidValues(finder.getKeyValues());
 309  0
                                                         field.setFieldInactiveValidValues(finder.getKeyValues(false));
 310  
                                                 }
 311  0
                                         } catch (InstantiationException e) {
 312  0
                                                 LOG.error("Unable to get new instance of finder class: " + keyFinderClassName);
 313  0
                                                 throw new RuntimeException("Unable to get new instance of finder class: " + keyFinderClassName);
 314  0
                                         } catch (IllegalAccessException e) {
 315  0
                                                 LOG.error("Unable to get new instance of finder class: " + keyFinderClassName);
 316  0
                                                 throw new RuntimeException("Unable to get new instance of finder class: " + keyFinderClassName);
 317  0
                                         }
 318  
                                 }
 319  
                         }
 320  
 
 321  0
                         if (Field.CHECKBOX.equals(fieldType) && convertForLookup) {
 322  0
                                 fieldType = Field.RADIO;
 323  0
                                 field.setFieldValidValues(IndicatorValuesFinder.INSTANCE.getKeyValues());
 324  
                         }
 325  
 
 326  
                         // for button control
 327  0
                         if (Field.BUTTON.equals(fieldType)) {
 328  0
                                 ButtonControlDefinition buttonControl = (ButtonControlDefinition) control;
 329  0
                                 field.setImageSrc(buttonControl.getImageSrc());
 330  0
                                 field.setStyleClass(buttonControl.getStyleClass());
 331  
                         }
 332  
 
 333  
                         // for link control
 334  0
                         if (Field.LINK.equals(fieldType)) {
 335  0
                                 LinkControlDefinition linkControl = (LinkControlDefinition) control;
 336  0
                                 field.setStyleClass(linkControl.getStyleClass());
 337  0
                                 field.setTarget(linkControl.getTarget());
 338  0
                                 field.setHrefText(linkControl.getHrefText());
 339  
                         }
 340  
 
 341  
                 }
 342  
 
 343  0
                 field.setFieldType(fieldType);
 344  0
         }
 345  
 
 346  
 
 347  
     /**
 348  
      * Builds up a Field object based on the propertyName and business object class.
 349  
      *
 350  
      * See KULRICE-2480 for info on convertForLookup flag
 351  
      *
 352  
      */
 353  
     public static Field getPropertyField(Class businessObjectClass, String attributeName, boolean convertForLookup) {
 354  0
         Field field = new Field();
 355  0
         field.setPropertyName(attributeName);
 356  0
         field.setFieldLabel(getDataDictionaryService().getAttributeLabel(businessObjectClass, attributeName));
 357  
 
 358  0
         setFieldControl(businessObjectClass, attributeName, convertForLookup, field);
 359  
 
 360  0
         Boolean fieldRequired = getBusinessObjectDictionaryService().getLookupAttributeRequired(businessObjectClass, attributeName);
 361  0
         if (fieldRequired != null) {
 362  0
             field.setFieldRequired(fieldRequired.booleanValue());
 363  
         }
 364  
 
 365  0
         Integer maxLength = getDataDictionaryService().getAttributeMaxLength(businessObjectClass, attributeName);
 366  0
         if (maxLength != null) {
 367  0
             field.setMaxLength(maxLength.intValue());
 368  
         }
 369  
 
 370  0
         Boolean upperCase = null;
 371  
         try {
 372  0
             upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass, attributeName);
 373  
         }
 374  0
         catch (UnknownBusinessClassAttributeException t) {
 375  
                 // do nothing
 376  0
                 LOG.warn( "UnknownBusinessClassAttributeException in fieldUtils.getPropertyField() : " + t.getMessage() );
 377  0
         }
 378  0
         if (upperCase != null) {
 379  0
             field.setUpperCase(upperCase.booleanValue());
 380  
         }
 381  
         
 382  0
                 if (!businessObjectClass.isInterface()) {
 383  
                         try {
 384  0
                                 field.setFormatter(
 385  
                         ObjectUtils.getFormatterWithDataDictionary(businessObjectClass.newInstance(), attributeName));
 386  0
                         } catch (InstantiationException e) {
 387  0
                                 LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e);
 388  
                                 // just swallow exception and leave formatter blank
 389  0
                         } catch (IllegalAccessException e) {
 390  0
                                 LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e);
 391  
                                 // just swallow exception and leave formatter blank
 392  0
                         }
 393  
                 }
 394  
 
 395  
         // set Field help properties
 396  0
         field.setBusinessObjectClassName(businessObjectClass.getName());
 397  0
         field.setFieldHelpName(attributeName);
 398  0
         field.setFieldHelpSummary(getDataDictionaryService().getAttributeSummary(businessObjectClass, attributeName));
 399  
 
 400  0
         return field;
 401  
     }
 402  
 
 403  
         /**
 404  
          * For attributes that are codes (determined by whether they have a
 405  
          * reference to a KualiCode bo and similar naming) sets the name as an
 406  
          * additional display property
 407  
          * 
 408  
          * @param businessObjectClass -
 409  
          *            class containing attribute
 410  
          * @param attributeName - 
 411  
          *            name of attribute in the business object
 412  
          * @param field - 
 413  
          *            property display element
 414  
          */
 415  
         public static void setAdditionalDisplayPropertyForCodes(Class businessObjectClass, String attributeName, PropertyRenderingConfigElement field) {
 416  
                 try {
 417  0
                         DataObjectRelationship relationship = getBusinessObjectMetaDataService().getBusinessObjectRelationship(
 418  
                                         (BusinessObject) businessObjectClass.newInstance(), attributeName);
 419  
 
 420  0
                         if (relationship != null && attributeName.startsWith(relationship.getParentAttributeName())
 421  
                                         && KualiCode.class.isAssignableFrom(relationship.getRelatedClass())) {
 422  0
                                 field.setAdditionalDisplayPropertyName(relationship.getParentAttributeName() + "."
 423  
                                                 + KRADPropertyConstants.NAME);
 424  
                         }
 425  0
                 } catch (Exception e) {
 426  0
                         throw new RuntimeException("Cannot get new instance of class to check for KualiCode references: "
 427  
                                         + e.getMessage());
 428  0
                 }
 429  0
         }
 430  
 
 431  
 
 432  
     /**
 433  
      * Wraps each Field in the list into a Row.
 434  
      *
 435  
      * @param fields
 436  
      * @return List of Row objects
 437  
      */
 438  
     public static List wrapFields(List fields) {
 439  0
         return wrapFields(fields, KRADConstants.DEFAULT_NUM_OF_COLUMNS);
 440  
     }
 441  
 
 442  
     /**
 443  
      * This method is to implement multiple columns where the numberOfColumns is obtained from data dictionary.
 444  
      *
 445  
      * @param fields
 446  
      * @param numberOfColumns
 447  
      * @return
 448  
      */
 449  
     public static List<Row> wrapFields(List<Field> fields, int numberOfColumns) {
 450  
 
 451  0
         List<Row> rows = new ArrayList();
 452  0
         List<Field> fieldOnlyList = new ArrayList();
 453  
 
 454  0
         List<Field> visableFields = getVisibleFields(fields);
 455  0
             List<Field> nonVisableFields = getNonVisibleFields(fields);
 456  
 
 457  0
         int fieldsPosition = 0;
 458  0
         for (Field element : visableFields) {
 459  0
             if (Field.SUB_SECTION_SEPARATOR.equals(element.getFieldType()) || Field.CONTAINER.equals(element.getFieldType())) {
 460  0
                 fieldsPosition = createBlankSpace(fieldOnlyList, rows, numberOfColumns, fieldsPosition);
 461  0
                 List fieldList = new ArrayList();
 462  0
                 fieldList.add(element);
 463  0
                 rows.add(new Row(fieldList));
 464  0
             }
 465  
             else {
 466  0
                 if (fieldsPosition < numberOfColumns) {
 467  0
                     fieldOnlyList.add(element);
 468  0
                     fieldsPosition++;
 469  
                 }
 470  
                 else {
 471  0
                     rows.add(new Row(new ArrayList(fieldOnlyList)));
 472  0
                     fieldOnlyList.clear();
 473  0
                     fieldOnlyList.add(element);
 474  0
                     fieldsPosition = 1;
 475  
                 }
 476  
             }
 477  
         }
 478  0
         createBlankSpace(fieldOnlyList, rows, numberOfColumns, fieldsPosition);
 479  
 
 480  
      // Add back the non Visible Rows
 481  0
             if(nonVisableFields != null && !nonVisableFields.isEmpty()){
 482  0
                     Row nonVisRow = new Row();
 483  0
                     nonVisRow.setFields(nonVisableFields);
 484  0
                     rows.add(nonVisRow);
 485  
             }
 486  
 
 487  
 
 488  0
         return rows;
 489  
     }
 490  
 
 491  
     private static List<Field> getVisibleFields(List<Field> fields){
 492  0
             List<Field> rList = new ArrayList<Field>();
 493  
 
 494  0
                    for(Field f: fields){
 495  0
                            if(!Field.HIDDEN.equals(f.getFieldType()) &&  !Field.BLANK_SPACE.equals(f.getFieldType())){
 496  0
                                    rList.add(f);
 497  
                            }
 498  
                    }
 499  
 
 500  0
             return rList;
 501  
     }
 502  
 
 503  
     private static List<Field> getNonVisibleFields(List<Field> fields){
 504  0
             List<Field> rList = new ArrayList<Field>();
 505  
 
 506  0
                    for(Field f: fields){
 507  0
                            if(Field.HIDDEN.equals(f.getFieldType()) || Field.BLANK_SPACE.equals(f.getFieldType())){
 508  0
                                    rList.add(f);
 509  
                            }
 510  
                    }
 511  
 
 512  0
             return rList;
 513  
     }
 514  
 
 515  
     /**
 516  
      * This is a helper method to create and add a blank space to the fieldOnly List.
 517  
      *
 518  
      * @param fieldOnlyList
 519  
      * @param rows
 520  
      * @param numberOfColumns
 521  
      * @return fieldsPosition
 522  
      */
 523  
     private static int createBlankSpace(List<Field> fieldOnlyList, List<Row> rows, int numberOfColumns, int fieldsPosition) {
 524  0
         int fieldOnlySize = fieldOnlyList.size();
 525  0
         if (fieldOnlySize > 0) {
 526  0
             for (int i = 0; i < (numberOfColumns - fieldOnlySize); i++) {
 527  0
                 Field empty = new Field();
 528  0
                 empty.setFieldType(Field.BLANK_SPACE);
 529  
                 // Must be set or AbstractLookupableHelperServiceImpl::preprocessDateFields dies
 530  0
                 empty.setPropertyName(Field.BLANK_SPACE);
 531  0
                 fieldOnlyList.add(empty);
 532  
             }
 533  0
             rows.add(new Row(new ArrayList(fieldOnlyList)));
 534  0
             fieldOnlyList.clear();
 535  0
             fieldsPosition = 0;
 536  
         }
 537  0
         return fieldsPosition;
 538  
     }
 539  
 
 540  
     /**
 541  
      * Wraps list of fields into a Field of type CONTAINER
 542  
      *
 543  
      * @param name name for the field
 544  
      * @param label label for the field
 545  
      * @param fields list of fields that should be contained in the container
 546  
      * @return Field of type CONTAINER
 547  
      */
 548  
     public static Field constructContainerField(String name, String label, List fields) {
 549  0
         return constructContainerField(name, label, fields, KRADConstants.DEFAULT_NUM_OF_COLUMNS);
 550  
     }
 551  
 
 552  
     /**
 553  
      * Wraps list of fields into a Field of type CONTAINER and arrange them into multiple columns.
 554  
      *
 555  
      * @param name name for the field
 556  
      * @param label label for the field
 557  
      * @param fields list of fields that should be contained in the container
 558  
      * @param numberOfColumns the number of columns for each row that the fields should be arranged into
 559  
      * @return Field of type CONTAINER
 560  
      */
 561  
     public static Field constructContainerField(String name, String label, List fields, int numberOfColumns) {
 562  0
         Field containerField = new Field();
 563  0
         containerField.setPropertyName(name);
 564  0
         containerField.setFieldLabel(label);
 565  0
         containerField.setFieldType(Field.CONTAINER);
 566  0
         containerField.setNumberOfColumnsForCollection(numberOfColumns);
 567  
 
 568  0
         List rows = wrapFields(fields, numberOfColumns);
 569  0
         containerField.setContainerRows(rows);
 570  
 
 571  0
         return containerField;
 572  
     }
 573  
 
 574  
     /**
 575  
      * Uses reflection to get the property names of the business object, then checks for a matching field property name. If found,
 576  
      * takes the value of the business object property and populates the field value. Iterates through for all fields in the list.
 577  
      *
 578  
      * @param fields list of Field object to populate
 579  
      * @param bo business object to get field values from
 580  
      * @return List of fields with values populated from business object.
 581  
      */
 582  
     public static List<Field> populateFieldsFromBusinessObject(List<Field> fields, BusinessObject bo) {
 583  0
         List<Field> populatedFields = new ArrayList<Field>();
 584  
 
 585  0
         if (bo instanceof PersistableBusinessObject) {
 586  0
                 ((PersistableBusinessObject) bo).refreshNonUpdateableReferences();
 587  
         }
 588  
         
 589  0
         for (Iterator<Field> iter = fields.iterator(); iter.hasNext();) {
 590  0
             Field element = iter.next();
 591  0
             if (element.containsBOData()) {
 592  0
                 String propertyName = element.getPropertyName();
 593  
 
 594  
                 // See: https://test.kuali.org/jira/browse/KULCOA-1185
 595  
                 // Properties that could not possibly be set by the BusinessObject should be ignored.
 596  
                 // (https://test.kuali.org/jira/browse/KULRNE-4354; this code was killing the src attribute of IMAGE_SUBMITs).
 597  0
                 if (isPropertyNested(propertyName) && !isObjectTreeNonNullAllTheWayDown(bo, propertyName) && ((!element.getFieldType().equals(Field.IMAGE_SUBMIT)) && !(element.getFieldType().equals(Field.CONTAINER)) && (!element.getFieldType().equals(Field.QUICKFINDER)))) {
 598  0
                     element.setPropertyValue(null);
 599  
                 }
 600  0
                 else if (PropertyUtils.isReadable(bo, propertyName)) {
 601  0
                         populateReadableField(element, bo);
 602  
                 }
 603  
                 
 604  0
                             if (StringUtils.isNotBlank(element.getAlternateDisplayPropertyName())) {
 605  0
                                     String alternatePropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, element
 606  
                                                     .getAlternateDisplayPropertyName());
 607  0
                                     element.setAlternateDisplayPropertyValue(alternatePropertyValue);
 608  
                             }
 609  
 
 610  0
                             if (StringUtils.isNotBlank(element.getAdditionalDisplayPropertyName())) {
 611  0
                                     String additionalPropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, element
 612  
                                                     .getAdditionalDisplayPropertyName());
 613  0
                                     element.setAdditionalDisplayPropertyValue(additionalPropertyValue);
 614  
                             }
 615  
             }
 616  0
             populatedFields.add(element);
 617  0
         }
 618  
 
 619  0
         return populatedFields;
 620  
     }
 621  
 
 622  
     public static void populateReadableField(Field field, BusinessObject businessObject){
 623  0
                 Object obj = ObjectUtils.getNestedValue(businessObject, field.getPropertyName());
 624  0
                 if (obj != null) {
 625  0
                         String formattedValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(businessObject, field.getPropertyName());
 626  0
                         field.setPropertyValue(formattedValue);
 627  
                 
 628  
             // for user fields, attempt to pull the principal ID and person's name from the source object
 629  0
             if ( field.getFieldType().equals(Field.KUALIUSER) ) {
 630  
                     // this is supplemental, so catch and log any errors
 631  
                     try {
 632  0
                             if ( StringUtils.isNotBlank(field.getUniversalIdAttributeName()) ) {
 633  0
                                     Object principalId = ObjectUtils.getNestedValue(businessObject, field.getUniversalIdAttributeName());
 634  0
                                     if ( principalId != null ) {
 635  0
                                             field.setUniversalIdValue(principalId.toString());
 636  
                                     }
 637  
                             }
 638  0
                             if ( StringUtils.isNotBlank(field.getPersonNameAttributeName()) ) {
 639  0
                                     Object personName = ObjectUtils.getNestedValue(businessObject, field.getPersonNameAttributeName());
 640  0
                                     if ( personName != null ) {
 641  0
                                             field.setPersonNameValue( personName.toString() );
 642  
                                     }
 643  
                             }
 644  0
                     } catch ( Exception ex ) {
 645  0
                             LOG.warn( "Unable to get principal ID or person name property in FieldBridge.", ex );
 646  0
                     }
 647  
             }
 648  
         }
 649  
         
 650  0
         populateSecureField(field, obj);
 651  0
     }
 652  
 
 653  
     public static void populateSecureField(Field field, Object fieldValue){
 654  
         // set encrypted & masked value if user does not have permission to see real value in UI
 655  
         // element.isSecure() => a non-null AttributeSecurity object is set in the field
 656  0
         if (field.isSecure()) {
 657  
             try {
 658  0
                 if (fieldValue != null && fieldValue.toString().endsWith(EncryptionService.HASH_POST_PREFIX)) {
 659  0
                         field.setEncryptedValue(fieldValue.toString());
 660  
                 }
 661  
                 else {
 662  0
                         field.setEncryptedValue(CoreApiServiceLocator.getEncryptionService().encrypt(fieldValue) + EncryptionService.ENCRYPTION_POST_PREFIX);
 663  
                 }
 664  
             }
 665  0
             catch (GeneralSecurityException e) {
 666  0
                 throw new RuntimeException("Unable to encrypt secure field " + e.getMessage());
 667  0
             }
 668  
             //field.setDisplayMaskValue(field.getAttributeSecurity().getDisplayMaskValue(fieldValue));
 669  
         }
 670  0
     }
 671  
 
 672  
     /**
 673  
      * This method indicates whether or not propertyName refers to a nested attribute.
 674  
      *
 675  
      * @param propertyName
 676  
      * @return true if propertyName refers to a nested property (e.g. "x.y")
 677  
      */
 678  
     static private boolean isPropertyNested(String propertyName) {
 679  0
         return -1 != propertyName.indexOf('.');
 680  
     }
 681  
 
 682  
     /**
 683  
      * This method verifies that all of the parent objects of propertyName are non-null.
 684  
      *
 685  
      * @param bo
 686  
      * @param propertyName
 687  
      * @return true if all parents are non-null, otherwise false
 688  
      */
 689  
 
 690  
     static private boolean isObjectTreeNonNullAllTheWayDown(BusinessObject bo, String propertyName) {
 691  0
         String[] propertyParts = propertyName.split("\\.");
 692  
 
 693  0
         StringBuffer property = new StringBuffer();
 694  0
         for (int i = 0; i < propertyParts.length - 1; i++) {
 695  
 
 696  0
             property.append((0 == property.length()) ? "" : ".").append(propertyParts[i]);
 697  
             try {
 698  0
                 if (null == PropertyUtils.getNestedProperty(bo, property.toString())) {
 699  0
                     return false;
 700  
                 }
 701  
             }
 702  0
             catch (Throwable t) {
 703  0
                 LOG.debug("Either getter or setter not specified for property \"" + property.toString() + "\"", t);
 704  0
                 return false;
 705  0
             }
 706  
         }
 707  
 
 708  0
         return true;
 709  
 
 710  
     }
 711  
 
 712  
     /**
 713  
      * @param bo
 714  
      * @param propertyName
 715  
      * @return true if one (or more) of the intermediate objects in the given propertyName is null
 716  
      */
 717  
     private static boolean containsIntermediateNull(Object bo, String propertyName) {
 718  0
         boolean containsNull = false;
 719  
 
 720  0
         if (StringUtils.contains(propertyName, ".")) {
 721  0
             String prefix = StringUtils.substringBefore(propertyName, ".");
 722  0
             Object propertyValue = ObjectUtils.getPropertyValue(bo, prefix);
 723  
 
 724  0
             if (propertyValue == null) {
 725  0
                 containsNull = true;
 726  
             }
 727  
             else {
 728  0
                 String suffix = StringUtils.substringAfter(propertyName, ".");
 729  0
                 containsNull = containsIntermediateNull(propertyValue, suffix);
 730  
             }
 731  
         }
 732  
 
 733  0
         return containsNull;
 734  
     }
 735  
 
 736  
     /**
 737  
      * Uses reflection to get the property names of the business object, then checks for the property name as a key in the passed
 738  
      * map. If found, takes the value from the map and sets the business object property.
 739  
      *
 740  
      * @param bo
 741  
      * @param fieldValues
 742  
      * @return Cached Values from any formatting failures
 743  
      */
 744  
     public static Map populateBusinessObjectFromMap(BusinessObject bo, Map fieldValues) {
 745  0
         return populateBusinessObjectFromMap(bo, fieldValues, "");
 746  
     }
 747  
 
 748  
     /**
 749  
      * Uses reflection to get the property names of the business object, then checks for the property name as a key in the passed
 750  
      * map. If found, takes the value from the map and sets the business object property.
 751  
      *
 752  
      * @param bo
 753  
      * @param fieldValues
 754  
      * @param propertyNamePrefix this value will be prepended to all property names in the returned unformattable values map
 755  
      * @return Cached Values from any formatting failures
 756  
      */
 757  
     public static Map populateBusinessObjectFromMap(BusinessObject bo, Map<String, ?> fieldValues, String propertyNamePrefix) {
 758  0
         Map cachedValues = new HashMap();
 759  0
         MessageMap errorMap = GlobalVariables.getMessageMap();
 760  
 
 761  
         try {
 762  0
             for (Iterator<String> iter = fieldValues.keySet().iterator(); iter.hasNext();) {
 763  0
                 String propertyName = iter.next();
 764  
 
 765  0
                 if (propertyName.endsWith(KRADConstants.CHECKBOX_PRESENT_ON_FORM_ANNOTATION)) {
 766  
                     // since checkboxes do not post values when unchecked, this code detects whether a checkbox was unchecked, and
 767  
                     // sets the value to false.
 768  0
                     if (StringUtils.isNotBlank((String) fieldValues.get(propertyName))) {
 769  0
                         String checkboxName = StringUtils.removeEnd(propertyName, KRADConstants.CHECKBOX_PRESENT_ON_FORM_ANNOTATION);
 770  0
                         String checkboxValue = (String) fieldValues.get(checkboxName);
 771  0
                         if (checkboxValue == null) {
 772  
                             // didn't find a checkbox value, assume that it is unchecked
 773  0
                             if (PropertyUtils.isWriteable(bo, checkboxName)) {
 774  0
                                 Class type = ObjectUtils.easyGetPropertyType(bo, checkboxName);
 775  0
                                 if (type == Boolean.TYPE || type == Boolean.class) {
 776  
                                     // ASSUMPTION: unchecked means false
 777  0
                                     ObjectUtils.setObjectProperty(bo, checkboxName, type, "false");
 778  
                                 }
 779  
                             }
 780  
                         }
 781  0
                     }
 782  
                     // else, if not null, then it has a value, and we'll let the rest of the code handle it when the param is processed on
 783  
                     // another iteration (may be before or after this iteration).
 784  
                 }
 785  0
                 else if (PropertyUtils.isWriteable(bo, propertyName) && fieldValues.get(propertyName) != null ) {
 786  
                     // if the field propertyName is a valid property on the bo class
 787  0
                     Class type = ObjectUtils.easyGetPropertyType(bo, propertyName);
 788  
                     try {
 789  0
                             Object fieldValue = fieldValues.get(propertyName);
 790  0
                         ObjectUtils.setObjectProperty(bo, propertyName, type, fieldValue);
 791  
                     }
 792  0
                     catch (FormatException e) {
 793  0
                         cachedValues.put(propertyNamePrefix + propertyName, fieldValues.get(propertyName));
 794  0
                         errorMap.putError(propertyNamePrefix + propertyName, e.getErrorKey(), e.getErrorArgs());
 795  0
                     }
 796  
                 }
 797  0
             }
 798  
         }
 799  0
         catch (IllegalAccessException e) {
 800  0
             LOG.error("unable to populate business object" + e.getMessage());
 801  0
             throw new RuntimeException(e.getMessage(), e);
 802  
         }
 803  0
         catch (InvocationTargetException e) {
 804  0
             LOG.error("unable to populate business object" + e.getMessage());
 805  0
             throw new RuntimeException(e.getMessage(), e);
 806  
         }
 807  0
         catch (NoSuchMethodException e) {
 808  0
             LOG.error("unable to populate business object" + e.getMessage());
 809  0
             throw new RuntimeException(e.getMessage(), e);
 810  0
         }
 811  
 
 812  0
         return cachedValues;
 813  
     }
 814  
 
 815  
     /**
 816  
      * Does prefixing and read only settings of a Field UI for display in a maintenance document.
 817  
      *
 818  
      * @param field - the Field object to be displayed
 819  
      * @param keyFieldNames - Primary key property names for the business object being maintained.
 820  
      * @param namePrefix - String to prefix Field names with.
 821  
      * @param maintenanceAction - The maintenance action requested.
 822  
      * @param readOnly - Indicates whether all fields should be read only.
 823  
      * @return Field
 824  
      */
 825  
     public static Field fixFieldForForm(Field field, List keyFieldNames, String namePrefix, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 826  0
         String propertyName = field.getPropertyName();
 827  
         // We only need to do the following processing if the field is not a sub section header
 828  0
         if (field.containsBOData()) {
 829  
 
 830  
             // don't prefix submit fields, must start with dispatch parameter name
 831  0
             if (!propertyName.startsWith(KRADConstants.DISPATCH_REQUEST_PARAMETER)) {
 832  
                 // if the developer hasn't set a specific prefix use the one supplied
 833  0
                 if (field.getPropertyPrefix() == null || field.getPropertyPrefix().equals("")) {
 834  0
                     field.setPropertyName(namePrefix + propertyName);
 835  
                 }
 836  
                 else {
 837  0
                     field.setPropertyName(field.getPropertyPrefix() + "." + propertyName);
 838  
                 }
 839  
             }
 840  
 
 841  0
             if (readOnly) {
 842  0
                 field.setReadOnly(true);
 843  
             }
 844  
 
 845  
             // set keys read only for edit
 846  0
             if ( KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction) ) {
 847  0
                     if (keyFieldNames.contains(propertyName) ) {
 848  0
                         field.setReadOnly(true);
 849  0
                         field.setKeyField(true);
 850  0
                     } else if ( StringUtils.isNotBlank( field.getUniversalIdAttributeName() )
 851  
                                     && keyFieldNames.contains(field.getUniversalIdAttributeName() ) ) {
 852  
                             // special handling for when the principal ID is the PK field for a record
 853  
                             // this causes locking down of the user ID field
 854  0
                         field.setReadOnly(true);
 855  0
                         field.setKeyField(true);
 856  
                     }
 857  
             }
 858  
 
 859  
             // apply any authorization restrictions to field availability on the UI
 860  0
             applyAuthorization(field, maintenanceAction, auths, documentStatus, documentInitiatorPrincipalId);
 861  
 
 862  
             // if fieldConversions specified, prefix with new constant
 863  0
             if (StringUtils.isNotBlank(field.getFieldConversions())) {
 864  0
                 String fieldConversions = field.getFieldConversions();
 865  0
                 String newFieldConversions = KRADConstants.EMPTY_STRING;
 866  0
                 String[] conversions = StringUtils.split(fieldConversions, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 867  
 
 868  0
                 for (int l = 0; l < conversions.length; l++) {
 869  0
                     String conversion = conversions[l];
 870  
                     //String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 871  0
                     String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
 872  0
                     String conversionFrom = conversionPair[0];
 873  0
                     String conversionTo = conversionPair[1];
 874  0
                     conversionTo = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + conversionTo;
 875  0
                     newFieldConversions += (conversionFrom + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + conversionTo);
 876  
 
 877  0
                     if (l < conversions.length) {
 878  0
                         newFieldConversions += KRADConstants.FIELD_CONVERSIONS_SEPARATOR;
 879  
                     }
 880  
                 }
 881  
 
 882  0
                 field.setFieldConversions(newFieldConversions);
 883  
             }
 884  
 
 885  
             // if inquiryParameters specified, prefix with new constant
 886  0
             if (StringUtils.isNotBlank(field.getInquiryParameters())) {
 887  0
                 String inquiryParameters = field.getInquiryParameters();
 888  0
                 StringBuilder newInquiryParameters = new StringBuilder();
 889  0
                 String[] parameters = StringUtils.split(inquiryParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 890  
 
 891  0
                 for (int l = 0; l < parameters.length; l++) {
 892  0
                     String parameter = parameters[l];
 893  
                     //String[] parameterPair = StringUtils.split(parameter, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 894  0
                     String[] parameterPair = StringUtils.split(parameter, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
 895  0
                     String conversionFrom = parameterPair[0];
 896  0
                     String conversionTo = parameterPair[1];
 897  
 
 898  
                     // append the conversionFrom string, prefixed by document.newMaintainable
 899  0
                     newInquiryParameters.append(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE).append(conversionFrom);
 900  
 
 901  0
                     newInquiryParameters.append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR).append(conversionTo);
 902  
 
 903  0
                     if (l < parameters.length - 1) {
 904  0
                         newInquiryParameters.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 905  
                     }
 906  
                 }
 907  
 
 908  0
                 field.setInquiryParameters(newInquiryParameters.toString());
 909  
             }
 910  
 
 911  0
             if (Field.KUALIUSER.equals(field.getFieldType())) {
 912  
                 // prefix the personNameAttributeName
 913  0
                     int suffixIndex = field.getPropertyName().indexOf( field.getUserIdAttributeName() );
 914  0
                     if ( suffixIndex != -1 ) {
 915  0
                             field.setPersonNameAttributeName( field.getPropertyName().substring( 0, suffixIndex ) + field.getPersonNameAttributeName() );
 916  0
                             field.setUniversalIdAttributeName( field.getPropertyName().substring( 0, suffixIndex ) + field.getUniversalIdAttributeName() );
 917  
                     } else {
 918  0
                             field.setPersonNameAttributeName(namePrefix + field.getPersonNameAttributeName());
 919  0
                             field.setUniversalIdAttributeName(namePrefix + field.getUniversalIdAttributeName());
 920  
                     }
 921  
 
 922  
                 // TODO: do we need to prefix the universalIdAttributeName in Field as well?
 923  
             }
 924  
 
 925  
             // if lookupParameters specified, prefix with new constant
 926  0
             if (StringUtils.isNotBlank(field.getLookupParameters())) {
 927  0
                 String lookupParameters = field.getLookupParameters();
 928  0
                 String newLookupParameters = KRADConstants.EMPTY_STRING;
 929  0
                 String[] conversions = StringUtils.split(lookupParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
 930  
 
 931  0
                 for (int m = 0; m < conversions.length; m++) {
 932  0
                     String conversion = conversions[m];
 933  
                     //String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
 934  0
                     String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
 935  0
                     String conversionFrom = conversionPair[0];
 936  0
                     String conversionTo = conversionPair[1];
 937  0
                     conversionFrom = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + conversionFrom;
 938  0
                     newLookupParameters += (conversionFrom + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + conversionTo);
 939  
 
 940  0
                     if (m < conversions.length) {
 941  0
                         newLookupParameters += KRADConstants.FIELD_CONVERSIONS_SEPARATOR;
 942  
                     }
 943  
                 }
 944  
 
 945  0
                 field.setLookupParameters(newLookupParameters);
 946  
             }
 947  
 
 948  
             // CONTAINER field types have nested rows and fields that need setup for the form
 949  0
             if (Field.CONTAINER.equals(field.getFieldType())) {
 950  0
                 List containerRows = field.getContainerRows();
 951  0
                 List fixedRows = new ArrayList();
 952  
 
 953  0
                 for (Iterator iter = containerRows.iterator(); iter.hasNext();) {
 954  0
                     Row containerRow = (Row) iter.next();
 955  0
                     List containerFields = containerRow.getFields();
 956  0
                     List fixedFields = new ArrayList();
 957  
 
 958  0
                     for (Iterator iterator = containerFields.iterator(); iterator.hasNext();) {
 959  0
                         Field containerField = (Field) iterator.next();
 960  0
                         containerField = fixFieldForForm(containerField, keyFieldNames, namePrefix, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 961  0
                         fixedFields.add(containerField);
 962  0
                     }
 963  
 
 964  0
                     fixedRows.add(new Row(fixedFields));
 965  0
                 }
 966  
 
 967  0
                 field.setContainerRows(fixedRows);
 968  
             }
 969  
         }
 970  0
         return field;
 971  
     }
 972  
 
 973  
     public static void applyAuthorization(Field field, String maintenanceAction, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 974  0
             String fieldName = "";
 975  0
             FieldRestriction fieldAuth = null;
 976  0
             Person user = GlobalVariables.getUserSession().getPerson();
 977  
         // only apply this on the newMaintainable
 978  0
         if (field.getPropertyName().startsWith(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
 979  
             // get just the actual fieldName, with the document.newMaintainableObject, etc etc removed
 980  0
             fieldName = field.getPropertyName().substring(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE.length());
 981  
 
 982  
             // if the field is restricted somehow
 983  0
             if (auths.hasRestriction(fieldName)) {
 984  0
                 fieldAuth = auths.getFieldRestriction(fieldName);
 985  0
                 if(KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)){
 986  0
                         if((KewApiConstants.ROUTE_HEADER_SAVED_CD.equals(documentStatus) || KewApiConstants.ROUTE_HEADER_INITIATED_CD.equals(documentStatus))
 987  
                                 && user.getPrincipalId().equals(documentInitiatorPrincipalId)){
 988  
 
 989  
                                 //user should be able to see the unmark value
 990  
                         }else{
 991  0
                                 if(fieldAuth.isPartiallyMasked()){
 992  0
                                     field.setSecure(true);
 993  0
                                     fieldAuth.setShouldBeEncrypted(true);
 994  0
                                     MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 995  0
                                     String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 996  0
                                     field.setDisplayMaskValue(displayMaskValue);
 997  0
                                     populateSecureField(field, field.getPropertyValue());
 998  0
                             }
 999  0
                             else if(fieldAuth.isMasked()){
 1000  0
                                     field.setSecure(true);
 1001  0
                                     fieldAuth.setShouldBeEncrypted(true);
 1002  0
                                     MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 1003  0
                                     String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 1004  0
                                     field.setDisplayMaskValue(displayMaskValue);
 1005  0
                                     populateSecureField(field, field.getPropertyValue());
 1006  
                             }
 1007  
                         }
 1008  
                 }
 1009  
 
 1010  0
                 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) {
 1011  
                         // if there's existing data on the page that we're not going to clear out, then we will mask it out
 1012  0
                         if(fieldAuth.isPartiallyMasked()){
 1013  0
                                 field.setSecure(true);
 1014  0
                                 fieldAuth.setShouldBeEncrypted(true);
 1015  0
                                 MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 1016  0
                                 String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 1017  0
                                 field.setDisplayMaskValue(displayMaskValue);
 1018  0
                                 populateSecureField(field, field.getPropertyValue());
 1019  0
                         }
 1020  0
                         else if(fieldAuth.isMasked()){
 1021  0
                                 field.setSecure(true);
 1022  0
                                 fieldAuth.setShouldBeEncrypted(true);
 1023  0
                                 MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 1024  0
                                 String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 1025  0
                                 field.setDisplayMaskValue(displayMaskValue);
 1026  0
                                 populateSecureField(field, field.getPropertyValue());
 1027  
                         }
 1028  
                 }
 1029  
 
 1030  0
                 if (Field.isInputField(field.getFieldType()) || field.getFieldType().equalsIgnoreCase(Field.CHECKBOX)) {
 1031  
                         // if its an editable field, allow decreasing availability to readonly or hidden
 1032  
                     // only touch the field if the restricted type is hidden or readonly
 1033  0
                     if (fieldAuth.isReadOnly()) {
 1034  0
                         if (!field.isReadOnly() && !fieldAuth.isMasked() && !fieldAuth.isPartiallyMasked()) {
 1035  0
                             field.setReadOnly(true);
 1036  
                         }
 1037  
                     }
 1038  0
                     else if (fieldAuth.isHidden()) {
 1039  0
                         if (field.getFieldType() != Field.HIDDEN) {
 1040  0
                             field.setFieldType(Field.HIDDEN);
 1041  
                         }
 1042  
                     }
 1043  
                 }
 1044  
 
 1045  0
                 if(Field.BUTTON.equalsIgnoreCase(field.getFieldType()) && fieldAuth.isHidden()){
 1046  0
                         field.setFieldType(Field.HIDDEN);
 1047  
                 }
 1048  
 
 1049  
                 // if the field is readOnly, and the authorization says it should be hidden,
 1050  
                 // then restrict it
 1051  0
                 if (field.isReadOnly() && fieldAuth.isHidden()) {
 1052  0
                     field.setFieldType(Field.HIDDEN);
 1053  
                 }
 1054  
 
 1055  
             }
 1056  
             // special check for old maintainable - need to ensure that fields hidden on the
 1057  
             // "new" side are also hidden on the old side
 1058  
         }
 1059  0
         else if (field.getPropertyName().startsWith(KRADConstants.MAINTENANCE_OLD_MAINTAINABLE)) {
 1060  
             // get just the actual fieldName, with the document.oldMaintainableObject, etc etc removed
 1061  0
             fieldName = field.getPropertyName().substring(KRADConstants.MAINTENANCE_OLD_MAINTAINABLE.length());
 1062  
             // if the field is restricted somehow
 1063  0
             if (auths.hasRestriction(fieldName)) {
 1064  0
                 fieldAuth = auths.getFieldRestriction(fieldName);
 1065  0
                 if(fieldAuth.isPartiallyMasked()){
 1066  0
                     field.setSecure(true);
 1067  0
                     MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 1068  0
                     String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 1069  0
                     field.setDisplayMaskValue(displayMaskValue);
 1070  0
                     field.setPropertyValue(displayMaskValue);
 1071  0
                     populateSecureField(field, field.getPropertyValue());
 1072  
 
 1073  
                }
 1074  
 
 1075  0
                if(fieldAuth.isMasked()){
 1076  0
                     field.setSecure(true);
 1077  0
                     MaskFormatter maskFormatter = fieldAuth.getMaskFormatter();
 1078  0
                     String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue());
 1079  0
                     field.setDisplayMaskValue(displayMaskValue);
 1080  0
                     field.setPropertyValue(displayMaskValue);
 1081  0
                     populateSecureField(field, field.getPropertyValue());
 1082  
                 }
 1083  
 
 1084  0
                 if (fieldAuth.isHidden()) {
 1085  0
                     field.setFieldType(Field.HIDDEN);
 1086  
                 }
 1087  
             }
 1088  
         }
 1089  0
     }
 1090  
 
 1091  
     /**
 1092  
      * Merges together sections of the old maintainable and new maintainable.
 1093  
      *
 1094  
      * @param oldSections
 1095  
      * @param newSections
 1096  
      * @param keyFieldNames
 1097  
      * @param maintenanceAction
 1098  
      * @param readOnly
 1099  
      * @return List of Section objects
 1100  
      */
 1101  
     public static List meshSections(List oldSections, List newSections, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 1102  0
         List meshedSections = new ArrayList();
 1103  
 
 1104  0
         for (int i = 0; i < newSections.size(); i++) {
 1105  0
             Section maintSection = (Section) newSections.get(i);
 1106  0
             List sectionRows = maintSection.getRows();
 1107  0
             Section oldMaintSection = (Section) oldSections.get(i);
 1108  0
             List oldSectionRows = oldMaintSection.getRows();
 1109  0
             List<Row> meshedRows = new ArrayList();
 1110  0
             meshedRows = meshRows(oldSectionRows, sectionRows, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 1111  0
             maintSection.setRows(meshedRows);
 1112  0
             if (StringUtils.isBlank(maintSection.getErrorKey())) {
 1113  0
                 maintSection.setErrorKey(MaintenanceUtils.generateErrorKeyForSection(maintSection));
 1114  
             }
 1115  0
             meshedSections.add(maintSection);
 1116  
         }
 1117  
 
 1118  0
         return meshedSections;
 1119  
     }
 1120  
 
 1121  
     /**
 1122  
      * Merges together rows of an old maintainable section and new maintainable section.
 1123  
      *
 1124  
      * @param oldRows
 1125  
      * @param newRows
 1126  
      * @param keyFieldNames
 1127  
      * @param maintenanceAction
 1128  
      * @param readOnly
 1129  
      * @return List of Row objects
 1130  
      */
 1131  
     public static List meshRows(List oldRows, List newRows, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 1132  0
         List<Row> meshedRows = new ArrayList<Row>();
 1133  
 
 1134  0
         for (int j = 0; j < newRows.size(); j++) {
 1135  0
             Row sectionRow = (Row) newRows.get(j);
 1136  0
             List rowFields = sectionRow.getFields();
 1137  0
             Row oldSectionRow = null;
 1138  0
             List oldRowFields = new ArrayList();
 1139  
 
 1140  0
             if (null != oldRows && oldRows.size() > j) {
 1141  0
                 oldSectionRow = (Row) oldRows.get(j);
 1142  0
                 oldRowFields = oldSectionRow.getFields();
 1143  
             }
 1144  
 
 1145  0
             List meshedFields = meshFields(oldRowFields, rowFields, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 1146  0
             if (meshedFields.size() > 0) {
 1147  0
                 Row meshedRow = new Row(meshedFields);
 1148  0
                 if (sectionRow.isHidden()) {
 1149  0
                     meshedRow.setHidden(true);
 1150  
                 }
 1151  
 
 1152  0
                 meshedRows.add(meshedRow);
 1153  
             }
 1154  
         }
 1155  
 
 1156  0
         return meshedRows;
 1157  
     }
 1158  
 
 1159  
 
 1160  
     /**
 1161  
      * Merges together fields and an old maintainble row and new maintainable row, for each field call fixFieldForForm.
 1162  
      *
 1163  
      * @param oldFields
 1164  
      * @param newFields
 1165  
      * @param keyFieldNames
 1166  
      * @param maintenanceAction
 1167  
      * @param readOnly
 1168  
      * @return List of Field objects
 1169  
      */
 1170  
     public static List meshFields(List oldFields, List newFields, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 1171  0
         List meshedFields = new ArrayList();
 1172  
 
 1173  0
         List newFieldsToMerge = new ArrayList();
 1174  0
         List oldFieldsToMerge = new ArrayList();
 1175  
 
 1176  0
         for (int k = 0; k < newFields.size(); k++) {
 1177  0
             Field newMaintField = (Field) newFields.get(k);
 1178  0
             String propertyName = newMaintField.getPropertyName();
 1179  
             // If this is an add button, then we have to have only this field for the entire row.
 1180  0
             if (Field.IMAGE_SUBMIT.equals(newMaintField.getFieldType())) {
 1181  0
                 meshedFields.add(newMaintField);
 1182  
             }
 1183  0
             else if (Field.CONTAINER.equals(newMaintField.getFieldType())) {
 1184  0
                 if (oldFields.size() > k) {
 1185  0
                     Field oldMaintField = (Field) oldFields.get(k);
 1186  0
                     newMaintField = meshContainerFields(oldMaintField, newMaintField, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 1187  0
                 }
 1188  
                 else {
 1189  0
                     newMaintField = meshContainerFields(newMaintField, newMaintField, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 1190  
                 }
 1191  0
                 meshedFields.add(newMaintField);
 1192  
             }
 1193  
             else {
 1194  0
                 newMaintField = FieldUtils.fixFieldForForm(newMaintField, keyFieldNames, KRADConstants.MAINTENANCE_NEW_MAINTAINABLE, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId);
 1195  
                 // add old fields for edit
 1196  0
                 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) {
 1197  0
                     Field oldMaintField = (Field) oldFields.get(k);
 1198  
 
 1199  
                     // compare values for change, and set new maintainable fields for highlighting
 1200  
                     // no point in highlighting the hidden fields, since they won't be rendered anyways
 1201  0
                     if (!StringUtils.equalsIgnoreCase(newMaintField.getPropertyValue(), oldMaintField.getPropertyValue())
 1202  
                             && !Field.HIDDEN.equals(newMaintField.getFieldType())) {
 1203  0
                         newMaintField.setHighlightField(true);
 1204  
                     }
 1205  
 
 1206  0
                     oldMaintField = FieldUtils.fixFieldForForm(oldMaintField, keyFieldNames, KRADConstants.MAINTENANCE_OLD_MAINTAINABLE, maintenanceAction, true, auths, documentStatus, documentInitiatorPrincipalId);
 1207  0
                     oldFieldsToMerge.add(oldMaintField);
 1208  
                 }
 1209  
 
 1210  0
                 newFieldsToMerge.add(newMaintField);
 1211  
 
 1212  0
                 for (Iterator iter = oldFieldsToMerge.iterator(); iter.hasNext();) {
 1213  0
                     Field element = (Field) iter.next();
 1214  0
                     meshedFields.add(element);
 1215  0
                 }
 1216  
 
 1217  0
                 for (Iterator iter = newFieldsToMerge.iterator(); iter.hasNext();) {
 1218  0
                     Field element = (Field) iter.next();
 1219  0
                     meshedFields.add(element);
 1220  0
                 }
 1221  
             }
 1222  
         }
 1223  0
         return meshedFields;
 1224  
     }
 1225  
 
 1226  
     /**
 1227  
      * Determines whether field level help is enabled for the field corresponding to the dataObjectClass and attribute name
 1228  
      *
 1229  
      * If this value is true, then the field level help will be enabled.
 1230  
      * If false, then whether a field is enabled is determined by the value returned by {@link #isLookupFieldLevelHelpDisabled(Class, String)} and the system-wide
 1231  
      * parameter setting.  Note that if a field is read-only, that may cause field-level help to not be rendered.
 1232  
      *
 1233  
      * @param businessObjectClass the looked up class
 1234  
      * @param attributeName the attribute for the field
 1235  
      * @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
 1236  
      * affects the enablement of field level help
 1237  
      */
 1238  
     protected static boolean isLookupFieldLevelHelpEnabled(Class businessObjectClass, String attributeName) {
 1239  0
         return false;
 1240  
     }
 1241  
 
 1242  
     /**
 1243  
      * Determines whether field level help is disabled for the field corresponding to the dataObjectClass and attribute name
 1244  
      *
 1245  
      * If this value is true and {@link #isLookupFieldLevelHelpEnabled(Class, String)} returns false,
 1246  
      * then the field level help will not be rendered.  If both this and {@link #isLookupFieldLevelHelpEnabled(Class, String)} return false, then the system-wide
 1247  
      * setting will determine whether field level help is enabled.  Note that if a field is read-only, that may cause field-level help to not be rendered.
 1248  
      *
 1249  
      * @param businessObjectClass the looked up class
 1250  
      * @param attributeName the attribute for the field
 1251  
      * @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
 1252  
      * affects the enablement of field level help
 1253  
      */
 1254  
     protected static boolean isLookupFieldLevelHelpDisabled(Class businessObjectClass, String attributeName) {
 1255  0
         return false;
 1256  
     }
 1257  
 
 1258  
     public static List createAndPopulateFieldsForLookup(List<String> lookupFieldAttributeList, List<String> readOnlyFieldsList, Class businessObjectClass) throws InstantiationException, IllegalAccessException {
 1259  0
         List<Field> fields = new ArrayList<Field>();
 1260  0
         BusinessObjectEntry boe = (BusinessObjectEntry) getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(businessObjectClass.getName());
 1261  
 
 1262  0
         Map<String, Boolean> isHiddenMap = new HashMap<String, Boolean>();
 1263  0
         Map<String, Boolean> isReadOnlyMap = new HashMap<String, Boolean>();
 1264  
 
 1265  
         /*
 1266  
              * Check if any field is hidden or read only.  This allows us to
 1267  
              * set lookup criteria as hidden/readonly outside the controlDefinition.
 1268  
              */
 1269  0
             if(boe.hasLookupDefinition()){
 1270  0
                     List<FieldDefinition> fieldDefs = boe.getLookupDefinition().getLookupFields();
 1271  0
                     for(FieldDefinition field : fieldDefs){
 1272  0
                                 isReadOnlyMap.put(field.getAttributeName(), Boolean.valueOf(field.isReadOnly()));
 1273  0
                                 isHiddenMap.put(field.getAttributeName(), Boolean.valueOf(field.isHidden()));
 1274  
                     }
 1275  
             }
 1276  
 
 1277  0
         for( String attributeName : lookupFieldAttributeList )
 1278  
         {
 1279  0
             Field field = FieldUtils.getPropertyField(businessObjectClass, attributeName, true);
 1280  
 
 1281  0
             if(field.isDatePicker() && field.isRanged()) {
 1282  
 
 1283  0
                     Field newDate = createRangeDateField(field);
 1284  0
                     fields.add(newDate);
 1285  
             }
 1286  
 
 1287  
             BusinessObject newBusinessObjectInstance;
 1288  0
             if (ExternalizableBusinessObjectUtils.isExternalizableBusinessObjectInterface(businessObjectClass)) {
 1289  0
                     ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(businessObjectClass);
 1290  0
                     newBusinessObjectInstance = (BusinessObject) moduleService.createNewObjectFromExternalizableClass(businessObjectClass);
 1291  0
             }
 1292  
             else {
 1293  0
                     newBusinessObjectInstance = (BusinessObject) businessObjectClass.newInstance();
 1294  
             }
 1295  
             //quickFinder is synonymous with a field-based Lookup
 1296  0
             field = LookupUtils.setFieldQuickfinder(newBusinessObjectInstance, attributeName, field, lookupFieldAttributeList);
 1297  0
             field = LookupUtils.setFieldDirectInquiry(newBusinessObjectInstance, attributeName, field);
 1298  
 
 1299  
             // overwrite maxLength to allow for wildcards and ranges in the select, but only if it's not a mulitselect box, because maxLength determines the # of entries
 1300  0
             if (!Field.MULTISELECT.equals(field.getFieldType())) {
 1301  0
                     field.setMaxLength(100);
 1302  
             }
 1303  
 
 1304  
             // if the attrib name is "active", and BO is Inactivatable, then set the default value to Y
 1305  0
             if (attributeName.equals(KRADPropertyConstants.ACTIVE) && MutableInactivatable.class.isAssignableFrom(businessObjectClass)) {
 1306  0
                     field.setPropertyValue(KRADConstants.YES_INDICATOR_VALUE);
 1307  0
                     field.setDefaultValue(KRADConstants.YES_INDICATOR_VALUE);
 1308  
             }
 1309  
             // set default value
 1310  0
             String defaultValue = getBusinessObjectMetaDataService().getLookupFieldDefaultValue(businessObjectClass, attributeName);
 1311  0
             if (defaultValue != null) {
 1312  0
                 field.setPropertyValue(defaultValue);
 1313  0
                 field.setDefaultValue(defaultValue);
 1314  
             }
 1315  
 
 1316  0
             Class defaultValueFinderClass = getBusinessObjectMetaDataService().getLookupFieldDefaultValueFinderClass(businessObjectClass, attributeName);
 1317  
             //getBusinessObjectMetaDataService().getLookupFieldDefaultValue(dataObjectClass, attributeName)
 1318  0
             if (defaultValueFinderClass != null) {
 1319  0
                 field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
 1320  0
                 field.setDefaultValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue());
 1321  
             }
 1322  0
             if ( (readOnlyFieldsList != null && readOnlyFieldsList.contains(field.getPropertyName()))
 1323  
                             || ( isReadOnlyMap.containsKey(field.getPropertyName()) && isReadOnlyMap.get(field.getPropertyName()).booleanValue())
 1324  
                     ) {
 1325  0
                 field.setReadOnly(true);
 1326  
             }
 1327  
 
 1328  0
             populateQuickfinderDefaultsForLookup(businessObjectClass, attributeName, field);
 1329  
 
 1330  0
                         if ((isHiddenMap.containsKey(field.getPropertyName()) && isHiddenMap.get(field.getPropertyName()).booleanValue())) {
 1331  0
                                 field.setFieldType(Field.HIDDEN);
 1332  
                         }
 1333  
             
 1334  0
             boolean triggerOnChange = getBusinessObjectDictionaryService().isLookupFieldTriggerOnChange(businessObjectClass, attributeName);
 1335  0
             field.setTriggerOnChange(triggerOnChange);
 1336  
 
 1337  0
             field.setFieldLevelHelpEnabled(isLookupFieldLevelHelpEnabled(businessObjectClass, attributeName));
 1338  0
             field.setFieldLevelHelpDisabled(isLookupFieldLevelHelpDisabled(businessObjectClass, attributeName));
 1339  
             
 1340  0
             fields.add(field);
 1341  0
         }
 1342  0
         return fields;
 1343  
     }
 1344  
 
 1345  
 
 1346  
         /**
 1347  
          * This method ...
 1348  
          *
 1349  
          * @param businessObjectClass
 1350  
          * @param attributeName
 1351  
          * @param field
 1352  
          * @throws InstantiationException
 1353  
          * @throws IllegalAccessException
 1354  
          */
 1355  
         private static void populateQuickfinderDefaultsForLookup(
 1356  
                         Class businessObjectClass, String attributeName, Field field)
 1357  
                         throws InstantiationException, IllegalAccessException {
 1358  
                 // handle quickfinderParameterString / quickfinderParameterFinderClass
 1359  0
                 String quickfinderParamString = getBusinessObjectMetaDataService().getLookupFieldQuickfinderParameterString(businessObjectClass, attributeName);
 1360  0
                 Class<? extends ValueFinder> quickfinderParameterFinderClass =
 1361  
                         getBusinessObjectMetaDataService().getLookupFieldQuickfinderParameterStringBuilderClass(businessObjectClass, attributeName);
 1362  0
                 if (quickfinderParameterFinderClass != null) {
 1363  0
                         quickfinderParamString = quickfinderParameterFinderClass.newInstance().getValue();
 1364  
                 }
 1365  
 
 1366  0
                 if (!StringUtils.isEmpty(quickfinderParamString)) {
 1367  0
                         String [] params = quickfinderParamString.split(",");
 1368  0
                         if (params != null) for (String param : params) {
 1369  0
                                 if (param.contains(KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER)) {
 1370  0
                                         String[] paramChunks = param.split(KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER, 2);
 1371  0
                                         field.appendLookupParameters(
 1372  
                                                         KRADConstants.LOOKUP_PARAMETER_LITERAL_PREFIX+KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER+
 1373  
                                                         paramChunks[1]+":"+paramChunks[0]);
 1374  
                                 }
 1375  
                         }
 1376  
                 }
 1377  0
         }
 1378  
 
 1379  
 
 1380  
         /**
 1381  
          * creates an extra field for date from/to ranges
 1382  
          * @param field
 1383  
          * @return a new date field
 1384  
          */
 1385  
         public static Field createRangeDateField(Field field) {
 1386  0
                 Field newDate = (Field)ObjectUtils.deepCopy(field);
 1387  0
                 newDate.setFieldLabel(newDate.getFieldLabel()+" "+KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL);
 1388  0
                 field.setFieldLabel(field.getFieldLabel()+" "+KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL);
 1389  0
                 newDate.setPropertyName(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX+newDate.getPropertyName());
 1390  0
                 return newDate;
 1391  
         }
 1392  
 
 1393  
     private static Field meshContainerFields(Field oldMaintField, Field newMaintField, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) {
 1394  0
         List resultingRows = new ArrayList();
 1395  0
         resultingRows.addAll(meshRows(oldMaintField.getContainerRows(), newMaintField.getContainerRows(), keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId));
 1396  0
         Field resultingField = newMaintField;
 1397  0
         resultingField.setFieldType(Field.CONTAINER);
 1398  
 
 1399  
         // save the summary info
 1400  0
         resultingField.setContainerElementName(newMaintField.getContainerElementName());
 1401  0
         resultingField.setContainerDisplayFields(newMaintField.getContainerDisplayFields());
 1402  0
         resultingField.setNumberOfColumnsForCollection(newMaintField.getNumberOfColumnsForCollection());
 1403  
 
 1404  0
         resultingField.setContainerRows(resultingRows);
 1405  0
         List resultingRowsList = newMaintField.getContainerRows();
 1406  0
         if (resultingRowsList.size() > 0) {
 1407  0
             List resultingFieldsList = ((Row) resultingRowsList.get(0)).getFields();
 1408  0
             if (resultingFieldsList.size() > 0) {
 1409  
                 // todo: assign the correct propertyName to the container in the first place. For now, I'm wary of the weird usages
 1410  
                 // of constructContainerField().
 1411  0
                 String containedFieldName = ((Field) (resultingFieldsList.get(0))).getPropertyName();
 1412  0
                 resultingField.setPropertyName(containedFieldName.substring(0, containedFieldName.lastIndexOf('.')));
 1413  
             }
 1414  0
         }
 1415  
         else {
 1416  0
             resultingField.setPropertyName(oldMaintField.getPropertyName());
 1417  
         }
 1418  0
         return resultingField;
 1419  
     }
 1420  
 
 1421  
     /**
 1422  
      * This method modifies the passed in field so that it may be used to render a multiple values lookup button
 1423  
      *
 1424  
      * @param field this object will be modified by this method
 1425  
      * @param parents
 1426  
      * @param definition
 1427  
      */
 1428  
     static final public void modifyFieldToSupportMultipleValueLookups(Field field, String parents, MaintainableCollectionDefinition definition) {
 1429  0
         field.setMultipleValueLookedUpCollectionName(parents + definition.getName());
 1430  0
         field.setMultipleValueLookupClassName(definition.getSourceClassName().getName());
 1431  0
         field.setMultipleValueLookupClassLabel(getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(definition.getSourceClassName().getName()).getObjectLabel());
 1432  0
     }
 1433  
 
 1434  
     /**
 1435  
      * Returns whether the passed in collection has been properly configured in the maint doc dictionary to support multiple value
 1436  
      * lookups.
 1437  
      *
 1438  
      * @param definition
 1439  
      * @return
 1440  
      */
 1441  
     static final public boolean isCollectionMultipleLookupEnabled(MaintainableCollectionDefinition definition) {
 1442  0
         return definition.getSourceClassName() != null && definition.isIncludeMultipleLookupLine();
 1443  
     }
 1444  
 
 1445  
     /**
 1446  
      * This method removes any duplicating spacing (internal or on the ends) from a String, meant to be exposed as a tag library
 1447  
      * function.
 1448  
      *
 1449  
      * @param s String to remove duplicate spacing from.
 1450  
      * @return String without duplicate spacing.
 1451  
      */
 1452  
     public static String scrubWhitespace(String s) {
 1453  0
         return s.replaceAll("(\\s)(\\s+)", " ");
 1454  
     }
 1455  
 
 1456  
     public static List<Row> convertRemotableAttributeFields(List<RemotableAttributeField> remotableAttributeFields) {
 1457  0
         List<Row> rows = new ArrayList<Row>();
 1458  0
         for (RemotableAttributeField remotableAttributeField : remotableAttributeFields) {
 1459  0
             List<Field> fields = convertRemotableAttributeField(remotableAttributeField);
 1460  
             // each field goes in it's own row...
 1461  0
             for (Field field : fields) {
 1462  0
                 Row row = new Row(field);
 1463  0
                 rows.add(row);
 1464  0
             }
 1465  0
         }
 1466  0
         return rows;
 1467  
     }
 1468  
 
 1469  
     public static List<Field> convertRemotableAttributeField(RemotableAttributeField remotableAttributeField) {
 1470  
         // will produce two fields in the case of a range
 1471  0
         List<Field> fields = constructFieldsForAttributeDefinition(remotableAttributeField);
 1472  0
         for (Field field : fields) {
 1473  0
             applyControlAttributes(remotableAttributeField, field);
 1474  0
             applyLookupAttributes(remotableAttributeField, field);
 1475  0
             applyWidgetAttributes(remotableAttributeField, field);
 1476  
         }
 1477  0
         return fields;
 1478  
     }
 1479  
 
 1480  
     private static List<Field> constructFieldsForAttributeDefinition(RemotableAttributeField remotableAttributeField) {
 1481  0
         List<Field> fields = new ArrayList<Field>();
 1482  0
         if (remotableAttributeField.getAttributeLookupSettings() != null && remotableAttributeField.getAttributeLookupSettings().isRanged()) {
 1483  
             // create two fields, one for the "from" and one for the "to"
 1484  0
             AttributeLookupSettings lookupSettings = remotableAttributeField.getAttributeLookupSettings();
 1485  0
             String lowerBoundName = lookupSettings.getLowerBoundName();
 1486  0
             String upperBoundName = lookupSettings.getUpperBoundName();
 1487  0
             String lowerBoundLabel = lookupSettings.getLowerBoundLabel();
 1488  0
             String upperBoundLabel = lookupSettings.getUpperBoundLabel();
 1489  0
             if (StringUtils.isBlank(lowerBoundName)) {
 1490  0
                 lowerBoundName = "from_" + remotableAttributeField.getName();
 1491  
             }
 1492  0
             if (StringUtils.isBlank(upperBoundName)) {
 1493  0
                 upperBoundName = "to_" + remotableAttributeField.getName();
 1494  
             }
 1495  0
             if (StringUtils.isBlank(lowerBoundLabel)) {
 1496  0
                 lowerBoundLabel = "From " + remotableAttributeField.getLongLabel();
 1497  
             }
 1498  0
             if (StringUtils.isBlank(upperBoundLabel)) {
 1499  0
                 upperBoundLabel = "To " + remotableAttributeField.getLongLabel();
 1500  
             }
 1501  
 
 1502  0
             Field lowerField = new Field(lowerBoundName, lowerBoundLabel);
 1503  0
             lowerField.setMemberOfRange(true);
 1504  0
             lowerField.setAllowInlineRange(false);
 1505  0
             lowerField.setRangeFieldInclusive(lookupSettings.isLowerBoundInclusive());
 1506  0
             fields.add(lowerField);
 1507  
 
 1508  0
             Field upperField = new Field(upperBoundName, upperBoundLabel);
 1509  0
             upperField.setMemberOfRange(true);
 1510  0
             upperField.setAllowInlineRange(false);
 1511  0
             upperField.setRangeFieldInclusive(lookupSettings.isUpperBoundInclusive());
 1512  0
             fields.add(upperField);
 1513  0
         } else {
 1514  
             //this ain't right....
 1515  0
             Field tempField = new Field(remotableAttributeField.getName(), remotableAttributeField.getLongLabel());
 1516  0
             tempField.setFieldLabel(remotableAttributeField.getShortLabel());
 1517  0
             fields.add(tempField);
 1518  
         }
 1519  0
         return fields;
 1520  
     }
 1521  
 
 1522  
     public static List<RemotableAttributeField> convertRowsToAttributeFields(List<Row> rows) {
 1523  0
         List<RemotableAttributeField> attributeFields = new ArrayList<RemotableAttributeField>();
 1524  0
         for (Row row : rows) {
 1525  0
             attributeFields.addAll(convertRowToAttributeFields(row));
 1526  
         }
 1527  0
         return attributeFields;
 1528  
     }
 1529  
 
 1530  
     public static List<RemotableAttributeField> convertRowToAttributeFields(Row row) {
 1531  0
         List<RemotableAttributeField> attributeFields = new ArrayList<RemotableAttributeField>();
 1532  0
         for (Field field : row.getFields()) {
 1533  0
             RemotableAttributeField remotableAttributeField = convertFieldToAttributeField(field);
 1534  0
             if (remotableAttributeField != null) {
 1535  0
                 attributeFields.add(remotableAttributeField);
 1536  
             }
 1537  0
         }
 1538  0
         return attributeFields;
 1539  
     }
 1540  
 
 1541  
     public static RemotableAttributeField convertFieldToAttributeField(Field field) {
 1542  0
         RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create(field.getPropertyName());
 1543  
 
 1544  0
         List<RemotableAbstractWidget.Builder> widgets = new ArrayList<RemotableAbstractWidget.Builder>();
 1545  0
         builder.setDataType(DataType.valueOf(field.getFieldDataType().toUpperCase()));
 1546  
 
 1547  0
         builder.setShortLabel(field.getFieldLabel());
 1548  0
         builder.setLongLabel(field.getMainFieldLabel());
 1549  0
         builder.setHelpSummary(field.getFieldHelpSummary());
 1550  
         //builder.setHelpConstraint(field.)
 1551  
         //builder.setHelpDescription();
 1552  0
         builder.setForceUpperCase(field.isUpperCase());
 1553  
         //builder.setMinLength()
 1554  0
         builder.setMaxLength(new Integer(field.getMaxLength()));
 1555  
         //builder.setMinValue();
 1556  
         //builder.setMaxValue();
 1557  
         //builder.setRegexConstraint(field.);
 1558  
         //builder.setRegexContraintMsg();
 1559  0
         builder.setRequired(field.isFieldRequired());
 1560  0
         builder.setDefaultValues(Collections.singletonList(field.getDefaultValue()));
 1561  0
         builder.setControl(FieldUtils.constructControl(field.getFieldType(), field.getFieldValidValues()));
 1562  0
         if (field.getHasLookupable()) {
 1563  0
             builder.setAttributeLookupSettings(RemotableAttributeLookupSettings.Builder.create());
 1564  0
             RemotableQuickFinder.Builder quickfinder =
 1565  
                     RemotableQuickFinder.Builder.create(field.getBaseLookupUrl(), field.getQuickFinderClassNameImpl());
 1566  0
             quickfinder.setFieldConversions(toMap(field.getFieldConversions()));
 1567  0
             quickfinder.setLookupParameters(toMap(field.getLookupParameters()));
 1568  0
             widgets.add(quickfinder);
 1569  
         }
 1570  0
         if (field.isDatePicker()) {
 1571  0
             widgets.add(RemotableDatepicker.Builder.create());
 1572  
         }
 1573  0
         if (field.isExpandedTextArea()) {
 1574  0
             widgets.add(RemotableTextExpand.Builder.create());
 1575  
         }
 1576  0
         builder.setWidgets(widgets);
 1577  
 
 1578  0
         return builder.build();
 1579  
     }
 1580  
 
 1581  
     private static RemotableAbstractControl.Builder constructControl(String type, List<KeyValue> options) {
 1582  
 
 1583  0
         RemotableAbstractControl.Builder control = null;
 1584  0
         Map<String, String> optionMap = new HashMap<String, String>();
 1585  0
         if (options != null) {
 1586  0
             for (KeyValue option : options) {
 1587  0
                 optionMap.put(option.getKey(), option.getValue());
 1588  
             }
 1589  
         }
 1590  0
         if (Field.TEXT.equals(type) || Field.DATEPICKER.equals(type)) {
 1591  0
                         control = RemotableTextInput.Builder.create();
 1592  0
         } else if (Field.TEXT_AREA.equals(type)) {
 1593  0
             control = RemotableTextarea.Builder.create();
 1594  0
                 } else if (Field.DROPDOWN.equals(type)) {
 1595  0
             control = RemotableSelect.Builder.create(optionMap);
 1596  0
         } else if (Field.CHECKBOX.equals(type)) {
 1597  0
             control = RemotableCheckboxGroup.Builder.create(optionMap);
 1598  0
                 } else if (Field.RADIO.equals(type)) {
 1599  0
             control = RemotableRadioButtonGroup.Builder.create(optionMap);
 1600  0
                 } else if (Field.HIDDEN.equals(type)) {
 1601  0
             control = RemotableHiddenInput.Builder.create();
 1602  0
                 } else if (Field.MULTIBOX.equals(type)) {
 1603  0
             RemotableSelect.Builder builder = RemotableSelect.Builder.create(optionMap);
 1604  0
             builder.setMultiple(true);
 1605  0
             control = builder;
 1606  0
         } else {
 1607  0
                     throw new IllegalArgumentException("Illegal field type found: " + type);
 1608  
         }
 1609  0
         return control;
 1610  
 
 1611  
     }
 1612  
 
 1613  
     private static void applyControlAttributes(RemotableAttributeField remotableField, Field field) {
 1614  0
         Control control = remotableField.getControl();
 1615  0
         String fieldType = null;
 1616  
 
 1617  0
         if (control == null) {
 1618  0
             throw new IllegalStateException("Given attribute field with the following name has a null control: " + remotableField.getName());
 1619  
         }
 1620  0
         if (control == null || control instanceof RemotableTextInput) {
 1621  0
             fieldType = Field.TEXT;
 1622  0
         } else if (control instanceof RemotableCheckboxGroup) {
 1623  0
             RemotableCheckboxGroup checkbox = (RemotableCheckboxGroup)control;
 1624  0
             fieldType = Field.CHECKBOX;
 1625  0
             field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(checkbox.getKeyLabels()));
 1626  0
         } else if (control instanceof RemotableHiddenInput) {
 1627  0
             fieldType = Field.HIDDEN;
 1628  0
         } else if (control instanceof RemotablePasswordInput) {
 1629  0
             throw new IllegalStateException("Password control not currently supported.");
 1630  0
         } else if (control instanceof RemotableRadioButtonGroup) {
 1631  0
             fieldType = Field.RADIO;
 1632  0
             RemotableRadioButtonGroup radioControl = (RemotableRadioButtonGroup)control;
 1633  0
             field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(radioControl.getKeyLabels()));
 1634  0
         } else if (control instanceof RemotableSelect) {
 1635  0
             RemotableSelect selectControl = (RemotableSelect)control;
 1636  
 
 1637  0
             field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(selectControl.getKeyLabels()));
 1638  0
             if (selectControl.isMultiple()) {
 1639  0
                 fieldType = Field.MULTISELECT;
 1640  
             } else {
 1641  0
                 fieldType = Field.DROPDOWN;
 1642  
             }
 1643  0
         } else if (control instanceof RemotableTextarea) {
 1644  0
             fieldType = Field.TEXT_AREA;
 1645  
         } else {
 1646  0
             throw new IllegalArgumentException("Given control type is not supported: " + control.getClass());
 1647  
         }
 1648  0
         field.setFieldType(fieldType);
 1649  0
     }
 1650  
 
 1651  
     private static List<KeyValue> convertMapToKeyValueList(Map<String, String> values) {
 1652  0
         ArrayList<KeyValue> validValues = new ArrayList<KeyValue>(values.size());
 1653  0
         for (Map.Entry<String, String> entry : values.entrySet()) {
 1654  0
             validValues.add(new ConcreteKeyValue(entry.getKey(), entry.getValue()));
 1655  
         }
 1656  0
         return validValues;
 1657  
     }
 1658  
 
 1659  
     private static void applyLookupAttributes(RemotableAttributeField remotableField, Field field) {
 1660  0
         AttributeLookupSettings lookupSettings = remotableField.getAttributeLookupSettings();
 1661  0
         if (lookupSettings != null) {
 1662  0
             field.setColumnVisible(lookupSettings.isInResults());
 1663  0
             if (!lookupSettings.isInCriteria()) {
 1664  0
                 field.setFieldType(Field.HIDDEN);
 1665  
             }
 1666  
         }
 1667  0
     }
 1668  
 
 1669  
     private static void applyWidgetAttributes(RemotableAttributeField remotableField, Field field) {
 1670  0
         Collection<? extends RemotableAbstractWidget> widgets = remotableField.getWidgets();
 1671  
 
 1672  0
         for (RemotableAbstractWidget widget : widgets) {
 1673  
             //yuck, do we really have to do this if else if stuff here?
 1674  0
             if (widget instanceof RemotableQuickFinder) {
 1675  0
                 field.setQuickFinderClassNameImpl(((RemotableQuickFinder)widget).getDataObjectClass());
 1676  0
                 field.setBaseLookupUrl(((RemotableQuickFinder)widget).getBaseLookupUrl());
 1677  0
                 field.setLookupParameters(((RemotableQuickFinder)widget).getLookupParameters());
 1678  0
                 field.setFieldConversions(((RemotableQuickFinder)widget).getFieldConversions());
 1679  0
             } else if (widget instanceof RemotableDatepicker) {
 1680  0
                 field.setDatePicker(true);
 1681  0
             } else if (widget instanceof RemotableTextExpand) {
 1682  0
                 field.setExpandedTextArea(true);
 1683  
             }
 1684  
 
 1685  
         }
 1686  0
     }
 1687  
 
 1688  
     public static Column constructColumnFromAttributeField(RemotableAttributeField attributeField) {
 1689  0
         if (attributeField == null) {
 1690  0
             throw new IllegalArgumentException("attributeField was null");
 1691  
         }
 1692  0
         DataType dataType = DataType.STRING;
 1693  0
         if (attributeField.getDataType() != null) {
 1694  0
             dataType = attributeField.getDataType();
 1695  
         }
 1696  0
         Column column = new Column();
 1697  0
         String columnTitle = "";
 1698  0
         if (StringUtils.isBlank(attributeField.getShortLabel())) {
 1699  0
             if (StringUtils.isBlank(attributeField.getLongLabel())) {
 1700  0
                 columnTitle = attributeField.getName();
 1701  
             } else {
 1702  0
                 columnTitle = attributeField.getLongLabel();
 1703  
             }
 1704  
         } else {
 1705  0
             columnTitle = attributeField.getShortLabel();
 1706  
         }
 1707  0
         column.setColumnTitle(columnTitle);
 1708  0
         column.setSortable(Boolean.TRUE.toString());
 1709  
         // TODO - KULRICE-5743 - maybe need this to be smaller than the actual attribute's max length?
 1710  0
         if (attributeField.getMaxLength() != null) {
 1711  0
             column.setMaxLength(attributeField.getMaxLength());
 1712  
         }
 1713  0
         column.setPropertyName(attributeField.getName());
 1714  0
         if (attributeField.getDataType() == DataType.MARKUP) {
 1715  0
             column.setEscapeXMLValue(false);
 1716  
         } else {
 1717  0
             column.setEscapeXMLValue(true);
 1718  
         }
 1719  0
         column.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(dataType.getClass()));
 1720  0
         column.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(dataType.getClass()));
 1721  0
         column.setFormatter(FieldUtils.getFormatterForDataType(dataType));
 1722  0
         return column;
 1723  
     }
 1724  
 
 1725  
     public static List<Column> constructColumnsFromAttributeFields(List<RemotableAttributeField> attributeFields) {
 1726  0
         List<Column> attributeColumns = new ArrayList<Column>();
 1727  0
         if (attributeFields != null) {
 1728  0
             for (RemotableAttributeField attributeField : attributeFields) {
 1729  0
                 attributeColumns.add(constructColumnFromAttributeField(attributeField));
 1730  
             }
 1731  
         }
 1732  0
         return attributeColumns;
 1733  
     }
 1734  
 
 1735  
     public static Formatter getFormatterForDataType(DataType dataType) {
 1736  0
         return Formatter.getFormatter(dataType.getType());
 1737  
     }
 1738  
 
 1739  
     private static Map<String, String> toMap(String s) {
 1740  0
         if (StringUtils.isBlank(s)) {
 1741  0
             return Collections.emptyMap();
 1742  
         }
 1743  0
         final Map<String, String> map = new HashMap<String, String>();
 1744  0
         for (String string : s.split(",")) {
 1745  0
             String [] keyVal = string.split(":");
 1746  0
             map.put(keyVal[0], keyVal[1]);
 1747  
         }
 1748  0
         return Collections.unmodifiableMap(map);
 1749  
     }
 1750  
 
 1751  
     private static DataDictionaryService getDataDictionaryService() {
 1752  0
             if (dataDictionaryService == null) {
 1753  0
                     dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
 1754  
             }
 1755  0
             return dataDictionaryService;
 1756  
     }
 1757  
 
 1758  
     private static BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
 1759  0
             if (businessObjectMetaDataService == null) {
 1760  0
                     businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService();
 1761  
             }
 1762  0
             return businessObjectMetaDataService;
 1763  
     }
 1764  
 
 1765  
     private static BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
 1766  0
             if (businessObjectDictionaryService == null) {
 1767  0
                     businessObjectDictionaryService = KRADServiceLocatorWeb.getBusinessObjectDictionaryService();
 1768  
             }
 1769  0
             return businessObjectDictionaryService;
 1770  
     }
 1771  
 
 1772  
     private static KualiModuleService getKualiModuleService() {
 1773  0
             if (kualiModuleService == null) {
 1774  0
                     kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService();
 1775  
             }
 1776  0
             return kualiModuleService;
 1777  
     }
 1778  
 }