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 documentAttributeFieldValues.put(parameterName, StringUtils.join(value, " " + SearchOperator.OR.op() + " "));
236 }
237 }
238 }
239
240 documentAttributeFieldValues.putAll(LookupUtils.preProcessRangeFields(documentAttributeFieldValues));
241 cleanedUpFieldValues.putAll(documentAttributeFieldValues);
242
243 replaceCurrentUserInFields(cleanedUpFieldValues);
244
245 return cleanedUpFieldValues;
246 }
247
248 protected static void replaceCurrentUserInFields(Map<String, String> fields) {
249 Person person = GlobalVariables.getUserSession().getPerson();
250
251 for (Map.Entry<String, String> entry: fields.entrySet()) {
252 if (StringUtils.isNotEmpty(entry.getValue())) {
253 String replaced = replaceCurrentUserToken(entry.getValue(), person);
254 if (replaced != null) {
255 entry.setValue(replaced);
256 }
257 }
258 }
259 }
260
261
262
263
264
265 protected DocumentSearchCriteria loadCriteria(Map<String, String> fieldValues) {
266 fieldValues = cleanupFieldValues(fieldValues, getParameters());
267 String[] savedSearchToLoad = getParameters().get(SAVED_SEARCH_NAME_PARAM);
268 boolean savedSearch = savedSearchToLoad != null && savedSearchToLoad.length > 0 && StringUtils.isNotBlank(savedSearchToLoad[0]);
269 if (savedSearch) {
270 DocumentSearchCriteria criteria = getDocumentSearchService().getNamedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchToLoad[0]);
271 if (criteria != null) {
272 getFormFields().setFieldValues(getDocumentSearchCriteriaTranslator().translateCriteriaToFields(criteria));
273 return criteria;
274 }
275 }
276
277 return getDocumentSearchCriteriaTranslator().translateFieldsToCriteria(fieldValues);
278 }
279
280 protected List<DocumentSearchCriteriaBo> populateSearchResults(List<DocumentSearchResult> lookupResults) {
281 List<DocumentSearchCriteriaBo> searchResults = new ArrayList<DocumentSearchCriteriaBo>();
282 for (DocumentSearchResult searchResult : lookupResults) {
283 DocumentSearchCriteriaBo result = new DocumentSearchCriteriaBo();
284 result.populateFromDocumentSearchResult(searchResult);
285 searchResults.add(result);
286 }
287 return searchResults;
288 }
289
290 @Override
291 public Collection<? extends BusinessObject> performLookup(LookupForm lookupForm, Collection<ResultRow> resultTable, boolean bounded) {
292 Collection<? extends BusinessObject> lookupResult = super.performLookup(lookupForm, resultTable, bounded);
293 postProcessResults(resultTable, this.searchResults);
294 return lookupResult;
295 }
296
297
298
299
300 protected void overrideFieldValue(Field field, Map<String, String[]> newValues, Map<String, String[]> oldValues) {
301 if (StringUtils.isNotBlank(field.getPropertyName())) {
302 if (newValues.get(field.getPropertyName()) != null) {
303 getFormFields().setFieldValue(field, newValues.get(field.getPropertyName()));
304 } else if (oldValues.get(field.getPropertyName()) != null) {
305 getFormFields().setFieldValue(field, oldValues.get(field.getPropertyName()));
306 }
307 }
308 }
309
310
311
312
313
314 protected void toggleFormView() {
315 Map<String,String[]> fieldValues = new HashMap<String,String[]>();
316 Map<String, String[]> savedValues = getFormFields().getFieldValues();
317
318
319
320
321
322 for (Field field: getFormFields().getFields()) {
323 overrideFieldValue(field, this.getParameters(), savedValues);
324
325
326 applyFieldAuthorizationsFromNestedLookups(field);
327 fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
328 }
329
330
331 if (checkForAdditionalFieldsMultiValued(fieldValues)) {
332 for (Field field: getFormFields().getFields()) {
333 overrideFieldValue(field, this.getParameters(), savedValues);
334 fieldValues.put(field.getPropertyName(), new String[] { field.getPropertyValue() });
335 }
336 }
337
338
339
340 getFormFields().setFieldValue(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, "");
341 }
342
343
344
345
346
347 protected boolean loadSavedSearch(boolean ignoreErrors) {
348 Map<String,String[]> fieldValues = new HashMap<String,String[]>();
349
350 String savedSearchName = getSavedSearchName();
351 if(StringUtils.isEmpty(savedSearchName) || "*ignore*".equals(savedSearchName)) {
352 if(!ignoreErrors) {
353 GlobalVariables.getMessageMap().putError(SAVED_SEARCH_NAME_PARAM, RiceKeyConstants.ERROR_CUSTOM, "You must select a saved search");
354 } else {
355
356 return false;
357 }
358 getFormFields().setFieldValue(SAVED_SEARCH_NAME_PARAM, "");
359 }
360 if (!GlobalVariables.getMessageMap().hasNoErrors()) {
361 throw new ValidationException("errors in search criteria");
362 }
363
364 DocumentSearchCriteria criteria = KEWServiceLocator.getDocumentSearchService().getSavedSearchCriteria(GlobalVariables.getUserSession().getPrincipalId(), savedSearchName);
365
366
367 String docTypeName = criteria.getDocumentTypeName();
368
369
370 if(this.getParameters().containsKey(KRADConstants.ADVANCED_SEARCH_FIELD)) {
371 Map<String, String[]> parameters = this.getParameters();
372 String[] params = (String[])parameters.get(KRADConstants.ADVANCED_SEARCH_FIELD);
373 if (ArrayUtils.isNotEmpty(params)) {
374 params[0] = criteria.getIsAdvancedSearch();
375 this.setParameters(parameters);
376 }
377 }
378
379
380 setRows(docTypeName);
381
382
383
384
385
386 for (Map.Entry<String, List<String>> entry: criteria.getDocumentAttributeValues().entrySet()) {
387 fieldValues.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
388 }
389
390
391 for (Field field : getFormFields().getFields()) {
392 if (field.getPropertyName() != null && !field.getPropertyName().equals("")) {
393
394
395 String[] values = null;
396 if (fieldValues.get(field.getPropertyName()) != null) {
397 values = fieldValues.get(field.getPropertyName());
398 } else {
399
400 try {
401 if (field.isRanged() && field.isDatePicker()) {
402 if (field.getPropertyName().startsWith(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX)) {
403 String lowerBoundName = field.getPropertyName().replace(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX, "") + "From";
404 Object lowerBoundDate = PropertyUtils.getProperty(criteria, lowerBoundName);
405 if (lowerBoundDate != null) {
406 values = new String[] { CoreApiServiceLocator.getDateTimeService().toDateTimeString(((org.joda.time.DateTime)lowerBoundDate).toDate()) };
407 }
408 } else {
409
410 String upperBoundName = field.getPropertyName().replace(KRADConstants.LOOKUP_RANGE_UPPER_BOUND_PROPERTY_PREFIX, "") + "To";
411 Object upperBoundDate = PropertyUtils.getProperty(criteria, upperBoundName);
412 if (upperBoundDate != null) {
413 values = new String[] { CoreApiServiceLocator.getDateTimeService().toDateTimeString(
414 ((org.joda.time.DateTime)upperBoundDate)
415 .toDate()) };
416 }
417 }
418 } else {
419 values = new String[] { ObjectUtils.toString(PropertyUtils.getProperty(criteria, field.getPropertyName())) };
420 }
421 } catch (IllegalAccessException e) {
422 e.printStackTrace();
423 } catch (InvocationTargetException e) {
424 e.printStackTrace();
425 } catch (NoSuchMethodException e) {
426
427
428 }
429 }
430 if (values != null) {
431 getFormFields().setFieldValue(field, values);
432 }
433 }
434 }
435
436 return true;
437 }
438
439
440
441
442
443
444
445
446
447
448 @Override
449 public boolean performCustomAction(boolean ignoreErrors) {
450
451 if (isClearSavedSearch()) {
452 KEWServiceLocator.getDocumentSearchService().clearNamedSearches(GlobalVariables.getUserSession().getPrincipalId());
453 return false;
454 }
455 else if (getSavedSearchName() != null) {
456 return loadSavedSearch(ignoreErrors);
457 } else {
458 toggleFormView();
459
460 return false;
461 }
462 }
463
464
465
466
467 @Override
468 public HtmlData getInquiryUrl(BusinessObject bo, String propertyName) {
469 DocumentSearchCriteriaBo criteriaBo = (DocumentSearchCriteriaBo)bo;
470 if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_DOCUMENT_ID.equals(propertyName)) {
471 return generateDocumentHandlerUrl(criteriaBo.getDocumentId(), criteriaBo.getDocumentType(),
472 isSuperUserSearch());
473 } else if (KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG.equals(propertyName)) {
474 return generateRouteLogUrl(criteriaBo.getDocumentId());
475 } else if(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_INITIATOR_DISPLAY_NAME.equals(propertyName)) {
476 return generateInitiatorUrl(criteriaBo.getInitiatorPerson());
477 }
478 return super.getInquiryUrl(bo, propertyName);
479 }
480
481
482
483
484
485 protected HtmlData.AnchorHtmlData generateDocumentHandlerUrl(String documentId, DocumentType documentType, boolean superUserSearch) {
486 HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
487 link.setDisplayText(documentId);
488 if (isDocumentHandlerPopup()) {
489 link.setTarget("_blank");
490 }else{
491 link.setTarget("_self");
492 }
493 String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/";
494 if (superUserSearch) {
495 if (documentType.getUseWorkflowSuperUserDocHandlerUrl().getPolicyValue().booleanValue()) {
496 url += "SuperUser.do?methodToCall=displaySuperUserDocument&documentId=" + documentId;
497 } else {
498 url = KewApiConstants.DOC_HANDLER_REDIRECT_PAGE
499 + "?" + KewApiConstants.COMMAND_PARAMETER + "="
500 + KewApiConstants.SUPERUSER_COMMAND + "&"
501 + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
502 + documentId;
503 }
504 } else {
505 url += KewApiConstants.DOC_HANDLER_REDIRECT_PAGE + "?"
506 + KewApiConstants.COMMAND_PARAMETER + "="
507 + KewApiConstants.DOCSEARCH_COMMAND + "&"
508 + KewApiConstants.DOCUMENT_ID_PARAMETER + "="
509 + documentId;
510 }
511 link.setHref(url);
512 return link;
513 }
514
515 protected HtmlData.AnchorHtmlData generateRouteLogUrl(String documentId) {
516 HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
517
518 if (isRouteLogPopup()) {
519 link.setTarget("_blank");
520 }
521 else {
522 link.setTarget("_self");
523 }
524 link.setDisplayText("Route Log for document " + documentId);
525 String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KEW_URL) + "/" +
526 "RouteLog.do?documentId=" + documentId;
527 link.setHref(url);
528 return link;
529 }
530
531 protected HtmlData.AnchorHtmlData generateInitiatorUrl(Person person) {
532 HtmlData.AnchorHtmlData link = new HtmlData.AnchorHtmlData();
533 if (isRouteLogPopup()) {
534 link.setTarget("_blank");
535 }
536 else {
537 link.setTarget("_self");
538 }
539 link.setDisplayText("Initiator Inquiry for User with ID:" + person.getPrincipalId());
540 String url = ConfigContext.getCurrentContextConfig().getProperty(Config.KIM_URL) + "/" +
541 "identityManagementPersonInquiry.do?principalId=" + person.getPrincipalId();
542 link.setHref(url);
543 return link;
544 }
545
546
547
548
549 protected boolean isDocumentHandlerPopup() {
550 return BooleanUtils.toBooleanDefaultIfNull(
551 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
552 KewApiConstants.KEW_NAMESPACE,
553 KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
554 KewApiConstants.DOCUMENT_SEARCH_DOCUMENT_POPUP_IND),
555 DOCUMENT_HANDLER_POPUP_DEFAULT);
556 }
557
558
559
560
561 public boolean isRouteLogPopup() {
562 return BooleanUtils.toBooleanDefaultIfNull(
563 CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KewApiConstants.KEW_NAMESPACE,
564 KRADConstants.DetailTypes.DOCUMENT_SEARCH_DETAIL_TYPE,
565 KewApiConstants.DOCUMENT_SEARCH_ROUTE_LOG_POPUP_IND), ROUTE_LOG_POPUP_DEFAULT);
566 }
567
568
569
570
571 protected boolean isFlagSet(String flagName) {
572 if(this.getParameters().containsKey(flagName)) {
573 String[] params = (String[])this.getParameters().get(flagName);
574 if (ArrayUtils.isNotEmpty(params)) {
575 return "YES".equalsIgnoreCase(params[0]);
576 }
577 }
578 return false;
579 }
580
581
582
583
584 protected boolean isSuperUserSearch() {
585 return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD);
586 }
587
588
589
590
591 protected boolean isAdvancedSearch() {
592 return isFlagSet(KRADConstants.ADVANCED_SEARCH_FIELD);
593 }
594
595
596
597
598 protected boolean isClearSavedSearch() {
599 return isFlagSet(DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD);
600 }
601
602 protected String getSavedSearchName() {
603 String[] savedSearchName = getParameters().get(SAVED_SEARCH_NAME_PARAM);
604 if (savedSearchName != null && savedSearchName.length > 0) {
605 return savedSearchName[0];
606 }
607 return null;
608 }
609
610
611
612
613 @Override
614 protected void setRows() {
615 this.setRows(null);
616 }
617
618
619
620
621 protected FormFields getFormFields() {
622 return new FormFields(this.getRows());
623 }
624
625
626
627
628
629
630
631
632
633 protected void setRows(String documentTypeName) {
634
635 super.setRows();
636
637 List<Row> lookupRows = new ArrayList<Row>();
638
639 for (Row row : getRows()) {
640 lookupRows.add(row);
641 }
642
643 getRows().clear();
644
645 DocumentType docType = getValidDocumentType(documentTypeName);
646
647 boolean advancedSearch = isAdvancedSearch();
648 boolean superUserSearch = isSuperUserSearch();
649
650
651 List<Row> rows = getDocumentSearchCriteriaProcessor().getRows(docType,lookupRows, advancedSearch, superUserSearch);
652
653 BusinessObjectEntry boe = (BusinessObjectEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(this.getBusinessObjectClass().getName());
654 int numCols = boe.getLookupDefinition().getNumOfColumns();
655 if(numCols == 0) {
656 numCols = KRADConstants.DEFAULT_NUM_OF_COLUMNS;
657 }
658
659 super.getRows().addAll(FieldUtils.wrapFields(new FormFields(rows).getFieldList(), numCols));
660
661 }
662
663
664
665
666
667
668 private DocumentType getValidDocumentType(String documentTypeName) {
669 if (StringUtils.isNotEmpty(documentTypeName)) {
670 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByNameCaseInsensitive(documentTypeName.trim());
671 if (documentType != null && documentType.isActive()) {
672 return documentType;
673 }
674 }
675 return null;
676 }
677
678 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''/>";
679
680 @Override
681 public String getSupplementalMenuBar() {
682 boolean advancedSearch = isAdvancedSearch();
683 boolean superUserSearch = isSuperUserSearch();
684 StringBuilder suppMenuBar = new StringBuilder();
685
686
687
688
689 String type = advancedSearch ? "basic" : "detailed";
690 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleAdvancedSearch", KewApiConstants.WEBAPP_DIRECTORY, type, type));
691
692
693 suppMenuBar.append(" ");
694 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, "toggleSuperUserSearch", KewApiConstants.WEBAPP_DIRECTORY, superUserSearch ? "nonsupu" : "superuser", superUserSearch ? "non-superuser" : "superuser"));
695
696
697 suppMenuBar.append(" ");
698 suppMenuBar.append(MessageFormat.format(TOGGLE_BUTTON, DocumentSearchCriteriaProcessorKEWAdapter.CLEARSAVED_SEARCH_FIELD, KewApiConstants.WEBAPP_DIRECTORY, "clearsaved", "clear saved searches"));
699
700
701 suppMenuBar.append("<script type=\"text/javascript\">"
702 + " jQuery(document).ready(function () {"
703 + " jQuery(\"#documentTypeName\").blur(function () { validateDocTypeAndRefresh( this ); });"
704 + "});</script>");
705
706 return suppMenuBar.toString();
707 }
708
709 @Override
710 public boolean shouldDisplayHeaderNonMaintActions() {
711 return true;
712 }
713
714 @Override
715 public boolean shouldDisplayLookupCriteria() {
716 return true;
717 }
718
719
720
721
722
723 @Override
724 public boolean checkForAdditionalFields(Map<String, String> fieldValues) {
725 return checkForAdditionalFieldsForDocumentType(fieldValues.get(DOCUMENT_TYPE_NAME_PARAM));
726 }
727
728 private boolean checkForAdditionalFieldsMultiValued(Map<String, String[]> fieldValues) {
729 String[] valArray = fieldValues.get(DOCUMENT_TYPE_NAME_PARAM);
730 String val = null;
731 if (valArray != null && valArray.length > 0) {
732 val = valArray[0];
733 }
734 return checkForAdditionalFieldsForDocumentType(val);
735 }
736
737 private boolean checkForAdditionalFieldsForDocumentType(String documentTypeName) {
738 if (StringUtils.isNotBlank(documentTypeName)) {
739 setRows(documentTypeName);
740 }
741 return true;
742 }
743
744 @Override
745 public Field getExtraField() {
746 SavedSearchValuesFinder savedSearchValuesFinder = new SavedSearchValuesFinder();
747 List<KeyValue> savedSearchValues = savedSearchValuesFinder.getKeyValues();
748 Field savedSearch = new Field();
749 savedSearch.setPropertyName(SAVED_SEARCH_NAME_PARAM);
750 savedSearch.setFieldType(Field.DROPDOWN_SCRIPT);
751 savedSearch.setScript("customLookupChanged()");
752 savedSearch.setFieldValidValues(savedSearchValues);
753 savedSearch.setFieldLabel("Saved Searches");
754 return savedSearch;
755 }
756
757 @Override
758 public void performClear(LookupForm lookupForm) {
759
760 Map<String, String> formFields = LookupUtils.preProcessRangeFields(lookupForm.getFields());
761 DocumentSearchCriteria criteria = loadCriteria(formFields);
762 super.performClear(lookupForm);
763 repopulateSearchTypeFlags();
764 DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
765 if (documentType != null) {
766 DocumentSearchCriteria clearedCriteria = documentSearchService.clearCriteria(documentType, criteria);
767 applyCriteriaChangesToFields(DocumentSearchCriteria.Builder.create(clearedCriteria));
768 }
769 }
770
771
772
773
774 protected void repopulateSearchTypeFlags() {
775 boolean advancedSearch = isAdvancedSearch();
776 boolean superUserSearch = isSuperUserSearch();
777 int fieldsRepopulated = 0;
778 Map<String, String[]> values = new HashMap<String, String[]>();
779 values.put(KRADConstants.ADVANCED_SEARCH_FIELD, new String[] { advancedSearch ? "YES" : "NO" });
780 values.put(DocumentSearchCriteriaProcessorKEWAdapter.SUPERUSER_SEARCH_FIELD, new String[] { superUserSearch ? "YES" : "NO" });
781 getFormFields().setFieldValues(values);
782 }
783
784
785
786
787 protected void postProcessResults(Collection<ResultRow> resultRows, DocumentSearchResults searchResults) {
788 if (resultRows.size() != searchResults.getSearchResults().size()) {
789 throw new IllegalStateException("Encountered a mismatch between ResultRow items and document search results "
790 + resultRows.size() + " != " + searchResults.getSearchResults().size());
791 }
792 DocumentType documentType = getValidDocumentType(criteria.getDocumentTypeName());
793 DocumentSearchResultSetConfiguration resultSetConfiguration = null;
794 DocumentSearchCriteriaConfiguration criteriaConfiguration = null;
795 if (documentType != null) {
796 resultSetConfiguration = KEWServiceLocator.getDocumentSearchCustomizationMediator().customizeResultSetConfiguration(documentType, criteria);
797 criteriaConfiguration = KEWServiceLocator.getDocumentSearchCustomizationMediator().getDocumentSearchCriteriaConfiguration(documentType);
798 }
799 int index = 0;
800 for (ResultRow resultRow : resultRows) {
801 DocumentSearchResult searchResult = searchResults.getSearchResults().get(index);
802 executeColumnCustomization(resultRow, searchResult, resultSetConfiguration, criteriaConfiguration);
803 index++;
804 }
805 }
806
807
808
809
810
811 protected void executeColumnCustomization(ResultRow resultRow, DocumentSearchResult searchResult,
812 DocumentSearchResultSetConfiguration resultSetConfiguration,
813 DocumentSearchCriteriaConfiguration criteriaConfiguration) {
814 if (resultSetConfiguration == null) {
815 resultSetConfiguration = DocumentSearchResultSetConfiguration.Builder.create().build();
816 }
817 if (criteriaConfiguration == null) {
818 criteriaConfiguration = DocumentSearchCriteriaConfiguration.Builder.create().build();
819 }
820 List<StandardResultField> standardFieldsToRemove = resultSetConfiguration.getStandardResultFieldsToRemove();
821 if (standardFieldsToRemove == null) {
822 standardFieldsToRemove = Collections.emptyList();
823 }
824 List<Column> newColumns = new ArrayList<Column>();
825 for (Column standardColumn : resultRow.getColumns()) {
826 if (!standardFieldsToRemove.contains(StandardResultField.fromFieldName(standardColumn.getPropertyName()))) {
827 newColumns.add(standardColumn);
828
829
830 if (standardColumn.getPropertyName().equals(
831 KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_ROUTE_LOG)) {
832 standardColumn.setEscapeXMLValue(false);
833 }
834 }
835 }
836
837
838 List<RemotableAttributeField> searchAttributeFields = criteriaConfiguration.getFlattenedSearchAttributeFields();
839 List<String> additionalFieldNamesToInclude = new ArrayList<String>();
840 if (!resultSetConfiguration.isOverrideSearchableAttributes()) {
841 for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
842
843
844 if (searchAttributeField.getAttributeLookupSettings() == null ||
845 searchAttributeField.getAttributeLookupSettings().isInResults()) {
846 additionalFieldNamesToInclude.add(searchAttributeField.getName());
847 }
848 }
849 }
850 if (resultSetConfiguration.getCustomFieldNamesToAdd() != null) {
851 additionalFieldNamesToInclude.addAll(resultSetConfiguration.getCustomFieldNamesToAdd());
852 }
853
854
855 List<Column> customColumns = new ArrayList<Column>();
856 List<Column> additionalAttributeColumns = FieldUtils.constructColumnsFromAttributeFields(resultSetConfiguration.getAdditionalAttributeFields());
857
858 outer:for (String additionalFieldNameToInclude : additionalFieldNamesToInclude) {
859
860 for (RemotableAttributeField searchAttributeField : searchAttributeFields) {
861 if (additionalFieldNameToInclude.equals(searchAttributeField.getName())) {
862 Column searchAttributeColumn = FieldUtils.constructColumnFromAttributeField(searchAttributeField);
863 wrapDocumentAttributeColumnName(searchAttributeColumn);
864 customColumns.add(searchAttributeColumn);
865 continue outer;
866 }
867 }
868 for (Column additionalAttributeColumn : additionalAttributeColumns) {
869 if (additionalFieldNameToInclude.equals(additionalAttributeColumn.getPropertyName())) {
870 wrapDocumentAttributeColumnName(additionalAttributeColumn);
871 customColumns.add(additionalAttributeColumn);
872 continue outer;
873 }
874 }
875 LOG.warn("Failed to locate a proper column definition for requested additional field to include in"
876 + "result set with name '"
877 + additionalFieldNameToInclude
878 + "'");
879 }
880 populateCustomColumns(customColumns, searchResult);
881
882
883 if (newColumns.isEmpty() || !StandardResultField.ROUTE_LOG.isFieldNameValid(newColumns.get(newColumns.size() - 1).getPropertyName())) {
884 newColumns.addAll(customColumns);
885 } else {
886 newColumns.addAll(newColumns.size() - 1, customColumns);
887 }
888 resultRow.setColumns(newColumns);
889 }
890
891 protected void populateCustomColumns(List<Column> customColumns, DocumentSearchResult searchResult) {
892 for (Column customColumn : customColumns) {
893 DocumentAttribute documentAttribute = searchResult.getSingleDocumentAttributeByName(customColumn.getPropertyName());
894 if (documentAttribute != null && documentAttribute.getValue() != null) {
895 wrapDocumentAttributeColumnName(customColumn);
896
897 Formatter formatter = customColumn.getFormatter();
898 Object attributeValue = documentAttribute.getValue();
899 if (formatter.getPropertyType().equals(KualiDecimal.class)
900 && documentAttribute.getValue() instanceof BigDecimal) {
901 attributeValue = new KualiDecimal((BigDecimal)attributeValue);
902 } else if (formatter.getPropertyType().equals(KualiPercent.class)
903 && documentAttribute.getValue() instanceof BigDecimal) {
904 attributeValue = new KualiPercent((BigDecimal)attributeValue);
905 }
906 customColumn.setPropertyValue(formatter.format(attributeValue).toString());
907 }
908 }
909 }
910
911 private void wrapDocumentAttributeColumnName(Column column) {
912
913
914 }
915
916 public void setDocumentSearchService(DocumentSearchService documentSearchService) {
917 this.documentSearchService = documentSearchService;
918 }
919
920 public DocumentSearchService getDocumentSearchService() {
921 return documentSearchService;
922 }
923
924 public DocumentSearchCriteriaProcessor getDocumentSearchCriteriaProcessor() {
925 return documentSearchCriteriaProcessor;
926 }
927
928 public void setDocumentSearchCriteriaProcessor(DocumentSearchCriteriaProcessor documentSearchCriteriaProcessor) {
929 this.documentSearchCriteriaProcessor = documentSearchCriteriaProcessor;
930 }
931
932 public DocumentSearchCriteriaTranslator getDocumentSearchCriteriaTranslator() {
933 return documentSearchCriteriaTranslator;
934 }
935
936 public void setDocumentSearchCriteriaTranslator(DocumentSearchCriteriaTranslator documentSearchCriteriaTranslator) {
937 this.documentSearchCriteriaTranslator = documentSearchCriteriaTranslator;
938 }
939 }