Coverage Report - org.kuali.rice.krad.lookup.LookupableImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
LookupableImpl
0%
0/369
0%
0/174
3.25
 
 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.krad.lookup;
 17  
 
 18  
 import org.apache.commons.beanutils.PropertyUtils;
 19  
 import org.apache.commons.lang.BooleanUtils;
 20  
 import org.apache.commons.lang.StringUtils;
 21  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 22  
 import org.kuali.rice.core.api.config.property.ConfigurationService;
 23  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 24  
 import org.kuali.rice.core.api.search.SearchOperator;
 25  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 26  
 import org.kuali.rice.core.api.util.type.TypeUtils;
 27  
 import org.kuali.rice.kim.api.identity.Person;
 28  
 import org.kuali.rice.krad.bo.ExternalizableBusinessObject;
 29  
 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
 30  
 import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
 31  
 import org.kuali.rice.krad.service.DataObjectAuthorizationService;
 32  
 import org.kuali.rice.krad.service.DataObjectMetaDataService;
 33  
 import org.kuali.rice.krad.service.DocumentDictionaryService;
 34  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 35  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 36  
 import org.kuali.rice.krad.service.LookupService;
 37  
 import org.kuali.rice.krad.service.ModuleService;
 38  
 import org.kuali.rice.krad.uif.UifConstants;
 39  
 import org.kuali.rice.krad.uif.UifParameters;
 40  
 import org.kuali.rice.krad.uif.control.Control;
 41  
 import org.kuali.rice.krad.uif.control.ValueConfiguredControl;
 42  
 import org.kuali.rice.krad.uif.field.InputField;
 43  
 import org.kuali.rice.krad.uif.field.LookupInputField;
 44  
 import org.kuali.rice.krad.uif.util.ComponentUtils;
 45  
 import org.kuali.rice.krad.uif.view.LookupView;
 46  
 import org.kuali.rice.krad.uif.view.View;
 47  
 import org.kuali.rice.krad.uif.control.HiddenControl;
 48  
 import org.kuali.rice.krad.uif.field.LinkField;
 49  
 import org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl;
 50  
 import org.kuali.rice.krad.uif.util.LookupInquiryUtils;
 51  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 52  
 import org.kuali.rice.krad.util.BeanPropertyComparator;
 53  
 import org.kuali.rice.krad.util.GlobalVariables;
 54  
 import org.kuali.rice.krad.util.KRADConstants;
 55  
 import org.kuali.rice.krad.util.KRADUtils;
 56  
 import org.kuali.rice.krad.util.ObjectUtils;
 57  
 import org.kuali.rice.krad.util.UrlFactory;
 58  
 import org.kuali.rice.krad.web.form.LookupForm;
 59  
 
 60  
 import java.security.GeneralSecurityException;
 61  
 import java.util.ArrayList;
 62  
 import java.util.Collection;
 63  
 import java.util.Collections;
 64  
 import java.util.HashMap;
 65  
 import java.util.List;
 66  
 import java.util.Map;
 67  
 import java.util.Properties;
 68  
 
 69  
 /**
 70  
  * Default implementation of <code>Lookupable</code>
 71  
  *
 72  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 73  
  */
 74  0
 public class LookupableImpl extends ViewHelperServiceImpl implements Lookupable {
 75  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LookupableImpl.class);
 76  
 
 77  
     private Class<?> dataObjectClass;
 78  
 
 79  
     private Map<String, String> parameters;
 80  
     private List<String> defaultSortAttributeNames;
 81  
 
 82  
     // TODO delyea: where to take into account the sort ascending value (old KNS appeared to ignore?)
 83  
     private boolean sortAscending;
 84  
 
 85  
     private Map<String, String> fieldConversions;
 86  
     private List<String> readOnlyFieldsList;
 87  
 
 88  
     private transient ConfigurationService configurationService;
 89  
     private transient DataObjectAuthorizationService dataObjectAuthorizationService;
 90  
     private transient DataObjectMetaDataService dataObjectMetaDataService;
 91  
     private transient DocumentDictionaryService documentDictionaryService;
 92  
     private transient LookupService lookupService;
 93  
     private transient EncryptionService encryptionService;
 94  
 
 95  
     /**
 96  
      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#populateViewFromRequestParameters(org.kuali.rice.krad.uif.view.View,
 97  
      *      java.util.Map)
 98  
      */
 99  
     @Override
 100  
     public void populateViewFromRequestParameters(View view, Map<String, String> parameters) {
 101  0
         super.populateViewFromRequestParameters(view, parameters);
 102  
         /* On the old Lookupable and LookupableHelperService in KNS the parameters list used to have multipart form
 103  
            * data in it where it may not in the new KRAD. See PojoFormBase.populate() method for more information
 104  
            */
 105  0
         setParameters(parameters);
 106  0
     }
 107  
 
 108  
     /**
 109  
      * Initialization of Lookupable requires that the business object class be set for the {@link
 110  
      * #initializeAttributeFieldFromDataDictionary(View, org.kuali.rice.krad.uif.field.InputField)} method
 111  
      *
 112  
      * @see org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
 113  
      */
 114  
     @Override
 115  
     public void performInitialization(View view, Object model) {
 116  0
         if (!LookupView.class.isAssignableFrom(view.getClass())) {
 117  0
             throw new IllegalArgumentException(
 118  
                     "View class '" + view.getClass() + " is not assignable from the '" + LookupView.class + "'");
 119  
         }
 120  
 
 121  0
         LookupView lookupView = (LookupView) view;
 122  0
         initializeLookupViewHelperService(lookupView);
 123  
 
 124  0
         super.performInitialization(view, model);
 125  0
     }
 126  
 
 127  
     /**
 128  
      * Initializes properties on this lookupable from the <code>LookupView</code>
 129  
      *
 130  
      * @param lookupView - lookup view instance
 131  
      */
 132  
     protected void initializeLookupViewHelperService(LookupView lookupView) {
 133  0
         setDefaultSortAttributeNames(lookupView.getDefaultSortAttributeNames());
 134  0
         setSortAscending(lookupView.isDefaultSortAscending());
 135  0
         setDataObjectClass(lookupView.getDataObjectClassName());
 136  0
     }
 137  
 
 138  
     /**
 139  
      * @see org.kuali.rice.krad.lookup.Lookupable#performSearch
 140  
      */
 141  
     @Override
 142  
     public Collection<?> performSearch(LookupForm form, Map<String, String> searchCriteria, boolean bounded) {
 143  
         Collection<?> displayList;
 144  
 
 145  0
         LookupUtils.preprocessDateFields(searchCriteria);
 146  
 
 147  
         // TODO: force uppercase will be done in binding at some point
 148  0
         displayList = getSearchResults(form, LookupUtils.forceUppercase(getDataObjectClass(), searchCriteria),
 149  
                 !bounded);
 150  
 
 151  
         // TODO delyea - is this the best way to set that the entire set has a returnable row?
 152  0
         List<String> pkNames = getDataObjectMetaDataService().listPrimaryKeyFieldNames(getDataObjectClass());
 153  0
         Person user = GlobalVariables.getUserSession().getPerson();
 154  
 
 155  0
         for (Object object : displayList) {
 156  0
             if (isResultReturnable(object)) {
 157  0
                 form.setAtLeastOneRowReturnable(true);
 158  
             }
 159  
         }
 160  
 
 161  0
         return displayList;
 162  
     }
 163  
 
 164  
     protected List<?> getSearchResults(LookupForm form, Map<String, String> searchCriteria, boolean unbounded) {
 165  
         List<?> searchResults;
 166  
 
 167  
         // removed blank search values and decrypt any encrypted search values
 168  0
         Map<String, String> nonBlankSearchCriteria = processSearchCriteria(form, searchCriteria);
 169  
 
 170  0
         boolean searchUsingOnlyPrimaryKeyValues =
 171  
                 getLookupService().allPrimaryKeyValuesPresentAndNotWildcard(getDataObjectClass(), searchCriteria);
 172  
 
 173  
         // if this class is an EBO, just call the module service to get the results
 174  0
         if (ExternalizableBusinessObject.class.isAssignableFrom(getDataObjectClass())) {
 175  0
             return getSearchResultsForEBO(nonBlankSearchCriteria, unbounded);
 176  
         }
 177  
 
 178  
         // if any of the properties refer to an embedded EBO, call the EBO
 179  
         // lookups first and apply to the local lookup
 180  
         try {
 181  0
             if (LookupUtils.hasExternalBusinessObjectProperty(getDataObjectClass(), nonBlankSearchCriteria)) {
 182  0
                 Map<String, String> eboSearchCriteria = adjustCriteriaForNestedEBOs(nonBlankSearchCriteria, unbounded);
 183  
 
 184  0
                 if (LOG.isDebugEnabled()) {
 185  0
                     LOG.debug("Passing these results into the lookup service: " + eboSearchCriteria);
 186  
                 }
 187  
 
 188  
                 // add those results as criteria run the normal search (but with the EBO criteria added)
 189  0
                 searchResults = (List<?>) getLookupService()
 190  
                         .findCollectionBySearchHelper(getDataObjectClass(), eboSearchCriteria, unbounded);
 191  0
             } else {
 192  0
                 searchResults = (List<?>) getLookupService()
 193  
                         .findCollectionBySearchHelper(getDataObjectClass(), nonBlankSearchCriteria, unbounded);
 194  
             }
 195  0
         } catch (IllegalAccessException e) {
 196  0
             LOG.error("Error trying to perform search", e);
 197  0
             throw new RuntimeException("Error trying to perform search", e);
 198  0
         } catch (InstantiationException e1) {
 199  0
             LOG.error("Error trying to perform search", e1);
 200  0
             throw new RuntimeException("Error trying to perform search", e1);
 201  0
         }
 202  
 
 203  0
         if (searchResults == null) {
 204  0
             searchResults = new ArrayList<Object>();
 205  
         }
 206  
 
 207  
         // sort list if default sort column given
 208  0
         List<String> defaultSortColumns = getDefaultSortAttributeNames();
 209  0
         if ((defaultSortColumns != null) && (defaultSortColumns.size() > 0)) {
 210  0
             Collections.sort(searchResults, new BeanPropertyComparator(defaultSortColumns, true));
 211  
         }
 212  
 
 213  0
         return searchResults;
 214  
     }
 215  
 
 216  
     protected Map<String, String> processSearchCriteria(LookupForm lookupForm, Map<String, String> searchCriteria) {
 217  0
         Map<String, InputField> criteriaFields = getCriteriaFieldsForValidation((LookupView) lookupForm.getView(),
 218  
                 lookupForm);
 219  
 
 220  0
         Map<String, String> nonBlankSearchCriteria = new HashMap<String, String>();
 221  0
         for (String fieldName : searchCriteria.keySet()) {
 222  0
             String fieldValue = searchCriteria.get(fieldName);
 223  
 
 224  
             // don't add hidden criteria
 225  0
             LookupView lookupView = (LookupView) lookupForm.getView();
 226  0
             InputField inputField = criteriaFields.get(fieldName);
 227  0
             if (inputField.getControl() instanceof HiddenControl) {
 228  0
                 continue;
 229  
             }
 230  
 
 231  
             // only add criteria if non blank
 232  0
             if (StringUtils.isNotBlank(fieldValue)) {
 233  0
                 if (fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 234  0
                     String encryptedValue = StringUtils.removeEnd(fieldValue, EncryptionService.ENCRYPTION_POST_PREFIX);
 235  
                     try {
 236  0
                         fieldValue = getEncryptionService().decrypt(encryptedValue);
 237  0
                     } catch (GeneralSecurityException e) {
 238  0
                         LOG.error("Error decrypting value for business object class " + getDataObjectClass() +
 239  
                                 " attribute " + fieldName, e);
 240  0
                         throw new RuntimeException(
 241  
                                 "Error decrypting value for business object class " + getDataObjectClass() +
 242  
                                         " attribute " + fieldName, e);
 243  0
                     }
 244  
                 }
 245  
 
 246  0
                 nonBlankSearchCriteria.put(fieldName, fieldValue);
 247  
             }
 248  0
         }
 249  
 
 250  0
         return nonBlankSearchCriteria;
 251  
     }
 252  
 
 253  
     protected List<?> getSearchResultsForEBO(Map<String, String> searchCriteria, boolean unbounded) {
 254  0
         ModuleService eboModuleService =
 255  
                 KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(getDataObjectClass());
 256  0
         BusinessObjectEntry ddEntry =
 257  
                 eboModuleService.getExternalizableBusinessObjectDictionaryEntry(getDataObjectClass());
 258  
 
 259  0
         Map<String, String> filteredFieldValues = new HashMap<String, String>();
 260  0
         for (String fieldName : searchCriteria.keySet()) {
 261  0
             if (ddEntry.getAttributeNames().contains(fieldName)) {
 262  0
                 filteredFieldValues.put(fieldName, searchCriteria.get(fieldName));
 263  
             }
 264  
         }
 265  
 
 266  0
         List<?> searchResults = eboModuleService.getExternalizableBusinessObjectsListForLookup(
 267  
                 (Class<? extends ExternalizableBusinessObject>) getDataObjectClass(), (Map) filteredFieldValues,
 268  
                 unbounded);
 269  
 
 270  0
         return searchResults;
 271  
     }
 272  
 
 273  
     protected Map<String, String> adjustCriteriaForNestedEBOs(Map<String, String> searchCriteria,
 274  
             boolean unbounded) throws InstantiationException, IllegalAccessException {
 275  0
         if (LOG.isDebugEnabled()) {
 276  0
             LOG.debug("has EBO reference: " + getDataObjectClass());
 277  0
             LOG.debug("properties: " + searchCriteria);
 278  
         }
 279  
 
 280  
         // remove the EBO criteria
 281  0
         Map<String, String> nonEboFieldValues =
 282  
                 LookupUtils.removeExternalizableBusinessObjectFieldValues(getDataObjectClass(), searchCriteria);
 283  0
         if (LOG.isDebugEnabled()) {
 284  0
             LOG.debug("Non EBO properties removed: " + nonEboFieldValues);
 285  
         }
 286  
 
 287  
         // get the list of EBO properties attached to this object
 288  0
         List<String> eboPropertyNames =
 289  
                 LookupUtils.getExternalizableBusinessObjectProperties(getDataObjectClass(), searchCriteria);
 290  0
         if (LOG.isDebugEnabled()) {
 291  0
             LOG.debug("EBO properties: " + eboPropertyNames);
 292  
         }
 293  
 
 294  
         // loop over those properties
 295  0
         for (String eboPropertyName : eboPropertyNames) {
 296  
             // extract the properties as known to the EBO
 297  0
             Map<String, String> eboFieldValues =
 298  
                     LookupUtils.getExternalizableBusinessObjectFieldValues(eboPropertyName, searchCriteria);
 299  0
             if (LOG.isDebugEnabled()) {
 300  0
                 LOG.debug("EBO properties for master EBO property: " + eboPropertyName);
 301  0
                 LOG.debug("properties: " + eboFieldValues);
 302  
             }
 303  
 
 304  
             // run search against attached EBO's module service
 305  0
             ModuleService eboModuleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(
 306  
                     LookupUtils.getExternalizableBusinessObjectClass(getDataObjectClass(), eboPropertyName));
 307  
 
 308  
             // KULRICE-4401 made eboResults an empty list and only filled if
 309  
             // service is found.
 310  0
             List<?> eboResults = Collections.emptyList();
 311  0
             if (eboModuleService != null) {
 312  0
                 eboResults = eboModuleService.getExternalizableBusinessObjectsListForLookup(
 313  
                         LookupUtils.getExternalizableBusinessObjectClass(getDataObjectClass(), eboPropertyName),
 314  
                         (Map) eboFieldValues, unbounded);
 315  
             } else {
 316  0
                 LOG.debug("EBO ModuleService is null: " + eboPropertyName);
 317  
             }
 318  
             // get the mapping/relationship between the EBO object and it's
 319  
             // parent object
 320  
             // use that to adjust the searchCriteria
 321  
 
 322  
             // get the parent property type
 323  
             Class<?> eboParentClass;
 324  
             String eboParentPropertyName;
 325  0
             if (ObjectUtils.isNestedAttribute(eboPropertyName)) {
 326  0
                 eboParentPropertyName = StringUtils.substringBeforeLast(eboPropertyName, ".");
 327  
                 try {
 328  0
                     eboParentClass =
 329  
                             PropertyUtils.getPropertyType(getDataObjectClass().newInstance(), eboParentPropertyName);
 330  0
                 } catch (Exception ex) {
 331  0
                     throw new RuntimeException("Unable to create an instance of the business object class: " +
 332  
                             getDataObjectClass().getName(), ex);
 333  0
                 }
 334  
             } else {
 335  0
                 eboParentClass = getDataObjectClass();
 336  0
                 eboParentPropertyName = null;
 337  
             }
 338  
 
 339  0
             if (LOG.isDebugEnabled()) {
 340  0
                 LOG.debug("determined EBO parent class/property name: " + eboParentClass + "/" + eboParentPropertyName);
 341  
             }
 342  
 
 343  
             // look that up in the DD (BOMDS)
 344  
             // find the appropriate relationship
 345  
             // CHECK THIS: what if eboPropertyName is a nested attribute -
 346  
             // need to strip off the eboParentPropertyName if not null
 347  0
             RelationshipDefinition rd =
 348  
                     getDataObjectMetaDataService().getDictionaryRelationship(eboParentClass, eboPropertyName);
 349  0
             if (LOG.isDebugEnabled()) {
 350  0
                 LOG.debug("Obtained RelationshipDefinition for " + eboPropertyName);
 351  0
                 LOG.debug(rd);
 352  
             }
 353  
 
 354  
             // copy the needed properties (primary only) to the field values KULRICE-4446 do
 355  
             // so only if the relationship definition exists
 356  
             // NOTE: this will work only for single-field PK unless the ORM
 357  
             // layer is directly involved
 358  
             // (can't make (field1,field2) in ( (v1,v2),(v3,v4) ) style
 359  
             // queries in the lookup framework
 360  0
             if (ObjectUtils.isNotNull(rd)) {
 361  0
                 if (rd.getPrimitiveAttributes().size() > 1) {
 362  0
                     throw new RuntimeException(
 363  
                             "EBO Links don't work for relationships with multiple-field primary keys.");
 364  
                 }
 365  0
                 String boProperty = rd.getPrimitiveAttributes().get(0).getSourceName();
 366  0
                 String eboProperty = rd.getPrimitiveAttributes().get(0).getTargetName();
 367  0
                 StringBuffer boPropertyValue = new StringBuffer();
 368  
 
 369  
                 // loop over the results, making a string that the lookup
 370  
                 // DAO will convert into an
 371  
                 // SQL "IN" clause
 372  0
                 for (Object ebo : eboResults) {
 373  0
                     if (boPropertyValue.length() != 0) {
 374  0
                         boPropertyValue.append(SearchOperator.OR.op());
 375  
                     }
 376  
                     try {
 377  0
                         boPropertyValue.append(PropertyUtils.getProperty(ebo, eboProperty).toString());
 378  0
                     } catch (Exception ex) {
 379  0
                         LOG.warn("Unable to get value for " + eboProperty + " on " + ebo);
 380  0
                     }
 381  
                 }
 382  
 
 383  0
                 if (eboParentPropertyName == null) {
 384  
                     // non-nested property containing the EBO
 385  0
                     nonEboFieldValues.put(boProperty, boPropertyValue.toString());
 386  
                 } else {
 387  
                     // property nested within the main searched-for BO that
 388  
                     // contains the EBO
 389  0
                     nonEboFieldValues.put(eboParentPropertyName + "." + boProperty, boPropertyValue.toString());
 390  
                 }
 391  
             }
 392  0
         }
 393  
 
 394  0
         return nonEboFieldValues;
 395  
     }
 396  
 
 397  
     /**
 398  
      * @see org.kuali.rice.krad.lookup.Lookupable#performClear
 399  
      */
 400  
     @Override
 401  
     public Map<String, String> performClear(LookupForm form, Map<String, String> searchCriteria) {
 402  0
         Map<String, InputField> criteriaFieldMap = getCriteriaFieldsForValidation((LookupView) form.getView(), form);
 403  0
         Map<String, String> clearedSearchCriteria = new HashMap<String, String>();
 404  0
         for (Map.Entry<String, String> searchKeyValue : searchCriteria.entrySet()) {
 405  0
             String searchPropertyName = searchKeyValue.getKey();
 406  
 
 407  0
             InputField inputField = criteriaFieldMap.get(searchPropertyName);
 408  0
             if (inputField != null) {
 409  
                 // TODO: check secure fields
 410  
 //                                if (field.isSecure()) {
 411  
 //                    field.setSecure(false);
 412  
 //                    field.setDisplayMaskValue(null);
 413  
 //                    field.setEncryptedValue(null);
 414  
 //                }
 415  
 
 416  
                 // TODO: need formatting on default value and make sure it works when control converts
 417  
                 // from checkbox to radio
 418  0
                 clearedSearchCriteria.put(searchPropertyName, inputField.getDefaultValue());
 419  
             } else {
 420  0
                 throw new RuntimeException("Invalid search field sent for property name: " + searchPropertyName);
 421  
             }
 422  0
         }
 423  
 
 424  0
         return clearedSearchCriteria;
 425  
     }
 426  
 
 427  
     /**
 428  
      * @see org.kuali.rice.krad.lookup.Lookupable#validateSearchParameters
 429  
      */
 430  
     @Override
 431  
     public boolean validateSearchParameters(LookupForm form, Map<String, String> searchCriteria) {
 432  0
         boolean valid = true;
 433  
 
 434  0
         if (!getViewDictionaryService().isLookupable(getDataObjectClass())) {
 435  0
             throw new RuntimeException("Lookup not defined for data object " + getDataObjectClass());
 436  
         }
 437  
 
 438  0
         Map<String, InputField> criteriaFields = getCriteriaFieldsForValidation((LookupView) form.getView(), form);
 439  
 
 440  
         // validate required
 441  
         // TODO: this will be done by the uif validation service at some point
 442  0
         for (Map.Entry<String, String> searchKeyValue : searchCriteria.entrySet()) {
 443  0
             String searchPropertyName = searchKeyValue.getKey();
 444  0
             String searchPropertyValue = searchKeyValue.getValue();
 445  
 
 446  0
             LookupView lookupView = (LookupView) form.getView();
 447  0
             InputField inputField = criteriaFields.get(searchPropertyName);
 448  0
             if (inputField != null) {
 449  0
                 if (StringUtils.isBlank(searchPropertyValue) && BooleanUtils.isTrue(inputField.getRequired())) {
 450  0
                     GlobalVariables.getMessageMap()
 451  
                             .putError(inputField.getPropertyName(), RiceKeyConstants.ERROR_REQUIRED,
 452  
                                     inputField.getLabel());
 453  
                 }
 454  
 
 455  0
                 validateSearchParameterWildcardAndOperators(inputField, searchPropertyValue);
 456  
             } else {
 457  0
                 throw new RuntimeException("Invalid search field sent for property name: " + searchPropertyName);
 458  
             }
 459  0
         }
 460  
 
 461  0
         if (GlobalVariables.getMessageMap().hasErrors()) {
 462  0
             valid = false;
 463  
         }
 464  
 
 465  0
         return valid;
 466  
     }
 467  
 
 468  
     protected Map<String, InputField> getCriteriaFieldsForValidation(LookupView lookupView, LookupForm form) {
 469  0
         Map<String, InputField> criteriaFieldMap = new HashMap<String, InputField>();
 470  
 
 471  
         // TODO; need hooks for code generated components and also this doesn't have lifecycle which
 472  
         // could change fields
 473  0
         List<InputField> fields = ComponentUtils.getComponentsOfTypeDeep(lookupView.getCriteriaFields(),
 474  
                 InputField.class);
 475  0
         for (InputField field : fields) {
 476  0
             criteriaFieldMap.put(field.getPropertyName(), field);
 477  
         }
 478  
 
 479  0
         return criteriaFieldMap;
 480  
     }
 481  
 
 482  
     /**
 483  
      * Validates that any wildcards contained within the search value are valid wilcards and allowed for the
 484  
      * property type for which the field is searching
 485  
      *
 486  
      * @param inputField - attribute field instance for the field that is being searched
 487  
      * @param searchPropertyValue - value given for field to search for
 488  
      */
 489  
     protected void validateSearchParameterWildcardAndOperators(InputField inputField,
 490  
             String searchPropertyValue) {
 491  0
         if (StringUtils.isBlank(searchPropertyValue))
 492  0
             return;
 493  
 
 494  
         // make sure a wildcard/operator is in the value
 495  0
         boolean found = false;
 496  0
         for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
 497  0
             String queryCharacter = op.op();
 498  
 
 499  0
             if (searchPropertyValue.contains(queryCharacter)) {
 500  0
                 found = true;
 501  
             }
 502  0
         }
 503  
 
 504  0
         if (!found) {
 505  0
             return;
 506  
         }
 507  
 
 508  0
         String attributeLabel = inputField.getLabel();
 509  0
         if ((LookupInputField.class.isAssignableFrom(inputField.getClass())) &&
 510  
                 (((LookupInputField) inputField).isTreatWildcardsAndOperatorsAsLiteral())) {
 511  0
             Object dataObjectExample = null;
 512  
             try {
 513  0
                 dataObjectExample = getDataObjectClass().newInstance();
 514  0
             } catch (Exception e) {
 515  0
                 LOG.error("Exception caught instantiating " + getDataObjectClass().getName(), e);
 516  0
                 throw new RuntimeException("Cannot instantiate " + getDataObjectClass().getName(), e);
 517  0
             }
 518  
 
 519  0
             Class<?> propertyType =
 520  
                     ObjectPropertyUtils.getPropertyType(getDataObjectClass(), inputField.getPropertyName());
 521  0
             if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType) ||
 522  
                     TypeUtils.isTemporalClass(propertyType)) {
 523  0
                 GlobalVariables.getMessageMap().putError(inputField.getPropertyName(),
 524  
                         RiceKeyConstants.ERROR_WILDCARDS_AND_OPERATORS_NOT_ALLOWED_ON_FIELD, attributeLabel);
 525  
             }
 526  
 
 527  0
             if (TypeUtils.isStringClass(propertyType)) {
 528  0
                 GlobalVariables.getMessageMap().putInfo(inputField.getPropertyName(),
 529  
                         RiceKeyConstants.INFO_WILDCARDS_AND_OPERATORS_TREATED_LITERALLY, attributeLabel);
 530  
             }
 531  0
         } else {
 532  0
             if (getDataObjectAuthorizationService()
 533  
                     .attributeValueNeedsToBeEncryptedOnFormsAndLinks(getDataObjectClass(),
 534  
                             inputField.getPropertyName())) {
 535  0
                 if (!searchPropertyValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 536  
                     // encrypted values usually come from the DB, so we don't
 537  
                     // need to filter for wildcards
 538  
                     // wildcards are not allowed on restricted fields, because
 539  
                     // they are typically encrypted, and wildcard searches cannot be performed without
 540  
                     // decrypting every row, which is currently not supported by KRAD
 541  
 
 542  0
                     GlobalVariables.getMessageMap()
 543  
                             .putError(inputField.getPropertyName(), RiceKeyConstants.ERROR_SECURE_FIELD,
 544  
                                     attributeLabel);
 545  
                 }
 546  
             }
 547  
         }
 548  0
     }
 549  
 
 550  
     /**
 551  
      * @see org.kuali.rice.krad.lookup.Lookupable#getReturnUrlForResults
 552  
      */
 553  
     public void getReturnUrlForResults(LinkField returnLinkField, Object model) {
 554  0
         LookupForm lookupForm = (LookupForm) model;
 555  0
         LookupView lookupView = (LookupView) returnLinkField.getContext().get(UifConstants.ContextVariableNames.VIEW);
 556  
 
 557  0
         Object dataObject = returnLinkField.getContext().get(UifConstants.ContextVariableNames.LINE);
 558  
 
 559  
         // don't render return link if the object is null or if the row is not returnable
 560  0
         if ((dataObject == null) || (!isResultReturnable(dataObject))) {
 561  0
             returnLinkField.setRender(false);
 562  0
             return;
 563  
         }
 564  
 
 565  
         // build return link href
 566  0
         String href = getReturnUrl(lookupView, lookupForm, dataObject);
 567  0
         if (StringUtils.isBlank(href)) {
 568  0
             returnLinkField.setRender(false);
 569  0
             return;
 570  
         }
 571  
         // TODO: need to handle returning anchor
 572  0
         returnLinkField.setHrefText(href);
 573  
 
 574  
         // build return link label and title
 575  0
         String linkLabel = getConfigurationService().getPropertyValueAsString(
 576  
                         KRADConstants.Lookup.TITLE_RETURN_URL_PREPENDTEXT_PROPERTY);
 577  0
         returnLinkField.setLinkLabel(linkLabel);
 578  
 
 579  0
         List<String> returnKeys = getReturnKeys(lookupView, lookupForm, dataObject);
 580  0
         Map<String, String> returnKeyValues = KRADUtils.getPropertyKeyValuesFromDataObject(returnKeys, dataObject);
 581  
 
 582  0
         String title = LookupInquiryUtils.getLinkTitleText(linkLabel, getDataObjectClass(), returnKeyValues);
 583  0
         returnLinkField.setTitle(title);
 584  
 
 585  
         // Add the return target if it is set
 586  0
         String returnTarget = lookupView.getReturnTarget();
 587  0
         if (returnTarget != null) {
 588  0
             returnLinkField.setTarget(returnTarget);
 589  
 
 590  
             //  Add the close script if lookup is in a light box
 591  0
             if (!returnTarget.equals("_self")) {
 592  
 
 593  
                 // Add the return script if the returnByScript flag is set
 594  0
                 if (lookupView.isReturnByScript()) {
 595  0
                     Properties props = getReturnUrlParameters(lookupView, lookupForm, dataObject);
 596  
 
 597  
 //                    StringBuilder script = new StringBuilder("e.preventDefault();");
 598  0
                     StringBuilder script = new StringBuilder("e.preventDefault();");
 599  0
                     for (String returnField : lookupForm.getFieldConversions().values()) {
 600  0
                         if (props.containsKey(returnField)) {
 601  0
                             Object fieldName = returnField.replace("'", "\\'");
 602  0
                             Object value = props.get(returnField);
 603  0
                             script = script.append("returnLookupResultByScript('" + returnField + "', '" + value + "');");
 604  0
                         }
 605  
                     }
 606  0
                     returnLinkField.setOnClickScript(script.append("closeLightbox();").toString());
 607  0
                 }  else{
 608  
                     // Close the light box if return target is not _self or _parent
 609  0
                     returnLinkField.setOnClickScript("e.preventDefault();closeLightbox();createLoading(true);window.open(jq(this).attr('href'), jq(this).attr('target'));");
 610  
                 }
 611  
             }
 612  
         } else {
 613  
             // If no return target is set return in same frame
 614  
             // This is to insure that non light box lookups return correctly
 615  0
             returnLinkField.setTarget("_self");
 616  
         }
 617  0
     }
 618  
 
 619  
     /**
 620  
      * Builds the URL for returning the given data object result row
 621  
      *
 622  
      * <p>
 623  
      * Note return URL will only be built if a return location is specified on the <code>LookupForm</code>
 624  
      * </p>
 625  
      *
 626  
      * @param lookupView - lookup view instance containing lookup configuration
 627  
      * @param lookupForm - lookup form instance containing the data
 628  
      * @param dataObject - data object instance for the current line and for which the return URL is being built
 629  
      * @return String return URL or blank if URL cannot be built
 630  
      */
 631  
     protected String getReturnUrl(LookupView lookupView, LookupForm lookupForm, Object dataObject) {
 632  0
         Properties props = getReturnUrlParameters(lookupView, lookupForm, dataObject);
 633  
 
 634  0
         String href = "";
 635  0
         if (StringUtils.isNotBlank(lookupForm.getReturnLocation())) {
 636  0
             href = UrlFactory.parameterizeUrl(lookupForm.getReturnLocation(), props);
 637  
         }
 638  
 
 639  0
         return href;
 640  
     }
 641  
 
 642  
     /**
 643  
      * Builds up a <code>Properties</code> object that will be used to provide the request parameters for the
 644  
      * return URL link
 645  
      *
 646  
      * @param lookupView - lookup view instance containing lookup configuration
 647  
      * @param lookupForm - lookup form instance containing the data
 648  
      * @param dataObject - data object instance for the current line and for which the return URL is being built
 649  
      * @return Properties instance containing request parameters for return URL
 650  
      */
 651  
     protected Properties getReturnUrlParameters(LookupView lookupView, LookupForm lookupForm, Object dataObject) {
 652  0
         Properties props = new Properties();
 653  0
         props.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.RETURN_METHOD_TO_CALL);
 654  
 
 655  0
         if (StringUtils.isNotBlank(lookupForm.getReturnFormKey())) {
 656  0
             props.put(UifParameters.FORM_KEY, lookupForm.getReturnFormKey());
 657  
         }
 658  
 
 659  0
         props.put(KRADConstants.REFRESH_CALLER, lookupView.getId());
 660  0
         props.put(KRADConstants.REFRESH_DATA_OBJECT_CLASS, getDataObjectClass().getName());
 661  
 
 662  0
         if (StringUtils.isNotBlank(lookupForm.getDocNum())) {
 663  0
             props.put(UifParameters.DOC_NUM, lookupForm.getDocNum());
 664  
         }
 665  
 
 666  0
         if (StringUtils.isNotBlank(lookupForm.getReferencesToRefresh())) {
 667  0
             props.put(KRADConstants.REFERENCES_TO_REFRESH, lookupForm.getReferencesToRefresh());
 668  
         }
 669  
 
 670  0
         List<String> returnKeys = getReturnKeys(lookupView, lookupForm, dataObject);
 671  0
         Map<String, String> returnKeyValues = KRADUtils.getPropertyKeyValuesFromDataObject(returnKeys, dataObject);
 672  
 
 673  0
         for (String returnKey : returnKeyValues.keySet()) {
 674  0
             String returnValue = returnKeyValues.get(returnKey);
 675  0
             if (lookupForm.getFieldConversions().containsKey(returnKey)) {
 676  0
                 returnKey = lookupForm.getFieldConversions().get(returnKey);
 677  
             }
 678  
 
 679  0
             props.put(returnKey, returnValue);
 680  0
         }
 681  
 
 682  0
         return props;
 683  
     }
 684  
 
 685  
     /**
 686  
      * Returns the configured return key property names or if not configured defaults to the primary keys
 687  
      * for the data object class
 688  
      *
 689  
      * @return List<String> property names which should be passed back on the return URL
 690  
      */
 691  
     protected List<String> getReturnKeys(LookupView lookupView, LookupForm lookupForm, Object dataObject) {
 692  
         List<String> returnKeys;
 693  0
         if (lookupForm.getFieldConversions() != null && !lookupForm.getFieldConversions().isEmpty()) {
 694  0
             returnKeys = new ArrayList<String>(lookupForm.getFieldConversions().keySet());
 695  
         } else {
 696  0
             returnKeys = getDataObjectMetaDataService().listPrimaryKeyFieldNames(getDataObjectClass());
 697  
         }
 698  
 
 699  0
         return returnKeys;
 700  
     }
 701  
 
 702  
     /**
 703  
      * @see org.kuali.rice.krad.lookup.Lookupable#getMaintenanceActionLink
 704  
      */
 705  
     public void getMaintenanceActionLink(LinkField actionLinkField, Object model, String maintenanceMethodToCall) {
 706  0
         LookupForm lookupForm = (LookupForm) model;
 707  0
         LookupView lookupView = (LookupView) actionLinkField.getContext().get(UifConstants.ContextVariableNames.VIEW);
 708  0
         Object dataObject = actionLinkField.getContext().get(UifConstants.ContextVariableNames.LINE);
 709  
 
 710  0
         List<String> pkNames = getDataObjectMetaDataService().listPrimaryKeyFieldNames(getDataObjectClass());
 711  
 
 712  
         // build maintenance link href
 713  0
         String href = getActionUrlHref(lookupForm, dataObject, maintenanceMethodToCall, pkNames);
 714  0
         if (StringUtils.isBlank(href)) {
 715  0
             actionLinkField.setRender(false);
 716  0
             return;
 717  
         }
 718  
         // TODO: need to handle returning anchor
 719  0
         actionLinkField.setHrefText(href);
 720  
 
 721  
         // build action title
 722  0
         String prependTitleText = actionLinkField.getLinkLabel() + " " +
 723  
                 getDataDictionaryService().getDataDictionary().getDataObjectEntry(getDataObjectClass().getName())
 724  
                         .getObjectLabel() + " " +
 725  
                 getConfigurationService().getPropertyValueAsString(
 726  
                         KRADConstants.Lookup.TITLE_ACTION_URL_PREPENDTEXT_PROPERTY);
 727  
 
 728  0
         Map<String, String> primaryKeyValues = KRADUtils.getPropertyKeyValuesFromDataObject(pkNames, dataObject);
 729  0
         String title = LookupInquiryUtils.getLinkTitleText(prependTitleText, getDataObjectClass(), primaryKeyValues);
 730  0
         actionLinkField.setTitle(title);
 731  
         // TODO : do not hardcode the _self string
 732  0
         actionLinkField.setTarget("_self");
 733  0
         lookupForm.setAtLeastOneRowHasActions(true);
 734  0
     }
 735  
 
 736  
     /**
 737  
      * Generates a URL to perform a maintenance action on the given result data object
 738  
      *
 739  
      * <p>
 740  
      * Will build a URL containing keys of the data object to invoke the given maintenance action method
 741  
      * within the maintenance controller
 742  
      * </p>
 743  
      *
 744  
      * @param dataObject - data object instance for the line to build the maintenance action link for
 745  
      * @param methodToCall - method name on the maintenance controller that should be invoked
 746  
      * @param pkNames - list of primary key field names for the data object whose key/value pairs will be added to
 747  
      * the maintenance link
 748  
      * @return String URL link for the maintenance action
 749  
      */
 750  
     protected String getActionUrlHref(LookupForm lookupForm, Object dataObject, String methodToCall,
 751  
             List<String> pkNames) {
 752  0
         LookupView lookupView = (LookupView) lookupForm.getView();
 753  
 
 754  0
         Properties props = new Properties();
 755  0
         props.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, methodToCall);
 756  
 
 757  0
         Map<String, String> primaryKeyValues = KRADUtils.getPropertyKeyValuesFromDataObject(pkNames, dataObject);
 758  0
         for (String primaryKey : primaryKeyValues.keySet()) {
 759  0
             String primaryKeyValue = primaryKeyValues.get(primaryKey);
 760  
 
 761  0
             props.put(primaryKey, primaryKeyValue);
 762  0
         }
 763  
 
 764  0
         if (StringUtils.isNotBlank(lookupForm.getReturnLocation())) {
 765  0
             props.put(KRADConstants.RETURN_LOCATION_PARAMETER, lookupForm.getReturnLocation());
 766  
         }
 767  
 
 768  0
         props.put(UifParameters.DATA_OBJECT_CLASS_NAME, lookupForm.getDataObjectClassName());
 769  0
         props.put(UifParameters.VIEW_TYPE_NAME, UifConstants.ViewType.MAINTENANCE.name());
 770  
 
 771  0
         String maintenanceMapping = KRADConstants.Maintenance.REQUEST_MAPPING_MAINTENANCE;
 772  0
         if (StringUtils.isNotBlank(lookupView.getMaintenanceUrlMapping())) {
 773  0
             maintenanceMapping = lookupView.getMaintenanceUrlMapping();
 774  
         }
 775  
 
 776  0
         return UrlFactory.parameterizeUrl(maintenanceMapping, props);
 777  
     }
 778  
 
 779  
     /**
 780  
      * Sets the value for the attribute field control to contain the field conversion values for the line
 781  
      *
 782  
      * @see org.kuali.rice.krad.lookup.LookupableImpl#setMultiValueLookupSelect
 783  
      */
 784  
     @Override
 785  
     public void setMultiValueLookupSelect(InputField selectField, Object model) {
 786  0
         LookupForm lookupForm = (LookupForm) model;
 787  0
         Object lineDataObject = selectField.getContext().get(UifConstants.ContextVariableNames.LINE);
 788  0
         if (lineDataObject == null) {
 789  0
             throw new RuntimeException("Unable to get data object for line from component: " + selectField.getId());
 790  
         }
 791  
 
 792  0
         Control selectControl = ((InputField) selectField).getControl();
 793  0
         if ((selectControl != null) && (selectControl instanceof ValueConfiguredControl)) {
 794  0
             String lineIdentifier = "";
 795  
 
 796  
             // get value for each field conversion from line and add to lineIdentifier
 797  0
             Map<String, String> fieldConversions = lookupForm.getFieldConversions();
 798  0
             List<String> fromFieldNames = new ArrayList<String>(fieldConversions.keySet());
 799  0
             Collections.sort(fromFieldNames);
 800  0
             for (String fromFieldName : fromFieldNames) {
 801  0
                 Object fromFieldValue = ObjectPropertyUtils.getPropertyValue(lineDataObject, fromFieldName);
 802  0
                 if (fromFieldValue != null) {
 803  0
                     lineIdentifier += fromFieldValue;
 804  
                 }
 805  0
                 lineIdentifier += ":";
 806  0
             }
 807  0
             lineIdentifier = StringUtils.removeEnd(lineIdentifier, ":");
 808  
 
 809  0
             ((ValueConfiguredControl) selectControl).setValue(lineIdentifier);
 810  
         }
 811  0
     }
 812  
 
 813  
     /**
 814  
      * Determines if given data object has associated maintenance document that allows new or copy
 815  
      * maintenance
 816  
      * actions
 817  
      *
 818  
      * @return boolean true if the maintenance new or copy action is allowed for the data object instance, false
 819  
      *         otherwise
 820  
      */
 821  
     public boolean allowsMaintenanceNewOrCopyAction() {
 822  0
         boolean allowsNewOrCopy = false;
 823  
 
 824  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 825  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 826  0
             allowsNewOrCopy = getDataObjectAuthorizationService()
 827  
                     .canCreate(getDataObjectClass(), GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 828  
         }
 829  
 
 830  0
         return allowsNewOrCopy;
 831  
     }
 832  
 
 833  
     /**
 834  
      * Determines if given data object has associated maintenance document that allows edit maintenance
 835  
      * actions
 836  
      *
 837  
      * @return boolean true if the maintenance edit action is allowed for the data object instance, false otherwise
 838  
      */
 839  
     public boolean allowsMaintenanceEditAction(Object dataObject) {
 840  0
         boolean allowsEdit = false;
 841  
 
 842  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 843  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 844  0
             allowsEdit = getDataObjectAuthorizationService()
 845  
                     .canMaintain(dataObject, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 846  
         }
 847  
 
 848  0
         return allowsEdit;
 849  
     }
 850  
 
 851  
     /**
 852  
      * Determines if given data object has associated maintenance document that allows delete maintenance
 853  
      * actions.
 854  
      *
 855  
      * @return boolean true if the maintenance delete action is allowed for the data object instance, false otherwise
 856  
      */
 857  
     public boolean allowsMaintenanceDeleteAction(Object dataObject) {
 858  0
         boolean allowsMaintain = false;
 859  0
         boolean allowsDelete = false;
 860  
 
 861  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 862  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 863  0
             allowsMaintain = getDataObjectAuthorizationService()
 864  
                     .canMaintain(dataObject, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 865  
         }
 866  
 
 867  0
         allowsDelete = getDocumentDictionaryService().getAllowsRecordDeletion(getDataObjectClass());
 868  
 
 869  0
         return allowsDelete && allowsMaintain;
 870  
     }
 871  
 
 872  
     /**
 873  
      * Returns the maintenance document type associated with the business object class or null if one does not exist.
 874  
      *
 875  
      * @return String representing the maintenance document type name
 876  
      */
 877  
     protected String getMaintenanceDocumentTypeName() {
 878  0
         DocumentDictionaryService dd = getDocumentDictionaryService();
 879  0
         String maintDocTypeName = dd.getMaintenanceDocumentTypeName(getDataObjectClass());
 880  
 
 881  0
         return maintDocTypeName;
 882  
     }
 883  
 
 884  
     /**
 885  
      * Determines whether a given data object that's returned as one of the lookup's results is considered returnable,
 886  
      * which means that for single-value lookups, a "return value" link may be rendered, and for multiple
 887  
      * value lookups, a checkbox is rendered.
 888  
      *
 889  
      * Note that this can be part of an authorization mechanism, but not the complete authorization mechanism.  The
 890  
      * component that invoked the lookup/ lookup caller (e.g. document, nesting lookup, etc.) needs to check
 891  
      * that the object that was passed to it was returnable as well because there are ways around this method
 892  
      * (e.g. crafting a custom return URL).
 893  
      *
 894  
      * @param dataObject - an object from the search result set
 895  
      * @return true if the row is returnable and false if it is not
 896  
      */
 897  
     protected boolean isResultReturnable(Object dataObject) {
 898  0
         return true;
 899  
     }
 900  
 
 901  
     /**
 902  
      * @see org.kuali.rice.krad.lookup.Lookupable#setDataObjectClass
 903  
      */
 904  
     @Override
 905  
     public void setDataObjectClass(Class<?> dataObjectClass) {
 906  0
         this.dataObjectClass = dataObjectClass;
 907  0
     }
 908  
 
 909  
     /**
 910  
      * @see org.kuali.rice.krad.lookup.Lookupable#getDataObjectClass
 911  
      */
 912  
     @Override
 913  
     public Class<?> getDataObjectClass() {
 914  0
         return this.dataObjectClass;
 915  
     }
 916  
 
 917  
     /**
 918  
      * @see org.kuali.rice.krad.lookup.Lookupable#setFieldConversions
 919  
      */
 920  
     @Override
 921  
     public void setFieldConversions(Map<String, String> fieldConversions) {
 922  0
         this.fieldConversions = fieldConversions;
 923  0
     }
 924  
 
 925  
     /**
 926  
      * @see org.kuali.rice.krad.lookup.Lookupable#setReadOnlyFieldsList
 927  
      */
 928  
     @Override
 929  
     public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) {
 930  0
         this.readOnlyFieldsList = readOnlyFieldsList;
 931  0
     }
 932  
 
 933  
     public Map<String, String> getParameters() {
 934  0
         return parameters;
 935  
     }
 936  
 
 937  
     public void setParameters(Map<String, String> parameters) {
 938  0
         this.parameters = parameters;
 939  0
     }
 940  
 
 941  
     public List<String> getDefaultSortAttributeNames() {
 942  0
         return defaultSortAttributeNames;
 943  
     }
 944  
 
 945  
     public void setDefaultSortAttributeNames(List<String> defaultSortAttributeNames) {
 946  0
         this.defaultSortAttributeNames = defaultSortAttributeNames;
 947  0
     }
 948  
 
 949  
     public boolean isSortAscending() {
 950  0
         return sortAscending;
 951  
     }
 952  
 
 953  
     public void setSortAscending(boolean sortAscending) {
 954  0
         this.sortAscending = sortAscending;
 955  0
     }
 956  
 
 957  
     public List<String> getReadOnlyFieldsList() {
 958  0
         return readOnlyFieldsList;
 959  
     }
 960  
 
 961  
     public Map<String, String> getFieldConversions() {
 962  0
         return fieldConversions;
 963  
     }
 964  
 
 965  
     protected ConfigurationService getConfigurationService() {
 966  0
         if (configurationService == null) {
 967  0
             this.configurationService = KRADServiceLocator.getKualiConfigurationService();
 968  
         }
 969  0
         return configurationService;
 970  
     }
 971  
 
 972  
     public void setConfigurationService(ConfigurationService configurationService) {
 973  0
         this.configurationService = configurationService;
 974  0
     }
 975  
 
 976  
     protected DataObjectAuthorizationService getDataObjectAuthorizationService() {
 977  0
         if (dataObjectAuthorizationService == null) {
 978  0
             this.dataObjectAuthorizationService = KRADServiceLocatorWeb.getDataObjectAuthorizationService();
 979  
         }
 980  0
         return dataObjectAuthorizationService;
 981  
     }
 982  
 
 983  
     public void setDataObjectAuthorizationService(DataObjectAuthorizationService dataObjectAuthorizationService) {
 984  0
         this.dataObjectAuthorizationService = dataObjectAuthorizationService;
 985  0
     }
 986  
 
 987  
     protected DataObjectMetaDataService getDataObjectMetaDataService() {
 988  0
         if (dataObjectMetaDataService == null) {
 989  0
             this.dataObjectMetaDataService = KRADServiceLocatorWeb.getDataObjectMetaDataService();
 990  
         }
 991  0
         return dataObjectMetaDataService;
 992  
     }
 993  
 
 994  
     public void setDataObjectMetaDataService(DataObjectMetaDataService dataObjectMetaDataService) {
 995  0
         this.dataObjectMetaDataService = dataObjectMetaDataService;
 996  0
     }
 997  
 
 998  
     public DocumentDictionaryService getDocumentDictionaryService() {
 999  0
         if (documentDictionaryService == null) {
 1000  0
             documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
 1001  
         }
 1002  0
         return documentDictionaryService;
 1003  
     }
 1004  
 
 1005  
     public void setDocumentDictionaryService(DocumentDictionaryService documentDictionaryService) {
 1006  0
         this.documentDictionaryService = documentDictionaryService;
 1007  0
     }
 1008  
 
 1009  
     protected LookupService getLookupService() {
 1010  0
         if (lookupService == null) {
 1011  0
             this.lookupService = KRADServiceLocatorWeb.getLookupService();
 1012  
         }
 1013  0
         return lookupService;
 1014  
     }
 1015  
 
 1016  
     public void setLookupService(LookupService lookupService) {
 1017  0
         this.lookupService = lookupService;
 1018  0
     }
 1019  
 
 1020  
     protected EncryptionService getEncryptionService() {
 1021  0
         if (encryptionService == null) {
 1022  0
             this.encryptionService = CoreApiServiceLocator.getEncryptionService();
 1023  
         }
 1024  0
         return encryptionService;
 1025  
     }
 1026  
 
 1027  
     public void setEncryptionService(EncryptionService encryptionService) {
 1028  0
         this.encryptionService = encryptionService;
 1029  0
     }
 1030  
 }