Coverage Report - org.kuali.rice.kew.bo.lookup.DocSearchCriteriaDTOLookupableHelperServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DocSearchCriteriaDTOLookupableHelperServiceImpl
0%
0/526
0%
0/378
12.316
 
 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.kew.bo.lookup;
 18  
 
 19  
 import org.apache.commons.beanutils.PropertyUtils;
 20  
 import org.apache.commons.lang.StringUtils;
 21  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 22  
 import org.kuali.rice.core.api.datetime.DateTimeService;
 23  
 import org.kuali.rice.core.api.search.SearchOperator;
 24  
 import org.kuali.rice.core.api.util.KeyValue;
 25  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 26  
 import org.kuali.rice.core.api.util.type.KualiDecimal;
 27  
 import org.kuali.rice.core.api.util.type.KualiPercent;
 28  
 import org.kuali.rice.core.web.format.BooleanFormatter;
 29  
 import org.kuali.rice.core.web.format.CollectionFormatter;
 30  
 import org.kuali.rice.core.web.format.DateFormatter;
 31  
 import org.kuali.rice.core.web.format.Formatter;
 32  
 import org.kuali.rice.core.web.format.TimestampAMPMFormatter;
 33  
 import org.kuali.rice.kew.docsearch.DocSearchCriteriaDTO;
 34  
 import org.kuali.rice.kew.docsearch.DocumentLookupCriteriaBuilder;
 35  
 import org.kuali.rice.kew.docsearch.DocumentLookupCriteriaProcessor;
 36  
 import org.kuali.rice.kew.docsearch.DocumentLookupCriteriaProcessorKEWAdapter;
 37  
 import org.kuali.rice.kew.docsearch.DocumentRouteHeaderEBO;
 38  
 import org.kuali.rice.kew.docsearch.DocumentSearchGenerator;
 39  
 import org.kuali.rice.kew.docsearch.DocumentSearchResult;
 40  
 import org.kuali.rice.kew.docsearch.DocumentSearchResultComponents;
 41  
 import org.kuali.rice.kew.docsearch.SavedSearchResult;
 42  
 import org.kuali.rice.kew.docsearch.SearchAttributeCriteriaComponent;
 43  
 import org.kuali.rice.kew.docsearch.service.DocumentSearchService;
 44  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 45  
 import org.kuali.rice.kew.exception.WorkflowServiceError;
 46  
 import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
 47  
 import org.kuali.rice.kew.lookup.valuefinder.SavedSearchValuesFinder;
 48  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 49  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 50  
 import org.kuali.rice.kew.util.KEWConstants;
 51  
 import org.kuali.rice.kew.util.KEWPropertyConstants;
 52  
 import org.kuali.rice.kew.web.KeyValueSort;
 53  
 import org.kuali.rice.kim.bo.Person;
 54  
 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
 55  
 import org.kuali.rice.kns.document.authorization.BusinessObjectRestrictions;
 56  
 import org.kuali.rice.kns.lookup.HtmlData;
 57  
 import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
 58  
 import org.kuali.rice.kns.util.FieldUtils;
 59  
 import org.kuali.rice.kns.web.comparator.CellComparatorHelper;
 60  
 import org.kuali.rice.kns.web.struts.form.LookupForm;
 61  
 import org.kuali.rice.kns.web.ui.Column;
 62  
 import org.kuali.rice.kns.web.ui.Field;
 63  
 import org.kuali.rice.kns.web.ui.ResultRow;
 64  
 import org.kuali.rice.kns.web.ui.Row;
 65  
 import org.kuali.rice.krad.bo.BusinessObject;
 66  
 import org.kuali.rice.krad.exception.ValidationException;
 67  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 68  
 import org.kuali.rice.krad.util.GlobalVariables;
 69  
 import org.kuali.rice.krad.util.KRADConstants;
 70  
 import org.kuali.rice.krad.util.MessageMap;
 71  
 import org.kuali.rice.krad.util.ObjectUtils;
 72  
 import org.kuali.rice.krad.util.UrlFactory;
 73  
 
 74  
 import java.lang.reflect.InvocationTargetException;
 75  
 import java.math.BigDecimal;
 76  
 import java.sql.Date;
 77  
 import java.sql.Timestamp;
 78  
 import java.util.ArrayList;
 79  
 import java.util.Collection;
 80  
 import java.util.HashMap;
 81  
 import java.util.List;
 82  
 import java.util.Map;
 83  
 import java.util.Properties;
 84  
 import java.util.regex.Matcher;
 85  
 import java.util.regex.Pattern;
 86  
 
 87  
 /**
 88  
  * Lookupable helper class for new doc search
 89  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 90  
  *
 91  
  */
 92  0
 public class DocSearchCriteriaDTOLookupableHelperServiceImpl extends KualiLookupableHelperServiceImpl {
 93  
 
 94  
     private static final long serialVersionUID = -5162419674659967408L;
 95  0
     private static final Pattern HREF_PATTERN = Pattern.compile("<a href=\"([^\"]+)\"");
 96  
 
 97  0
     protected boolean savedSearch = false;
 98  
 
 99  
         private DocumentLookupCriteriaProcessor documentLookupCriteriaProcessor;
 100  
 
 101  
         /**
 102  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#performLookup(org.kuali.rice.krad.web.struts.form.LookupForm, java.util.Collection, boolean)
 103  
          */
 104  
         @Override
 105  
         public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
 106  
 
 107  
                 //TODO: ideally implement KNS updates to make this not require code from the parent
 108  
 
 109  0
             Map<String,String[]> parameters = this.getParameters();
 110  
 
 111  0
             DocSearchCriteriaDTO criteria = null;
 112  0
             if(savedSearch) {
 113  
                     //TODO: set the criteria on this from below method instead of this (so we're not calling out twice for the same object)
 114  0
                     DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService();
 115  
 
 116  0
                     String savedSearchName = ((String[])getParameters().get("savedSearchName"))[0];
 117  0
                     SavedSearchResult savedSearchResult = null;
 118  0
                     if(StringUtils.isNotEmpty(savedSearchName)) {
 119  0
                             savedSearchResult = docSearchService.getSavedSearchResults(GlobalVariables.getUserSession().getPrincipalId(), savedSearchName);
 120  
                     }
 121  0
                     if(savedSearchResult!=null){
 122  0
                             criteria = savedSearchResult.getDocSearchCriteriaDTO();
 123  
                     }
 124  0
                     savedSearch=false;
 125  0
             } else {
 126  0
                     Map<String,String[]> fixedParameters = new HashMap<String,String[]>();
 127  0
                     Map<String,String> changedDateFields = preprocessDateFields(lookupForm.getFieldsForLookup());
 128  0
                     fixedParameters.putAll(this.getParameters());
 129  0
                     for (Map.Entry<String,String> prop : changedDateFields.entrySet()) {
 130  0
                                 fixedParameters.remove(prop.getKey());
 131  0
                             fixedParameters.put(prop.getKey(), new String[]{prop.getValue()});
 132  
                         }
 133  0
                     criteria = DocumentLookupCriteriaBuilder.populateCriteria(fixedParameters);
 134  
 
 135  
             }
 136  
 
 137  0
             Collection<DocumentSearchResult> displayList=null;
 138  
 
 139  0
             DocumentSearchResultComponents components = null;
 140  
             try {
 141  0
                     components = KEWServiceLocator.getDocumentSearchService().getList(GlobalVariables.getUserSession().getPrincipalId(), criteria);
 142  0
             } catch (WorkflowServiceErrorException wsee) {
 143  0
                     for (WorkflowServiceError workflowServiceError : (List<WorkflowServiceError>)wsee.getServiceErrors()) {
 144  0
                                 if(workflowServiceError.getMessageMap() != null && workflowServiceError.getMessageMap().hasErrors()){
 145  
                                         // merge the message maps
 146  0
                                         GlobalVariables.getMessageMap().merge(workflowServiceError.getMessageMap());
 147  
                                 }else{
 148  
                                         //TODO: can we add something to this to get it to highlight the right field too?  Maybe in arg1
 149  0
                                         GlobalVariables.getMessageMap().putError(workflowServiceError.getMessage(), RiceKeyConstants.ERROR_CUSTOM, workflowServiceError.getMessage());
 150  
                                 }
 151  
                     };
 152  0
             }
 153  
 
 154  0
             if(!GlobalVariables.getMessageMap().hasNoErrors()) {
 155  0
                 throw new ValidationException("error with doc search");
 156  
         }
 157  
 
 158  
             // check various warning conditions
 159  
 
 160  0
             if (criteria.isOverThreshold() && criteria.getSecurityFilteredRows() > 0) {
 161  0
                 GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, "docsearch.DocumentSearchService.exceededThresholdAndSecurityFiltered", String.valueOf(components.getSearchResults().size()), String.valueOf(criteria.getSecurityFilteredRows()));
 162  0
             } else if (criteria.getSecurityFilteredRows() > 0) {
 163  0
                 GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, "docsearch.DocumentSearchService.securityFiltered", String.valueOf(criteria.getSecurityFilteredRows()));
 164  0
             } else if (criteria.isOverThreshold()) {
 165  0
                     GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES,"docsearch.DocumentSearchService.exceededThreshold", String.valueOf(components.getSearchResults().size()));
 166  
             }
 167  
 
 168  0
             for (Row row : this.getRows()) {
 169  0
                         for (Field field : row.getFields()) {
 170  0
                                 if(StringUtils.equals(field.getPropertyName(),"fromDateCreated") && StringUtils.isEmpty(field.getPropertyValue())) {
 171  0
                                         field.setPropertyValue(criteria.getFromDateCreated());
 172  
                                 }
 173  
                         }
 174  
                 }
 175  
 
 176  0
             List<DocumentSearchResult> result = components.getSearchResults();
 177  0
                 displayList = result;
 178  
         
 179  0
         setBackLocation((String) lookupForm.getFieldsForLookup().get(KRADConstants.BACK_LOCATION));
 180  0
         setDocFormKey((String) lookupForm.getFieldsForLookup().get(KRADConstants.DOC_FORM_KEY));
 181  
 
 182  0
         HashMap<String,Class> propertyTypes = new HashMap<String, Class>();
 183  
 
 184  0
         boolean hasReturnableRow = false;
 185  
 
 186  0
         List returnKeys = getReturnKeys();
 187  0
         List pkNames = getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(getBusinessObjectClass());
 188  0
         Person user = GlobalVariables.getUserSession().getPerson();
 189  
 
 190  
         // iterate through result list and wrap rows with return url and action urls
 191  
 
 192  0
         DocumentRouteHeaderEBO element = new DocSearchCriteriaDTO();
 193  
         //TODO: additional BORestrictions through generator or component to lock down per document?
 194  0
             BusinessObjectRestrictions businessObjectRestrictions = getBusinessObjectAuthorizationService().getLookupResultRestrictions(element, user);
 195  
 
 196  0
         for (DocumentSearchResult documentSearchResult : result) {
 197  
 
 198  0
                 DocumentSearchResult docSearchResult = (DocumentSearchResult)documentSearchResult;
 199  0
                 String actionUrls = "";
 200  
 
 201  0
             List<? extends Column> origColumns = components.getColumns();
 202  0
             List<Column> newColumns = new ArrayList<Column>();
 203  0
             List<KeyValueSort> keyValues = docSearchResult.getResultContainers();
 204  0
             for (int i = 0; i < origColumns.size(); i++) {
 205  
 
 206  0
                       Column col = (Column) origColumns.get(i);
 207  0
                       KeyValueSort keyValue = null;
 208  0
                       for (KeyValueSort keyValueFromList : keyValues) {
 209  0
                               if(StringUtils.equals(col.getPropertyName(), keyValueFromList.getKey())) {
 210  0
                                       keyValue = keyValueFromList;
 211  0
                                       break;
 212  
                               }
 213  
                       }
 214  0
                       if(keyValue==null) {
 215  
                               //means we didn't find an indexed value for this, this seems bad but happens a lot we should research why
 216  0
                               keyValue = new KeyValueSort();
 217  
                       }
 218  
 
 219  
                       //Set values from keyvalue on column
 220  0
                       col.setPropertyValue(keyValue.getUserDisplayValue());
 221  
 
 222  0
                       String propertyName = col.getPropertyName();
 223  0
                                 if(StringUtils.isEmpty(col.getColumnTitle())) {
 224  
                               String labelMessageKey;
 225  0
                               if(StringUtils.equals(propertyName,KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG)) {
 226  
                                       //TODO: find a better place for this
 227  0
                                       labelMessageKey = "Route Log";
 228  
                               } else {
 229  
                                       //TODO: change this to an enum (or another dd property)
 230  0
                                       propertyName=(StringUtils.equals(propertyName,"docTypeLabel"))?"docTypeFullName":propertyName;
 231  0
                                       propertyName=(StringUtils.equals(propertyName,"docRouteStatusCodeDesc"))?"docRouteStatus":propertyName;
 232  0
                                       propertyName=(StringUtils.equals(propertyName,"documentTitle"))?"docTitle":propertyName;
 233  0
                                       labelMessageKey = getDataDictionaryService().getAttributeLabel(DocSearchCriteriaDTO.class,propertyName);
 234  
                               }
 235  0
                               col.setColumnTitle(labelMessageKey);
 236  
                       }
 237  
 
 238  0
                                 if(StringUtils.equals(propertyName, KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_DOCUMENT_ID)) {
 239  0
                                         ((DocSearchCriteriaDTO)element).setDocumentId(col.getPropertyValue());
 240  
                                 }
 241  
 
 242  0
                     Formatter formatter = col.getFormatter();
 243  
 
 244  
                 // pick off result column from result list, do formatting
 245  0
                 String propValue = KRADConstants.EMPTY_STRING;
 246  0
                 Object prop=keyValue.getSortValue();
 247  
 
 248  
                 // set comparator and formatter based on property type
 249  0
                 Class propClass = propertyTypes.get(propertyName);
 250  0
                 if ( propClass == null ) {
 251  
                     try {
 252  0
                             if(prop!=null) {
 253  0
                                     propertyTypes.put(propertyName, prop.getClass());
 254  0
                                     propClass = prop.getClass();
 255  
                             }
 256  
 
 257  0
                     } catch (Exception e) {
 258  
                         // TODO why are we eating this?
 259  0
                     }
 260  
                 }
 261  
 
 262  
 
 263  
                 //TODO: check exisiting formatter here, ideally we should be getting this formatter from col.getFormatter in most cases
 264  
                 // formatters
 265  0
                 if (prop != null) {
 266  0
                     if (formatter == null) {
 267  
                         // for Booleans, always use BooleanFormatter
 268  0
                         if (prop instanceof Boolean) {
 269  0
                             formatter = new BooleanFormatter();
 270  
                         }
 271  
 
 272  
                         // for Dates, always use DateFormatter
 273  0
                         if (prop instanceof Date) {
 274  0
                             formatter = new DateFormatter();
 275  
                         }
 276  
                         //#ADDED 3
 277  0
                         if (prop instanceof Timestamp) {
 278  0
                             formatter = new TimestampAMPMFormatter();
 279  
                         }
 280  
 
 281  
                         // for collection, use the list formatter if a formatter hasn't been defined yet
 282  0
                         if (prop instanceof Collection && formatter == null) {
 283  0
                             formatter = new CollectionFormatter();
 284  
                         }
 285  
                     }
 286  0
                     if (formatter != null) {
 287  
                         //hack for Currency values as big decimal
 288  0
                         if (prop instanceof BigDecimal  && formatter.getImplementationClass().equals("org.kuali.rice.krad.web.format.CurrencyFormatter")) {
 289  0
                             prop = new KualiDecimal((BigDecimal)prop);
 290  0
                         } else if (prop instanceof BigDecimal  && formatter.getImplementationClass().equals("org.kuali.rice.krad.web.format.PercentageFormatter")) {
 291  0
                             prop = new KualiPercent((BigDecimal)prop);
 292  
                         }
 293  0
                          propValue = (String) formatter.format(prop);
 294  
                     }
 295  
                     else {
 296  0
                         propValue = prop.toString();
 297  
                     }
 298  
                 }
 299  
 
 300  
                 // comparator
 301  0
                 col.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(propClass));
 302  0
                 col.setValueComparator(CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(propClass));
 303  
 
 304  
                 //TODO: can we call into a method in the result processor to get this (or set something on the criteria)
 305  
 //                propValue = maskValueIfNecessary(element.getClass(), col.getPropertyName(), propValue, businessObjectRestrictions);
 306  
 
 307  0
                 col.setPropertyValue(propValue);
 308  
 
 309  0
                 if (StringUtils.isNotBlank(propValue)) {
 310  
 //                    col.setColumnAnchor(getInquiryUrl(element, col.getPropertyName()));
 311  
 //ADDED (3 lines)
 312  0
                         HtmlData.AnchorHtmlData anchor = new HtmlData.AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING);
 313  
                         //TODO: change to grab URL from config variable
 314  0
                         if(StringUtils.isNotEmpty(keyValue.getValue()) && StringUtils.equals("documentId", keyValue.getKey())) {
 315  0
                             String target = StringUtils.substringBetween(keyValue.getValue(), "target=\"", "\"");
 316  0
                             if (target == null) {
 317  0
                                 target = "_self";
 318  
                             }
 319  0
                             anchor.setTarget(target.trim());
 320  0
                                 if(!DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equals(criteria.getSuperUserSearch())) {
 321  0
                                         anchor.setHref(".."+KEWConstants.WEBAPP_DIRECTORY+"/"+StringUtils.substringBetween(keyValue.getValue(), "<a href=\"", "docId=")+"docId="+keyValue.getUserDisplayValue());
 322  
                                 } else {
 323  
                                         // KULRICE-3035: Append the doc search's returnLocation parameter to the superuser page URL.
 324  0
                                                     String returnLoc = "";
 325  0
                                                     if (this.getParameters().containsKey(KRADConstants.RETURN_LOCATION_PARAMETER)) {
 326  0
                                                             returnLoc = (new StringBuilder()).append("&").append(KRADConstants.RETURN_LOCATION_PARAMETER).append("=").append(
 327  
                                                                             ((String[])this.getParameters().get(KRADConstants.RETURN_LOCATION_PARAMETER))[0]).toString();
 328  
                                                     }
 329  0
                                                     else if (StringUtils.isNotBlank(this.getBackLocation())) {
 330  0
                                                             returnLoc = (new StringBuilder()).append("&").append(KRADConstants.RETURN_LOCATION_PARAMETER).append("=").append(
 331  
                                                                             this.getBackLocation()).toString();
 332  
                                                     }
 333  
 
 334  0
                                         anchor.setHref(".."+KEWConstants.WEBAPP_DIRECTORY+"/"+StringUtils.substringBetween(keyValue.getValue(), "<a href=\"", "documentId=")+"documentId="+keyValue.getUserDisplayValue() + returnLoc);
 335  
                                 }
 336  0
                         col.setMaxLength(100); //for now force this
 337  0
                         } else if(StringUtils.isNotEmpty(keyValue.getValue()) && StringUtils.equals(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG, keyValue.getKey())) {
 338  0
                                 Matcher hrefMatcher = HREF_PATTERN.matcher(keyValue.getValue());
 339  0
                                 String matchedURL = "";
 340  0
                                 if (hrefMatcher.find()) {
 341  0
                                         matchedURL = hrefMatcher.group(1);
 342  
                                 }
 343  0
                                 anchor.setHref(".."+KEWConstants.WEBAPP_DIRECTORY+"/"+matchedURL);
 344  0
                                 String target = StringUtils.substringBetween(keyValue.getValue(), "target=\"", "\"");
 345  0
                         if (target == null) {
 346  0
                             target = "_self";
 347  
                         }
 348  0
                         anchor.setTarget(target.trim());
 349  0
                                 col.setMaxLength(100); //for now force this
 350  0
                         keyValue.setValue(keyValue.getUserDisplayValue());
 351  0
                         col.setEscapeXMLValue(false);
 352  0
                         } else if (StringUtils.isNotEmpty(keyValue.getValue()) && StringUtils.equals(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_INITIATOR, keyValue.getKey())) {
 353  0
                                 anchor.setHref(StringUtils.substringBetween(keyValue.getValue(), "<a href=\"", "\" target=\"_blank\""));
 354  0
                                 col.setMaxLength(100); //for now force this
 355  
                         }
 356  
 
 357  0
                         col.setColumnAnchor(anchor);
 358  
 
 359  
                 }
 360  0
                 Column newCol = (Column)ObjectUtils.deepCopy(col);
 361  0
                 newColumns.add(newCol);
 362  
 
 363  
             }
 364  
 
 365  0
             HtmlData returnUrl = getReturnUrl(element, lookupForm, returnKeys, businessObjectRestrictions);
 366  0
             ResultRow row = new ResultRow(newColumns, returnUrl.constructCompleteHtmlTag(), actionUrls);
 367  0
             row.setRowId(returnUrl.getName());
 368  
             // because of concerns of the BO being cached in session on the ResultRow,
 369  
             // let's only attach it when needed (currently in the case of export)
 370  0
             if (getBusinessObjectDictionaryService().isExportable(getBusinessObjectClass())) {
 371  
                     //                    row.setBusinessObject(element);
 372  
             }
 373  
 
 374  
             //            boolean rowReturnable = isResultReturnable(element);
 375  
             //ADDED
 376  0
             boolean rowReturnable = true;
 377  0
             row.setRowReturnable(rowReturnable);
 378  0
             if (rowReturnable) {
 379  0
                     hasReturnableRow = true;
 380  
             }
 381  0
             resultTable.add(row);
 382  0
         }
 383  
 
 384  
 
 385  0
         lookupForm.setHasReturnableRow(hasReturnableRow);
 386  
 
 387  0
         return displayList;
 388  
                 //####END COPIED CODE#########
 389  
         }
 390  
 
 391  
 
 392  
 
 393  
 
 394  
 
 395  
         /**
 396  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#getInquiryUrl(org.kuali.rice.krad.bo.BusinessObject, java.lang.String)
 397  
          */
 398  
         @Override
 399  
         public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
 400  
                 //FIXME: ctk - make sure and check that it's ok to do this here.  I may move this out to the doc search processor
 401  0
                 if(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_DOCUMENT_ID.equals(propertyName)) {
 402  
 
 403  0
                         HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
 404  0
                         DocumentRouteHeaderValue doc = (DocumentRouteHeaderValue)bo;
 405  
                         //if !superuser
 406  0
                         String documentId = doc.getDocumentId();
 407  0
                         link.setDisplayText(documentId+"");
 408  
 
 409  0
                         String href = ConfigContext.getCurrentContextConfig().getKRBaseURL()+"/"+ KEWConstants.APP_CODE + "/" +
 410  
                         KEWConstants.DOC_HANDLER_REDIRECT_PAGE + "?" + KEWConstants.COMMAND_PARAMETER + "=" +
 411  
                         KEWConstants.DOCSEARCH_COMMAND + "&" + KEWConstants.DOCUMENT_ID_PARAMETER + "=" + documentId;
 412  
 
 413  0
                         link.setHref(href);
 414  
 
 415  0
                         return link;
 416  
                 }
 417  
 
 418  0
                 return super.getInquiryUrl(bo, propertyName);
 419  
         }
 420  
 
 421  
 
 422  
         /**
 423  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#setRows()
 424  
          */
 425  
         @Override
 426  
         protected void setRows() {
 427  0
             this.setRows(new HashMap<String,String[]>(), null);
 428  0
         }
 429  
 
 430  
 
 431  
         /**
 432  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#setRows()
 433  
          */
 434  
         protected void setRows(Map fieldValues, String docTypeName) {
 435  
                 // TODO chris - this method should call the criteria processor adapter which will
 436  
                 //call the criteria processor (either standard or custom) and massage the data into the proper format
 437  
                 //this is called by setbo in super(which is called by form) so should be called when the page needs refreshing
 438  
 
 439  
                 //TODO: move over code that checks for doctype (actually should that be in the refresh, since that's where the doc type will be coming back to?)
 440  
 
 441  
 
 442  
                 //###START LOOKUP ROW CODE Not sure if we need these but they may be valuable for eventually forcing all standard field customization in the xml
 443  0
                 if (getRows() == null) {
 444  0
                     super.setRows();
 445  
                 }
 446  0
                 List<Row> lookupRows = new ArrayList<Row>();
 447  
                 //copy the current rows
 448  0
                 for (Row row : getRows()) {
 449  0
                         lookupRows.add(row);
 450  
                 }
 451  
                 //clear out
 452  0
                 getRows().clear();
 453  
 
 454  0
                 DocumentType docType = null;
 455  
 
 456  0
                 if(StringUtils.isNotEmpty(docTypeName)) {
 457  0
                         docType = getValidDocumentType((String)docTypeName);
 458  
                 }
 459  
 
 460  0
                 boolean detailed=false;
 461  0
                 if(this.getParameters().containsKey("isAdvancedSearch")) {
 462  0
                         detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("isAdvancedSearch"))[0]);
 463  0
                 } else if(fieldValues.containsKey("isAdvancedSearch")) {
 464  0
                         detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String) fieldValues.get("isAdvancedSearch"));
 465  
                 }
 466  
 
 467  0
                 boolean superSearch=false;
 468  0
                 if(this.getParameters().containsKey(("superUserSearch"))) {
 469  0
                         superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("superUserSearch"))[0]);
 470  0
                 } else if(fieldValues.containsKey("superUserSearch")) {
 471  0
                         superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String)fieldValues.get("superUserSearch"));
 472  
                 }
 473  
 
 474  
                 //call get rows
 475  0
                 List<Row> rows = getDocumentLookupCriteriaProcessor().getRows(docType,lookupRows, detailed, superSearch);
 476  
 
 477  0
                 BusinessObjectEntry boe = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(this.getBusinessObjectClass().getName());
 478  0
         int numCols = boe.getLookupDefinition().getNumOfColumns();
 479  0
         if(numCols == 0) {
 480  0
                         numCols = KRADConstants.DEFAULT_NUM_OF_COLUMNS;
 481  
                 }
 482  
 
 483  0
                 super.getRows().addAll(FieldUtils.wrapFields(this.getFields(rows), numCols));
 484  
 
 485  0
         }
 486  
 
 487  
          private List<Field> getFields(List<Row> rows){
 488  0
                     List<Field> rList = new ArrayList<Field>();
 489  
 
 490  0
                     for(Row r: rows){
 491  0
                             for(Field f: r.getFields()){
 492  0
                                     rList.add(f);
 493  
                             }
 494  
                     }
 495  
 
 496  0
                     return rList;
 497  
             }
 498  
 
 499  
            private void setRowsAfterClear(DocSearchCriteriaDTO searchCriteria, Map<String,String[]> fieldValues) {
 500  
                 // TODO chris - this method should call the criteria processor adapter which will
 501  
                 //call the criteria processor (either standard or custom) and massage the data into the proper format
 502  
                 //this is called by setbo in super(which is called by form) so should be called when the page needs refreshing
 503  
 
 504  
                 //TODO: move over code that checks for doctype (actually should that be in the refresh, since that's where the doc type will be coming back to?)
 505  0
                if (getRows() == null) {
 506  0
                     super.setRows();
 507  
                 }
 508  0
                List<Row> lookupRows = new ArrayList<Row>();
 509  
                 //copy the current rows
 510  0
                 for (Row row : getRows()) {
 511  0
                     lookupRows.add(row);
 512  
                 }
 513  0
                 super.getRows().clear();
 514  
 
 515  0
                 String docTypeName = searchCriteria.getDocTypeFullName();
 516  0
                 DocumentType docType = null;
 517  
 
 518  0
                 if(StringUtils.isNotEmpty(docTypeName)) {
 519  0
                     docType = getValidDocumentType(docTypeName);
 520  
                 }
 521  
 
 522  0
                 boolean detailed=false;
 523  0
                 if(this.getParameters().containsKey("isAdvancedSearch")) {
 524  0
                     detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("isAdvancedSearch"))[0]);
 525  0
                 } else if(fieldValues.containsKey("isAdvancedSearch")) {
 526  0
                     detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String) fieldValues.get("isAdvancedSearch")[0]);
 527  
                 }
 528  
 
 529  0
                 boolean superSearch=false;
 530  0
                 if(this.getParameters().containsKey(("superUserSearch"))) {
 531  0
                     superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("superUserSearch"))[0]);
 532  0
                 } else if(fieldValues.containsKey("superUserSearch")) {
 533  0
                     superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String)fieldValues.get("superUserSearch")[0]);
 534  
                 }
 535  
                 //call get rows
 536  0
                 List<Row> rows = getDocumentLookupCriteriaProcessor().getRows(docType, super.getRows(), detailed, superSearch);
 537  
 
 538  0
                 super.getRows().addAll(rows);
 539  
 
 540  
                 //Set field values from DocSearchCriteria
 541  0
                 if(StringUtils.isNotEmpty(docTypeName)) {
 542  0
                     for (Row row : super.getRows()) {
 543  0
                         for (Field field : row.getFields()) {
 544  
                             //if from date, strip off prefix
 545  0
                             String propertyName = null;
 546  0
                             if(field.getPropertyName().startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 547  0
                                 propertyName = StringUtils.remove(field.getPropertyName(), KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
 548  
                             } else {
 549  0
                                 propertyName = field.getPropertyName();
 550  
                             }
 551  
                             //We don't need to set field if it was already empty
 552  0
                             if (fieldValues.get(propertyName) != null) {
 553  0
                                 Object value = this.getDocSearchCriteriaDTOFieldValue(searchCriteria, field.getPropertyName());
 554  0
                                 if (value instanceof String
 555  
                                         && StringUtils.isNotEmpty((String)value)) {
 556  0
                                     field.setPropertyValue(value);
 557  0
                                 } else if (value instanceof List){
 558  0
                                     field.setPropertyValues((String[])((List)value).toArray());
 559  
                                 }
 560  
                             }
 561  0
                         }
 562  
                     }
 563  
                 }
 564  0
             }
 565  
 
 566  
 
 567  
         /**
 568  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#performClear()
 569  
          */
 570  
         @Override
 571  
         public void performClear(LookupForm lookupForm) {
 572  
                 //Map<String,String[]> fieldsToClear = new HashMap<String,String[]>();
 573  
 
 574  
                 //for (Row row : this.getRows()) {
 575  
                 //        for (Field field : row.getFields()) {
 576  
                 //                String[] propertyValue = {};
 577  
                 //                if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 578  
                 //                        propertyValue = new String[]{field.getPropertyValue()};
 579  
                 //                } else {
 580  
                 //                        propertyValue = field.getPropertyValues();
 581  
                 //                }
 582  
                 //                fieldsToClear.put(field.getPropertyName(), propertyValue);
 583  
                 //        }
 584  
                 //}
 585  
 
 586  0
             Map<String,String[]> fixedParameters = new HashMap<String,String[]>();
 587  0
         Map<String,String> changedDateFields = preprocessDateFields(lookupForm.getFieldsForLookup());
 588  0
         fixedParameters.putAll(this.getParameters());
 589  0
         for (Map.Entry<String,String> prop : changedDateFields.entrySet()) {
 590  0
             fixedParameters.remove(prop.getKey());
 591  0
             fixedParameters.put(prop.getKey(), new String[]{prop.getValue()});
 592  
         }
 593  
                 //TODO: also check if standard here (maybe from object if use criteria)
 594  0
                 String docTypeName = fixedParameters.get("docTypeFullName")[0];
 595  
 
 596  0
                 DocumentType docType = getValidDocumentType(docTypeName);
 597  
 
 598  0
                 if(docType == null) {
 599  0
                     super.performClear(lookupForm);
 600  
 
 601  
                     // Retrieve the detailed/superuser search statuses.
 602  0
                 boolean detailed=false;
 603  0
                 if(this.getParameters().containsKey("isAdvancedSearch")) {
 604  0
                     detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("isAdvancedSearch"))[0]);
 605  0
                 } else if(fixedParameters.containsKey("isAdvancedSearch")) {
 606  0
                     detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String) fixedParameters.get("isAdvancedSearch")[0]);
 607  
                 }
 608  
 
 609  0
                 boolean superSearch=false;
 610  0
                 if(this.getParameters().containsKey(("superUserSearch"))) {
 611  0
                     superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("superUserSearch"))[0]);
 612  0
                 } else if(fixedParameters.containsKey("superUserSearch")) {
 613  0
                     superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase((String) fixedParameters.get("superUserSearch")[0]);
 614  
                 }
 615  
 
 616  
                 // Repopulate the fields indicating detailed/superuser search status.
 617  0
                 int fieldsRepopulated = 0;
 618  0
                 List<Row> rows = super.getRows();
 619  0
                 int index = rows.size() - 1;
 620  0
                 while (index >= 0 && fieldsRepopulated < 2) {
 621  0
                         for (Field tempField : rows.get(index).getFields()) {
 622  0
                                 if ("isAdvancedSearch".equals(tempField.getPropertyName())) {
 623  0
                                         tempField.setPropertyValue(detailed?"YES":"NO");
 624  0
                                         fieldsRepopulated++;
 625  
                                 }
 626  0
                                 else if ("superUserSearch".equals(tempField.getPropertyName())) {
 627  0
                                         tempField.setPropertyValue(superSearch?"YES":"NO");
 628  0
                                         fieldsRepopulated++;
 629  
                                 }
 630  
                         }
 631  0
                         index--;
 632  
                 }
 633  0
                 } else {
 634  0
                     DocSearchCriteriaDTO docCriteria = DocumentLookupCriteriaBuilder.populateCriteria(fixedParameters);
 635  0
                     docCriteria = docType.getDocumentSearchGenerator().clearSearch(docCriteria);
 636  0
             if (docCriteria == null) {
 637  0
                 docCriteria = new DocSearchCriteriaDTO();
 638  
             }
 639  
 
 640  0
             this.setRowsAfterClear(docCriteria, fixedParameters);
 641  
                 }
 642  
 
 643  0
         }
 644  
         /**
 645  
          *
 646  
          * retrieve a document type. This is not a case sensitive search so "TravelRequest" == "Travelrequest"
 647  
          *
 648  
          * @param docTypeName
 649  
          * @return
 650  
          */
 651  
     private static DocumentType getValidDocumentType(String docTypeName) {
 652  0
             if (StringUtils.isNotEmpty(docTypeName)) {
 653  0
             DocumentType dTypeCriteria = new DocumentType();
 654  0
                     dTypeCriteria.setName(docTypeName.trim());
 655  0
                     dTypeCriteria.setActive(true);
 656  0
                     Collection<DocumentType> docTypeList = KEWServiceLocator.getDocumentTypeService().find(dTypeCriteria, null, false);
 657  
 
 658  
                     // Return the first valid doc type.
 659  0
                     DocumentType firstDocumentType = null;
 660  0
                     if(docTypeList != null){
 661  0
                             for(DocumentType dType: docTypeList){
 662  0
                                 if (firstDocumentType == null) {
 663  0
                                     firstDocumentType = dType;
 664  
                                 }
 665  0
                                 if (StringUtils.equals(docTypeName.toUpperCase(), dType.getName().toUpperCase())) {
 666  0
                                     return dType;
 667  
                                 }
 668  
                             }
 669  0
                             return firstDocumentType;
 670  
                     }
 671  
             }
 672  
 
 673  0
             return null;
 674  
     }
 675  
 
 676  
 
 677  
         /**
 678  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#getSupplementalMenuBar()
 679  
          */
 680  
         @Override
 681  
         public String getSupplementalMenuBar() {
 682  0
                 boolean detailed = false;
 683  0
                 if(this.getParameters().containsKey("isAdvancedSearch")) {
 684  0
                         detailed = DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("isAdvancedSearch"))[0]);
 685  
                 }
 686  
 
 687  0
                 boolean superSearch = false;
 688  0
                 if(this.getParameters().containsKey("superUserSearch")) {
 689  0
                         superSearch = DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING.equalsIgnoreCase(((String[])this.getParameters().get("superUserSearch"))[0]);
 690  
                 }
 691  
 
 692  0
                 StringBuilder suppMenuBar = new StringBuilder();
 693  
 
 694  
                 // Add the detailed-search-toggling button.
 695  0
                 suppMenuBar.append("<input type=\"image\" name=\"methodToCall.customLookupableMethodCall.(((").append(detailed ? "NO" : DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING).append("))).((`").append(superSearch ? DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING : "NO").append(
 696  
                                 "`))\" class=\"tinybutton\" src=\"..").append(KEWConstants.WEBAPP_DIRECTORY).append(detailed ? "/images/tinybutton-basicsearch.gif\" alt=\"basic search\" title=\"basic search\" />" : "/images/tinybutton-detailedsearch.gif\" alt=\"detailed search\" title=\"detailed search\" />");
 697  
 
 698  
                 // Add the superuser-search-toggling button.
 699  0
                 suppMenuBar.append("&nbsp;").append("<input type=\"image\" name=\"methodToCall.customLookupableMethodCall.(((").append((!detailed && superSearch) ? "NO" : DocSearchCriteriaDTO.ADVANCED_SEARCH_INDICATOR_STRING).append("))).((`").append(superSearch ? "NO" : DocSearchCriteriaDTO.SUPER_USER_SEARCH_INDICATOR_STRING).append(
 700  
                                 "`))\" class=\"tinybutton\" src=\"..").append(KEWConstants.WEBAPP_DIRECTORY).append(superSearch ? "/images/tinybutton-nonsupusearch.gif\" alt=\"non-superuser search\" title=\"non-superuser search\" />" : "/images/tinybutton-superusersearch.gif\" alt=\"superuser search\" title=\"superuser search\" />");
 701  
 
 702  
                 // Add the "clear saved searches" button.
 703  0
                 suppMenuBar.append("&nbsp;").append("<input type=\"image\" name=\"methodToCall.customLookupableMethodCall.(([true]))\" class=\"tinybutton\" src=\"..").append(KEWConstants.WEBAPP_DIRECTORY).append("/images/tinybutton-clearsavedsearch.gif\" alt=\"clear saved searches\" title=\"clear saved searches\" />");
 704  
 
 705  0
         Properties parameters = new Properties();
 706  0
         parameters.put(KRADConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, this.getBusinessObjectClass().getName());
 707  0
         this.getParameters().keySet();
 708  0
         for (Object parameter : this.getParameters().keySet()) {
 709  0
                         parameters.put(parameter, this.getParameters().get(parameter));
 710  
                 }
 711  
 
 712  0
                 UrlFactory.parameterizeUrl(KRADConstants.LOOKUP_ACTION, parameters);
 713  0
                 return suppMenuBar.toString();
 714  
         }
 715  
 
 716  
 //    /**
 717  
 //     * This method is called by performLookup method to generate supplemental action urls.
 718  
 //     * It calls the method getCustomActionUrls to get html data, calls getMaintenanceUrl to get the actual html tag,
 719  
 //     * and returns a formatted/concatenated string of action urls.
 720  
 //     *
 721  
 //     * @see org.kuali.core.lookup.LookupableHelperService#getActionUrls(org.kuali.core.bo.BusinessObject)
 722  
 //     */
 723  
 //    public String getSupplementalActionUrls(List<HtmlData> htmlDataList) {
 724  
 //        StringBuffer actions = new StringBuffer();
 725  
 //
 726  
 //        for(HtmlData htmlData: htmlDataList){
 727  
 //                actions.append(getMaintenanceUrl(businessObject, htmlData, pkNames, businessObjectRestrictions));
 728  
 //            if(htmlData.getChildUrlDataList()!=null){
 729  
 //                    if(htmlData.getChildUrlDataList().size()>0){
 730  
 //                    actions.append(ACTION_URLS_CHILDREN_STARTER);
 731  
 //                            for(HtmlData childURLData: htmlData.getChildUrlDataList()){
 732  
 //                                actions.append(getMaintenanceUrl(businessObject, childURLData, pkNames, businessObjectRestrictions));
 733  
 //                            actions.append(ACTION_URLS_CHILDREN_SEPARATOR);
 734  
 //                            }
 735  
 //                            if(actions.toString().endsWith(ACTION_URLS_CHILDREN_SEPARATOR))
 736  
 //                                    actions.delete(actions.length()-ACTION_URLS_CHILDREN_SEPARATOR.length(), actions.length());
 737  
 //                    actions.append(ACTION_URLS_CHILDREN_END);
 738  
 //                    }
 739  
 //            }
 740  
 //                actions.append(ACTION_URLS_SEPARATOR);
 741  
 //        }
 742  
 //        if(actions.toString().endsWith(ACTION_URLS_SEPARATOR))
 743  
 //                actions.delete(actions.length()-ACTION_URLS_SEPARATOR.length(), actions.length());
 744  
 //        return actions.toString();
 745  
 //    }
 746  
 
 747  
         /**
 748  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#shouldDisplayHeaderNonMaintActions()
 749  
          */
 750  
         @Override
 751  
         public boolean shouldDisplayHeaderNonMaintActions() {
 752  0
                 return getDocumentLookupCriteriaProcessor().shouldDisplayHeaderNonMaintActions();
 753  
         }
 754  
 
 755  
 
 756  
         /**
 757  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#shouldDisplayLookupCriteria()
 758  
          */
 759  
         @Override
 760  
         public boolean shouldDisplayLookupCriteria() {
 761  0
                 return getDocumentLookupCriteriaProcessor().shouldDisplayLookupCriteria();
 762  
         }
 763  
 
 764  
 
 765  
         /**
 766  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#checkForAdditionalFields(java.util.Map)
 767  
          */
 768  
         @Override
 769  
         public boolean checkForAdditionalFields(Map fieldValues) {
 770  
                 // TODO chris - THIS METHOD NEEDS JAVADOCS
 771  
 //                return super.checkForAdditionalFields(fieldValues);
 772  0
                 String docTypeName = null;
 773  0
                 if(this.getParameters().get("docTypeFullName")!=null) {
 774  0
                         docTypeName = ((String[])this.getParameters().get("docTypeFullName"))[0];
 775  
                 }
 776  0
                 else if(fieldValues.get("docTypeFullName")!=null) {
 777  0
                         docTypeName = (String)fieldValues.get("docTypeFullName");
 778  
                 }
 779  0
                 if(!StringUtils.isEmpty(docTypeName)) {
 780  0
                     DocumentType dType = getValidDocumentType(docTypeName);
 781  
 
 782  0
             DocSearchCriteriaDTO criteria = DocumentLookupCriteriaBuilder.populateCriteria(getParameters());
 783  0
             if (dType != null) {
 784  0
                     MessageMap messages = getValidDocumentType(dType.getName()).getDocumentSearchGenerator().getMessageMap(criteria);
 785  0
                     if (messages != null
 786  
                             && messages.hasMessages()) {
 787  0
                         GlobalVariables.mergeErrorMap(messages);
 788  
                     }
 789  0
                     setRows(fieldValues,dType.getName());
 790  0
                     return true;
 791  
             }
 792  
         }
 793  
 
 794  0
                 setRows(fieldValues, docTypeName);
 795  
 
 796  0
                 return true;
 797  
         }
 798  
 
 799  
         /**
 800  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#validateSearchParameters(java.util.Map)
 801  
          */
 802  
         @Override
 803  
     public void validateSearchParameters(Map fieldValues) {
 804  0
         super.validateSearchParameters(fieldValues);
 805  0
         DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService();
 806  0
         DocSearchCriteriaDTO criteria = DocumentLookupCriteriaBuilder.populateCriteria(getParameters());
 807  0
         DocumentType docType = null;
 808  0
         if(StringUtils.isNotEmpty(criteria.getDocTypeFullName())) {
 809  0
                         docType = getValidDocumentType((String)criteria.getDocTypeFullName());
 810  
                 }
 811  0
         DocumentSearchGenerator generator=null;
 812  0
         if(docType!=null) {
 813  0
                 generator = docType.getDocumentSearchGenerator();
 814  
         } else {
 815  0
                 generator = KEWServiceLocator.getDocumentSearchService().getStandardDocumentSearchGenerator();
 816  
         }
 817  
         try {
 818  0
                 docSearchService.validateDocumentSearchCriteria(generator, criteria);
 819  0
                 } catch (WorkflowServiceErrorException wsee) {
 820  0
                         for (WorkflowServiceError workflowServiceError : (List<WorkflowServiceError>)wsee.getServiceErrors()) {
 821  0
                                 if(workflowServiceError.getMessageMap() != null && workflowServiceError.getMessageMap().hasErrors()){
 822  
                                         // merge the message maps
 823  0
                                         GlobalVariables.getMessageMap().merge(workflowServiceError.getMessageMap());
 824  
                                 }else{
 825  
                                         //TODO: can we add something to this to get it to highlight the right field too?  Maybe in arg1
 826  0
                                         GlobalVariables.getMessageMap().putError(workflowServiceError.getMessage(), RiceKeyConstants.ERROR_CUSTOM, workflowServiceError.getMessage());
 827  
                                 }
 828  
                         };
 829  0
                 }
 830  0
         if(!GlobalVariables.getMessageMap().hasNoErrors()) {
 831  0
                 throw new ValidationException("errors in search criteria");
 832  
         }
 833  
 
 834  0
     }
 835  
 
 836  
 
 837  
         /**
 838  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#performCustomAction(boolean)
 839  
          */
 840  
         @Override
 841  
         public boolean performCustomAction(boolean ignoreErrors) {
 842  0
                 DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService();
 843  
 
 844  0
                 Map<String,String> fieldValues = new HashMap<String,String>();
 845  0
                 Map<String,String[]> multFieldValues = new HashMap<String,String[]>();
 846  
 
 847  
                 // Determine if there are any properties embedded in the methodToCall parameter, and retrieve them if so.
 848  0
                 String[] methodToCallArray = ((String[])this.getParameters().get(
 849  
                 KRADConstants.DISPATCH_REQUEST_PARAMETER + ".customLookupableMethodCall"));
 850  0
                 if (methodToCallArray == null) {
 851  0
                     for (String parameter: new ArrayList<String>(this.getParameters().keySet())) {
 852  0
                         String[] parameterSplit = StringUtils.split(parameter, ".");
 853  0
                         String parameterValue = "";
 854  0
                         if (StringUtils.contains(parameter, KRADConstants.DISPATCH_REQUEST_PARAMETER + ".customLookupableMethodCall.")) {
 855  0
                             if (parameter.trim().endsWith(".x")) {
 856  0
                                 parameterValue = StringUtils.substringBetween(parameter, KRADConstants.DISPATCH_REQUEST_PARAMETER + ".customLookupableMethodCall.", ".x");
 857  0
                             } else if (parameter.trim().endsWith(".y")) {
 858  0
                                 parameterValue = StringUtils.substringBetween(parameter, KRADConstants.DISPATCH_REQUEST_PARAMETER + ".customLookupableMethodCall.", ".y");
 859  
                             } 
 860  0
                             if (StringUtils.isNotEmpty(parameterValue)) {
 861  0
                                 methodToCallArray = new String[]{ parameterValue };
 862  0
                             break;
 863  
                             }
 864  
                         }
 865  0
                     }
 866  
                 }
 867  
                 //String[] methodToCallArray = ((String[])this.getParameters().get(KRADConstants.DISPATCH_REQUEST_PARAMETER + ".customLookupableMethodCall"));
 868  0
                 if (ObjectUtils.isNotNull(methodToCallArray) && methodToCallArray.length > 0) {
 869  0
                         String methodToCallVal = methodToCallArray[0];
 870  0
                         if (StringUtils.isNotBlank(methodToCallVal)) {
 871  0
                                 boolean resetRows = false;
 872  
                                 // Retrieve the isAdvancedSearch property, if present.
 873  0
                                 String advancedSearchVal = StringUtils.substringBetween(methodToCallVal, KRADConstants.METHOD_TO_CALL_PARM1_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM1_RIGHT_DEL);
 874  0
                                 if (StringUtils.isNotBlank(advancedSearchVal)) {
 875  0
                                         if (this.getParameters().containsKey("isAdvancedSearch")) {
 876  0
                                                 ((String[]) this.getParameters().get("isAdvancedSearch"))[0] = advancedSearchVal;
 877  
                                         }
 878  
                                         else {
 879  0
                                                 fieldValues.put("isAdvancedSearch", advancedSearchVal);
 880  
                                         }
 881  0
                                         resetRows = true;
 882  
                                 }
 883  
                                 // Retrieve the superUserSearch property, if present.
 884  0
                                 String superUserSearchVal = StringUtils.substringBetween(methodToCallVal, KRADConstants.METHOD_TO_CALL_PARM2_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM2_RIGHT_DEL);
 885  0
                                 if (StringUtils.isNotBlank(superUserSearchVal)) {
 886  0
                                         if (this.getParameters().containsKey("superUserSearch")) {
 887  0
                                                 ((String[]) this.getParameters().get("superUserSearch"))[0] = superUserSearchVal;
 888  
                                         } else {
 889  0
                                                 fieldValues.put("superUserSearch", superUserSearchVal);
 890  
                                         }
 891  0
                                         resetRows = true;
 892  
                                 }
 893  
                                 // Retrieve and act upon the resetSavedSearch property, if present and set to true.
 894  0
                                 String resetSavedSearchVal = StringUtils.substringBetween(methodToCallVal, KRADConstants.METHOD_TO_CALL_PARM4_LEFT_DEL, KRADConstants.METHOD_TO_CALL_PARM4_RIGHT_DEL);
 895  0
                                 if (Boolean.parseBoolean(resetSavedSearchVal)) {
 896  0
                                         docSearchService.clearNamedSearches(GlobalVariables.getUserSession().getPrincipalId());
 897  0
                                         resetRows = true;
 898  
                                 }
 899  
 
 900  
                                 // If any of the above properties were found, reset the rows in a manner similar to KualiLookupAction.refresh, but with
 901  
                                 // enough modifications to prevent any changed isAdvancedSearch or superUserSearch values from being overridden again.
 902  0
                                 if (resetRows) {
 903  0
                                         Map<String,String> values = new HashMap<String,String>();
 904  0
                                         for (Field tempField : getFields(this.getRows())) {
 905  0
                                                 values.put(tempField.getPropertyName(), tempField.getPropertyValue());
 906  
                                         }
 907  
 
 908  0
                                 for (Row row : this.getRows()) {
 909  0
                                         for (Field field : row.getFields()) {
 910  0
                                                 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
 911  0
                                                         if (this.getParameters().get(field.getPropertyName()) != null) {
 912  0
                                                                 if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 913  0
                                                                         field.setPropertyValue(((String[])this.getParameters().get(field.getPropertyName()))[0]);
 914  
                                                                 } else {
 915  
                                                                         //multi value, set to values
 916  0
                                                                         field.setPropertyValues((String[])this.getParameters().get(field.getPropertyName()));
 917  
                                                                 }
 918  
                                                         }
 919  
                                                 }
 920  0
                                                 else if (values.get(field.getPropertyName()) != null) {
 921  0
                                                         field.setPropertyValue(values.get(field.getPropertyName()));
 922  
                                                 }
 923  
 
 924  0
                                                 applyFieldAuthorizationsFromNestedLookups(field);
 925  
 
 926  0
                                                 fieldValues.put(field.getPropertyName(), field.getPropertyValue());
 927  
                                         }
 928  
                                 }
 929  
 
 930  0
                                 if (checkForAdditionalFields(fieldValues)) {
 931  0
                                     for (Row row : this.getRows()) {
 932  0
                                         for (Field field : row.getFields()) {
 933  0
                                             if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
 934  0
                                                 if (this.getParameters().get(field.getPropertyName()) != null) {
 935  0
                                                         if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 936  0
                                                                             field.setPropertyValue(((String[])this.getParameters().get(field.getPropertyName()))[0]);
 937  
                                                                     } else {
 938  
                                                                             //multi value, set to values
 939  0
                                                                             field.setPropertyValues((String[])this.getParameters().get(field.getPropertyName()));
 940  
                                                                     }
 941  
                                                                     //FIXME: any reason this is inside this "if" instead of the outer one, like above - this seems inconsistent
 942  0
                                                                     fieldValues.put(field.getPropertyName(), ((String[])this.getParameters().get(field.getPropertyName()))[0]);
 943  
                                                 }
 944  0
                                                 else if (values.get(field.getPropertyName()) != null) {
 945  0
                                                         field.setPropertyValue(values.get(field.getPropertyName()));
 946  
                                                 }
 947  
                                             }
 948  
                                         }
 949  
                                     }
 950  
                                 }
 951  
                                 // Finally, return false to prevent the search from being performed and to skip the other custom processing below.
 952  0
                                 return false;
 953  
                                 }
 954  
 
 955  
                         }
 956  
                 } // End of methodToCall parameter retrieval.
 957  
 
 958  0
                 String[] resetSavedSearch = ((String[])getParameters().get("resetSavedSearch"));
 959  0
                 if(resetSavedSearch!=null) {
 960  0
                         docSearchService.clearNamedSearches(GlobalVariables.getUserSession().getPrincipalId());
 961  0
                         setRows(fieldValues,"");
 962  0
                         return false;
 963  
                 }
 964  
 
 965  0
                 String savedSearchName = ((String[])getParameters().get("savedSearchName"))[0];
 966  0
                 if(StringUtils.isEmpty(savedSearchName)||"*ignore*".equals(savedSearchName)) {
 967  0
                         if(!ignoreErrors) {
 968  0
                                 GlobalVariables.getMessageMap().putError("savedSearchName", RiceKeyConstants.ERROR_CUSTOM, "You must select a saved search");
 969  
                         } else {
 970  
                                 //if we're ignoring errors and we got an error just return, no reason to continue.  Also set false to indicate not to perform lookup
 971  0
                                 return false;
 972  
                         }
 973  
                         //TODO: is there a better way to override a single field value?
 974  0
                         List<Row> rows = this.getRows();
 975  0
                         for (Row row : rows) {
 976  0
                                 List<Field> fields = row.getFields();
 977  0
                                 for (Field field : fields) {
 978  0
                                         if(StringUtils.equals(field.getPropertyName(), "savedSearchName")) {
 979  0
                                                 field.setPropertyValue("");
 980  0
                                                 break;
 981  
                                         }
 982  
                                 }
 983  0
                         }
 984  
                 }
 985  0
         if (!GlobalVariables.getMessageMap().hasNoErrors()) {
 986  0
             throw new ValidationException("errors in search criteria");
 987  
         }
 988  
 
 989  
 
 990  0
                 SavedSearchResult savedSearchResult = null;
 991  0
                 if(StringUtils.isNotEmpty(savedSearchName)) {
 992  0
                         savedSearchResult = docSearchService.getSavedSearchResults(GlobalVariables.getUserSession().getPrincipalId(), savedSearchName);
 993  
                 }
 994  0
                 DocSearchCriteriaDTO criteria=null;
 995  0
                 if(savedSearchResult!=null){
 996  0
                         criteria = savedSearchResult.getDocSearchCriteriaDTO();
 997  
                 }
 998  
                 //put the doc type from the criteria in the map to send to setRows and then call setRows
 999  0
                 String docTypeName = criteria.getDocTypeFullName();
 1000  
 
 1001  
 
 1002  0
                 setRows(fieldValues,docTypeName);
 1003  
 
 1004  
                 //set field values (besides search atts) here
 1005  
 //                fieldValues.put("docTypeFullName", docTypeName);
 1006  
 //                fieldValues.put("fromDateCreated", criteria.getFromDateCreated());
 1007  0
                 fieldValues.put("savedSearchName", "");
 1008  
 
 1009  
 
 1010  0
                 for (SearchAttributeCriteriaComponent searchAtt : criteria.getSearchableAttributes()) {
 1011  0
                         if(!searchAtt.isCanHoldMultipleValues()) {
 1012  0
                                 fieldValues.put(searchAtt.getSavedKey(), searchAtt.getValue());
 1013  
                         } else {
 1014  0
                                 List<String> values = searchAtt.getValues();
 1015  0
                                 String[] arrayValues = {};
 1016  0
                                 arrayValues = values.toArray(arrayValues);
 1017  0
                                 multFieldValues.put(searchAtt.getSavedKey(), arrayValues);
 1018  0
                         }
 1019  
 
 1020  
                 }
 1021  0
                 Object fieldValue = null;
 1022  0
         for (Row row2 : getRows()) {
 1023  0
             Row row = (Row) row2;
 1024  0
             for (Field field2 : row.getFields()) {
 1025  0
                 Field field = (Field) field2;
 1026  0
                 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
 1027  0
                         if (fieldValues.get(field.getPropertyName()) != null) {
 1028  0
                                         field.setPropertyValue(fieldValues.get(field.getPropertyName()));
 1029  0
                     } else if(multFieldValues.get(field.getPropertyName())!=null){
 1030  0
                                          field.setPropertyValues(multFieldValues.get(field.getPropertyName()));
 1031  
                     } else {
 1032  
                             //may be on the root of the criteria object, try looking there:
 1033  
                             try {
 1034  0
                                                         fieldValue = PropertyUtils.getProperty(criteria, field.getPropertyName());
 1035  0
                                                 } catch (IllegalAccessException e) {
 1036  0
                                                         e.printStackTrace();
 1037  0
                                                 } catch (InvocationTargetException e) {
 1038  0
                                                         e.printStackTrace();
 1039  0
                                                 } catch (NoSuchMethodException e) {
 1040  
 //                                                        e.printStackTrace();
 1041  
                                                         //hmm what to do here, we should be able to find everything either in the search atts or at the base as far as I know.
 1042  0
                                                 }
 1043  0
                                                 if(fieldValue!=null) {
 1044  0
                                                         field.setPropertyValue(fieldValue);
 1045  
                                                 }
 1046  
 
 1047  
                     }
 1048  
                 }
 1049  0
             }
 1050  0
         }
 1051  
         //indicate to subsequent actions (search in this case) that a saved search was just populated
 1052  0
         savedSearch=true;
 1053  
 
 1054  0
         return true;
 1055  
         }
 1056  
 
 1057  
         /**
 1058  
          * @see org.kuali.rice.krad.lookup.AbstractLookupableHelperServiceImpl#getExtraField()
 1059  
          */
 1060  
         @Override
 1061  
         public Field getExtraField() {
 1062  0
                 SavedSearchValuesFinder savedSearchValuesFinder = new SavedSearchValuesFinder();
 1063  0
                 List<KeyValue> savedSearchValues = savedSearchValuesFinder.getKeyValues();
 1064  
 
 1065  0
                 Field savedSearch = new Field();
 1066  0
                 savedSearch.setPropertyName("savedSearchName");
 1067  0
                 savedSearch.setFieldType(Field.DROPDOWN_SCRIPT);
 1068  0
                 savedSearch.setScript("customLookupChanged()");
 1069  0
                 savedSearch.setFieldValidValues(savedSearchValues);
 1070  0
                 savedSearch.setFieldLabel("Saved Searches");
 1071  0
                 return savedSearch;
 1072  
 
 1073  
         }
 1074  
 
 1075  
         private Object getDocSearchCriteriaDTOFieldValue (DocSearchCriteriaDTO searchCriteria, String fieldName) {
 1076  0
         Class<?> clazz = searchCriteria.getClass();
 1077  0
         String propertyName = fieldName;
 1078  0
         if(fieldName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 1079  0
             propertyName = StringUtils.remove(fieldName, KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
 1080  
         }
 1081  
         try {
 1082  0
             String methodName = new StringBuffer("get").append(propertyName.toUpperCase().charAt(0)).append(propertyName.substring(1)).toString();
 1083  0
             java.lang.reflect.Method method = clazz.getMethod(methodName);
 1084  0
             return method.invoke(searchCriteria);
 1085  0
         } catch (SecurityException e) {
 1086  0
             return null;
 1087  0
         } catch (IllegalArgumentException e) {
 1088  0
             return null;
 1089  0
         } catch (IllegalAccessException e) {
 1090  0
             return null;
 1091  0
         } catch (InvocationTargetException e) {
 1092  0
             return null;
 1093  0
         } catch (NoSuchMethodException e) {
 1094  0
             return getSearchableAttributeFieldValue(searchCriteria, fieldName);
 1095  
         }
 1096  
     }
 1097  
 
 1098  
         private Object getSearchableAttributeFieldValue(DocSearchCriteriaDTO searchCriteria, String fieldName) {
 1099  0
             Object valueToReturn = null;
 1100  0
             String propertyName = fieldName;
 1101  0
             boolean isDateTime = false;
 1102  0
         if(fieldName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 1103  0
             propertyName = StringUtils.remove(fieldName, KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX);
 1104  
         }
 1105  0
             if (searchCriteria.getSearchableAttributes() != null) {
 1106  0
                 for (SearchAttributeCriteriaComponent sa : searchCriteria.getSearchableAttributes()) {
 1107  0
                     if (StringUtils.equals(propertyName, sa.getFormKey())) {
 1108  0
                         if (StringUtils.equals(sa.getSearchableAttributeValue().getOjbConcreteClass(), "org.kuali.rice.kew.docsearch.SearchableAttributeDateTimeValue")) {
 1109  0
                             isDateTime = true;
 1110  
                         }
 1111  0
                         if (sa.isCanHoldMultipleValues()) {
 1112  0
                             valueToReturn = sa.getValues();
 1113  
                         } else {
 1114  0
                             valueToReturn = sa.getValue();
 1115  
                         }
 1116  0
                         break;
 1117  
                     }
 1118  
                 }
 1119  
             }
 1120  
 
 1121  0
             if (valueToReturn != null
 1122  
                     && valueToReturn instanceof String
 1123  
                     && isDateTime) {
 1124  0
                 if(fieldName.startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
 1125  0
                     if (StringUtils.contains((String)valueToReturn, SearchOperator.BETWEEN.op())) {
 1126  0
                         valueToReturn = StringUtils.split((String)valueToReturn, SearchOperator.BETWEEN.op())[0];
 1127  0
                     } else if (StringUtils.contains((String)valueToReturn, SearchOperator.GREATER_THAN_EQUAL.op())) {
 1128  0
                         valueToReturn = StringUtils.split((String)valueToReturn, SearchOperator.GREATER_THAN_EQUAL.op())[0];
 1129  
                     } else {
 1130  0
                         valueToReturn = null;
 1131  
                     }
 1132  
                 } else {
 1133  0
                     if (StringUtils.contains((String)valueToReturn, SearchOperator.BETWEEN.op())) {
 1134  0
                     valueToReturn = StringUtils.split((String)valueToReturn, SearchOperator.BETWEEN.op())[1];
 1135  0
                 } else if (StringUtils.contains((String)valueToReturn, SearchOperator.GREATER_THAN_EQUAL.op())) {
 1136  0
                     valueToReturn = null;
 1137  0
                 } else if (StringUtils.contains((String)valueToReturn, SearchOperator.LESS_THAN_EQUAL.op())) {
 1138  0
                     valueToReturn = StringUtils.split((String)valueToReturn, SearchOperator.LESS_THAN_EQUAL.op())[0];
 1139  
                 }
 1140  
 
 1141  
                 }
 1142  
             }
 1143  
 
 1144  0
             return valueToReturn;
 1145  
         }
 1146  
 
 1147  
         protected DocumentLookupCriteriaProcessor getDocumentLookupCriteriaProcessor() {
 1148  0
         return documentLookupCriteriaProcessor;
 1149  
     }
 1150  
 
 1151  
     public void setDocumentLookupCriteriaProcessor(DocumentLookupCriteriaProcessor documentLookupCriteriaProcessor) {
 1152  0
         this.documentLookupCriteriaProcessor = documentLookupCriteriaProcessor;
 1153  0
     }
 1154  
 
 1155  
 }