Coverage Report - org.kuali.rice.kns.lookup.AbstractLookupableHelperServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractLookupableHelperServiceImpl
0%
0/558
0%
0/290
2.778
 
 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.lookup;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 20  
 import org.kuali.rice.core.api.config.property.ConfigurationService;
 21  
 import org.kuali.rice.core.api.encryption.EncryptionService;
 22  
 import org.kuali.rice.core.api.search.SearchOperator;
 23  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 24  
 import org.kuali.rice.core.api.util.cache.CopiedObject;
 25  
 import org.kuali.rice.core.api.util.type.TypeUtils;
 26  
 import org.kuali.rice.core.framework.parameter.ParameterService;
 27  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 28  
 import org.kuali.rice.core.web.format.DateFormatter;
 29  
 import org.kuali.rice.core.web.format.Formatter;
 30  
 import org.kuali.rice.kim.api.identity.Person;
 31  
 import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
 32  
 import org.kuali.rice.kns.document.authorization.FieldRestriction;
 33  
 import org.kuali.rice.kns.inquiry.Inquirable;
 34  
 import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
 35  
 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
 36  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 37  
 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
 38  
 import org.kuali.rice.kns.util.FieldUtils;
 39  
 import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
 40  
 import org.kuali.rice.kns.web.struts.form.LookupForm;
 41  
 import org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm;
 42  
 import org.kuali.rice.kns.web.ui.Column;
 43  
 import org.kuali.rice.kns.web.ui.Field;
 44  
 import org.kuali.rice.kns.web.ui.ResultRow;
 45  
 import org.kuali.rice.kns.web.ui.Row;
 46  
 import org.kuali.rice.krad.bo.BusinessObject;
 47  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 48  
 import org.kuali.rice.krad.datadictionary.AttributeSecurity;
 49  
 import org.kuali.rice.krad.datadictionary.mask.MaskFormatter;
 50  
 import org.kuali.rice.krad.exception.ValidationException;
 51  
 import org.kuali.rice.krad.service.BusinessObjectDictionaryService;
 52  
 import org.kuali.rice.krad.service.BusinessObjectService;
 53  
 import org.kuali.rice.krad.service.DataDictionaryService;
 54  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 55  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 56  
 import org.kuali.rice.krad.service.LookupService;
 57  
 import org.kuali.rice.krad.service.PersistenceStructureService;
 58  
 import org.kuali.rice.krad.service.SequenceAccessorService;
 59  
 import org.kuali.rice.krad.util.GlobalVariables;
 60  
 import org.kuali.rice.krad.util.KRADConstants;
 61  
 import org.kuali.rice.krad.util.ObjectUtils;
 62  
 import org.kuali.rice.krad.util.UrlFactory;
 63  
 
 64  
 import java.security.GeneralSecurityException;
 65  
 import java.sql.Date;
 66  
 import java.util.ArrayList;
 67  
 import java.util.Collection;
 68  
 import java.util.HashMap;
 69  
 import java.util.HashSet;
 70  
 import java.util.Iterator;
 71  
 import java.util.List;
 72  
 import java.util.Map;
 73  
 import java.util.Properties;
 74  
 import java.util.Set;
 75  
 
 76  
 /**
 77  
  * This class declares many of the common spring injected properties, the get/set-ers for them,
 78  
  * and some common util methods that require the injected services
 79  
  */
 80  
 public abstract class AbstractLookupableHelperServiceImpl implements LookupableHelperService {
 81  
 
 82  
     protected static final String TITLE_RETURN_URL_PREPENDTEXT_PROPERTY = "title.return.url.value.prependtext";
 83  
     protected static final String TITLE_ACTION_URL_PREPENDTEXT_PROPERTY = "title.action.url.value.prependtext";
 84  
     protected static final String ACTION_URLS_CHILDREN_SEPARATOR = " | ";
 85  
     protected static final String ACTION_URLS_CHILDREN_STARTER = " [";
 86  
     protected static final String ACTION_URLS_CHILDREN_END = "]";
 87  
     protected static final String ACTION_URLS_SEPARATOR = "  ";
 88  
     protected static final String ACTION_URLS_EMPTY = " ";
 89  
 
 90  0
     protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AbstractLookupableHelperServiceImpl.class);
 91  
 
 92  
     protected Class businessObjectClass;
 93  
     protected Map<String, String[]> parameters;
 94  
     protected BusinessObjectDictionaryService businessObjectDictionaryService;
 95  
     protected BusinessObjectMetaDataService businessObjectMetaDataService;
 96  
     protected DataDictionaryService dataDictionaryService;
 97  
     protected PersistenceStructureService persistenceStructureService;
 98  
     protected EncryptionService encryptionService;
 99  
     protected List<String> readOnlyFieldsList;
 100  
     protected String backLocation;
 101  
     protected String docFormKey;
 102  
     protected Map fieldConversions;
 103  
     protected LookupService lookupService;
 104  
     protected List<Row> rows;
 105  
     protected String referencesToRefresh;
 106  
     protected SequenceAccessorService sequenceAccessorService;
 107  
     protected BusinessObjectService businessObjectService;
 108  
     protected LookupResultsService lookupResultsService;
 109  
     protected String docNum;
 110  
     protected ConfigurationService configurationService;
 111  
     protected ParameterService parameterService;
 112  
     protected BusinessObjectAuthorizationService businessObjectAuthorizationService;
 113  
 
 114  
     /**
 115  
      * @return the docNum
 116  
      */
 117  
     public String getDocNum() {
 118  0
         return this.docNum;
 119  
     }
 120  
 
 121  
     /**
 122  
      * @param docNum the docNum to set
 123  
      */
 124  
     public void setDocNum(String docNum) {
 125  0
         this.docNum = docNum;
 126  0
     }
 127  
 
 128  0
     public AbstractLookupableHelperServiceImpl() {
 129  0
         rows = null;
 130  0
     }
 131  
 
 132  
     /**
 133  
      * This implementation always returns false.
 134  
      *
 135  
      * @see LookupableHelperService#checkForAdditionalFields(java.util.Map)
 136  
      */
 137  
     public boolean checkForAdditionalFields(Map fieldValues) {
 138  0
         return false;
 139  
     }
 140  
 
 141  
     /**
 142  
      * @see LookupableHelperService#getBusinessObjectClass()
 143  
      */
 144  
     public Class getBusinessObjectClass() {
 145  0
         return businessObjectClass;
 146  
     }
 147  
 
 148  
     /**
 149  
      * @see LookupableHelperService#setBusinessObjectClass(java.lang.Class)
 150  
      */
 151  
     public void setBusinessObjectClass(Class businessObjectClass) {
 152  0
         this.businessObjectClass = businessObjectClass;
 153  0
         setRows();
 154  0
     }
 155  
 
 156  
     /**
 157  
      * @see LookupableHelperService#getParameters()
 158  
      */
 159  
     public Map<String, String[]> getParameters() {
 160  0
         return parameters;
 161  
     }
 162  
 
 163  
     /**
 164  
      * @see LookupableHelperService#setParameters(java.util.Map)
 165  
      */
 166  
     public void setParameters(Map<String, String[]> parameters) {
 167  0
         this.parameters = parameters;
 168  0
     }
 169  
 
 170  
     /**
 171  
      * Gets the dataDictionaryService attribute.
 172  
      *
 173  
      * @return Returns the dataDictionaryService.
 174  
      */
 175  
     public DataDictionaryService getDataDictionaryService() {
 176  0
         return dataDictionaryService != null ? dataDictionaryService : KRADServiceLocatorWeb.getDataDictionaryService();
 177  
     }
 178  
 
 179  
     /**
 180  
      * Sets the dataDictionaryService attribute value.
 181  
      *
 182  
      * @param dataDictionaryService The dataDictionaryService to set.
 183  
      */
 184  
     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
 185  0
         this.dataDictionaryService = dataDictionaryService;
 186  0
     }
 187  
 
 188  
     /**
 189  
      * Gets the businessObjectDictionaryService attribute.
 190  
      *
 191  
      * @return Returns the businessObjectDictionaryService.
 192  
      */
 193  
     public BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
 194  0
         return businessObjectDictionaryService != null ? businessObjectDictionaryService : KRADServiceLocatorWeb
 195  
                 .getBusinessObjectDictionaryService();
 196  
     }
 197  
 
 198  
     /**
 199  
      * Sets the businessObjectDictionaryService attribute value.
 200  
      *
 201  
      * @param businessObjectDictionaryService
 202  
      *         The businessObjectDictionaryService to set.
 203  
      */
 204  
     public void setBusinessObjectDictionaryService(BusinessObjectDictionaryService businessObjectDictionaryService) {
 205  0
         this.businessObjectDictionaryService = businessObjectDictionaryService;
 206  0
     }
 207  
 
 208  
     /**
 209  
      * Gets the businessObjectMetaDataService attribute.
 210  
      *
 211  
      * @return Returns the businessObjectMetaDataService.
 212  
      */
 213  
     public BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
 214  0
         return businessObjectMetaDataService != null ? businessObjectMetaDataService : KNSServiceLocator
 215  
                 .getBusinessObjectMetaDataService();
 216  
     }
 217  
 
 218  
     /**
 219  
      * Sets the businessObjectMetaDataService attribute value.
 220  
      *
 221  
      * @param businessObjectMetaDataService The businessObjectMetaDataService to set.
 222  
      */
 223  
     public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService businessObjectMetaDataService) {
 224  0
         this.businessObjectMetaDataService = businessObjectMetaDataService;
 225  0
     }
 226  
 
 227  
     /**
 228  
      * Gets the persistenceStructureService attribute.
 229  
      *
 230  
      * @return Returns the persistenceStructureService.
 231  
      */
 232  
     protected PersistenceStructureService getPersistenceStructureService() {
 233  0
         return persistenceStructureService != null ? persistenceStructureService : KRADServiceLocator
 234  
                 .getPersistenceStructureService();
 235  
     }
 236  
 
 237  
     /**
 238  
      * Sets the persistenceStructureService attribute value.
 239  
      *
 240  
      * @param persistenceStructureService The persistenceStructureService to set.
 241  
      */
 242  
     public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
 243  0
         this.persistenceStructureService = persistenceStructureService;
 244  0
     }
 245  
 
 246  
     /**
 247  
      * Gets the encryptionService attribute.
 248  
      *
 249  
      * @return Returns the encryptionService.
 250  
      */
 251  
     protected EncryptionService getEncryptionService() {
 252  0
         return encryptionService != null ? encryptionService : CoreApiServiceLocator.getEncryptionService();
 253  
     }
 254  
 
 255  
     /**
 256  
      * Sets the encryptionService attribute value.
 257  
      *
 258  
      * @param encryptionService The encryptionService to set.
 259  
      */
 260  
     public void setEncryptionService(EncryptionService encryptionService) {
 261  0
         this.encryptionService = encryptionService;
 262  0
     }
 263  
 
 264  
     protected MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 265  
 
 266  
     public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
 267  0
         if (maintenanceDocumentDictionaryService == null) {
 268  0
             maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
 269  
         }
 270  0
         return maintenanceDocumentDictionaryService;
 271  
     }
 272  
 
 273  
 
 274  
     public BusinessObjectAuthorizationService getBusinessObjectAuthorizationService() {
 275  0
         if (businessObjectAuthorizationService == null) {
 276  0
             businessObjectAuthorizationService = KNSServiceLocator.getBusinessObjectAuthorizationService();
 277  
         }
 278  0
         return businessObjectAuthorizationService;
 279  
     }
 280  
 
 281  
     protected Inquirable kualiInquirable;
 282  
 
 283  
     public Inquirable getKualiInquirable() {
 284  0
         if (kualiInquirable == null) {
 285  0
             kualiInquirable = KNSServiceLocator.getKualiInquirable();
 286  
         }
 287  0
         return kualiInquirable;
 288  
     }
 289  
 
 290  
     public void setMaintenanceDocumentDictionaryService(MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
 291  0
         this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
 292  0
     }
 293  
 
 294  
     public void setKualiInquirable(Inquirable kualiInquirable) {
 295  0
         this.kualiInquirable = kualiInquirable;
 296  0
     }
 297  
 
 298  
 
 299  
     public ConfigurationService getKualiConfigurationService() {
 300  0
         if (configurationService == null) {
 301  0
             configurationService = KRADServiceLocator.getKualiConfigurationService();
 302  
         }
 303  0
         return configurationService;
 304  
     }
 305  
 
 306  
     public void setParameterService(ConfigurationService configurationService) {
 307  0
         this.configurationService = configurationService;
 308  0
     }
 309  
 
 310  
 
 311  
     public ParameterService getParameterService() {
 312  0
         if (parameterService == null) {
 313  0
             parameterService = CoreFrameworkServiceLocator.getParameterService();
 314  
         }
 315  0
         return parameterService;
 316  
     }
 317  
 
 318  
     public void setParameterService(ParameterService parameterService) {
 319  0
         this.parameterService = parameterService;
 320  0
     }
 321  
 
 322  
     /**
 323  
      * Determines if underlying lookup bo has associated maintenance document that allows new or copy maintenance actions.
 324  
      *
 325  
      * @return true if bo has maint doc that allows new or copy actions
 326  
      */
 327  
     public boolean allowsMaintenanceNewOrCopyAction() {
 328  0
         boolean allowsNewOrCopy = false;
 329  
 
 330  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 331  0
         Class boClass = this.getBusinessObjectClass();
 332  
 
 333  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 334  0
             allowsNewOrCopy = getBusinessObjectAuthorizationService().canCreate(boClass, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 335  
         }
 336  0
         return allowsNewOrCopy;
 337  
     }
 338  
 
 339  
     protected boolean allowsMaintenanceEditAction(BusinessObject businessObject) {
 340  0
         boolean allowsEdit = false;
 341  
 
 342  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 343  
 
 344  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 345  0
             allowsEdit = getBusinessObjectAuthorizationService().canMaintain(businessObject, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 346  
         }
 347  0
         return allowsEdit;
 348  
     }
 349  
 
 350  
 
 351  
     /**
 352  
      * Build a maintenance url.
 353  
      *
 354  
      * @param bo           - business object representing the record for maint.
 355  
      * @param methodToCall - maintenance action
 356  
      * @return
 357  
      */
 358  
     final public String getMaintenanceUrl(BusinessObject businessObject, HtmlData htmlData, List pkNames, BusinessObjectRestrictions businessObjectRestrictions) {
 359  0
         htmlData.setTitle(getActionUrlTitleText(businessObject, htmlData.getDisplayText(), pkNames, businessObjectRestrictions));
 360  0
         return htmlData.constructCompleteHtmlTag();
 361  
     }
 362  
 
 363  
     /**
 364  
      * This method is called by performLookup method to generate action urls.
 365  
      * It calls the method getCustomActionUrls to get html data, calls getMaintenanceUrl to get the actual html tag,
 366  
      * and returns a formatted/concatenated string of action urls.
 367  
      *
 368  
      * @see LookupableHelperService#getActionUrls(org.kuali.rice.krad.bo.BusinessObject)
 369  
      */
 370  
     final public String getActionUrls(BusinessObject businessObject, List pkNames, BusinessObjectRestrictions businessObjectRestrictions) {
 371  0
         StringBuffer actions = new StringBuffer();
 372  0
         List<HtmlData> htmlDataList = getCustomActionUrls(businessObject, pkNames);
 373  0
         for (HtmlData htmlData : htmlDataList) {
 374  0
             actions.append(getMaintenanceUrl(businessObject, htmlData, pkNames, businessObjectRestrictions));
 375  0
             if (htmlData.getChildUrlDataList() != null) {
 376  0
                 if (htmlData.getChildUrlDataList().size() > 0) {
 377  0
                     actions.append(ACTION_URLS_CHILDREN_STARTER);
 378  0
                     for (HtmlData childURLData : htmlData.getChildUrlDataList()) {
 379  0
                         actions.append(getMaintenanceUrl(businessObject, childURLData, pkNames, businessObjectRestrictions));
 380  0
                         actions.append(ACTION_URLS_CHILDREN_SEPARATOR);
 381  
                     }
 382  0
                     if (actions.toString().endsWith(ACTION_URLS_CHILDREN_SEPARATOR))
 383  0
                         actions.delete(actions.length() - ACTION_URLS_CHILDREN_SEPARATOR.length(), actions.length());
 384  0
                     actions.append(ACTION_URLS_CHILDREN_END);
 385  
                 }
 386  
             }
 387  0
             actions.append(ACTION_URLS_SEPARATOR);
 388  
         }
 389  0
         if (actions.toString().endsWith(ACTION_URLS_SEPARATOR))
 390  0
             actions.delete(actions.length() - ACTION_URLS_SEPARATOR.length(), actions.length());
 391  0
         return actions.toString();
 392  
     }
 393  
 
 394  
     /**
 395  
      * Child classes should override this method if they want to return some other action urls.
 396  
      *
 397  
      * @returns This default implementation returns links to edit and copy maintenance action for
 398  
      * the current maintenance record if the business object class has an associated maintenance document.
 399  
      * Also checks value of allowsNewOrCopy in maintenance document xml before rendering the copy link.
 400  
      * @see LookupableHelperService#getCustomActionUrls(org.kuali.rice.krad.bo.BusinessObject, java.util.List, java.util.List pkNames)
 401  
      */
 402  
     public List<HtmlData> getCustomActionUrls(BusinessObject businessObject, List pkNames) {
 403  0
         List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
 404  0
         if (allowsMaintenanceEditAction(businessObject)) {
 405  0
             htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_EDIT_METHOD_TO_CALL, pkNames));
 406  
         }
 407  0
         if (allowsMaintenanceNewOrCopyAction()) {
 408  0
             htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_COPY_METHOD_TO_CALL, pkNames));
 409  
         }
 410  0
         if (allowsMaintenanceDeleteAction(businessObject)) {
 411  0
             htmlDataList.add(getUrlData(businessObject, KRADConstants.MAINTENANCE_DELETE_METHOD_TO_CALL, pkNames));
 412  
         }
 413  0
         return htmlDataList;
 414  
     }
 415  
 
 416  
     /**
 417  
      * This method ...
 418  
      * for KULRice 3070
 419  
      *
 420  
      * @return
 421  
      */
 422  
     protected boolean allowsMaintenanceDeleteAction(BusinessObject businessObject) {
 423  
 
 424  0
         boolean allowsMaintain = false;
 425  0
         boolean allowsDelete = false;
 426  
 
 427  0
         String maintDocTypeName = getMaintenanceDocumentTypeName();
 428  
 
 429  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 430  0
             allowsMaintain = getBusinessObjectAuthorizationService().canMaintain(businessObject, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 431  
         }
 432  
 
 433  0
         allowsDelete = KNSServiceLocator.getMaintenanceDocumentDictionaryService().getAllowsRecordDeletion(businessObjectClass);
 434  
 
 435  0
         return allowsDelete && allowsMaintain;
 436  
     }
 437  
 
 438  
     /**
 439  
      * This method constructs an AnchorHtmlData.
 440  
      * This method can be overriden by child classes if they want to construct the html data in a different way.
 441  
      * Foe example, if they want different type of html tag, like input/image.
 442  
      *
 443  
      * @param businessObject
 444  
      * @param methodToCall
 445  
      * @param displayText
 446  
      * @param pkNames
 447  
      * @return
 448  
      */
 449  
     protected HtmlData.AnchorHtmlData getUrlData(BusinessObject businessObject, String methodToCall, String displayText, List pkNames) {
 450  
 
 451  0
         String href = getActionUrlHref(businessObject, methodToCall, pkNames);
 452  
         //String title = StringUtils.isBlank(href)?"":getActionUrlTitleText(businessObject, displayText, pkNames);
 453  0
         HtmlData.AnchorHtmlData anchorHtmlData = new HtmlData.AnchorHtmlData(href, methodToCall, displayText);
 454  0
         return anchorHtmlData;
 455  
     }
 456  
 
 457  
     /**
 458  
      * This method calls its overloaded method with displayText as methodToCall
 459  
      *
 460  
      * @param businessObject
 461  
      * @param methodToCall
 462  
      * @param pkNames
 463  
      * @return
 464  
      */
 465  
     protected HtmlData.AnchorHtmlData getUrlData(BusinessObject businessObject, String methodToCall, List pkNames) {
 466  0
         return getUrlData(businessObject, methodToCall, methodToCall, pkNames);
 467  
     }
 468  
 
 469  
     /**
 470  
      * A utility method that returns an empty list of action urls.
 471  
      *
 472  
      * @return
 473  
      */
 474  
     protected List<HtmlData> getEmptyActionUrls() {
 475  0
         return new ArrayList<HtmlData>();
 476  
     }
 477  
 
 478  
     protected HtmlData getEmptyAnchorHtmlData() {
 479  0
         return new HtmlData.AnchorHtmlData();
 480  
     }
 481  
 
 482  
     /**
 483  
      * This method generates and returns href for the given parameters.
 484  
      * This method can be overridden by child classes if they have to generate href differently.
 485  
      * For example, refer to IntendedIncumbentLookupableHelperServiceImpl
 486  
      *
 487  
      * @param businessObject
 488  
      * @param methodToCall
 489  
      * @param pkNames
 490  
      * @return
 491  
      */
 492  
     protected String getActionUrlHref(BusinessObject businessObject, String methodToCall, List pkNames) {
 493  0
         Properties parameters = new Properties();
 494  0
         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, methodToCall);
 495  
         // TODO: why is this not using the businessObject parmeter's class?
 496  0
         parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, businessObject.getClass().getName());
 497  0
         parameters.putAll(getParametersFromPrimaryKey(businessObject, pkNames));
 498  0
         if (StringUtils.isNotBlank(getReturnLocation())) {
 499  0
             parameters.put(KRADConstants.RETURN_LOCATION_PARAMETER, getReturnLocation());
 500  
         }
 501  0
         return UrlFactory.parameterizeUrl(KRADConstants.MAINTENANCE_ACTION, parameters);
 502  
     }
 503  
 
 504  
     protected Properties getParametersFromPrimaryKey(BusinessObject businessObject, List pkNames) {
 505  0
         Properties parameters = new Properties();
 506  0
         for (Iterator iter = pkNames.iterator(); iter.hasNext();) {
 507  0
             String fieldNm = (String) iter.next();
 508  
 
 509  0
             Object fieldVal = ObjectUtils.getPropertyValue(businessObject, fieldNm);
 510  0
             if (fieldVal == null) {
 511  0
                 fieldVal = KRADConstants.EMPTY_STRING;
 512  
             }
 513  0
             if (fieldVal instanceof java.sql.Date) {
 514  0
                 String formattedString = "";
 515  0
                 if (Formatter.findFormatter(fieldVal.getClass()) != null) {
 516  0
                     Formatter formatter = Formatter.getFormatter(fieldVal.getClass());
 517  0
                     formattedString = (String) formatter.format(fieldVal);
 518  0
                     fieldVal = formattedString;
 519  
                 }
 520  
             }
 521  
 
 522  
             // Encrypt value if it is a secure field
 523  0
             if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, fieldNm)) {
 524  
                 try {
 525  0
                     fieldVal = getEncryptionService().encrypt(fieldVal) + EncryptionService.ENCRYPTION_POST_PREFIX;
 526  0
                 } catch (GeneralSecurityException e) {
 527  0
                     LOG.error("Exception while trying to encrypted value for inquiry framework.", e);
 528  0
                     throw new RuntimeException(e);
 529  0
                 }
 530  
 
 531  
             }
 532  
 
 533  0
             parameters.put(fieldNm, fieldVal.toString());
 534  0
         }
 535  0
         return parameters;
 536  
     }
 537  
 
 538  
     /**
 539  
      * This method generates and returns title text for action urls.
 540  
      * Child classes can override this if they want to generate the title text differently.
 541  
      * For example, refer to BatchJobStatusLookupableHelperServiceImpl
 542  
      *
 543  
      * @param businessObject
 544  
      * @param displayText
 545  
      * @param pkNames
 546  
      * @return
 547  
      */
 548  
     protected String getActionUrlTitleText(BusinessObject businessObject, String displayText, List pkNames, BusinessObjectRestrictions businessObjectRestrictions) {
 549  0
         String prependTitleText = displayText + " "
 550  
                 + getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(getBusinessObjectClass().getName()).getObjectLabel()
 551  
                 + " "
 552  
                 + this.getKualiConfigurationService().getPropertyValueAsString(TITLE_ACTION_URL_PREPENDTEXT_PROPERTY);
 553  0
         return HtmlData.getTitleText(prependTitleText, businessObject, pkNames, businessObjectRestrictions);
 554  
     }
 555  
 
 556  
     /**
 557  
      * Returns the maintenance document type associated with the business object class or null if one does not
 558  
      * exist.
 559  
      *
 560  
      * @return String representing the maintenance document type name
 561  
      */
 562  
     protected String getMaintenanceDocumentTypeName() {
 563  0
         MaintenanceDocumentDictionaryService dd = getMaintenanceDocumentDictionaryService();
 564  0
         String maintDocTypeName = dd.getDocumentTypeName(getBusinessObjectClass());
 565  0
         return maintDocTypeName;
 566  
     }
 567  
 
 568  
     /**
 569  
      * Gets the readOnlyFieldsList attribute.
 570  
      *
 571  
      * @return Returns the readOnlyFieldsList.
 572  
      */
 573  
     public List<String> getReadOnlyFieldsList() {
 574  0
         return readOnlyFieldsList;
 575  
     }
 576  
 
 577  
 
 578  
     /**
 579  
      * Sets the readOnlyFieldsList attribute value.
 580  
      *
 581  
      * @param readOnlyFieldsList The readOnlyFieldsList to set.
 582  
      */
 583  
     public void setReadOnlyFieldsList(List<String> readOnlyFieldsList) {
 584  0
         this.readOnlyFieldsList = readOnlyFieldsList;
 585  0
     }
 586  
 
 587  0
     protected HashMap<String, Boolean> noLookupResultFieldInquiryCache = new HashMap<String, Boolean>();
 588  0
     protected HashMap<Class, Class> inquirableClassCache = new HashMap<Class, Class>();
 589  0
     protected HashMap<String, Boolean> forceLookupResultFieldInquiryCache = new HashMap<String, Boolean>();
 590  
 
 591  
     /**
 592  
      * Returns the inquiry url for a field if one exist.
 593  
      *
 594  
      * @param bo           the business object instance to build the urls for
 595  
      * @param propertyName the property which links to an inquirable
 596  
      * @return String url to inquiry
 597  
      */
 598  
     public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
 599  0
         HtmlData inquiryUrl = new HtmlData.AnchorHtmlData();
 600  
 
 601  0
         String cacheKey = bo.getClass().getName() + "." + propertyName;
 602  0
         Boolean noLookupResultFieldInquiry = noLookupResultFieldInquiryCache.get(cacheKey);
 603  0
         if (noLookupResultFieldInquiry == null) {
 604  0
             noLookupResultFieldInquiry = getBusinessObjectDictionaryService().noLookupResultFieldInquiry(bo.getClass(), propertyName);
 605  0
             if (noLookupResultFieldInquiry == null) {
 606  0
                 noLookupResultFieldInquiry = Boolean.TRUE;
 607  
             }
 608  0
             noLookupResultFieldInquiryCache.put(cacheKey, noLookupResultFieldInquiry);
 609  
         }
 610  0
         if (!noLookupResultFieldInquiry) {
 611  
 
 612  0
             Class<Inquirable> inquirableClass = inquirableClassCache.get(bo.getClass());
 613  0
             if (!inquirableClassCache.containsKey(bo.getClass())) {
 614  0
                 inquirableClass = getBusinessObjectDictionaryService().getInquirableClass(bo.getClass());
 615  0
                 inquirableClassCache.put(bo.getClass(), inquirableClass);
 616  
             }
 617  0
             Inquirable inq = null;
 618  
             try {
 619  0
                 if (inquirableClass != null) {
 620  0
                     inq = inquirableClass.newInstance();
 621  
                 } else {
 622  0
                     inq = getKualiInquirable();
 623  0
                     if (LOG.isDebugEnabled()) {
 624  0
                         LOG.debug("Default Inquirable Class: " + inq.getClass());
 625  
                     }
 626  
                 }
 627  0
                 Boolean forceLookupResultFieldInquiry = forceLookupResultFieldInquiryCache.get(cacheKey);
 628  0
                 if (forceLookupResultFieldInquiry == null) {
 629  0
                     forceLookupResultFieldInquiry = getBusinessObjectDictionaryService().forceLookupResultFieldInquiry(bo.getClass(), propertyName);
 630  0
                     if (forceLookupResultFieldInquiry == null) {
 631  0
                         forceLookupResultFieldInquiry = Boolean.FALSE;
 632  
                     }
 633  0
                     forceLookupResultFieldInquiryCache.put(cacheKey, forceLookupResultFieldInquiry);
 634  
                 }
 635  0
                 inquiryUrl = inq.getInquiryUrl(bo, propertyName, forceLookupResultFieldInquiry);
 636  0
             } catch (Exception ex) {
 637  0
                 LOG.error("unable to create inquirable to get inquiry URL", ex);
 638  0
             }
 639  
         }
 640  
 
 641  0
         return inquiryUrl;
 642  
     }
 643  
 
 644  0
     protected CopiedObject<ArrayList<Column>> resultColumns = null;
 645  
 
 646  
     /**
 647  
      * Constructs the list of columns for the search results. All properties for the column objects come from the DataDictionary.
 648  
      */
 649  
     public List<Column> getColumns() {
 650  0
         if (resultColumns == null) {
 651  0
             ArrayList<Column> columns = new ArrayList<Column>();
 652  0
             for (String attributeName : getBusinessObjectDictionaryService().getLookupResultFieldNames(getBusinessObjectClass())) {
 653  0
                 Column column = new Column();
 654  0
                 column.setPropertyName(attributeName);
 655  0
                 String columnTitle = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), attributeName);
 656  0
                 Boolean useShortLabel = getBusinessObjectDictionaryService().getLookupResultFieldUseShortLabel(businessObjectClass, attributeName);
 657  0
                 if (useShortLabel != null && useShortLabel) {
 658  0
                     columnTitle = getDataDictionaryService().getAttributeShortLabel(getBusinessObjectClass(), attributeName);
 659  
                 }
 660  0
                 if (StringUtils.isBlank(columnTitle)) {
 661  0
                     columnTitle = getDataDictionaryService().getCollectionLabel(getBusinessObjectClass(), attributeName);
 662  
                 }
 663  0
                 column.setColumnTitle(columnTitle);
 664  0
                 column.setMaxLength(getColumnMaxLength(attributeName));
 665  
 
 666  0
                 if (!businessObjectClass.isInterface()) {
 667  
                     try {
 668  0
                         column.setFormatter(ObjectUtils.getFormatterWithDataDictionary(getBusinessObjectClass()
 669  
                                 .newInstance(), attributeName));
 670  0
                     } catch (InstantiationException e) {
 671  0
                         LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e);
 672  
                         // just swallow exception and leave formatter blank
 673  0
                     } catch (IllegalAccessException e) {
 674  0
                         LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e);
 675  
                         // just swallow exception and leave formatter blank
 676  0
                     }
 677  
                 }
 678  
 
 679  0
                 String alternateDisplayPropertyName = getBusinessObjectDictionaryService()
 680  
                         .getLookupFieldAlternateDisplayAttributeName(getBusinessObjectClass(), attributeName);
 681  0
                 if (StringUtils.isNotBlank(alternateDisplayPropertyName)) {
 682  0
                     column.setAlternateDisplayPropertyName(alternateDisplayPropertyName);
 683  
                 }
 684  
 
 685  0
                 String additionalDisplayPropertyName = getBusinessObjectDictionaryService()
 686  
                         .getLookupFieldAdditionalDisplayAttributeName(getBusinessObjectClass(), attributeName);
 687  0
                 if (StringUtils.isNotBlank(additionalDisplayPropertyName)) {
 688  0
                     column.setAdditionalDisplayPropertyName(additionalDisplayPropertyName);
 689  
                 } else {
 690  0
                     boolean translateCodes = getBusinessObjectDictionaryService().tranlateCodesInLookup(getBusinessObjectClass());
 691  0
                     if (translateCodes) {
 692  0
                         FieldUtils.setAdditionalDisplayPropertyForCodes(getBusinessObjectClass(), attributeName, column);
 693  
                     }
 694  
                 }
 695  
 
 696  0
                 column.setTotal(getBusinessObjectDictionaryService().getLookupResultFieldTotal(getBusinessObjectClass(), attributeName));
 697  
 
 698  0
                 columns.add(column);
 699  0
             }
 700  0
             resultColumns = ObjectUtils.deepCopyForCaching(columns);
 701  0
             return columns;
 702  
         }
 703  0
         return resultColumns.getContent();
 704  
     }
 705  
 
 706  0
     protected static Integer RESULTS_DEFAULT_MAX_COLUMN_LENGTH = null;
 707  
 
 708  
     protected int getColumnMaxLength(String attributeName) {
 709  0
         Integer fieldDefinedMaxLength = getBusinessObjectDictionaryService().getLookupResultFieldMaxLength(getBusinessObjectClass(), attributeName);
 710  0
         if (fieldDefinedMaxLength == null) {
 711  0
             if (RESULTS_DEFAULT_MAX_COLUMN_LENGTH == null) {
 712  
                 try {
 713  0
                     RESULTS_DEFAULT_MAX_COLUMN_LENGTH = Integer.valueOf(getParameterService().getParameterValueAsString(
 714  
                             KRADConstants.KRAD_NAMESPACE, KRADConstants.DetailTypes.LOOKUP_PARM_DETAIL_TYPE, KRADConstants.RESULTS_DEFAULT_MAX_COLUMN_LENGTH));
 715  0
                 } catch (NumberFormatException ex) {
 716  0
                     LOG.error("Lookup field max length parameter not found and unable to parse default set in system parameters (RESULTS_DEFAULT_MAX_COLUMN_LENGTH).");
 717  0
                 }
 718  
             }
 719  0
             return RESULTS_DEFAULT_MAX_COLUMN_LENGTH.intValue();
 720  
         }
 721  0
         return fieldDefinedMaxLength.intValue();
 722  
     }
 723  
 
 724  
     /**
 725  
      * @return Returns the backLocation.
 726  
      */
 727  
     public String getBackLocation() {
 728  0
         return backLocation;
 729  
     }
 730  
 
 731  
     /**
 732  
      * @param backLocation The backLocation to set.
 733  
      */
 734  
     public void setBackLocation(String backLocation) {
 735  0
         this.backLocation = backLocation;
 736  0
     }
 737  
 
 738  
     /**
 739  
      * @see LookupableHelperService#getReturnLocation()
 740  
      */
 741  
     public String getReturnLocation() {
 742  0
         return backLocation;
 743  
     }
 744  
 
 745  
     /**
 746  
      * This method is for lookupable implementations
 747  
      *
 748  
      * @see LookupableHelperService#getReturnUrl(org.kuali.rice.krad.bo.BusinessObject, java.util.Map, java.lang.String, java.util.List)
 749  
      */
 750  
     final public HtmlData getReturnUrl(BusinessObject businessObject, Map fieldConversions, String lookupImpl, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions) {
 751  0
         String href = getReturnHref(businessObject, fieldConversions, lookupImpl, returnKeys);
 752  0
         String returnUrlAnchorLabel =
 753  
                 this.getKualiConfigurationService().getPropertyValueAsString(TITLE_RETURN_URL_PREPENDTEXT_PROPERTY);
 754  0
         HtmlData.AnchorHtmlData anchor = new HtmlData.AnchorHtmlData(href, HtmlData.getTitleText(returnUrlAnchorLabel, businessObject, returnKeys, businessObjectRestrictions));
 755  0
         anchor.setDisplayText(returnUrlAnchorLabel);
 756  0
         return anchor;
 757  
     }
 758  
 
 759  
     /**
 760  
      * This method is for lookupable implementations
 761  
      *
 762  
      * @param businessObject
 763  
      * @param fieldConversions
 764  
      * @param lookupImpl
 765  
      * @param returnKeys
 766  
      * @return
 767  
      */
 768  
     final protected String getReturnHref(BusinessObject businessObject, Map fieldConversions, String lookupImpl, List returnKeys) {
 769  0
         if (StringUtils.isNotBlank(backLocation)) {
 770  0
             return UrlFactory.parameterizeUrl(backLocation, getParameters(
 771  
                     businessObject, fieldConversions, lookupImpl, returnKeys));
 772  
         }
 773  0
         return "";
 774  
     }
 775  
 
 776  
     /**
 777  
      * @see LookupableHelperService#getReturnUrl(org.kuali.core.bo.BusinessObject, java.util.Map, java.lang.String)
 778  
      */
 779  
     public HtmlData getReturnUrl(BusinessObject businessObject, LookupForm lookupForm, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions) {
 780  0
         Properties parameters = getParameters(
 781  
                 businessObject, lookupForm.getFieldConversions(), lookupForm.getLookupableImplServiceName(), returnKeys);
 782  0
         if (StringUtils.isEmpty(lookupForm.getHtmlDataType()) || HtmlData.ANCHOR_HTML_DATA_TYPE.equals(lookupForm.getHtmlDataType()))
 783  0
             return getReturnAnchorHtmlData(businessObject, parameters, lookupForm, returnKeys, businessObjectRestrictions);
 784  
         else
 785  0
             return getReturnInputHtmlData(businessObject, parameters, lookupForm, returnKeys, businessObjectRestrictions);
 786  
     }
 787  
 
 788  
     protected HtmlData getReturnInputHtmlData(BusinessObject businessObject, Properties parameters, LookupForm lookupForm, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions) {
 789  0
         String returnUrlAnchorLabel =
 790  
                 this.getKualiConfigurationService().getPropertyValueAsString(TITLE_RETURN_URL_PREPENDTEXT_PROPERTY);
 791  0
         String name = KRADConstants.MULTIPLE_VALUE_LOOKUP_SELECTED_OBJ_ID_PARAM_PREFIX + lookupForm.getLookupObjectId();
 792  0
         HtmlData.InputHtmlData input = new HtmlData.InputHtmlData(name, HtmlData.InputHtmlData.CHECKBOX_INPUT_TYPE);
 793  0
         input.setTitle(HtmlData.getTitleText(returnUrlAnchorLabel, businessObject, returnKeys, businessObjectRestrictions));
 794  0
         if (((MultipleValueLookupForm) lookupForm).getCompositeObjectIdMap() == null ||
 795  
                 ((MultipleValueLookupForm) lookupForm).getCompositeObjectIdMap().get(
 796  
                         ((PersistableBusinessObject) businessObject).getObjectId()) == null) {
 797  0
             input.setChecked("");
 798  
         } else {
 799  0
             input.setChecked(HtmlData.InputHtmlData.CHECKBOX_CHECKED_VALUE);
 800  
         }
 801  0
         input.setValue(HtmlData.InputHtmlData.CHECKBOX_CHECKED_VALUE);
 802  0
         return input;
 803  
     }
 804  
 
 805  
     protected HtmlData getReturnAnchorHtmlData(BusinessObject businessObject, Properties parameters, LookupForm lookupForm, List returnKeys, BusinessObjectRestrictions businessObjectRestrictions) {
 806  0
         String returnUrlAnchorLabel =
 807  
                 this.getKualiConfigurationService().getPropertyValueAsString(TITLE_RETURN_URL_PREPENDTEXT_PROPERTY);
 808  0
         HtmlData.AnchorHtmlData anchor = new HtmlData.AnchorHtmlData(
 809  
                 getReturnHref(parameters, lookupForm, returnKeys),
 810  
                 HtmlData.getTitleText(returnUrlAnchorLabel, businessObject, returnKeys, businessObjectRestrictions));
 811  0
         anchor.setDisplayText(returnUrlAnchorLabel);
 812  0
         return anchor;
 813  
     }
 814  
 
 815  
     protected String getReturnHref(Properties parameters, LookupForm lookupForm, List returnKeys) {
 816  0
         if (StringUtils.isNotBlank(backLocation)) {
 817  0
             String href = UrlFactory.parameterizeUrl(backLocation, parameters);
 818  0
             return addToReturnHref(href, lookupForm);
 819  
         }
 820  0
         return "";
 821  
     }
 822  
 
 823  
     protected String addToReturnHref(String href, LookupForm lookupForm) {
 824  0
         String lookupAnchor = "";
 825  0
         if (StringUtils.isNotEmpty(lookupForm.getAnchor())) {
 826  0
             lookupAnchor = lookupForm.getAnchor();
 827  
         }
 828  0
         href += "&anchor=" + lookupAnchor + "&docNum=" + (StringUtils.isEmpty(getDocNum()) ? "" : getDocNum());
 829  0
         return href;
 830  
     }
 831  
 
 832  
     protected Properties getParameters(BusinessObject bo, Map fieldConversions, String lookupImpl, List returnKeys) {
 833  0
         Properties parameters = new Properties();
 834  0
         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.RETURN_METHOD_TO_CALL);
 835  0
         if (getDocFormKey() != null) {
 836  0
             parameters.put(KRADConstants.DOC_FORM_KEY, getDocFormKey());
 837  
         }
 838  0
         if (lookupImpl != null) {
 839  0
             parameters.put(KRADConstants.REFRESH_CALLER, lookupImpl);
 840  
         }
 841  0
         if (getDocNum() != null) {
 842  0
             parameters.put(KRADConstants.DOC_NUM, getDocNum());
 843  
         }
 844  
 
 845  0
         if (getReferencesToRefresh() != null) {
 846  0
             parameters.put(KRADConstants.REFERENCES_TO_REFRESH, getReferencesToRefresh());
 847  
         }
 848  
 
 849  0
         Iterator returnKeysIt = getReturnKeys().iterator();
 850  0
         while (returnKeysIt.hasNext()) {
 851  0
             String fieldNm = (String) returnKeysIt.next();
 852  
 
 853  0
             Object fieldVal = ObjectUtils.getPropertyValue(bo, fieldNm);
 854  0
             if (fieldVal == null) {
 855  0
                 fieldVal = KRADConstants.EMPTY_STRING;
 856  
             }
 857  
 
 858  0
             if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, fieldNm)) {
 859  
                 try {
 860  0
                     fieldVal = getEncryptionService().encrypt(fieldVal) + EncryptionService.ENCRYPTION_POST_PREFIX;
 861  0
                 } catch (GeneralSecurityException e) {
 862  0
                     LOG.error("Exception while trying to encrypted value for inquiry framework.", e);
 863  0
                     throw new RuntimeException(e);
 864  0
                 }
 865  
 
 866  
             }
 867  
 
 868  
             //need to format date in url
 869  0
             if (fieldVal instanceof Date) {
 870  0
                 DateFormatter dateFormatter = new DateFormatter();
 871  0
                 fieldVal = dateFormatter.format(fieldVal);
 872  
             }
 873  
 
 874  0
             if (fieldConversions.containsKey(fieldNm)) {
 875  0
                 fieldNm = (String) fieldConversions.get(fieldNm);
 876  
             }
 877  
 
 878  0
             parameters.put(fieldNm, fieldVal.toString());
 879  0
         }
 880  
 
 881  0
         return parameters;
 882  
     }
 883  
 
 884  
     /**
 885  
      * @return a List of the names of fields which are marked in data dictionary as return fields.
 886  
      */
 887  
     public List getReturnKeys() {
 888  
         List returnKeys;
 889  0
         if (fieldConversions != null && !fieldConversions.isEmpty()) {
 890  0
             returnKeys = new ArrayList(fieldConversions.keySet());
 891  
         } else {
 892  0
             returnKeys = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
 893  
         }
 894  
 
 895  0
         return returnKeys;
 896  
     }
 897  
 
 898  
     /**
 899  
      * Gets the docFormKey attribute.
 900  
      *
 901  
      * @return Returns the docFormKey.
 902  
      */
 903  
     public String getDocFormKey() {
 904  0
         return docFormKey;
 905  
     }
 906  
 
 907  
     /**
 908  
      * Sets the docFormKey attribute value.
 909  
      *
 910  
      * @param docFormKey The docFormKey to set.
 911  
      */
 912  
     public void setDocFormKey(String docFormKey) {
 913  0
         this.docFormKey = docFormKey;
 914  0
     }
 915  
 
 916  
     /**
 917  
      * @see org.kuali.core.lookup.LookupableHelperService#setFieldConversions(java.util.Map)
 918  
      */
 919  
     public void setFieldConversions(Map fieldConversions) {
 920  0
         this.fieldConversions = fieldConversions;
 921  0
     }
 922  
 
 923  
     /**
 924  
      * Gets the lookupService attribute.
 925  
      *
 926  
      * @return Returns the lookupService.
 927  
      */
 928  
     protected LookupService getLookupService() {
 929  0
         return lookupService != null ? lookupService : KRADServiceLocatorWeb.getLookupService();
 930  
     }
 931  
 
 932  
     /**
 933  
      * Sets the lookupService attribute value.
 934  
      *
 935  
      * @param lookupService The lookupService to set.
 936  
      */
 937  
     public void setLookupService(LookupService lookupService) {
 938  0
         this.lookupService = lookupService;
 939  0
     }
 940  
 
 941  
     /**
 942  
      * Uses the DD to determine which is the default sort order.
 943  
      *
 944  
      * @return property names that will be used to sort on by default
 945  
      */
 946  
     public List getDefaultSortColumns() {
 947  0
         return getBusinessObjectDictionaryService().getLookupDefaultSortFieldNames(getBusinessObjectClass());
 948  
     }
 949  
 
 950  
     /**
 951  
      * Checks that any required search fields have value.
 952  
      *
 953  
      * @see org.kuali.core.lookup.LookupableHelperService#validateSearchParameters(java.util.Map)
 954  
      */
 955  
     public void validateSearchParameters(Map fieldValues) {
 956  0
         List<String> lookupFieldAttributeList = null;
 957  0
         if (getBusinessObjectMetaDataService().isLookupable(getBusinessObjectClass())) {
 958  0
             lookupFieldAttributeList = getBusinessObjectMetaDataService().getLookupableFieldNames(getBusinessObjectClass());
 959  
         }
 960  0
         if (lookupFieldAttributeList == null) {
 961  0
             throw new RuntimeException("Lookup not defined for business object " + getBusinessObjectClass());
 962  
         }
 963  0
         for (Iterator iter = lookupFieldAttributeList.iterator(); iter.hasNext();) {
 964  0
             String attributeName = (String) iter.next();
 965  0
             if (fieldValues.containsKey(attributeName)) {
 966  
                 // get label of attribute for message
 967  0
                 String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), attributeName);
 968  
 
 969  0
                 String attributeValue = (String) fieldValues.get(attributeName);
 970  
 
 971  
                 // check for required if field does not have value
 972  0
                 if (StringUtils.isBlank(attributeValue)) {
 973  0
                     if ((getBusinessObjectDictionaryService().getLookupAttributeRequired(getBusinessObjectClass(), attributeName)).booleanValue()) {
 974  0
                         GlobalVariables.getMessageMap().putError(attributeName, RiceKeyConstants.ERROR_REQUIRED, attributeLabel);
 975  
                     }
 976  
                 }
 977  0
                 validateSearchParameterWildcardAndOperators(attributeName, attributeValue);
 978  
             }
 979  0
         }
 980  
 
 981  0
         if (GlobalVariables.getMessageMap().hasErrors()) {
 982  0
             throw new ValidationException("errors in search criteria");
 983  
         }
 984  0
     }
 985  
 
 986  
     protected void validateSearchParameterWildcardAndOperators(String attributeName, String attributeValue) {
 987  0
         if (StringUtils.isBlank(attributeValue))
 988  0
             return;
 989  
 
 990  
         // make sure a wildcard/operator is in the value
 991  0
         boolean found = false;
 992  0
         for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
 993  0
             String queryCharacter = op.op();
 994  
 
 995  0
             if (attributeValue.contains(queryCharacter)) {
 996  0
                 found = true;
 997  
             }
 998  0
         }
 999  0
         if (!found)
 1000  0
             return;
 1001  
 
 1002  0
         String attributeLabel = getDataDictionaryService().getAttributeLabel(getBusinessObjectClass(), attributeName);
 1003  0
         if (getBusinessObjectDictionaryService().isLookupFieldTreatWildcardsAndOperatorsAsLiteral(businessObjectClass, attributeName)) {
 1004  0
             BusinessObject example = null;
 1005  
             try {
 1006  0
                 example = (BusinessObject) businessObjectClass.newInstance();
 1007  0
             } catch (Exception e) {
 1008  0
                 LOG.error("Exception caught instantiating " + businessObjectClass.getName(), e);
 1009  0
                 throw new RuntimeException("Cannot instantiate " + businessObjectClass.getName(), e);
 1010  0
             }
 1011  
 
 1012  0
             Class propertyType = ObjectUtils.getPropertyType(example, attributeName, getPersistenceStructureService());
 1013  0
             if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType) || TypeUtils.isTemporalClass(propertyType)) {
 1014  0
                 GlobalVariables.getMessageMap().putError(attributeName, RiceKeyConstants.ERROR_WILDCARDS_AND_OPERATORS_NOT_ALLOWED_ON_FIELD, attributeLabel);
 1015  
             }
 1016  0
             if (TypeUtils.isStringClass(propertyType)) {
 1017  0
                 GlobalVariables.getMessageMap().putInfo(attributeName, RiceKeyConstants.INFO_WILDCARDS_AND_OPERATORS_TREATED_LITERALLY, attributeLabel);
 1018  
             }
 1019  0
         } else {
 1020  0
             if (getBusinessObjectAuthorizationService().attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, attributeName)) {
 1021  0
                 if (!attributeValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 1022  
                     // encrypted values usually come from the DB, so we don't need to filter for wildcards
 1023  
 
 1024  
                     // wildcards are not allowed on restricted fields, because they are typically encrypted, and wildcard searches cannot be performed without
 1025  
                     // decrypting every row, which is currently not supported by KNS
 1026  
 
 1027  0
                     GlobalVariables.getMessageMap().putError(attributeName, RiceKeyConstants.ERROR_SECURE_FIELD, attributeLabel);
 1028  
                 }
 1029  
             }
 1030  
         }
 1031  0
     }
 1032  
 
 1033  
     /**
 1034  
      * Constructs the list of rows for the search fields. All properties for the field objects come
 1035  
      * from the DataDictionary. To be called by setBusinessObject
 1036  
      */
 1037  
     protected void setRows() {
 1038  0
         List<String> lookupFieldAttributeList = null;
 1039  0
         if (getBusinessObjectMetaDataService().isLookupable(getBusinessObjectClass())) {
 1040  0
             lookupFieldAttributeList = getBusinessObjectMetaDataService().getLookupableFieldNames(
 1041  
                     getBusinessObjectClass());
 1042  
         }
 1043  0
         if (lookupFieldAttributeList == null) {
 1044  0
             throw new RuntimeException("Lookup not defined for business object " + getBusinessObjectClass());
 1045  
         }
 1046  
 
 1047  
         // construct field object for each search attribute
 1048  0
         List fields = new ArrayList();
 1049  
         try {
 1050  0
             fields = FieldUtils.createAndPopulateFieldsForLookup(lookupFieldAttributeList, getReadOnlyFieldsList(),
 1051  
                     getBusinessObjectClass());
 1052  0
         } catch (InstantiationException e) {
 1053  0
             throw new RuntimeException("Unable to create instance of business object class" + e.getMessage());
 1054  0
         } catch (IllegalAccessException e) {
 1055  0
             throw new RuntimeException("Unable to create instance of business object class" + e.getMessage());
 1056  0
         }
 1057  
 
 1058  0
         int numCols = getBusinessObjectDictionaryService().getLookupNumberOfColumns(this.getBusinessObjectClass());
 1059  
 
 1060  0
         this.rows = FieldUtils.wrapFields(fields, numCols);
 1061  0
     }
 1062  
 
 1063  
     public List<Row> getRows() {
 1064  0
         return rows;
 1065  
     }
 1066  
 
 1067  
     public abstract List<? extends BusinessObject> getSearchResults(Map<String, String> fieldValues);
 1068  
 
 1069  
     /**
 1070  
      * This implementation of this method throws an UnsupportedOperationException, since not every implementation
 1071  
      * may actually want to use this operation.  Subclasses desiring other behaviors
 1072  
      * will need to override this.
 1073  
      *
 1074  
      * @see org.kuali.core.lookup.LookupableHelperService#getSearchResultsUnbounded(java.util.Map)
 1075  
      */
 1076  
     public List<? extends BusinessObject> getSearchResultsUnbounded(Map<String, String> fieldValues) {
 1077  0
         throw new UnsupportedOperationException("Lookupable helper services do not always support getSearchResultsUnbounded");
 1078  
     }
 1079  
 
 1080  
     /**
 1081  
      * Performs the lookup and returns a collection of lookup items
 1082  
      *
 1083  
      * @param lookupForm
 1084  
      * @param resultTable
 1085  
      * @param bounded
 1086  
      * @return
 1087  
      */
 1088  
     public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
 1089  0
         Map lookupFormFields = lookupForm.getFieldsForLookup();
 1090  
 
 1091  0
         setBackLocation((String) lookupForm.getFieldsForLookup().get(KRADConstants.BACK_LOCATION));
 1092  0
         setDocFormKey((String) lookupForm.getFieldsForLookup().get(KRADConstants.DOC_FORM_KEY));
 1093  
         Collection displayList;
 1094  
 
 1095  0
         preProcessRangeFields(lookupFormFields);
 1096  
 
 1097  0
         Map fieldsForLookup = new HashMap(lookupForm.getFieldsForLookup());
 1098  
         // call search method to get results
 1099  0
         if (bounded) {
 1100  0
             displayList = getSearchResults(lookupForm.getFieldsForLookup());
 1101  
         } else {
 1102  0
             displayList = getSearchResultsUnbounded(lookupForm.getFieldsForLookup());
 1103  
         }
 1104  
 
 1105  0
         boolean hasReturnableRow = false;
 1106  
 
 1107  0
         List returnKeys = getReturnKeys();
 1108  0
         List pkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
 1109  0
         Person user = GlobalVariables.getUserSession().getPerson();
 1110  
 
 1111  
         // iterate through result list and wrap rows with return url and action
 1112  
         // urls
 1113  0
         for (Iterator iter = displayList.iterator(); iter.hasNext();) {
 1114  0
             BusinessObject element = (BusinessObject) iter.next();
 1115  
 
 1116  0
             final String lookupId = KNSServiceLocator.getLookupResultsService().getLookupId(element);
 1117  0
             if (lookupId != null) {
 1118  0
                 lookupForm.setLookupObjectId(lookupId);
 1119  
             }
 1120  
 
 1121  0
             BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService()
 1122  
                     .getLookupResultRestrictions(element, user);
 1123  
 
 1124  0
             HtmlData returnUrl = getReturnUrl(element, lookupForm, returnKeys, businessObjectRestrictions);
 1125  0
             String actionUrls = getActionUrls(element, pkNames, businessObjectRestrictions);
 1126  
             // Fix for JIRA - KFSMI-2417
 1127  0
             if ("".equals(actionUrls)) {
 1128  0
                 actionUrls = ACTION_URLS_EMPTY;
 1129  
             }
 1130  
 
 1131  0
             List<Column> columns = getColumns();
 1132  0
             for (Iterator iterator = columns.iterator(); iterator.hasNext();) {
 1133  0
                 Column col = (Column) iterator.next();
 1134  
 
 1135  0
                 String propValue = ObjectUtils.getFormattedPropertyValue(element, col.getPropertyName(), col.getFormatter());
 1136  0
                 Class propClass = getPropertyClass(element, col.getPropertyName());
 1137  
 
 1138  0
                 col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
 1139  0
                 col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
 1140  
 
 1141  0
                 String propValueBeforePotientalMasking = propValue;
 1142  0
                 propValue = maskValueIfNecessary(element.getClass(), col.getPropertyName(), propValue,
 1143  
                         businessObjectRestrictions);
 1144  0
                 col.setPropertyValue(propValue);
 1145  
 
 1146  
                 // if property value is masked, don't display additional or alternate properties, or allow totals
 1147  0
                 if (StringUtils.equals(propValueBeforePotientalMasking, propValue)) {
 1148  0
                     if (StringUtils.isNotBlank(col.getAlternateDisplayPropertyName())) {
 1149  0
                         String alternatePropertyValue = ObjectUtils.getFormattedPropertyValue(element, col
 1150  
                                 .getAlternateDisplayPropertyName(), null);
 1151  0
                         col.setPropertyValue(alternatePropertyValue);
 1152  
                     }
 1153  
 
 1154  0
                     if (StringUtils.isNotBlank(col.getAdditionalDisplayPropertyName())) {
 1155  0
                         String additionalPropertyValue = ObjectUtils.getFormattedPropertyValue(element, col
 1156  
                                 .getAdditionalDisplayPropertyName(), null);
 1157  0
                         col.setPropertyValue(col.getPropertyValue() + " *-* " + additionalPropertyValue);
 1158  0
                     }
 1159  
                 } else {
 1160  0
                     col.setTotal(false);
 1161  
                 }
 1162  
 
 1163  0
                 if (col.isTotal()) {
 1164  0
                     Object unformattedPropValue = ObjectUtils.getPropertyValue(element, col.getPropertyName());
 1165  0
                     col.setUnformattedPropertyValue(unformattedPropValue);
 1166  
                 }
 1167  
 
 1168  0
                 if (StringUtils.isNotBlank(propValue)) {
 1169  0
                     col.setColumnAnchor(getInquiryUrl(element, col.getPropertyName()));
 1170  
                 }
 1171  0
             }
 1172  
 
 1173  0
             ResultRow row = new ResultRow(columns, returnUrl.constructCompleteHtmlTag(), actionUrls);
 1174  0
             row.setRowId(returnUrl.getName());
 1175  0
             row.setReturnUrlHtmlData(returnUrl);
 1176  
 
 1177  
             // because of concerns of the BO being cached in session on the
 1178  
             // ResultRow,
 1179  
             // let's only attach it when needed (currently in the case of
 1180  
             // export)
 1181  0
             if (getBusinessObjectDictionaryService().isExportable(getBusinessObjectClass())) {
 1182  0
                 row.setBusinessObject(element);
 1183  
             }
 1184  
 
 1185  0
             if (lookupId != null) {
 1186  0
                 row.setObjectId(lookupId);
 1187  
             }
 1188  
 
 1189  0
             boolean rowReturnable = isResultReturnable(element);
 1190  0
             row.setRowReturnable(rowReturnable);
 1191  0
             if (rowReturnable) {
 1192  0
                 hasReturnableRow = true;
 1193  
             }
 1194  0
             resultTable.add(row);
 1195  0
         }
 1196  
 
 1197  0
         lookupForm.setHasReturnableRow(hasReturnableRow);
 1198  
 
 1199  0
         return displayList;
 1200  
     }
 1201  
 
 1202  
     /**
 1203  
      * Gets the Class for the property in the given BusinessObject instance, if
 1204  
      * property is not accessible then runtime exception is thrown
 1205  
      *
 1206  
      * @param element      BusinessObject instance that contains property
 1207  
      * @param propertyName Name of property in BusinessObject to get class for
 1208  
      * @return Type for property as Class
 1209  
      */
 1210  
     protected Class getPropertyClass(BusinessObject element, String propertyName) {
 1211  0
         Class propClass = null;
 1212  
 
 1213  
         try {
 1214  0
             propClass = ObjectUtils.getPropertyType(element, propertyName, getPersistenceStructureService());
 1215  
 
 1216  0
         } catch (Exception e) {
 1217  0
             throw new RuntimeException("Cannot access PropertyType for property " + "'" + propertyName + "' "
 1218  
                     + " on an instance of '" + element.getClass().getName() + "'.", e);
 1219  0
         }
 1220  
 
 1221  0
         return propClass;
 1222  
     }
 1223  
 
 1224  
     /**
 1225  
      * Changes ranged search fields like from/to dates into the range operators the lookupable dao expects
 1226  
      * ("..",">" etc) this method modifies the passed in map and returns a list containing only the modified fields
 1227  
      */
 1228  
     protected Map<String, String> preProcessRangeFields(Map<String, String> lookupFormFields) {
 1229  0
         Map<String, String> fieldsToUpdate = new HashMap<String, String>();
 1230  0
         Set<String> fieldsForLookup = lookupFormFields.keySet();
 1231  0
         for (String propName : fieldsForLookup) {
 1232  0
             if (propName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 1233  0
                 String rangedLowerBoundValue = lookupFormFields.get(propName);
 1234  0
                 String rangedFieldName = StringUtils.remove(propName, KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
 1235  0
                 String rangedValue = lookupFormFields.get(rangedFieldName);
 1236  0
                 String newPropValue = rangedValue;
 1237  0
                 if (StringUtils.isNotEmpty(rangedLowerBoundValue) && StringUtils.isNotEmpty(rangedValue)) {
 1238  0
                     newPropValue = rangedLowerBoundValue + SearchOperator.BETWEEN + rangedValue;
 1239  0
                 } else if (StringUtils.isNotEmpty(rangedLowerBoundValue) && StringUtils.isEmpty(rangedValue)) {
 1240  0
                     newPropValue = ">=" + rangedLowerBoundValue;
 1241  0
                 } else if (StringUtils.isNotEmpty(rangedValue) && StringUtils.isEmpty(rangedLowerBoundValue)) {
 1242  0
                     newPropValue = "<=" + rangedValue;
 1243  
                 }
 1244  0
                 fieldsToUpdate.put(rangedFieldName, newPropValue);
 1245  0
             }
 1246  
         }
 1247  
         //update lookup values from found ranged values to update
 1248  0
         Set<String> keysToUpdate = fieldsToUpdate.keySet();
 1249  0
         for (String updateKey : keysToUpdate) {
 1250  0
             lookupFormFields.put(updateKey, fieldsToUpdate.get(updateKey));
 1251  
         }
 1252  0
         return fieldsToUpdate;
 1253  
     }
 1254  
 
 1255  
     protected String maskValueIfNecessary(Class businessObjectClass, String propertyName, String propertyValue, BusinessObjectRestrictions businessObjectRestrictions) {
 1256  0
         String maskedPropertyValue = propertyValue;
 1257  0
         if (businessObjectRestrictions != null) {
 1258  0
             FieldRestriction fieldRestriction = businessObjectRestrictions.getFieldRestriction(propertyName);
 1259  0
             if (fieldRestriction != null && (fieldRestriction.isMasked() || fieldRestriction.isPartiallyMasked())) {
 1260  0
                 maskedPropertyValue = fieldRestriction.getMaskFormatter().maskValue(propertyValue);
 1261  
             }
 1262  
         }
 1263  0
         return maskedPropertyValue;
 1264  
     }
 1265  
 
 1266  
 
 1267  
     protected void setReferencesToRefresh(String referencesToRefresh) {
 1268  0
         this.referencesToRefresh = referencesToRefresh;
 1269  0
     }
 1270  
 
 1271  
     public String getReferencesToRefresh() {
 1272  0
         return referencesToRefresh;
 1273  
     }
 1274  
 
 1275  
     protected SequenceAccessorService getSequenceAccessorService() {
 1276  0
         return sequenceAccessorService != null ? sequenceAccessorService : KRADServiceLocator
 1277  
                 .getSequenceAccessorService();
 1278  
     }
 1279  
 
 1280  
     public void setSequenceAccessorService(SequenceAccessorService sequenceAccessorService) {
 1281  0
         this.sequenceAccessorService = sequenceAccessorService;
 1282  0
     }
 1283  
 
 1284  
     public BusinessObjectService getBusinessObjectService() {
 1285  0
         return businessObjectService != null ? businessObjectService : KRADServiceLocator.getBusinessObjectService();
 1286  
     }
 1287  
 
 1288  
     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
 1289  0
         this.businessObjectService = businessObjectService;
 1290  0
     }
 1291  
 
 1292  
     protected LookupResultsService getLookupResultsService() {
 1293  0
         return lookupResultsService != null ? lookupResultsService : KNSServiceLocator.getLookupResultsService();
 1294  
     }
 1295  
 
 1296  
     public void setLookupResultsService(LookupResultsService lookupResultsService) {
 1297  0
         this.lookupResultsService = lookupResultsService;
 1298  0
     }
 1299  
 
 1300  
     /**
 1301  
      * @return false always, subclasses should override to do something smarter
 1302  
      * @see org.kuali.core.lookup.LookupableHelperService#isSearchUsingOnlyPrimaryKeyValues()
 1303  
      */
 1304  
     public boolean isSearchUsingOnlyPrimaryKeyValues() {
 1305  
         // by default, this implementation returns false, as lookups may not necessarily support this
 1306  0
         return false;
 1307  
     }
 1308  
 
 1309  
     /**
 1310  
      * Returns "N/A"
 1311  
      *
 1312  
      * @return "N/A"
 1313  
      * @see org.kuali.core.lookup.LookupableHelperService#getPrimaryKeyFieldLabels()
 1314  
      */
 1315  
     public String getPrimaryKeyFieldLabels() {
 1316  0
         return KRADConstants.NOT_AVAILABLE_STRING;
 1317  
     }
 1318  
 
 1319  
     /**
 1320  
      * @see org.kuali.core.lookup.LookupableHelperService#isResultReturnable(org.kuali.core.bo.BusinessObject)
 1321  
      */
 1322  
     public boolean isResultReturnable(BusinessObject object) {
 1323  0
         return true;
 1324  
     }
 1325  
 
 1326  
     /**
 1327  
      * This method does the logic for the clear action.
 1328  
      *
 1329  
      * @see LookupableHelperService#performClear()
 1330  
      */
 1331  
     public void performClear(LookupForm lookupForm) {
 1332  0
         for (Iterator iter = this.getRows().iterator(); iter.hasNext();) {
 1333  0
             Row row = (Row) iter.next();
 1334  0
             for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
 1335  0
                 Field field = (Field) iterator.next();
 1336  0
                 if (field.isSecure()) {
 1337  0
                     field.setSecure(false);
 1338  0
                     field.setDisplayMaskValue(null);
 1339  0
                     field.setEncryptedValue(null);
 1340  
                 }
 1341  
 
 1342  0
                 if (!field.getFieldType().equals(Field.RADIO)) {
 1343  0
                     field.setPropertyValue(field.getDefaultValue());
 1344  
                 }
 1345  0
             }
 1346  0
         }
 1347  0
     }
 1348  
 
 1349  
     /**
 1350  
      * @see LookupableHelperService#shouldDisplayHeaderNonMaintActions()
 1351  
      */
 1352  
     public boolean shouldDisplayHeaderNonMaintActions() {
 1353  0
         return true;
 1354  
     }
 1355  
 
 1356  
     /**
 1357  
      * @see LookupableHelperService#shouldDisplayLookupCriteria()
 1358  
      */
 1359  
     public boolean shouldDisplayLookupCriteria() {
 1360  0
         return true;
 1361  
     }
 1362  
 
 1363  
     /**
 1364  
      * @see LookupableHelperService#getSupplementalMenuBar()
 1365  
      */
 1366  
     public String getSupplementalMenuBar() {
 1367  0
         return new String();
 1368  
     }
 1369  
 
 1370  
     /**
 1371  
      * @see LookupableHelperService#getTitle()
 1372  
      */
 1373  
     public String getTitle() {
 1374  0
         return getBusinessObjectDictionaryService().getLookupTitle(getBusinessObjectClass());
 1375  
     }
 1376  
 
 1377  
     /**
 1378  
      * @see LookupableHelperService#performCustomAction(boolean)
 1379  
      */
 1380  
     public boolean performCustomAction(boolean ignoreErrors) {
 1381  0
         return false;
 1382  
     }
 1383  
 
 1384  
     /**
 1385  
      * @see Lookupable#getExtraField()
 1386  
      */
 1387  
     public Field getExtraField() {
 1388  0
         return null;
 1389  
     }
 1390  
 
 1391  
     public boolean allowsNewOrCopyAction(String documentTypeName) {
 1392  0
         throw new UnsupportedOperationException("Function not supported.");
 1393  
     }
 1394  
 
 1395  
     /**
 1396  
      * Functional requirements state that users are able to perform searches using criteria values that they are not allowed to view.
 1397  
      *
 1398  
      * @see LookupableHelperService#applyFieldAuthorizationsFromNestedLookups(org.kuali.rice.krad.web.ui.Field)
 1399  
      */
 1400  
     public void applyFieldAuthorizationsFromNestedLookups(Field field) {
 1401  0
         BusinessObjectAuthorizationService boAuthzService = this.getBusinessObjectAuthorizationService();
 1402  0
         if (!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 1403  0
             if (field.getPropertyValue() != null && field.getPropertyValue().endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
 1404  0
                 if (boAuthzService.attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, field.getPropertyName())) {
 1405  0
                     AttributeSecurity attributeSecurity = getDataDictionaryService().getAttributeSecurity(businessObjectClass.getName(), field.getPropertyName());
 1406  0
                     Person user = GlobalVariables.getUserSession().getPerson();
 1407  
                     String decryptedValue;
 1408  
                     try {
 1409  0
                         String cipherText = StringUtils.removeEnd(field.getPropertyValue(), EncryptionService.ENCRYPTION_POST_PREFIX);
 1410  0
                         decryptedValue = getEncryptionService().decrypt(cipherText);
 1411  0
                     } catch (GeneralSecurityException e) {
 1412  0
                         throw new RuntimeException("Error decrypting value for business object " + businessObjectClass + " attribute " + field.getPropertyName(), e);
 1413  0
                     }
 1414  0
                     if (attributeSecurity.isMask() && !boAuthzService.canFullyUnmaskField(user,
 1415  
                             businessObjectClass, field.getPropertyName(), null)) {
 1416  0
                         MaskFormatter maskFormatter = attributeSecurity.getMaskFormatter();
 1417  0
                         field.setEncryptedValue(field.getPropertyValue());
 1418  0
                         field.setDisplayMaskValue(maskFormatter.maskValue(decryptedValue));
 1419  0
                         field.setSecure(true);
 1420  0
                     } else if (attributeSecurity.isPartialMask() && !boAuthzService.canPartiallyUnmaskField(user,
 1421  
                             businessObjectClass, field.getPropertyName(), null)) {
 1422  0
                         MaskFormatter maskFormatter = attributeSecurity.getPartialMaskFormatter();
 1423  0
                         field.setEncryptedValue(field.getPropertyValue());
 1424  0
                         field.setDisplayMaskValue(maskFormatter.maskValue(decryptedValue));
 1425  0
                         field.setSecure(true);
 1426  0
                     } else {
 1427  0
                         field.setPropertyValue(org.kuali.rice.krad.lookup.LookupUtils
 1428  
                                 .forceUppercase(businessObjectClass, field.getPropertyName(), decryptedValue));
 1429  
                     }
 1430  0
                 } else {
 1431  0
                     throw new RuntimeException("Field " + field.getPersonNameAttributeName() + " was encrypted on " + businessObjectClass.getName() +
 1432  
                             " lookup was encrypted when it should not have been encrypted according to the data dictionary.");
 1433  
                 }
 1434  
             }
 1435  
         } else {
 1436  0
             if (boAuthzService.attributeValueNeedsToBeEncryptedOnFormsAndLinks(businessObjectClass, field.getPropertyName())) {
 1437  0
                 LOG.error("Cannot handle multiple value field types that have field authorizations, please implement custom lookupable helper service");
 1438  0
                 throw new RuntimeException("Cannot handle multiple value field types that have field authorizations.");
 1439  
             }
 1440  
         }
 1441  0
     }
 1442  
 
 1443  
     /**
 1444  
      * Calls methods that can be overridden by child lookupables to implement conditional logic for setting
 1445  
      * read-only, required, and hidden attributes. Called in the last part of the lookup lifecycle so the
 1446  
      * fields values that will be sent will be correctly reflected in the rows (like after a clear).
 1447  
      *
 1448  
      * @see #getConditionallyReadOnlyPropertyNames()
 1449  
      * @see #getConditionallyRequiredPropertyNames()
 1450  
      * @see #getConditionallyHiddenPropertyNames()
 1451  
      * @see LookupableHelperService#applyConditionalLogicForFieldDisplay()
 1452  
      */
 1453  
     public void applyConditionalLogicForFieldDisplay() {
 1454  0
         Set<String> readOnlyFields = getConditionallyReadOnlyPropertyNames();
 1455  0
         Set<String> requiredFields = getConditionallyRequiredPropertyNames();
 1456  0
         Set<String> hiddenFields = getConditionallyHiddenPropertyNames();
 1457  
 
 1458  0
         for (Iterator iter = this.getRows().iterator(); iter.hasNext();) {
 1459  0
             Row row = (Row) iter.next();
 1460  0
             for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
 1461  0
                 Field field = (Field) iterator.next();
 1462  
 
 1463  0
                 if (readOnlyFields != null && readOnlyFields.contains(field.getPropertyName())) {
 1464  0
                     field.setReadOnly(true);
 1465  
                 }
 1466  
 
 1467  0
                 if (requiredFields != null && requiredFields.contains(field.getPropertyName())) {
 1468  0
                     field.setFieldRequired(true);
 1469  
                 }
 1470  
 
 1471  0
                 if (hiddenFields != null && hiddenFields.contains(field.getPropertyName())) {
 1472  0
                     field.setFieldType(Field.HIDDEN);
 1473  
                 }
 1474  0
             }
 1475  0
         }
 1476  0
     }
 1477  
 
 1478  
     /**
 1479  
      * @return Set of property names that should be set as read only based on the current search
 1480  
      *         contents, note request parms containing search field values can be retrieved with
 1481  
      *         {@link #getParameters()}
 1482  
      */
 1483  
     public Set<String> getConditionallyReadOnlyPropertyNames() {
 1484  0
         return new HashSet<String>();
 1485  
     }
 1486  
 
 1487  
     /**
 1488  
      * @return Set of property names that should be set as required based on the current search
 1489  
      *         contents, note request parms containing search field values can be retrieved with
 1490  
      *         {@link #getParameters()}
 1491  
      */
 1492  
     public Set<String> getConditionallyRequiredPropertyNames() {
 1493  0
         return new HashSet<String>();
 1494  
     }
 1495  
 
 1496  
     /**
 1497  
      * @return Set of property names that should be set as hidden based on the current search
 1498  
      *         contents, note request parms containing search field values can be retrieved with
 1499  
      *         {@link #getParameters()}
 1500  
      */
 1501  
     public Set<String> getConditionallyHiddenPropertyNames() {
 1502  0
         return new HashSet<String>();
 1503  
     }
 1504  
 
 1505  
     /**
 1506  
      * Helper method to get the value for a property out of the row-field graph. If property is
 1507  
      * multi-value then the values will be joined by a semi-colon.
 1508  
      *
 1509  
      * @param propertyName - name of property to retrieve value for
 1510  
      * @return current property value as a String
 1511  
      */
 1512  
     protected String getCurrentSearchFieldValue(String propertyName) {
 1513  0
         String currentValue = null;
 1514  
 
 1515  0
         boolean fieldFound = false;
 1516  0
         for (Iterator iter = this.getRows().iterator(); iter.hasNext();) {
 1517  0
             Row row = (Row) iter.next();
 1518  0
             for (Iterator iterator = row.getFields().iterator(); iterator.hasNext();) {
 1519  0
                 Field field = (Field) iterator.next();
 1520  
 
 1521  0
                 if (StringUtils.equalsIgnoreCase(propertyName, field.getPropertyName())) {
 1522  0
                     if (Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 1523  0
                         currentValue = StringUtils.join(field.getPropertyValues(), ";");
 1524  
                     } else {
 1525  0
                         currentValue = field.getPropertyValue();
 1526  
                     }
 1527  0
                     fieldFound = true;
 1528  
                 }
 1529  
 
 1530  0
                 if (fieldFound) {
 1531  0
                     break;
 1532  
                 }
 1533  0
             }
 1534  
 
 1535  0
             if (fieldFound) {
 1536  0
                 break;
 1537  
             }
 1538  0
         }
 1539  
 
 1540  0
         return currentValue;
 1541  
     }
 1542  
 }