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