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