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