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