1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.api.util.type.KualiDecimal;
31 import org.kuali.rice.core.api.util.type.KualiPercent;
32 import org.kuali.rice.core.web.format.Formatter;
33 import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
34 import org.kuali.rice.kew.api.KEWPropertyConstants;
35 import org.kuali.rice.kew.api.KewApiConstants;
36 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
37 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
38 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteriaContract;
39 import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
40 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
41 import org.kuali.rice.kew.docsearch.DocumentSearchCriteriaProcessor;
42 import org.kuali.rice.kew.docsearch.DocumentSearchCriteriaProcessorKEWAdapter;
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.framework.document.search.DocumentSearchCriteriaConfiguration;
48 import org.kuali.rice.kew.framework.document.search.DocumentSearchResultSetConfiguration;
49 import org.kuali.rice.kew.framework.document.search.StandardResultField;
50 import org.kuali.rice.kew.lookup.valuefinder.SavedSearchValuesFinder;
51 import org.kuali.rice.kew.service.KEWServiceLocator;
52 import org.kuali.rice.kew.user.UserUtils;
53 import org.kuali.rice.kim.api.identity.Person;
54 import org.kuali.rice.kns.datadictionary.BusinessObjectEntry;
55 import org.kuali.rice.kns.lookup.HtmlData;
56 import org.kuali.rice.kns.lookup.KualiLookupableHelperServiceImpl;
57 import org.kuali.rice.kns.lookup.LookupUtils;
58 import org.kuali.rice.kns.util.FieldUtils;
59 import org.kuali.rice.kns.web.struts.form.LookupForm;
60 import org.kuali.rice.kns.web.ui.Column;
61 import org.kuali.rice.kns.web.ui.Field;
62 import org.kuali.rice.kns.web.ui.ResultRow;
63 import org.kuali.rice.kns.web.ui.Row;
64 import org.kuali.rice.krad.UserSession;
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
71 import java.lang.reflect.InvocationTargetException;
72 import java.math.BigDecimal;
73 import java.text.MessageFormat;
74 import java.util.ArrayList;
75 import java.util.Collection;
76 import java.util.Collections;
77 import java.util.HashMap;
78 import java.util.List;
79 import java.util.Map;
80 import java.util.regex.Matcher;
81 import java.util.regex.Pattern;
82
83
84
85
86
87
88
89 public class DocumentSearchCriteriaBoLookupableHelperService extends KualiLookupableHelperServiceImpl {
90
91 static final String SAVED_SEARCH_NAME_PARAM = "savedSearchToLoadAndExecute";
92 static final String DOCUMENT_TYPE_NAME_PARAM = "documentTypeName";
93
94
95
96 private static final String EXCEED_THRESHOLD_MESSAGE_KEY = "docsearch.DocumentSearchService.exceededThreshold";
97 private static final String SECURITY_FILTERED_MESSAGE_KEY = "docsearch.DocumentSearchService.securityFiltered";
98 private static final String EXCEED_THRESHOLD_AND_SECURITY_FILTERED_MESSAGE_KEY = "docsearch.DocumentSearchService.exceededThresholdAndSecurityFiltered";
99
100 private static final boolean DOCUMENT_HANDLER_POPUP_DEFAULT = true;
101 private static final boolean ROUTE_LOG_POPUP_DEFAULT = true;
102
103
104
105 private DocumentSearchService documentSearchService;
106 private DocumentSearchCriteriaProcessor documentSearchCriteriaProcessor;
107 private DocumentSearchCriteriaTranslator documentSearchCriteriaTranslator;
108
109
110
111
112 private DocumentSearchResults searchResults = null;
113 private DocumentSearchCriteria criteria = null;
114
115 @Override
116 protected List<? extends BusinessObject> getSearchResultsHelper(Map<String, String> fieldValues, boolean unbounded) {
117 criteria = loadCriteria(fieldValues);
118 searchResults = null;
119 try {
120 searchResults = KEWServiceLocator.getDocumentSearchService().lookupDocuments(GlobalVariables.getUserSession().getPrincipalId(), criteria);
121 if (searchResults.isCriteriaModified()) {
122 criteria = searchResults.getCriteria();
123 }
124 } catch (WorkflowServiceErrorException wsee) {
125 for (WorkflowServiceError workflowServiceError : (List<WorkflowServiceError>) wsee.getServiceErrors()) {
126 if (workflowServiceError.getMessageMap() != null && workflowServiceError.getMessageMap().hasErrors()) {
127
128 GlobalVariables.getMessageMap().merge(workflowServiceError.getMessageMap());
129 } else {
130 GlobalVariables.getMessageMap().putError(workflowServiceError.getMessage(), RiceKeyConstants.ERROR_CUSTOM, workflowServiceError.getMessage());
131 }
132 }
133 }
134
135 if (!GlobalVariables.getMessageMap().hasNoErrors() || searchResults == null) {
136 throw new ValidationException("error with doc search");
137 }
138
139 populateResultWarningMessages(searchResults);
140
141 List<DocumentSearchResult> individualSearchResults = searchResults.getSearchResults();
142
143 setBackLocation(fieldValues.get(KRADConstants.BACK_LOCATION));
144 setDocFormKey(fieldValues.get(KRADConstants.DOC_FORM_KEY));
145
146 applyCriteriaChangesToFields(criteria);
147
148 return populateSearchResults(individualSearchResults);
149
150 }
151
152
153
154
155 protected void populateResultWarningMessages(DocumentSearchResults searchResults) {
156
157 boolean overThreshold = searchResults.isOverThreshold();
158 int numFiltered = searchResults.getNumberOfSecurityFilteredResults();
159 int numResults = searchResults.getSearchResults().size();
160 if (overThreshold && numFiltered > 0) {
161 GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, EXCEED_THRESHOLD_AND_SECURITY_FILTERED_MESSAGE_KEY, String.valueOf(numResults), String.valueOf(numFiltered));
162 } else if (numFiltered > 0) {
163 GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, SECURITY_FILTERED_MESSAGE_KEY, String.valueOf(numFiltered));
164 } else if (overThreshold) {
165 GlobalVariables.getMessageMap().putWarning(KRADConstants.GLOBAL_MESSAGES, EXCEED_THRESHOLD_MESSAGE_KEY, String.valueOf(numResults));
166 }
167 }
168
169
170
171
172
173 protected void applyCriteriaChangesToFields(DocumentSearchCriteriaContract criteria) {
174 Field field = getFormFields().getField(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + "dateCreated");
175 if (field != null && StringUtils.isEmpty(field.getPropertyValue())) {
176 if (criteria.getDateCreatedFrom() != null) {
177 field.setPropertyValue(CoreApiServiceLocator.getDateTimeService().toDateString(criteria.getDateCreatedFrom().toDate()));
178 }
179 }
180 }
181
182
183
184 private static final Pattern CURRENT_USER_PATTERN = Pattern.compile("(?<=[\\s\\p{Punct}]|^)CURRENT_USER(\\.\\w+)?(?=[\\s\\p{Punct}]|$)");
185
186 protected static String replaceCurrentUserToken(String value, Person person) {
187 Matcher matcher = CURRENT_USER_PATTERN.matcher(value);
188 boolean matched = false;
189 StringBuffer sb = new StringBuffer();
190 while (matcher.find()) {
191 matched = true;
192 String idType = "principalName";
193 if (matcher.groupCount() > 0) {
194 String group = matcher.group(1);
195 if (group != null) {
196 idType = group.substring(1);
197 }
198 }
199 String idValue = UserUtils.getIdValue(idType, person);
200 if (!StringUtils.isBlank(idValue)) {
201 value = idValue;
202 } else {
203 value = matcher.group();
204 }
205 matcher.appendReplacement(sb, value);
206
207 }
208 matcher.appendTail(sb);
209 return matched ? sb.toString() : null;
210 }
211
212
213
214
215
216 protected static Map<String, String> cleanupFieldValues(Map<String, String> fieldValues, Map<String, String[]> parameters) {
217 Map<String, String> cleanedUpFieldValues = new HashMap<String, String>(fieldValues);
218 if (ArrayUtils.isNotEmpty(parameters.get(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE))) {
219 cleanedUpFieldValues.put(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE,
220 StringUtils.join(parameters.get(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE), ","));
221 }
222 Map<String, String> documentAttributeFieldValues = new HashMap<String, String>();
223 for (String parameterName : parameters.keySet()) {
224 if (parameterName.contains(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX)) {
225 String[] value = parameters.get(parameterName);
226 if (ArrayUtils.isNotEmpty(value)) {
227 documentAttributeFieldValues.put(parameterName, StringUtils.join(value, " " + SearchOperator.OR.op() + " "));
228 }
229 }
230 }
231
232 documentAttributeFieldValues.putAll(LookupUtils.preProcessRangeFields(documentAttributeFieldValues));
233 cleanedUpFieldValues.putAll(documentAttributeFieldValues);
234
235 replaceCurrentUserInFields(cleanedUpFieldValues);
236
237 return cleanedUpFieldValues;
238 }
239
240 protected static void replaceCurrentUserInFields(Map<String, String> fields) {
241 Person person = GlobalVariables.getUserSession().getPerson();
242
243 for (Map.Entry<String, String> entry: fields.entrySet()) {
244 if (StringUtils.isNotEmpty(entry.getValue())) {
245 String replaced = replaceCurrentUserToken(entry.getValue(), person);
246 if (replaced != null) {
247 entry.setValue(replaced);
248 }
249 }
250 }
251 }
252
253
254
255
256
257 protected DocumentSearchCriteria loadCriteria(Map<String, String> fieldValues) {
258 fieldValues = cleanupFieldValues(fieldValues, getParameters());
259 String[] savedSearchToLoad = getParameters().get(SAVED_SEARCH_NAME_PARAM);
260 boolean savedSearch = savedSearchToLoad != null && savedSearchToLoad.length > 0 && StringUtils.isNotBlank(savedSearchToLoad[0]);
261 if (savedSearch) {
262 DocumentSearchCriteria criteria = getDocumentSearchService().getNamedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchToLoad[0]);
263 if (criteria != null) {
264 getFormFields().setFieldValues(getDocumentSearchCriteriaTranslator().translateCriteriaToFields(criteria));
265 return criteria;
266 }
267 }
268
269 return getDocumentSearchCriteriaTranslator().translateFieldsToCriteria(fieldValues);
270 }
271
272 protected List<DocumentSearchCriteriaBo> populateSearchResults(List<DocumentSearchResult> lookupResults) {
273 List<DocumentSearchCriteriaBo> searchResults = new ArrayList<DocumentSearchCriteriaBo>();
274 for (DocumentSearchResult searchResult : lookupResults) {
275 DocumentSearchCriteriaBo result = new DocumentSearchCriteriaBo();
276 result.populateFromDocumentSearchResult(searchResult);
277 searchResults.add(result);
278 }
279 return searchResults;
280 }
281
282 @Override
283 public Collection<? extends BusinessObject> performLookup(LookupForm lookupForm, Collection<ResultRow> resultTable, boolean bounded) {
284 Collection<? extends BusinessObject> lookupResult = super.performLookup(lookupForm, resultTable, bounded);
285 postProcessResults(resultTable, this.searchResults);
286 return lookupResult;
287 }
288
289
290
291
292 protected void overrideFieldValue(Field field, Map<String, String[]> newValues, Map<String, String[]> oldValues) {
293 if (StringUtils.isNotBlank(field.getPropertyName())) {
294 if (newValues.get(field.getPropertyName()) != null) {
295 getFormFields().setFieldValue(field, newValues.get(field.getPropertyName()));
296 } else if (oldValues.get(field.getPropertyName()) != null) {
297 getFormFields().setFieldValue(field, oldValues.get(field.getPropertyName()));
298 }
299 }
300 }
301
302
303
304
305
306 protected void toggleFormView() {
307 Map<String,String[]> fieldValues = new HashMap<String,String[]>();
308 Map<String, String[]> savedValues = getFormFields().getFieldValues();
309
310
311
312
313
314 for (Field field: getFormFields().getFields()) {
315 overrideFieldValue(field, this.getParameters(), savedValues);
316
317
318 applyFieldAuthorizationsFromNestedLookups(field);
319 fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
320 }
321
322
323 if (checkForAdditionalFieldsMultiValued(fieldValues)) {
324 for (Field field: getFormFields().getFields()) {
325 overrideFieldValue(field, this.getParameters(), savedValues);
326 fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
327 }
328 }
329
330
331
332 getFormFields().setFieldValue(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, "");
333 }
334
335
336
337
338
339 protected boolean loadSavedSearch(boolean ignoreErrors) {
340 Map<String,String[]> fieldValues = new HashMap<String,String[]>();
341
342 String savedSearchName = getSavedSearchName();
343 if(StringUtils.isEmpty(savedSearchName) || "*ignore*".equals(savedSearchName)) {
344 if(!ignoreErrors) {
345 GlobalVariables.getMessageMap().putError(SAVED_SEARCH_NAME_PARAM, RiceKeyConstants.ERROR_CUSTOM, "You must select a saved search");
346 } else {
347
348 return false;
349 }
350 getFormFields().setFieldValue(SAVED_SEARCH_NAME_PARAM, "");
351 }
352 if (!GlobalVariables.getMessageMap().hasNoErrors()) {
353 throw new ValidationException("errors in search criteria");
354 }
355
356 DocumentSearchCriteria criteria = KEWServiceLocator.getDocumentSearchService().getSavedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchName);
357
358
359 String docTypeName = criteria.getDocumentTypeName();
360
361
362 if(this.getParameters().containsKey(DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD)) {
363 Map<String, String[]> parameters = this.getParameters();
364 String[] params = (String[])parameters.get(DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD);
365 if (ArrayUtils.isNotEmpty(params)) {
366 params[0] = criteria.getIsAdvancedSearch();
367 this.setParameters(parameters);
368 }
369 }
370
371
372 setRows(docTypeName);
373
374
375
376
377
378 for (Map.Entry<String, List<String>> entry: criteria.getDocumentAttributeValues().entrySet()) {
379 fieldValues.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
380 }
381
382
383 for (Field field : getFormFields().getFields()) {
384 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
385
386
387 String[] values = null;
388 if (fieldValues.get(field.getPropertyName()) != null) {
389 values = fieldValues.get(field.getPropertyName());
390 } else {
391
392 try {
393 values = new String[] { ObjectUtils.toString(PropertyUtils.getProperty(criteria, field.getPropertyName())) };
394 } catch (IllegalAccessException e) {
395 e.printStackTrace();
396 } catch (InvocationTargetException e) {
397 e.printStackTrace();
398 } catch (NoSuchMethodException e) {
399
400
401 }
402 }
403 if (values != null) {
404 getFormFields().setFieldValue(field, values);
405 }
406 }
407 }
408
409 return true;
410 }
411
412
413
414
415
416
417
418
419
420
421 @Override
422 public boolean performCustomAction(boolean ignoreErrors) {
423
424 if (isClearSavedSearch()) {
425 KEWServiceLocator.getDocumentSearchService().clearNamedSearches(GlobalVariables.getUserSession().getPrincipalId());
426 return false;
427 }
428 else if (getSavedSearchName() != null) {
429 return loadSavedSearch(ignoreErrors);
430 } else {
431 toggleFormView();
432
433 return false;
434 }
435 }
436
437
438
439
440 @Override
441 public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
442 DocumentSearchCriteriaBo criteriaBo = (DocumentSearchCriteriaBo)bo;
443 if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_DOCUMENT_ID.equals(propertyName)) {
444 return generateDocumentHandlerUrl(criteriaBo.getDocumentId(), criteriaBo.getDocumentType(),
445 isSuperUserSearch());
446 } else if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG.equals(propertyName)) {
447 return generateRouteLogUrl(criteriaBo.getDocumentId());
448 }
449 return super.getInquiryUrl(bo, propertyName);
450 }
451
452
453
454
455
456 protected HtmlData.AnchorHtmlData generateDocumentHandlerUrl(String documentId, DocumentType documentType, boolean superUserSearch) {
457 HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
458 link.setDisplayText(documentId);
459 if (isDocumentHandlerPopup()) {
460 link.setTarget("_blank");
461 }else{
462 link.setTarget("_self");
463 }
464 String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/";
465 if (superUserSearch) {
466 if (documentType.getUseWorkflowSuperUserDocHandlerUrl().getPolicyValue().booleanValue()) {
467 url += "SuperUser.do?methodToCall=displaySuperUserDocument&documentId=" + documentId;
468 } else {
469 url = KewApiConstants.DOC_HANDLER_REDIRECT_PAGE
470 + "?" + KewApiConstants.COMMAND_PARAMETER + "="
471 + KewApiConstants.SUPERUSER_COMMAND + "&"
472 + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
473 + documentId;
474 }
475 } else {
476 url += KewApiConstants.DOC_HANDLER_REDIRECT_PAGE + "?"
477 + KewApiConstants.COMMAND_PARAMETER + "="
478 + KewApiConstants.DOCSEARCH_COMMAND + "&"
479 + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
480 + documentId;
481 }
482 link.setHref(url);
483 return link;
484 }
485
486 protected HtmlData.AnchorHtmlData generateRouteLogUrl(String documentId) {
487 HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
488
489 if (isRouteLogPopup()) {
490 link.setTarget("_blank");
491 }
492 else {
493 link.setTarget("_self");
494 }
495 link.setDisplayText("Route Log for document " + documentId);
496 String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/" +
497 "RouteLog.do?documentId=" + documentId;
498 link.setHref(url);
499 return link;
500 }
501
502
503
504
505 protected boolean isDocumentHandlerPopup() {
506 return BooleanUtils.toBooleanDefaultIfNull(
507 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
508 KewApiConstants.KEW_NAMESPACE,
509 KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
510 KewApiConstants.DOCUMENT_SEARCH_DOCUMENT_POPUP_IND),
511 DOCUMENT_HANDLER_POPUP_DEFAULT);
512 }
513
514
515
516
517 public boolean isRouteLogPopup() {
518 return BooleanUtils.toBooleanDefaultIfNull(
519 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KewApiConstants.KEW_NAMESPACE,
520 KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
521 KewApiConstants.DOCUMENT_SEARCH_ROUTE_LOG_POPUP_IND), ROUTE_LOG_POPUP_DEFAULT);
522 }
523
524
525
526
527 protected boolean isFlagSet(String flagName) {
528 if(this.getParameters().containsKey(flagName)) {
529 String[] params = (String[])this.getParameters().get(flagName);
530 if (ArrayUtils.isNotEmpty(params)) {
531 return "YES".equalsIgnoreCase(params[0]);
532 }
533 }
534 return false;
535 }
536
537
538
539
540 protected boolean isSuperUserSearch() {
541 return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD);
542 }
543
544
545
546
547 protected boolean isAdvancedSearch() {
548 return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD);
549 }
550
551
552
553
554 protected boolean isClearSavedSearch() {
555 return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD);
556 }
557
558 protected String getSavedSearchName() {
559 String[] savedSearchName = getParameters().get(SAVED_SEARCH_NAME_PARAM);
560 if (savedSearchName != null && savedSearchName.length > 0) {
561 return savedSearchName[0];
562 }
563 return null;
564 }
565
566
567
568
569 @Override
570 protected void setRows() {
571 this.setRows(null);
572 }
573
574
575
576
577 protected FormFields getFormFields() {
578 return new FormFields(this.getRows());
579 }
580
581
582
583
584
585
586
587
588
589 protected void setRows(String documentTypeName) {
590
591 super.setRows();
592
593 List<Row> lookupRows = new ArrayList<Row>();
594
595 for (Row row : getRows()) {
596 lookupRows.add(row);
597 }
598
599 getRows().clear();
600
601 DocumentType docType = getValidDocumentType(documentTypeName);
602
603 boolean advancedSearch = isAdvancedSearch();
604 boolean superUserSearch = isSuperUserSearch();
605
606
607 List<Row> rows = getDocumentSearchCriteriaProcessor().getRows(docType,lookupRows, advancedSearch, superUserSearch);
608
609 BusinessObjectEntry boe = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(this.getBusinessObjectClass().getName());
610 int numCols = boe.getLookupDefinition().getNumOfColumns();
611 if(numCols == 0) {
612 numCols = KRADConstants.DEFAULT_NUM_OF_COLUMNS;
613 }
614
615 super.getRows().addAll(FieldUtils.wrapFields(new FormFields(rows).getFieldList(), numCols));
616
617 }
618
619
620
621
622
623
624 private DocumentType getValidDocumentType(String documentTypeName) {
625 if (StringUtils.isNotEmpty(documentTypeName)) {
626 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByNameCaseInsensitive(documentTypeName.trim());
627 if (documentType != null && documentType.isActive()) {
628 return documentType;
629 }
630 }
631 return null;
632 }
633
634 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''/>";
635
636 @Override
637 public String getSupplementalMenuBar() {
638 boolean advancedSearch = isAdvancedSearch();
639 boolean superUserSearch = isSuperUserSearch();
640 StringBuilder suppMenuBar = new StringBuilder();
641
642
643
644
645 String type = advancedSearch ? "basic" : "detailed";
646 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleAdvancedSearch", KewApiConstants.WEBAPP_DIRECTORY, type, type));
647
648
649 suppMenuBar.append(" ");
650 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleSuperUserSearch", KewApiConstants.WEBAPP_DIRECTORY, superUserSearch ? "nonsupu" : "superuser", superUserSearch ? "non-superuser" : "superuser"));
651
652
653 suppMenuBar.append(" ");
654 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, KewApiConstants.WEBAPP_DIRECTORY, "clearsaved", "clear saved searches"));
655
656
657 suppMenuBar.append("<script type=\"text/javascript\">"
658 + " jQuery(document).ready(function () {"
659 + " jQuery(\"#documentTypeName\").blur(function () { validateDocTypeAndRefresh( this ); });"
660 + "});</script>");
661
662 return suppMenuBar.toString();
663 }
664
665 @Override
666 public boolean shouldDisplayHeaderNonMaintActions() {
667 return true;
668 }
669
670 @Override
671 public boolean shouldDisplayLookupCriteria() {
672 return true;
673 }
674
675
676
677
678
679 @Override
680 public boolean checkForAdditionalFields(Map<String, String> fieldValues) {
681 return checkForAdditionalFieldsForDocumentType(fieldValues.get(DOCUMENT_TYPE_NAME_PARAM));
682 }
683
684 private boolean checkForAdditionalFieldsMultiValued(Map<String, String[]> fieldValues) {
685 String[] valArray = fieldValues.get(DOCUMENT_TYPE_NAME_PARAM);
686 String val = null;
687 if (valArray != null && valArray.length > 0) {
688 val = valArray[0];
689 }
690 return checkForAdditionalFieldsForDocumentType(val);
691 }
692
693 private boolean checkForAdditionalFieldsForDocumentType(String documentTypeName) {
694 if (StringUtils.isNotBlank(documentTypeName)) {
695 setRows(documentTypeName);
696 }
697 return true;
698 }
699
700 @Override
701 public Field getExtraField() {
702 SavedSearchValuesFinder savedSearchValuesFinder = new SavedSearchValuesFinder();
703 List<KeyValue> savedSearchValues = savedSearchValuesFinder.getKeyValues();
704 Field savedSearch = new Field();
705 savedSearch.setPropertyName(SAVED_SEARCH_NAME_PARAM);
706 savedSearch.setFieldType(Field.DROPDOWN_SCRIPT);
707 savedSearch.setScript("customLookupChanged()");
708 savedSearch.setFieldValidValues(savedSearchValues);
709 savedSearch.setFieldLabel("Saved Searches");
710 return savedSearch;
711 }
712
713 @Override
714 public void performClear(LookupForm lookupForm) {
715 DocumentSearchCriteria criteria = loadCriteria(lookupForm.getFields());
716 super.performClear(lookupForm);
717 repopulateSearchTypeFlags();
718 DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
719 if (documentType != null) {
720 DocumentSearchCriteria clearedCriteria = documentSearchService.clearCriteria(documentType, criteria);
721 applyCriteriaChangesToFields(DocumentSearchCriteria.Builder.create(clearedCriteria));
722 }
723 }
724
725
726
727
728 protected void repopulateSearchTypeFlags() {
729 boolean advancedSearch = isAdvancedSearch();
730 boolean superUserSearch = isSuperUserSearch();
731 int fieldsRepopulated = 0;
732 Map<String, String[]> values = new HashMap<String, String[]>();
733 values.put(DocumentSearchCriteriaProcessorKEWAdapter.ADVANCED_SEARCH_FIELD, new String[] { advancedSearch ? "YES" : "NO" });
734 values.put(DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD, new String[] { superUserSearch ? "YES" : "NO" });
735 getFormFields().setFieldValues(values);
736 }
737
738
739
740
741 protected void postProcessResults(Collection<ResultRow> resultRows, DocumentSearchResults searchResults) {
742 if (resultRows.size() != searchResults.getSearchResults().size()) {
743 throw new IllegalStateException("Encountered a mismatch between ResultRow items and document search results "
744 + resultRows.size() + " != " + searchResults.getSearchResults().size());
745 }
746 DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
747 DocumentSearchResultSetConfiguration resultSetConfiguration = null;
748 DocumentSearchCriteriaConfiguration criteriaConfiguration = null;
749 if (documentType != null) {
750 resultSetConfiguration = KEWServiceLocator.getDocumentSearchCustomizationMediator().customizeResultSetConfiguration(documentType, criteria);
751 criteriaConfiguration = KEWServiceLocator.getDocumentSearchCustomizationMediator().getDocumentSearchCriteriaConfiguration(documentType);
752 }
753 int index = 0;
754 for (ResultRow resultRow : resultRows) {
755 DocumentSearchResult searchResult = searchResults.getSearchResults().get(index);
756 executeColumnCustomization(resultRow, searchResult, resultSetConfiguration, criteriaConfiguration);
757 index++;
758 }
759 }
760
761
762
763
764
765 protected void executeColumnCustomization(ResultRow resultRow, DocumentSearchResult searchResult,
766 DocumentSearchResultSetConfiguration resultSetConfiguration,
767 DocumentSearchCriteriaConfiguration criteriaConfiguration) {
768 if (resultSetConfiguration == null) {
769 resultSetConfiguration = DocumentSearchResultSetConfiguration.Builder.create().build();
770 }
771 if (criteriaConfiguration == null) {
772 criteriaConfiguration = DocumentSearchCriteriaConfiguration.Builder.create().build();
773 }
774 List<StandardResultField> standardFieldsToRemove = resultSetConfiguration.getStandardResultFieldsToRemove();
775 if (standardFieldsToRemove == null) {
776 standardFieldsToRemove = Collections.emptyList();
777 }
778 List<Column> newColumns = new ArrayList<Column>();
779 for (Column standardColumn : resultRow.getColumns()) {
780 if (!standardFieldsToRemove.contains(StandardResultField.fromFieldName(standardColumn.getPropertyName()))) {
781 newColumns.add(standardColumn);
782
783
784 if (standardColumn.getPropertyName().equals(
785 KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG)) {
786 standardColumn.setEscapeXMLValue(false);
787 }
788 }
789 }
790
791
792 List<RemotableAttributeField> searchAttributeFields = criteriaConfiguration.getFlattenedSearchAttributeFields();
793 List<String> additionalFieldNamesToInclude = new ArrayList<String>();
794 if (!resultSetConfiguration.isOverrideSearchableAttributes()) {
795 for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
796
797
798 if (searchAttributeField.getAttributeLookupSettings() == null ||
799 searchAttributeField.getAttributeLookupSettings().isInResults()) {
800 additionalFieldNamesToInclude.add(searchAttributeField.getName());
801 }
802 }
803 }
804 if (resultSetConfiguration.getCustomFieldNamesToAdd() != null) {
805 additionalFieldNamesToInclude.addAll(resultSetConfiguration.getCustomFieldNamesToAdd());
806 }
807
808
809 List<Column> customColumns = new ArrayList<Column>();
810 List<Column> additionalAttributeColumns = FieldUtils.constructColumnsFromAttributeFields(resultSetConfiguration.getAdditionalAttributeFields());
811
812 outer:for (String additionalFieldNameToInclude : additionalFieldNamesToInclude) {
813
814 for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
815 if (additionalFieldNameToInclude.equals(searchAttributeField.getName())) {
816 Column searchAttributeColumn = FieldUtils.constructColumnFromAttributeField(searchAttributeField);
817 wrapDocumentAttributeColumnName(searchAttributeColumn);
818 customColumns.add(searchAttributeColumn);
819 continue outer;
820 }
821 }
822 for (Column additionalAttributeColumn : additionalAttributeColumns) {
823 if (additionalFieldNameToInclude.equals(additionalAttributeColumn.getPropertyName())) {
824 wrapDocumentAttributeColumnName(additionalAttributeColumn);
825 customColumns.add(additionalAttributeColumn);
826 continue outer;
827 }
828 }
829 LOG.warn("Failed to locate a proper column definition for requested additional field to include in"
830 + "result set with name '"
831 + additionalFieldNameToInclude
832 + "'");
833 }
834 populateCustomColumns(customColumns, searchResult);
835
836
837 if (newColumns.isEmpty() || !StandardResultField.ROUTE_LOG.isFieldNameValid(newColumns.get(newColumns.size() - 1).getPropertyName())) {
838 newColumns.addAll(customColumns);
839 } else {
840 newColumns.addAll(newColumns.size() - 1, customColumns);
841 }
842 resultRow.setColumns(newColumns);
843 }
844
845 protected void populateCustomColumns(List<Column> customColumns, DocumentSearchResult searchResult) {
846 for (Column customColumn : customColumns) {
847 DocumentAttribute documentAttribute = searchResult.getSingleDocumentAttributeByName(customColumn.getPropertyName());
848 if (documentAttribute != null && documentAttribute.getValue() != null) {
849 wrapDocumentAttributeColumnName(customColumn);
850
851 Formatter formatter = customColumn.getFormatter();
852 Object attributeValue = documentAttribute.getValue();
853 if (formatter.getPropertyType().equals(KualiDecimal.class)
854 && documentAttribute.getValue() instanceof BigDecimal) {
855 attributeValue = new KualiDecimal((BigDecimal)attributeValue);
856 } else if (formatter.getPropertyType().equals(KualiPercent.class)
857 && documentAttribute.getValue() instanceof BigDecimal) {
858 attributeValue = new KualiPercent((BigDecimal)attributeValue);
859 }
860 customColumn.setPropertyValue(formatter.format(attributeValue).toString());
861 }
862 }
863 }
864
865 private void wrapDocumentAttributeColumnName(Column column) {
866
867
868 }
869
870 public void setDocumentSearchService(DocumentSearchService documentSearchService) {
871 this.documentSearchService = documentSearchService;
872 }
873
874 public DocumentSearchService getDocumentSearchService() {
875 return documentSearchService;
876 }
877
878 public DocumentSearchCriteriaProcessor getDocumentSearchCriteriaProcessor() {
879 return documentSearchCriteriaProcessor;
880 }
881
882 public void setDocumentSearchCriteriaProcessor(DocumentSearchCriteriaProcessor documentSearchCriteriaProcessor) {
883 this.documentSearchCriteriaProcessor = documentSearchCriteriaProcessor;
884 }
885
886 public DocumentSearchCriteriaTranslator getDocumentSearchCriteriaTranslator() {
887 return documentSearchCriteriaTranslator;
888 }
889
890 public void setDocumentSearchCriteriaTranslator(DocumentSearchCriteriaTranslator documentSearchCriteriaTranslator) {
891 this.documentSearchCriteriaTranslator = documentSearchCriteriaTranslator;
892 }
893 }