Coverage Report - org.kuali.rice.kew.impl.document.search.DocumentSearchCriteriaBoLookupableHelperService
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentSearchCriteriaBoLookupableHelperService
0%
0/337
0%
0/204
3.468
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kew.impl.document.search;
 17  
 
 18  
 import org.apache.commons.beanutils.PropertyUtils;
 19  
 import org.apache.commons.lang.ArrayUtils;
 20  
 import org.apache.commons.lang.BooleanUtils;
 21  
 import org.apache.commons.lang.ObjectUtils;
 22  
 import org.apache.commons.lang.StringUtils;
 23  
 import org.kuali.rice.core.api.CoreApiServiceLocator;
 24  
 import org.kuali.rice.core.api.config.property.Config;
 25  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 26  
 import org.kuali.rice.core.api.search.SearchOperator;
 27  
 import org.kuali.rice.core.api.uif.RemotableAttributeField;
 28  
 import org.kuali.rice.core.api.util.KeyValue;
 29  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 30  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 31  
 import org.kuali.rice.core.web.format.Formatter;
 32  
 import org.kuali.rice.kew.api.KEWPropertyConstants;
 33  
 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
 34  
 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
 35  
 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteriaContract;
 36  
 import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
 37  
 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
 38  
 import org.kuali.rice.kew.docsearch.DocumentSearchCriteriaProcessor;
 39  
 import org.kuali.rice.kew.docsearch.DocumentSearchCriteriaProcessorKEWAdapter;
 40  
 import org.kuali.rice.kew.docsearch.service.DocumentSearchService;
 41  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 42  
 import org.kuali.rice.kew.exception.WorkflowServiceError;
 43  
 import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
 44  
 import org.kuali.rice.kew.framework.document.search.DocumentSearchCriteriaConfiguration;
 45  
 import org.kuali.rice.kew.framework.document.search.DocumentSearchResultSetConfiguration;
 46  
 import org.kuali.rice.kew.framework.document.search.StandardResultField;
 47  
 import org.kuali.rice.kew.impl.document.search.DocumentSearchCriteriaBo;
 48  
 import org.kuali.rice.kew.lookup.valuefinder.SavedSearchValuesFinder;
 49  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 50  
 import org.kuali.rice.kew.api.KewApiConstants;
 51  
 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
 52  
 import org.kuali.rice.kns.lookup.HtmlData;
 53  
 import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
 54  
 import org.kuali.rice.kns.util.FieldUtils;
 55  
 import org.kuali.rice.kns.web.struts.form.LookupForm;
 56  
 import org.kuali.rice.kns.web.ui.Column;
 57  
 import org.kuali.rice.kns.web.ui.Field;
 58  
 import org.kuali.rice.kns.web.ui.ResultRow;
 59  
 import org.kuali.rice.kns.web.ui.Row;
 60  
 import org.kuali.rice.krad.bo.BusinessObject;
 61  
 import org.kuali.rice.krad.exception.ValidationException;
 62  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 63  
 import org.kuali.rice.krad.util.GlobalVariables;
 64  
 import org.kuali.rice.krad.util.KRADConstants;
 65  
 
 66  
 import java.lang.reflect.InvocationTargetException;
 67  
 import java.text.MessageFormat;
 68  
 import java.util.ArrayList;
 69  
 import java.util.Collection;
 70  
 import java.util.Collections;
 71  
 import java.util.HashMap;
 72  
 import java.util.List;
 73  
 import java.util.Map;
 74  
 
 75  
 /**
 76  
  * Implementation of lookupable helper service which handles the complex lookup behavior required by the KEW
 77  
  * document search screen.
 78  
  *
 79  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 80  
  */
 81  0
 public class DocumentSearchCriteriaBoLookupableHelperService extends KualiLookupableHelperServiceImpl {
 82  
 
 83  
     private static final String DOCUMENT_ATTRIBUTE_PROPERTY_NAME_PREFIX = "documentAttribute.";
 84  
 
 85  
     static final String SAVED_SEARCH_NAME_PARAM = "savedSearchToLoadAndExecute";
 86  
 
 87  
     // warning message keys
 88  
 
 89  
     private static final String EXCEED_THRESHOLD_MESSAGE_KEY = "docsearch.DocumentSearchService.exceededThreshold";
 90  
     private static final String SECURITY_FILTERED_MESSAGE_KEY = "docsearch.DocumentSearchService.securityFiltered";
 91  
     private static final String EXCEED_THRESHOLD_AND_SECURITY_FILTERED_MESSAGE_KEY = "docsearch.DocumentSearchService.exceededThresholdAndSecurityFiltered";
 92  
 
 93  
     private static final boolean DOCUMENT_HANDLER_POPUP_DEFAULT = true;
 94  
     private static final boolean ROUTE_LOG_POPUP_DEFAULT = true;
 95  
 
 96  
     // injected services
 97  
 
 98  
     private DocumentSearchService documentSearchService;
 99  
     private DocumentSearchCriteriaProcessor documentSearchCriteriaProcessor;
 100  
     private DocumentSearchCriteriaTranslator documentSearchCriteriaTranslator;
 101  
 
 102  
     // unfortunately, lookup helpers are stateful, need to store these here for other methods to use
 103  0
     protected DocumentSearchResults searchResults = null;
 104  0
     protected DocumentSearchCriteria criteria = null;
 105  
 
 106  
     @Override
 107  
     protected List<? extends BusinessObject> getSearchResultsHelper(Map<String, String> fieldValues,
 108  
             boolean unbounded) {
 109  0
         criteria = loadCriteria(fieldValues);
 110  0
         searchResults = null;
 111  
         try {
 112  0
             searchResults = KEWServiceLocator.getDocumentSearchService().lookupDocuments(
 113  
                     GlobalVariables.getUserSession().getPrincipalId(), criteria);
 114  0
             if (searchResults.isCriteriaModified()) {
 115  0
                 criteria = searchResults.getCriteria();
 116  
             }
 117  0
         } catch (WorkflowServiceErrorException wsee) {
 118  0
             for (WorkflowServiceError workflowServiceError : (List<WorkflowServiceError>) wsee.getServiceErrors()) {
 119  0
                 if (workflowServiceError.getMessageMap() != null && workflowServiceError.getMessageMap().hasErrors()) {
 120  
                     // merge the message maps
 121  0
                     GlobalVariables.getMessageMap().merge(workflowServiceError.getMessageMap());
 122  
                 } else {
 123  0
                     GlobalVariables.getMessageMap().putError(workflowServiceError.getMessage(),
 124  
                             RiceKeyConstants.ERROR_CUSTOM, workflowServiceError.getMessage());
 125  
                 }
 126  
             }
 127  0
         }
 128  
 
 129  0
         if (!GlobalVariables.getMessageMap().hasNoErrors() || searchResults == null) {
 130  0
             throw new ValidationException("error with doc search");
 131  
         }
 132  
 
 133  0
         populateResultWarningMessages(searchResults);
 134  
 
 135  0
         List<DocumentSearchResult> individualSearchResults = searchResults.getSearchResults();
 136  
 
 137  0
         setBackLocation(fieldValues.get(KRADConstants.BACK_LOCATION));
 138  0
         setDocFormKey(fieldValues.get(KRADConstants.DOC_FORM_KEY));
 139  
 
 140  0
         applyCriteriaChangesToFields(criteria);
 141  
 
 142  0
         return populateSearchResults(individualSearchResults);
 143  
 
 144  
     }
 145  
 
 146  
     /**
 147  
      * Inspects the lookup results to determine if any warning messages should be published to the message map.
 148  
      */
 149  
     protected void populateResultWarningMessages(DocumentSearchResults searchResults) {
 150  
         // check various warning conditions
 151  0
         boolean overThreshold = searchResults.isOverThreshold();
 152  0
         int numFiltered = searchResults.getNumberOfSecurityFilteredResults();
 153  0
         int numResults = searchResults.getSearchResults().size();
 154  0
         if (overThreshold && numFiltered > 0) {
 155  0
             GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES,
 156  
                     EXCEED_THRESHOLD_AND_SECURITY_FILTERED_MESSAGE_KEY,
 157  
                     String.valueOf(numResults),
 158  
                     String.valueOf(numFiltered));
 159  0
         } else if (numFiltered > 0) {
 160  0
             GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES,
 161  
                     SECURITY_FILTERED_MESSAGE_KEY,
 162  
                     String.valueOf(numFiltered));
 163  0
         } else if (overThreshold) {
 164  0
             GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES,
 165  
                     EXCEED_THRESHOLD_MESSAGE_KEY,
 166  
                     String.valueOf(numResults));
 167  
         }
 168  0
     }
 169  
 
 170  
     /**
 171  
      * Applies changes that might have happened to the criteria back to the fields so that they show up on the form.
 172  
      * Namely, this handles populating the form with today's date if the create date was not filled in on the form.
 173  
      */
 174  
     protected void applyCriteriaChangesToFields(DocumentSearchCriteriaContract criteria) {
 175  0
         for (Field field: getFormFields()) {
 176  0
             if(StringUtils.equals(field.getPropertyName(), KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + "dateCreated") && StringUtils.isEmpty(field.getPropertyValue())) {
 177  0
                 if (criteria.getDateCreatedFrom() != null) {
 178  0
                     field.setPropertyValue(CoreApiServiceLocator.getDateTimeService().toDateString(criteria.getDateCreatedFrom().toDate()));
 179  
                 }
 180  
             }
 181  
         }
 182  0
     }
 183  
 
 184  
     /**
 185  
      * Cleans up various issues with fieldValues coming from the lookup form (namely, that they don't include
 186  
      * multi-valued field values!). Handles these by adding them comma-separated.
 187  
      */
 188  
     protected Map<String, String> cleanupFieldValues(Map<String, String> fieldValues, Map<String, String[]> parameters) {
 189  0
         Map<String, String> cleanedUpFieldValues = new HashMap<String, String>(fieldValues);
 190  0
         if (ArrayUtils.isNotEmpty(parameters.get(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE))) {
 191  0
             cleanedUpFieldValues.put(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE,
 192  
                     StringUtils.join(parameters.get(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE), ","));
 193  
         }
 194  0
         Map<String, String> documentAttributeFieldValues = new HashMap<String, String>();
 195  0
         for (String parameterName : parameters.keySet()) {
 196  0
             if (parameterName.contains(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX)) {
 197  0
                 String[] value = parameters.get(parameterName);
 198  0
                 if (ArrayUtils.isNotEmpty(value)) {
 199  0
                     documentAttributeFieldValues.put(parameterName, StringUtils.join(value, " " + SearchOperator.OR.op() + " "));
 200  
                 }
 201  0
             }
 202  
         }
 203  
         // if any of the document attributes are range values, process them
 204  0
         documentAttributeFieldValues.putAll(preProcessRangeFields(documentAttributeFieldValues));
 205  0
         cleanedUpFieldValues.putAll(documentAttributeFieldValues);
 206  0
         return cleanedUpFieldValues;
 207  
     }
 208  
 
 209  
     /**
 210  
      * Loads the document search criteria from the given map of field values as submitted from the search screen, and
 211  
      * populates the current form Rows/Fields with the saved criteria fields
 212  
      */
 213  
     protected DocumentSearchCriteria loadCriteria(Map<String, String> fieldValues) {
 214  0
         fieldValues = cleanupFieldValues(fieldValues, getParameters());
 215  0
         String[] savedSearchToLoad = getParameters().get(SAVED_SEARCH_NAME_PARAM);
 216  0
         boolean savedSearch = savedSearchToLoad != null && savedSearchToLoad.length > 0 && StringUtils.isNotBlank(savedSearchToLoad[0]);
 217  0
         if (savedSearch) {
 218  0
             DocumentSearchCriteria criteria = getDocumentSearchService().getSavedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchToLoad[0]);
 219  0
             if (criteria != null) {
 220  0
                 mergeFieldValues(getDocumentSearchCriteriaTranslator().translateCriteriaToFields(criteria));
 221  0
                 return criteria;
 222  
             }
 223  
         }
 224  
         // either it wasn't a saved search or the saved search failed to resolve
 225  0
         return getDocumentSearchCriteriaTranslator().translateFieldsToCriteria(fieldValues);
 226  
     }
 227  
 
 228  
     protected List<DocumentSearchCriteriaBo> populateSearchResults(List<DocumentSearchResult> lookupResults) {
 229  0
         List<DocumentSearchCriteriaBo> searchResults = new ArrayList<DocumentSearchCriteriaBo>();
 230  0
         for (DocumentSearchResult searchResult : lookupResults) {
 231  0
             DocumentSearchCriteriaBo result = new DocumentSearchCriteriaBo();
 232  0
             result.populateFromDocumentSearchResult(searchResult);
 233  0
             searchResults.add(result);
 234  0
         }
 235  0
         return searchResults;
 236  
     }
 237  
 
 238  
     @Override
 239  
     public Collection performLookup(LookupForm lookupForm, Collection resultTable, boolean bounded) {
 240  0
         Collection lookupResult = super.performLookup(lookupForm, resultTable, bounded);
 241  0
         postProcessResults(resultTable, this.searchResults);
 242  0
         return lookupResult;
 243  
     }
 244  
 
 245  
     /**
 246  
      * Sets a Field value appropriately, depending on whether it is a "multi-value" field type
 247  
      */
 248  
     protected static void setFieldValue(Field field, String[] values) {
 249  0
         if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 250  0
             field.setPropertyValue(values[0]);
 251  
         } else {
 252  
             //multi value, set to values
 253  0
             field.setPropertyValues(values);
 254  
         }
 255  0
     }
 256  
 
 257  
     /**
 258  
      * Preserves Field values, saving single or array property value depending on field type; single property value is
 259  
      * converted into String[1]
 260  
      * This implementation makes the assumption that a Field can either represent a single property value, or an array
 261  
      * of values but not both! (only one is preserved)
 262  
      * @return a Map<String, String[]> containing field values depending on field type
 263  
      */
 264  
     protected Map<String, String[]> getFormFieldsValues() {
 265  0
         Map<String, String[]> values = new HashMap<String, String[]>();
 266  0
         for (Field field : getFormFields()) {
 267  
             String[] value;
 268  0
             if(!Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType())) {
 269  0
                 value = new String[] { field.getPropertyValue() };
 270  
             } else {
 271  
                 //multi value, set to values
 272  0
                 value = field.getPropertyValues();
 273  
             }
 274  0
             values.put(field.getPropertyName(), value);
 275  0
         }
 276  0
         return values;
 277  
     }
 278  
 
 279  
     /**
 280  
      * Overrides a Field value; sets a fallback/restored value if there is no new value
 281  
      */
 282  
     protected static void overrideFieldValue(Field field, Map<String, String[]> newValues, Map<String, String[]> oldValues) {
 283  0
         if (StringUtils.isNotBlank(field.getPropertyName())) {
 284  0
             if (newValues.get(field.getPropertyName()) != null) {
 285  0
                 setFieldValue(field, newValues.get(field.getPropertyName()));
 286  0
             } else if (oldValues.get(field.getPropertyName()) != null) {
 287  0
                 setFieldValue(field, oldValues.get(field.getPropertyName()));
 288  
             }
 289  
         }
 290  0
     }
 291  
 
 292  
     /**
 293  
      * Overrides Row Field values with Map values
 294  
      * @param values
 295  
      */
 296  
     protected void mergeFieldValues(Map<String, String[]> values) {
 297  0
         for (Field field: getFormFields()) {
 298  0
             if (StringUtils.isNotBlank(field.getPropertyName())) {
 299  0
                 if (values.get(field.getPropertyName()) != null) {
 300  0
                     setFieldValue(field, values.get(field.getPropertyName()));
 301  
                 }
 302  
             }
 303  
         }
 304  0
     }
 305  
 
 306  
     /**
 307  
      * Sets a single form field
 308  
      */
 309  
     protected void setFormField(String name, String value) {
 310  0
         for (Field field : getFormFields()) {
 311  0
             if(StringUtils.equals(field.getPropertyName(), name)) {
 312  0
                 setFieldValue(field, new String[] { value });
 313  0
                 break;
 314  
             }
 315  
         }
 316  0
     }
 317  
 
 318  
     /**
 319  
      * Handles toggling between form views.
 320  
      * Reads and sets the Rows state.
 321  
      */
 322  
     protected void toggleFormView() {
 323  0
         Map<String,String[]> fieldValues = new HashMap<String,String[]>();
 324  0
         Map<String, String[]> savedValues = getFormFieldsValues();
 325  
 
 326  
         // the original implementation saved the form values and then re-applied them
 327  
         // we do the same here, however I suspect we may be able to avoid this re-application
 328  
         // of existing values
 329  
 
 330  0
         for (Field field: getFormFields()) {
 331  0
             overrideFieldValue(field, this.getParameters(), savedValues);
 332  
             // if we are sure this does not depend on or cause side effects in other fields
 333  
             // then this phase can be extracted and these loops simplified
 334  0
             applyFieldAuthorizationsFromNestedLookups(field);
 335  0
             fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
 336  
         }
 337  
 
 338  
         // checkForAdditionalFields generates the form (setRows)
 339  0
         if (checkForAdditionalFields(fieldValues)) {
 340  0
             for (Field field: getFormFields()) {
 341  0
                 overrideFieldValue(field, this.getParameters(), savedValues);
 342  0
                 fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
 343  
              }
 344  
         }
 345  
 
 346  
         // unset the clear search param, since this is not really a state, but just an action
 347  
         // it can never be toggled "off", just "on"
 348  0
         setFormField(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, "");
 349  0
     }
 350  
 
 351  
     /**
 352  
      * Loads a saved search
 353  
      * @return returns true on success to run the loaded search, false on error.
 354  
      */
 355  
     protected boolean loadSavedSearch(boolean ignoreErrors) {
 356  0
         Map<String,String[]> fieldValues = new HashMap<String,String[]>();
 357  
 
 358  0
         String savedSearchName = getSavedSearchName();
 359  0
         if(StringUtils.isEmpty(savedSearchName) || "*ignore*".equals(savedSearchName)) {
 360  0
             if(!ignoreErrors) {
 361  0
                 GlobalVariables.getMessageMap().putError(SAVED_SEARCH_NAME_PARAM, RiceKeyConstants.ERROR_CUSTOM, "You must select a saved search");
 362  
             } else {
 363  
                 //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
 364  0
                 return false;
 365  
             }
 366  0
             setFormField(SAVED_SEARCH_NAME_PARAM, "");
 367  
         }
 368  0
         if (!GlobalVariables.getMessageMap().hasNoErrors()) {
 369  0
             throw new ValidationException("errors in search criteria");
 370  
         }
 371  
 
 372  0
         DocumentSearchCriteria criteria = KEWServiceLocator.getDocumentSearchService().getSavedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchName);
 373  
 
 374  
         // get the document type
 375  0
         String docTypeName = criteria.getDocumentTypeName();
 376  
         // and set the rows based on doc type
 377  0
         setRows(docTypeName);
 378  
 
 379  
         // clear the name of the search in the form
 380  
         //fieldValues.put(SAVED_SEARCH_NAME_PARAM, new String[0]);
 381  
 
 382  
         // set the custom document attribute values on the search form
 383  0
         for (Map.Entry<String, List<String>> entry: criteria.getDocumentAttributeValues().entrySet()) {
 384  0
             fieldValues.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
 385  
         }
 386  
 
 387  
         // sets the field values on the form, trying criteria object properties if a field value is not present in the map
 388  0
         for (Field field : getFormFields()) {
 389  0
             if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
 390  
                 // UI Fields know whether they are single or multiple value
 391  
                 // just set both so they can make the determination and render appropriately
 392  0
                 String[] values = null;
 393  0
                 if (fieldValues.get(field.getPropertyName()) != null) {
 394  0
                     values = fieldValues.get(field.getPropertyName());
 395  
                 } else {
 396  
                     //may be on the root of the criteria object, try looking there:
 397  
                     try {
 398  0
                         values = new String[] { ObjectUtils.toString(PropertyUtils.getProperty(criteria, field.getPropertyName())) };
 399  0
                     } catch (IllegalAccessException e) {
 400  0
                         e.printStackTrace();
 401  0
                     } catch (InvocationTargetException e) {
 402  0
                         e.printStackTrace();
 403  0
                     } catch (NoSuchMethodException e) {
 404  
                         // e.printStackTrace();
 405  
                         //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.
 406  0
                     }
 407  
                 }
 408  0
                 if (values != null) {
 409  0
                     setFieldValue(field, values);
 410  
                 }
 411  0
             }
 412  
         }
 413  
 
 414  0
         return true;
 415  
     }
 416  
 
 417  
     /**
 418  
      * Performs custom document search/lookup actions.
 419  
      * 1) switching between simple/detailed search
 420  
      * 2) switching between non-superuser/superuser search
 421  
      * 3) clearing saved search results
 422  
      * 4) restoring a saved search and executing the search
 423  
      * @param ignoreErrors
 424  
      * @return whether to rerun the previous search; false in cases 1-3 because we are just updating the form
 425  
      */
 426  
     @Override
 427  
     public boolean performCustomAction(boolean ignoreErrors) {
 428  
         //boolean isConfigAction = isAdvancedSearch() || isSuperUserSearch() || isClearSavedSearch();
 429  0
         if (getSavedSearchName() != null) {
 430  0
             return loadSavedSearch(ignoreErrors);
 431  
         } else {
 432  0
             if (isClearSavedSearch()) {
 433  0
                 KEWServiceLocator.getDocumentSearchService().clearNamedSearches(GlobalVariables.getUserSession().getPrincipalId());
 434  
             } else {
 435  0
                 toggleFormView();
 436  
             }
 437  
             // Finally, return false to prevent the search from being performed and to skip the other custom processing below.
 438  0
             return false;
 439  
         }
 440  
     }
 441  
 
 442  
     /**
 443  
      * Custom implementation of getInquiryUrl that sets up doc handler link.
 444  
      */
 445  
     @Override
 446  
     public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
 447  0
         DocumentSearchCriteriaBo criteriaBo = (DocumentSearchCriteriaBo)bo;
 448  0
         if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_DOCUMENT_ID.equals(propertyName)) {
 449  0
             return generateDocumentHandlerUrl(criteriaBo.getDocumentId(), criteriaBo.getDocumentType(),
 450  
                     isSuperUserSearch());
 451  0
         } else if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG.equals(propertyName)) {
 452  0
             return generateRouteLogUrl(criteriaBo.getDocumentId());
 453  
         }
 454  0
         return super.getInquiryUrl(bo, propertyName);
 455  
     }
 456  
 
 457  
     /**
 458  
      * Generates the appropriate document handler url for the given document.  If superUserSearch is true then a super
 459  
      * user doc handler link will be generated if the document type policy allows it.
 460  
      */
 461  
     protected HtmlData.AnchorHtmlData generateDocumentHandlerUrl(String documentId, DocumentType documentType, boolean superUserSearch) {
 462  0
         HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
 463  0
         link.setDisplayText(documentId);
 464  0
         if (isDocumentHandlerPopup()) {
 465  0
             link.setTarget("_blank");
 466  
         }
 467  0
         String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/";
 468  0
         if (superUserSearch) {
 469  0
             if (documentType.getUseWorkflowSuperUserDocHandlerUrl().getPolicyValue().booleanValue()) {
 470  0
                 url += "SuperUser.do?methodToCall=displaySuperUserDocument&documentId=" + documentId;
 471  
             } else {
 472  0
                 url = KewApiConstants.DOC_HANDLER_REDIRECT_PAGE
 473  
                         + "?" + KewApiConstants.COMMAND_PARAMETER + "="
 474  
                         + KewApiConstants.SUPERUSER_COMMAND + "&"
 475  
                         + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
 476  
                         + documentId;
 477  
             }
 478  
         } else {
 479  0
             url += KewApiConstants.DOC_HANDLER_REDIRECT_PAGE + "?"
 480  
                     + KewApiConstants.COMMAND_PARAMETER + "="
 481  
                     + KewApiConstants.DOCSEARCH_COMMAND + "&"
 482  
                     + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
 483  
                     + documentId;
 484  
         }
 485  0
         link.setHref(url);
 486  0
         return link;
 487  
     }
 488  
 
 489  
     protected HtmlData.AnchorHtmlData generateRouteLogUrl(String documentId) {
 490  0
         HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
 491  0
         if (isRouteLogPopup()) {
 492  0
             link.setTarget("_blank");
 493  
         }
 494  0
         link.setDisplayText("Route Log for document " + documentId);
 495  0
         String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/" +
 496  
                 "RouteLog.do?documentId=" + documentId;
 497  0
         link.setHref(url);
 498  0
         return link;
 499  
     }
 500  
 
 501  
     /**
 502  
      * Returns true if the document handler should open in a new window.
 503  
      */
 504  
     protected boolean isDocumentHandlerPopup() {
 505  0
         return BooleanUtils.toBooleanDefaultIfNull(
 506  
                 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
 507  
                     KewApiConstants.KEW_NAMESPACE,
 508  
                     KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
 509  
                     KewApiConstants.DOCUMENT_SEARCH_DOCUMENT_POPUP_IND),
 510  
                 DOCUMENT_HANDLER_POPUP_DEFAULT);
 511  
     }
 512  
 
 513  
     /**
 514  
      * Returns true if the route log should open in a new window.
 515  
      */
 516  
     public boolean isRouteLogPopup() {
 517  0
         return BooleanUtils.toBooleanDefaultIfNull(
 518  
                 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KewApiConstants.KEW_NAMESPACE,
 519  
                         KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
 520  
                         KewApiConstants.DOCUMENT_SEARCH_ROUTE_LOG_POPUP_IND), ROUTE_LOG_POPUP_DEFAULT);
 521  
     }
 522  
 
 523  
     /**
 524  
      * Parses a boolean request parameter
 525  
      */
 526  
     protected boolean isFlagSet(String flagName) {
 527  0
         if(this.getParameters().containsKey(flagName)) {
 528  0
             String[] params = (String[])this.getParameters().get(flagName);
 529  0
             if (ArrayUtils.isNotEmpty(params)) {
 530  0
                 return "YES".equalsIgnoreCase(params[0]);
 531  
             }
 532  
         }
 533  0
         return false;
 534  
     }
 535  
 
 536  
     /**
 537  
      * Returns true if the current search being executed is a super user search.
 538  
      */
 539  
     protected boolean isSuperUserSearch() {
 540  0
         return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD);
 541  
     }
 542  
 
 543  
     /**
 544  
      * Returns true if the current search being executed is an "advanced" search.
 545  
      */
 546  
     protected boolean isAdvancedSearch() {
 547  0
         return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD);
 548  
     }
 549  
 
 550  
     /**
 551  
      * Returns true if the current "search" being executed is an "clear" search.
 552  
      */
 553  
     protected boolean isClearSavedSearch() {
 554  0
         return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD);
 555  
     }
 556  
 
 557  
     protected String getSavedSearchName() {
 558  0
         String[] savedSearchName = getParameters().get(SAVED_SEARCH_NAME_PARAM);
 559  0
         if (savedSearchName != null && savedSearchName.length > 0) {
 560  0
             return savedSearchName[0];
 561  
         }
 562  0
         return null;
 563  
     }
 564  
 
 565  
     /**
 566  
      * Override setRows in order to post-process and add documenttype-dependent fields
 567  
      */
 568  
     @Override
 569  
     protected void setRows() {
 570  0
         this.setRows(null);
 571  0
     }
 572  
 
 573  
     /**
 574  
      * Returns an iterable of current form fields
 575  
      */
 576  
     protected Iterable<Field> getFormFields() {
 577  0
         return getFields(this.getRows());
 578  
     }
 579  
 
 580  
     /**
 581  
      * Sets the rows for the search criteria.  This method will delegate to the DocumentSearchCriteriaProcessor
 582  
      * in order to pull in fields for custom search attributes.
 583  
      *
 584  
      * @param documentTypeName the name of the document type currently entered on the form, if this is a valid document
 585  
      * type then it may have search attribute fields that need to be displayed; documentType name may also be loaded
 586  
      * via a saved search
 587  
      */
 588  
     protected void setRows(String documentTypeName) {
 589  0
         if (getRows() == null) {
 590  0
             super.setRows();
 591  
         }
 592  0
         List<Row> lookupRows = new ArrayList<Row>();
 593  
         //copy the current rows
 594  0
         for (Row row : getRows()) {
 595  0
             lookupRows.add(row);
 596  
         }
 597  
         //clear out
 598  0
         getRows().clear();
 599  
 
 600  0
         DocumentType docType = getValidDocumentType(documentTypeName);
 601  
 
 602  0
         boolean advancedSearch = isAdvancedSearch();
 603  0
         boolean superUserSearch = isSuperUserSearch();
 604  
 
 605  
         //call get rows
 606  0
         List<Row> rows = getDocumentSearchCriteriaProcessor().getRows(docType,lookupRows, advancedSearch, superUserSearch);
 607  
 
 608  0
         BusinessObjectEntry boe = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(this.getBusinessObjectClass().getName());
 609  0
         int numCols = boe.getLookupDefinition().getNumOfColumns();
 610  0
         if(numCols == 0) {
 611  0
             numCols = KRADConstants.DEFAULT_NUM_OF_COLUMNS;
 612  
         }
 613  
 
 614  0
         super.getRows().addAll(FieldUtils.wrapFields(this.getFields(rows), numCols));
 615  
 
 616  0
     }
 617  
 
 618  
     private static List<Field> getFields(Collection<? extends Row> rows) {
 619  0
         List<Field> rList = new ArrayList<Field>();
 620  0
         for (Row r : rows) {
 621  0
             for (Field f : r.getFields()) {
 622  0
                 rList.add(f);
 623  
             }
 624  
         }
 625  0
         return rList;
 626  
     }
 627  
 
 628  
     /**
 629  
      * Checks for a valid document type with the given name in a case-sensitive manner.
 630  
      *
 631  
      * @return the DocumentType which matches the given name or null if no valid document type could be found
 632  
      */
 633  
     private DocumentType getValidDocumentType(String documentTypeName) {
 634  0
         if (StringUtils.isNotEmpty(documentTypeName)) {
 635  0
             DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByNameCaseInsensitive(documentTypeName.trim());
 636  0
             if (documentType != null && documentType.isActive()) {
 637  0
                 return documentType;
 638  
             }
 639  
         }
 640  0
         return null;
 641  
     }
 642  
 
 643  0
     private static String TOGGLE_BUTTON = "<input type='image' name=''{0}'' id=''{0}'' class='tinybutton' src=''..{1}/images/tinybutton-{2}search.gif'' alt=''{3} search'' title=''{3} search''/>";
 644  
 
 645  
     @Override
 646  
     public String getSupplementalMenuBar() {
 647  0
         boolean advancedSearch = isAdvancedSearch();
 648  0
         boolean superUserSearch = isSuperUserSearch();
 649  0
         StringBuilder suppMenuBar = new StringBuilder();
 650  
 
 651  
         // Add the detailed-search-toggling button.
 652  
         // to mimic previous behavior, basic search button is shown both when currently rendering detailed search AND super user search
 653  
         // as super user search is essentially a detailed search
 654  0
         String type = advancedSearch ? "basic" : "detailed";
 655  0
         suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleAdvancedSearch", KewApiConstants.WEBAPP_DIRECTORY, type, type));
 656  
 
 657  
         // Add the superuser-search-toggling button.
 658  0
         suppMenuBar.append("&nbsp;");
 659  0
         suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleSuperUserSearch", KewApiConstants.WEBAPP_DIRECTORY, superUserSearch ? "nonsupu" : "superuser", superUserSearch ? "non-superuser" : "superuser"));
 660  
 
 661  
         // Add the "clear saved searches" button.
 662  0
         suppMenuBar.append("&nbsp;");
 663  0
         suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, KewApiConstants.WEBAPP_DIRECTORY, "clearsaved", "clear saved searches"));
 664  
 
 665  0
         return suppMenuBar.toString();
 666  
     }
 667  
 
 668  
     @Override
 669  
     public boolean shouldDisplayHeaderNonMaintActions() {
 670  0
         return true;
 671  
     }
 672  
 
 673  
     @Override
 674  
     public boolean shouldDisplayLookupCriteria() {
 675  0
         return true;
 676  
     }
 677  
 
 678  
     /**
 679  
      * Determines if there should be more search fields rendered based on already entered search criteria, and
 680  
      * generates additional form rows.
 681  
      */
 682  
     @Override
 683  
     public boolean checkForAdditionalFields(Map fieldValues) {
 684  
         // The given map is a Map<String, String>
 685  0
         Object val = fieldValues.get("documentTypeName");
 686  
         String documentTypeName;
 687  0
         if (val instanceof String[]) {
 688  0
             documentTypeName = ((String[]) val)[0];
 689  
         } else {
 690  0
             documentTypeName = (String) val;
 691  
         }
 692  0
         if (StringUtils.isNotBlank(documentTypeName)) {
 693  0
             setRows(documentTypeName);
 694  
         }
 695  0
         return true;
 696  
     }
 697  
 
 698  
     @Override
 699  
     public Field getExtraField() {
 700  0
         SavedSearchValuesFinder savedSearchValuesFinder = new SavedSearchValuesFinder();
 701  0
         List<KeyValue> savedSearchValues = savedSearchValuesFinder.getKeyValues();
 702  0
         Field savedSearch = new Field();
 703  0
         savedSearch.setPropertyName(SAVED_SEARCH_NAME_PARAM);
 704  0
         savedSearch.setFieldType(Field.DROPDOWN_SCRIPT);
 705  0
         savedSearch.setScript("customLookupChanged()");
 706  0
         savedSearch.setFieldValidValues(savedSearchValues);
 707  0
         savedSearch.setFieldLabel("Saved Searches");
 708  0
         return savedSearch;
 709  
     }
 710  
 
 711  
     @Override
 712  
     public void performClear(LookupForm lookupForm) {
 713  0
         DocumentSearchCriteria criteria = loadCriteria(lookupForm.getFields());
 714  0
         super.performClear(lookupForm);
 715  0
         repopulateSearchTypeFlags();
 716  0
         DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
 717  0
         if (documentType != null) {
 718  0
             DocumentSearchCriteria clearedCriteria = documentSearchService.clearCriteria(documentType, criteria);
 719  0
             applyCriteriaChangesToFields(DocumentSearchCriteria.Builder.create(clearedCriteria));
 720  
         }
 721  0
     }
 722  
 
 723  
     /**
 724  
      * Repopulate the fields indicating advanced/superuser search type.
 725  
      */
 726  
     protected void repopulateSearchTypeFlags() {
 727  0
         boolean advancedSearch = isAdvancedSearch();
 728  0
         boolean superUserSearch = isSuperUserSearch();
 729  0
         int fieldsRepopulated = 0;
 730  0
         for (Field field: getFields(super.getRows())) {
 731  0
             if (fieldsRepopulated >= 2) {
 732  0
                 break;
 733  
             }
 734  0
             if (DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD.equals(field.getPropertyName())) {
 735  0
                 field.setPropertyValue(advancedSearch ? "YES" : "NO");
 736  0
                 fieldsRepopulated++;
 737  0
             } else if (DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD.equals(field.getPropertyName())) {
 738  0
                 field.setPropertyValue(advancedSearch ? "YES" : "NO");
 739  0
                 fieldsRepopulated++;
 740  
             }
 741  
         }
 742  
 
 743  0
     }
 744  
 
 745  
     /**
 746  
      * Takes a collection of result rows and does final processing on them.
 747  
      */
 748  
     protected void postProcessResults(Collection<ResultRow> resultRows, DocumentSearchResults searchResults) {
 749  0
         if (resultRows.size() != searchResults.getSearchResults().size()) {
 750  0
             throw new IllegalStateException("Encountered a mismatch between ResultRow items and document search results "
 751  
                     + resultRows.size() + " != " + searchResults.getSearchResults().size());
 752  
         }
 753  0
         DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
 754  0
         DocumentSearchResultSetConfiguration resultSetConfiguration = null;
 755  0
         DocumentSearchCriteriaConfiguration criteriaConfiguration = null;
 756  0
         if (documentType != null) {
 757  0
             resultSetConfiguration =
 758  
                 KEWServiceLocator.getDocumentSearchCustomizationMediator().customizeResultSetConfiguration(
 759  
                         documentType, criteria);
 760  0
             criteriaConfiguration =
 761  
                     KEWServiceLocator.getDocumentSearchCustomizationMediator().getDocumentSearchCriteriaConfiguration(
 762  
                             documentType);
 763  
 
 764  
         }
 765  0
         int index = 0;
 766  0
         for (ResultRow resultRow : resultRows) {
 767  0
             DocumentSearchResult searchResult = searchResults.getSearchResults().get(index);
 768  0
             executeColumnCustomization(resultRow, searchResult, resultSetConfiguration, criteriaConfiguration);
 769  0
             index++;
 770  0
         }
 771  0
     }
 772  
 
 773  
     /**
 774  
      * Executes customization of columns, could include removing certain columns or adding additional columns to the
 775  
      * result row (in cases where columns are added by document search customization, such as searchable attributes).
 776  
      */
 777  
     protected void executeColumnCustomization(ResultRow resultRow, DocumentSearchResult searchResult,
 778  
             DocumentSearchResultSetConfiguration resultSetConfiguration,
 779  
             DocumentSearchCriteriaConfiguration criteriaConfiguration) {
 780  0
         if (resultSetConfiguration == null) {
 781  0
             resultSetConfiguration = DocumentSearchResultSetConfiguration.Builder.create().build();
 782  
         }
 783  0
         if (criteriaConfiguration == null) {
 784  0
             criteriaConfiguration = DocumentSearchCriteriaConfiguration.Builder.create().build();
 785  
         }
 786  0
         List<StandardResultField> standardFieldsToRemove = resultSetConfiguration.getStandardResultFieldsToRemove();
 787  0
         if (standardFieldsToRemove == null) {
 788  0
             standardFieldsToRemove = Collections.emptyList();
 789  
         }
 790  0
         List<Column> newColumns = new ArrayList<Column>();
 791  0
         for (Column standardColumn : resultRow.getColumns()) {
 792  0
             if (!standardFieldsToRemove.contains(StandardResultField.fromFieldName(standardColumn.getPropertyName()))) {
 793  0
                 newColumns.add(standardColumn);
 794  
                 // modify the route log column so that xml values are not escaped (allows for the route log <img ...> to be
 795  
                 // rendered properly)
 796  0
                 if (standardColumn.getPropertyName().equals(
 797  
                         KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG)) {
 798  0
                     standardColumn.setEscapeXMLValue(false);
 799  
                 }
 800  
             }
 801  
         }
 802  
 
 803  
         // determine which document attribute fields should be added
 804  0
         List<RemotableAttributeField> searchAttributeFields = criteriaConfiguration.getFlattenedSearchAttributeFields();
 805  0
         List<String> additionalFieldNamesToInclude = new ArrayList<String>();
 806  0
         if (!resultSetConfiguration.isOverrideSearchableAttributes()) {
 807  0
             for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
 808  
                 // TODO - KULRICE-5738 - add check here to make sure the searchable attribute should be displayed in result set
 809  
                 // right now this is default always including all searchable attributes!
 810  0
                 additionalFieldNamesToInclude.add(searchAttributeField.getName());
 811  
             }
 812  
         }
 813  0
         if (resultSetConfiguration.getCustomFieldNamesToAdd() != null) {
 814  0
             additionalFieldNamesToInclude.addAll(resultSetConfiguration.getCustomFieldNamesToAdd());
 815  
         }
 816  
 
 817  
         // now assemble the custom columns
 818  0
         List<Column> customColumns = new ArrayList<Column>();
 819  0
         List<Column> additionalAttributeColumns = FieldUtils.constructColumnsFromAttributeFields(
 820  
                 resultSetConfiguration.getAdditionalAttributeFields());
 821  
 
 822  0
         outer:for (String additionalFieldNameToInclude : additionalFieldNamesToInclude) {
 823  
             // search the search attribute fields
 824  0
             for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
 825  0
                 if (additionalFieldNameToInclude.equals(searchAttributeField.getName())) {
 826  0
                     Column searchAttributeColumn = FieldUtils.constructColumnFromAttributeField(searchAttributeField);
 827  0
                     wrapDocumentAttributeColumnName(searchAttributeColumn);
 828  0
                     customColumns.add(searchAttributeColumn);
 829  0
                     continue outer;
 830  
                 }
 831  
             }
 832  0
             for (Column additionalAttributeColumn : additionalAttributeColumns) {
 833  0
                 if (additionalFieldNameToInclude.equals(additionalAttributeColumn.getPropertyName())) {
 834  0
                     wrapDocumentAttributeColumnName(additionalAttributeColumn);
 835  0
                     customColumns.add(additionalAttributeColumn);
 836  0
                     continue outer;
 837  
                 }
 838  
             }
 839  0
             LOG.warn("Failed to locate a proper column definition for requested additional field to include in"
 840  
                     + "result set with name '"
 841  
                     + additionalFieldNameToInclude
 842  
                     + "'");
 843  
         }
 844  0
         populateCustomColumns(customColumns, searchResult);
 845  
 
 846  
         // now merge the custom columns into the standard columns right before the route log (if the route log column wasn't removed!)
 847  0
         if (newColumns.isEmpty() || !StandardResultField.ROUTE_LOG.isFieldNameValid(newColumns.get(newColumns.size() - 1).getPropertyName())) {
 848  0
             newColumns.addAll(customColumns);
 849  
         } else {
 850  0
             newColumns.addAll(newColumns.size() - 1, customColumns);
 851  
         }
 852  0
         resultRow.setColumns(newColumns);
 853  0
     }
 854  
 
 855  
     protected void populateCustomColumns(List<Column> customColumns, DocumentSearchResult searchResult) {
 856  0
         for (Column customColumn : customColumns) {
 857  0
             DocumentAttribute documentAttribute =
 858  
                     searchResult.getSingleDocumentAttributeByName(customColumn.getPropertyName());
 859  0
             if (documentAttribute != null && documentAttribute.getValue() != null) {
 860  0
                 wrapDocumentAttributeColumnName(customColumn);
 861  
                 // list moving forward if the attribute has more than one value
 862  0
                 Formatter formatter = customColumn.getFormatter();
 863  0
                 customColumn.setPropertyValue(formatter.format(documentAttribute.getValue()).toString());
 864  
             }
 865  0
         }
 866  0
     }
 867  
 
 868  
     private void wrapDocumentAttributeColumnName(Column column) {
 869  
         // TODO - comment out for now, not sure we really want to do this...
 870  
         //column.setPropertyName(DOCUMENT_ATTRIBUTE_PROPERTY_NAME_PREFIX + column.getPropertyName());
 871  0
     }
 872  
 
 873  
     public void setDocumentSearchService(DocumentSearchService documentSearchService) {
 874  0
         this.documentSearchService = documentSearchService;
 875  0
     }
 876  
 
 877  
     public DocumentSearchService getDocumentSearchService() {
 878  0
         return documentSearchService;
 879  
     }
 880  
 
 881  
     public DocumentSearchCriteriaProcessor getDocumentSearchCriteriaProcessor() {
 882  0
         return documentSearchCriteriaProcessor;
 883  
     }
 884  
 
 885  
     public void setDocumentSearchCriteriaProcessor(DocumentSearchCriteriaProcessor documentSearchCriteriaProcessor) {
 886  0
         this.documentSearchCriteriaProcessor = documentSearchCriteriaProcessor;
 887  0
     }
 888  
 
 889  
     public DocumentSearchCriteriaTranslator getDocumentSearchCriteriaTranslator() {
 890  0
         return documentSearchCriteriaTranslator;
 891  
     }
 892  
 
 893  
     public void setDocumentSearchCriteriaTranslator(DocumentSearchCriteriaTranslator documentSearchCriteriaTranslator) {
 894  0
         this.documentSearchCriteriaTranslator = documentSearchCriteriaTranslator;
 895  0
     }
 896  
 
 897  
 }