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