1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.docsearch;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.uif.RemotableAttributeField;
20 import org.kuali.rice.core.api.util.ConcreteKeyValue;
21 import org.kuali.rice.core.api.util.KeyValue;
22 import org.kuali.rice.kew.api.KewApiConstants;
23 import org.kuali.rice.kew.doctype.ApplicationDocumentStatus;
24 import org.kuali.rice.kew.doctype.bo.DocumentType;
25 import org.kuali.rice.kew.engine.node.RouteNode;
26 import org.kuali.rice.kew.framework.document.search.DocumentSearchCriteriaConfiguration;
27 import org.kuali.rice.kew.impl.document.ApplicationDocumentStatusUtils;
28 import org.kuali.rice.kew.service.KEWServiceLocator;
29 import org.kuali.rice.kns.util.FieldUtils;
30 import org.kuali.rice.kns.web.ui.Field;
31 import org.kuali.rice.kns.web.ui.Row;
32 import org.kuali.rice.krad.util.KRADConstants;
33
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.LinkedHashMap;
38 import java.util.LinkedHashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class DocumentSearchCriteriaProcessorKEWAdapter implements DocumentSearchCriteriaProcessor {
70
71
72
73 public static final String SUPERUSER_SEARCH_FIELD = "superUserSearch";
74
75
76
77 public static final String CLEARSAVED_SEARCH_FIELD = "resetSavedSearch";
78
79
80
81
82 private static final String DOCUMENT_ATTRIBUTE_FIELD_MARKER = "DOCUMENT_ATTRIBUTE_FIELD_MARKER";
83
84 private static final String APPLICATION_DOCUMENT_STATUS = "applicationDocumentStatus";
85 private static final String DATE_APP_DOC_STATUS_CHANGED_FROM = "rangeLowerBoundKeyPrefix_dateApplicationDocumentStatusChanged";
86 private static final String DATE_APP_DOC_STATUS_CHANGED = "dateApplicationDocumentStatusChanged";
87 private static final String ROUTE_NODE_NAME = "routeNodeName";
88 private static final String ROUTE_NODE_LOGIC = "routeNodeLogic";
89
90 private static final String[] BASIC_FIELD_NAMES = {
91 "documentTypeName",
92 "initiatorPrincipalName",
93 "documentId",
94 APPLICATION_DOCUMENT_STATUS,
95 "dateCreated",
96 DOCUMENT_ATTRIBUTE_FIELD_MARKER,
97 "saveName"
98 };
99
100 private static final String[] ADVANCED_FIELD_NAMES = {
101 "documentTypeName",
102 "initiatorPrincipalName",
103 "approverPrincipalName",
104 "viewerPrincipalName",
105 "groupViewerName",
106 "groupViewerId",
107 "documentId",
108 "applicationDocumentId",
109 "statusCode",
110 APPLICATION_DOCUMENT_STATUS,
111 DATE_APP_DOC_STATUS_CHANGED,
112 ROUTE_NODE_NAME,
113 ROUTE_NODE_LOGIC,
114 "dateCreated",
115 "dateApproved",
116 "dateLastModified",
117 "dateFinalized",
118 "title",
119 DOCUMENT_ATTRIBUTE_FIELD_MARKER,
120 "saveName"
121 };
122
123
124
125
126 private static final Collection<String> DOCUMENTTYPE_DEPENDENT_FIELDS = Arrays.asList(new String[] { DOCUMENT_ATTRIBUTE_FIELD_MARKER, APPLICATION_DOCUMENT_STATUS, DATE_APP_DOC_STATUS_CHANGED_FROM, DATE_APP_DOC_STATUS_CHANGED, ROUTE_NODE_NAME, ROUTE_NODE_LOGIC });
127
128
129
130 private static final Collection<String> DOCSTATUS_DEPENDENT_FIELDS = Arrays.asList(new String[] { APPLICATION_DOCUMENT_STATUS, DATE_APP_DOC_STATUS_CHANGED_FROM, DATE_APP_DOC_STATUS_CHANGED });
131
132
133
134 private static final Collection<String> ROUTE_NODE_DEPENDENT_FIELDS = Arrays.asList(new String[] { ROUTE_NODE_NAME, ROUTE_NODE_LOGIC });
135
136
137 @Override
138 public List<Row> getRows(DocumentType documentType, List<Row> defaultRows, boolean advancedSearch, boolean superUserSearch) {
139 List<Row> rows = null;
140 if(advancedSearch) {
141 rows = loadRowsForAdvancedSearch(defaultRows, documentType);
142 } else {
143 rows = loadRowsForBasicSearch(defaultRows, documentType);
144 }
145 addHiddenFields(rows, advancedSearch, superUserSearch);
146 return rows;
147 }
148
149 protected List<Row> loadRowsForAdvancedSearch(List<Row> defaultRows, DocumentType documentType) {
150 List<Row> rows = new ArrayList<Row>();
151 loadRowsWithFields(rows, defaultRows, ADVANCED_FIELD_NAMES, documentType);
152 return rows;
153 }
154
155 protected List<Row> loadRowsForBasicSearch(List<Row> defaultRows, DocumentType documentType) {
156 List<Row> rows = new ArrayList<Row>();
157 loadRowsWithFields(rows, defaultRows, BASIC_FIELD_NAMES, documentType);
158 return rows;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173 protected void loadRowsWithFields(List<Row> rowsToLoad, List<Row> defaultRows, String[] fieldNames,
174 DocumentType documentType) {
175
176 for (String fieldName : fieldNames) {
177 if (DOCUMENTTYPE_DEPENDENT_FIELDS.contains(fieldName) && documentType == null) {
178 continue;
179 }
180
181 if (DOCSTATUS_DEPENDENT_FIELDS.contains(fieldName) && !documentType.isAppDocStatusInUse()) {
182 continue;
183 }
184
185
186 if (ROUTE_NODE_DEPENDENT_FIELDS.contains(fieldName) &&
187 getRouteNodesByDocumentType(documentType, false).size() == 0) {
188 continue;
189 }
190
191 if (fieldName.equals(DOCUMENT_ATTRIBUTE_FIELD_MARKER)) {
192 rowsToLoad.addAll(getDocumentAttributeRows(documentType));
193 continue;
194 }
195
196
197
198
199 for (Row row : defaultRows) {
200 boolean matched = false;
201
202
203 for (Field field : row.getFields()) {
204
205
206 if (field.getPropertyName().equals(fieldName) || field.getPropertyName().endsWith("_" + fieldName)) {
207 matched = true;
208 if (APPLICATION_DOCUMENT_STATUS.equals(field.getPropertyName())) {
209
210
211
212 applyApplicationDocumentStatusCustomizations(field, documentType);
213 break;
214 } else if (ROUTE_NODE_NAME.equals(field.getPropertyName())) {
215
216 applyRouteNodeNameCustomizations(field, documentType);
217 }
218 }
219 }
220 if (matched) {
221 rowsToLoad.add(row);
222 }
223 }
224 }
225 }
226
227
228
229
230 protected List<Row> getDocumentAttributeRows(DocumentType documentType) {
231 List<Row> documentAttributeRows = new ArrayList<Row>();
232 DocumentSearchCriteriaConfiguration configuration =
233 KEWServiceLocator.getDocumentSearchCustomizationMediator().
234 getDocumentSearchCriteriaConfiguration(documentType);
235 if (configuration != null) {
236 List<RemotableAttributeField> remotableAttributeFields = configuration.getFlattenedSearchAttributeFields();
237 if (remotableAttributeFields != null && !remotableAttributeFields.isEmpty()) {
238 documentAttributeRows.addAll(FieldUtils.convertRemotableAttributeFields(remotableAttributeFields));
239 }
240 }
241 List<Row> fixedDocumentAttributeRows = new ArrayList<Row>();
242 for (Row row : documentAttributeRows) {
243 List<Field> fields = row.getFields();
244 for (Field field : fields) {
245
246 if(field.getMaxLength() == 0) {
247 field.setMaxLength(100);
248 }
249
250 field.setPropertyName(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + field.getPropertyName());
251 if (StringUtils.isNotBlank(field.getLookupParameters())) {
252 field.setLookupParameters(prefixLookupParameters(field.getLookupParameters()));
253 }
254 if (StringUtils.isNotBlank(field.getFieldConversions())) {
255 field.setFieldConversions(prefixFieldConversions(field.getFieldConversions()));
256 }
257 }
258 fixedDocumentAttributeRows.add(row);
259 }
260
261 return fixedDocumentAttributeRows;
262 }
263
264
265
266
267
268
269
270
271
272 protected void applyApplicationDocumentStatusCustomizations(Field field, DocumentType documentType) {
273
274 if (documentType.getValidApplicationStatuses() == null || documentType.getValidApplicationStatuses().size() == 0){
275
276
277
278
279 field.setFieldType(Field.TEXT);
280 } else {
281
282
283 field.setFieldType(Field.MULTISELECT);
284 List<KeyValue> validValues = new ArrayList<KeyValue>();
285
286
287 Set<String> statusesToDisplay = new LinkedHashSet<String>();
288 for (ApplicationDocumentStatus status: documentType.getValidApplicationStatuses()) {
289 statusesToDisplay.add(status.getStatusName());
290 }
291
292
293
294 LinkedHashMap<String, List<String>> appDocStatusCategories =
295 ApplicationDocumentStatusUtils.getApplicationDocumentStatusCategories(documentType.getName());
296
297 if (!appDocStatusCategories.isEmpty()) {
298 for (Map.Entry<String,List<String>> group : appDocStatusCategories.entrySet()) {
299 boolean addedCategoryHeading = false;
300 for (String member : group.getValue()) {
301 if (statusesToDisplay.remove(member)) {
302 if (!addedCategoryHeading) {
303 addedCategoryHeading = true;
304 validValues.add(new ConcreteKeyValue("category:" + group.getKey(), group.getKey()));
305 }
306 validValues.add(new ConcreteKeyValue(member, "- " + member));
307 }
308 }
309 }
310 }
311
312
313 for (String member : statusesToDisplay) {
314 validValues.add(new ConcreteKeyValue(member, member));
315 }
316
317 field.setFieldValidValues(validValues);
318
319
320 if (validValues.size() > 5) {
321 field.setSize(5);
322 } else {
323 field.setSize(validValues.size());
324 }
325
326
327
328
329
330 }
331 }
332
333
334
335
336
337
338
339 protected List<RouteNode> getRouteNodesByDocumentType(DocumentType documentType, boolean includeBlankNodes) {
340 List<RouteNode> nodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(documentType, true);
341
342
343 if(nodes.size() > 0 && !includeBlankNodes) {
344 List<RouteNode> namedNodes = new ArrayList<RouteNode>();
345 for (RouteNode node : nodes) {
346 if (StringUtils.isNotBlank(node.getName())) {
347 namedNodes.add(node);
348 }
349 }
350 return namedNodes;
351 }
352
353 return nodes;
354 }
355
356
357 protected void applyRouteNodeNameCustomizations(Field field, DocumentType documentType) {
358 List<RouteNode> nodes = getRouteNodesByDocumentType(documentType, false);
359 List<KeyValue> values = new ArrayList<KeyValue>(nodes.size());
360 for (RouteNode node: nodes) {
361 values.add(new ConcreteKeyValue(node.getName(), node.getName()));
362 }
363
364 field.setFieldValidValues(values);
365 }
366
367 protected void addHiddenFields(List<Row> rows, boolean advancedSearch, boolean superUserSearch) {
368 Row hiddenRow = new Row();
369 hiddenRow.setHidden(true);
370
371 Field detailedField = new Field();
372 detailedField.setPropertyName(KRADConstants.ADVANCED_SEARCH_FIELD);
373 detailedField.setPropertyValue(advancedSearch ? "YES" : "NO");
374 detailedField.setFieldType(Field.HIDDEN);
375
376 Field superUserSearchField = new Field();
377 superUserSearchField.setPropertyName(SUPERUSER_SEARCH_FIELD);
378 superUserSearchField.setPropertyValue(superUserSearch ? "YES" : "NO");
379 superUserSearchField.setFieldType(Field.HIDDEN);
380
381 Field clearSavedSearchField = new Field();
382 clearSavedSearchField .setPropertyName(CLEARSAVED_SEARCH_FIELD);
383 clearSavedSearchField .setPropertyValue(superUserSearch ? "YES" : "NO");
384 clearSavedSearchField .setFieldType(Field.HIDDEN);
385
386 List<Field> hiddenFields = new ArrayList<Field>();
387 hiddenFields.add(detailedField);
388 hiddenFields.add(superUserSearchField);
389 hiddenFields.add(clearSavedSearchField);
390 hiddenRow.setFields(hiddenFields);
391 rows.add(hiddenRow);
392
393 }
394
395 private String prefixLookupParameters(String lookupParameters) {
396 StringBuilder newLookupParameters = new StringBuilder(KRADConstants.EMPTY_STRING);
397 String[] conversions = StringUtils.split(lookupParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
398
399 for (int m = 0; m < conversions.length; m++) {
400 String conversion = conversions[m];
401 String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
402 String conversionFrom = conversionPair[0];
403 String conversionTo = conversionPair[1];
404 conversionFrom = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + conversionFrom;
405 newLookupParameters.append(conversionFrom)
406 .append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR)
407 .append(conversionTo);
408
409 if (m < conversions.length) {
410 newLookupParameters.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
411 }
412 }
413 return newLookupParameters.toString();
414 }
415
416 private String prefixFieldConversions(String fieldConversions) {
417 StringBuilder newFieldConversions = new StringBuilder(KRADConstants.EMPTY_STRING);
418 String[] conversions = StringUtils.split(fieldConversions, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
419
420 for (int l = 0; l < conversions.length; l++) {
421 String conversion = conversions[l];
422
423 String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
424 String conversionFrom = conversionPair[0];
425 String conversionTo = conversionPair[1];
426 conversionTo = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + conversionTo;
427 newFieldConversions.append(conversionFrom)
428 .append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR)
429 .append(conversionTo);
430
431 if (l < conversions.length) {
432 newFieldConversions.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
433 }
434 }
435
436 return newFieldConversions.toString();
437 }
438
439 }