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 @Override
134 public List<Row> getRows(DocumentType documentType, List<Row> defaultRows, boolean advancedSearch, boolean superUserSearch) {
135 List<Row> rows = null;
136 if(advancedSearch) {
137 rows = loadRowsForAdvancedSearch(defaultRows, documentType);
138 } else {
139 rows = loadRowsForBasicSearch(defaultRows, documentType);
140 }
141 addHiddenFields(rows, advancedSearch, superUserSearch);
142 return rows;
143 }
144
145 protected List<Row> loadRowsForAdvancedSearch(List<Row> defaultRows, DocumentType documentType) {
146 List<Row> rows = new ArrayList<Row>();
147 loadRowsWithFields(rows, defaultRows, ADVANCED_FIELD_NAMES, documentType);
148 return rows;
149 }
150
151 protected List<Row> loadRowsForBasicSearch(List<Row> defaultRows, DocumentType documentType) {
152 List<Row> rows = new ArrayList<Row>();
153 loadRowsWithFields(rows, defaultRows, BASIC_FIELD_NAMES, documentType);
154 return rows;
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169 protected void loadRowsWithFields(List<Row> rowsToLoad, List<Row> defaultRows, String[] fieldNames,
170 DocumentType documentType) {
171
172 for (String fieldName : fieldNames) {
173 if (DOCUMENTTYPE_DEPENDENT_FIELDS.contains(fieldName) && documentType == null) {
174 continue;
175 }
176
177 if (DOCSTATUS_DEPENDENT_FIELDS.contains(fieldName) && !documentType.isAppDocStatusInUse()) {
178 continue;
179 }
180 if (fieldName.equals(DOCUMENT_ATTRIBUTE_FIELD_MARKER)) {
181 rowsToLoad.addAll(getDocumentAttributeRows(documentType));
182 continue;
183 }
184
185
186
187
188 for (Row row : defaultRows) {
189 boolean matched = false;
190
191
192 for (Field field : row.getFields()) {
193
194
195 if (field.getPropertyName().equals(fieldName) || field.getPropertyName().endsWith("_" + fieldName)) {
196 matched = true;
197 if (APPLICATION_DOCUMENT_STATUS.equals(field.getPropertyName())) {
198
199
200
201 applyApplicationDocumentStatusCustomizations(field, documentType);
202 break;
203 } else if (ROUTE_NODE_NAME.equals(field.getPropertyName())) {
204
205 applyRouteNodeNameCustomizations(field, documentType);
206 }
207 }
208 }
209 if (matched) {
210 rowsToLoad.add(row);
211 }
212 }
213 }
214 }
215
216
217
218
219 protected List<Row> getDocumentAttributeRows(DocumentType documentType) {
220 List<Row> documentAttributeRows = new ArrayList<Row>();
221 DocumentSearchCriteriaConfiguration configuration =
222 KEWServiceLocator.getDocumentSearchCustomizationMediator().
223 getDocumentSearchCriteriaConfiguration(documentType);
224 if (configuration != null) {
225 List<RemotableAttributeField> remotableAttributeFields = configuration.getFlattenedSearchAttributeFields();
226 if (remotableAttributeFields != null && !remotableAttributeFields.isEmpty()) {
227 documentAttributeRows.addAll(FieldUtils.convertRemotableAttributeFields(remotableAttributeFields));
228 }
229 }
230 List<Row> fixedDocumentAttributeRows = new ArrayList<Row>();
231 for (Row row : documentAttributeRows) {
232 List<Field> fields = row.getFields();
233 for (Field field : fields) {
234
235 if(field.getMaxLength() == 0) {
236 field.setMaxLength(100);
237 }
238
239 field.setPropertyName(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + field.getPropertyName());
240 if (StringUtils.isNotBlank(field.getLookupParameters())) {
241 field.setLookupParameters(prefixLookupParameters(field.getLookupParameters()));
242 }
243 if (StringUtils.isNotBlank(field.getFieldConversions())) {
244 field.setFieldConversions(prefixFieldConversions(field.getFieldConversions()));
245 }
246 }
247 fixedDocumentAttributeRows.add(row);
248 }
249
250 return fixedDocumentAttributeRows;
251 }
252
253
254
255
256
257
258
259
260
261 protected void applyApplicationDocumentStatusCustomizations(Field field, DocumentType documentType) {
262
263 if (documentType.getValidApplicationStatuses() == null || documentType.getValidApplicationStatuses().size() == 0){
264
265
266
267
268 field.setFieldType(Field.TEXT);
269 } else {
270
271
272 field.setFieldType(Field.MULTISELECT);
273 List<KeyValue> validValues = new ArrayList<KeyValue>();
274
275
276 Set<String> statusesToDisplay = new LinkedHashSet<String>();
277 for (ApplicationDocumentStatus status: documentType.getValidApplicationStatuses()) {
278 statusesToDisplay.add(status.getStatusName());
279 }
280
281
282
283 LinkedHashMap<String, List<String>> appDocStatusCategories =
284 ApplicationDocumentStatusUtils.getApplicationDocumentStatusCategories(documentType.getName());
285
286 if (!appDocStatusCategories.isEmpty()) {
287 for (Map.Entry<String,List<String>> group : appDocStatusCategories.entrySet()) {
288 boolean addedCategoryHeading = false;
289 for (String member : group.getValue()) {
290 if (statusesToDisplay.remove(member)) {
291 if (!addedCategoryHeading) {
292 addedCategoryHeading = true;
293 validValues.add(new ConcreteKeyValue("category:" + group.getKey(), group.getKey()));
294 }
295 validValues.add(new ConcreteKeyValue(member, "- " + member));
296 }
297 }
298 }
299 }
300
301
302 for (String member : statusesToDisplay) {
303 validValues.add(new ConcreteKeyValue(member, member));
304 }
305
306 field.setFieldValidValues(validValues);
307
308
309 if (validValues.size() > 5) {
310 field.setSize(5);
311 } else {
312 field.setSize(validValues.size());
313 }
314
315
316
317
318
319 }
320 }
321
322 protected void applyRouteNodeNameCustomizations(Field field, DocumentType documentType) {
323 List<RouteNode> nodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(documentType, true);
324 List<KeyValue> values = new ArrayList<KeyValue>(nodes.size());
325 for (RouteNode node: nodes) {
326 values.add(new ConcreteKeyValue(node.getName(), node.getName()));
327 }
328 field.setFieldValidValues(values);
329 }
330
331 protected void addHiddenFields(List<Row> rows, boolean advancedSearch, boolean superUserSearch) {
332 Row hiddenRow = new Row();
333 hiddenRow.setHidden(true);
334
335 Field detailedField = new Field();
336 detailedField.setPropertyName(KRADConstants.ADVANCED_SEARCH_FIELD);
337 detailedField.setPropertyValue(advancedSearch ? "YES" : "NO");
338 detailedField.setFieldType(Field.HIDDEN);
339
340 Field superUserSearchField = new Field();
341 superUserSearchField.setPropertyName(SUPERUSER_SEARCH_FIELD);
342 superUserSearchField.setPropertyValue(superUserSearch ? "YES" : "NO");
343 superUserSearchField.setFieldType(Field.HIDDEN);
344
345 Field clearSavedSearchField = new Field();
346 clearSavedSearchField .setPropertyName(CLEARSAVED_SEARCH_FIELD);
347 clearSavedSearchField .setPropertyValue(superUserSearch ? "YES" : "NO");
348 clearSavedSearchField .setFieldType(Field.HIDDEN);
349
350 List<Field> hiddenFields = new ArrayList<Field>();
351 hiddenFields.add(detailedField);
352 hiddenFields.add(superUserSearchField);
353 hiddenFields.add(clearSavedSearchField);
354 hiddenRow.setFields(hiddenFields);
355 rows.add(hiddenRow);
356
357 }
358
359 private String prefixLookupParameters(String lookupParameters) {
360 StringBuilder newLookupParameters = new StringBuilder(KRADConstants.EMPTY_STRING);
361 String[] conversions = StringUtils.split(lookupParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
362
363 for (int m = 0; m < conversions.length; m++) {
364 String conversion = conversions[m];
365 String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
366 String conversionFrom = conversionPair[0];
367 String conversionTo = conversionPair[1];
368 conversionFrom = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + conversionFrom;
369 newLookupParameters.append(conversionFrom)
370 .append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR)
371 .append(conversionTo);
372
373 if (m < conversions.length) {
374 newLookupParameters.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
375 }
376 }
377 return newLookupParameters.toString();
378 }
379
380 private String prefixFieldConversions(String fieldConversions) {
381 StringBuilder newFieldConversions = new StringBuilder(KRADConstants.EMPTY_STRING);
382 String[] conversions = StringUtils.split(fieldConversions, KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
383
384 for (int l = 0; l < conversions.length; l++) {
385 String conversion = conversions[l];
386
387 String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2);
388 String conversionFrom = conversionPair[0];
389 String conversionTo = conversionPair[1];
390 conversionTo = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + conversionTo;
391 newFieldConversions.append(conversionFrom)
392 .append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR)
393 .append(conversionTo);
394
395 if (l < conversions.length) {
396 newFieldConversions.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR);
397 }
398 }
399
400 return newFieldConversions.toString();
401 }
402
403 }