1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.kew.docsearch;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.joda.time.DateTime;
21 import org.kuali.rice.core.api.reflect.ObjectDefinition;
22 import org.kuali.rice.core.api.uif.DataType;
23 import org.kuali.rice.core.api.uif.RemotableAttributeField;
24 import org.kuali.rice.core.api.util.ClassLoaderUtils;
25 import org.kuali.rice.core.api.util.RiceConstants;
26 import org.kuali.rice.core.framework.resourceloader.ObjectDefinitionResolver;
27 import org.kuali.rice.kew.api.WorkflowRuntimeException;
28 import org.kuali.rice.kew.api.document.lookup.DocumentLookupConfiguration;
29 import org.kuali.rice.kew.docsearch.web.SearchAttributeFormContainer;
30 import org.kuali.rice.kew.doctype.bo.DocumentType;
31 import org.kuali.rice.kew.doctype.service.DocumentTypeService;
32 import org.kuali.rice.kew.service.KEWServiceLocator;
33 import org.kuali.rice.kew.user.UserUtils;
34 import org.kuali.rice.kns.util.FieldUtils;
35 import org.kuali.rice.kns.web.ui.Field;
36 import org.kuali.rice.krad.UserSession;
37 import org.kuali.rice.krad.util.GlobalVariables;
38
39 import java.sql.Date;
40 import java.sql.Timestamp;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.StringTokenizer;
48
49
50
51
52
53
54
55 public final class DocSearchUtils {
56
57 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocSearchUtils.class);
58
59 public static final List<Class<? extends SearchableAttributeValue>> SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST =
60 new ArrayList<Class<? extends SearchableAttributeValue>>();
61 static {
62 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeStringValue.class);
63 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeFloatValue.class);
64 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeLongValue.class);
65 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeDateTimeValue.class);
66 }
67
68 private DocSearchUtils() {
69 throw new UnsupportedOperationException("do not call");
70 }
71
72 public static List<SearchableAttributeValue> getSearchableAttributeValueObjectTypes() {
73 List<SearchableAttributeValue> searchableAttributeValueClasses = new ArrayList<SearchableAttributeValue>();
74 for (Class<? extends SearchableAttributeValue> searchAttributeValueClass : SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST) {
75 ObjectDefinition objDef = new ObjectDefinition(searchAttributeValueClass);
76 SearchableAttributeValue attributeValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
77 searchableAttributeValueClasses.add(attributeValue);
78 }
79 return searchableAttributeValueClasses;
80 }
81
82
83
84
85 public static SearchableAttributeValue getSearchableAttributeValueByDataTypeString(String dataType) {
86 SearchableAttributeValue returnableValue = null;
87 if (StringUtils.isBlank(dataType)) {
88 return returnableValue;
89 }
90 for (SearchableAttributeValue attValue : getSearchableAttributeValueObjectTypes())
91 {
92 if (dataType.equalsIgnoreCase(attValue.getAttributeDataType()))
93 {
94 if (returnableValue != null)
95 {
96 String errorMsg = "Found two SearchableAttributeValue objects with same data type string ('" + dataType + "' while ignoring case): " + returnableValue.getClass().getName() + " and " + attValue.getClass().getName();
97 LOG.error("getSearchableAttributeValueByDataTypeString() " + errorMsg);
98 throw new RuntimeException(errorMsg);
99 }
100 LOG.debug("getSearchableAttributeValueByDataTypeString() SearchableAttributeValue class name is " + attValue.getClass().getName() + "... ojbConcreteClassName is " + attValue.getOjbConcreteClass());
101 ObjectDefinition objDef = new ObjectDefinition(attValue.getClass());
102 returnableValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
103 }
104 }
105 return returnableValue;
106 }
107
108 public static SearchableAttributeValue getSearchableAttributeValueByDataTypeString(DataType dataType) {
109 if (dataType == null || dataType == DataType.STRING || dataType == DataType.BOOLEAN) {
110 return new SearchableAttributeStringValue();
111 } else if (dataType == DataType.DATE || dataType == DataType.TRUNCATED_DATE) {
112 return new SearchableAttributeDateTimeValue();
113 } else if (dataType == DataType.FLOAT || dataType == DataType.DOUBLE) {
114 return new SearchableAttributeFloatValue();
115 } else if (dataType == DataType.INTEGER || dataType == DataType.LONG) {
116 return new SearchableAttributeLongValue();
117 }
118 throw new IllegalArgumentException("Could not determine appropriate searchable attribute data type to use for the given DataType: " + dataType);
119 }
120
121 public static List<SearchAttributeCriteriaComponent> translateSearchFieldToCriteriaComponent(RemotableAttributeField searchField) {
122 List<SearchAttributeCriteriaComponent> components = new ArrayList<SearchAttributeCriteriaComponent>();
123 SearchableAttributeValue searchableAttributeValue = DocSearchUtils.getSearchableAttributeValueByDataTypeString(searchField.getDataType());
124 List<Field> fields = FieldUtils.convertRemotableAttributeField(searchField);
125 for (Field field : fields) {
126 SearchAttributeCriteriaComponent sacc = new SearchAttributeCriteriaComponent(field.getPropertyName(), null, field.getPropertyName(), searchableAttributeValue);
127
128 sacc.setRangeSearch(field.isMemberOfRange());
129 sacc.setSearchInclusive(field.isInclusive());
130 sacc.setSearchable(field.isIndexedForSearch());
131 sacc.setLookupableFieldType(field.getFieldType());
132 sacc.setCanHoldMultipleValues(Field.MULTI_VALUE_FIELD_TYPES.contains(field.getFieldType()));
133 components.add(sacc);
134 }
135 return components;
136 }
137
138 public static String getDisplayValueWithDateOnly(DateTime value) {
139 return getDisplayValueWithDateOnly(new Timestamp(value.getMillis()));
140 }
141
142 public static String getDisplayValueWithDateOnly(Timestamp value) {
143 return RiceConstants.getDefaultDateFormat().format(new Date(value.getTime()));
144 }
145
146 public static String getDisplayValueWithDateTime(Timestamp value) {
147 return RiceConstants.getDefaultDateAndTimeFormat().format(new Date(value.getTime()));
148 }
149
150
151
152 private static final String CURRENT_USER_PREFIX = "CURRENT_USER.";
153
154
155
156
157
158
159
160
161
162 public static List<SearchAttributeCriteriaComponent> buildSearchableAttributesFromString(String searchableAttributeString, String documentTypeName) {
163 List<SearchAttributeCriteriaComponent> searchableAttributes = new ArrayList<SearchAttributeCriteriaComponent>();
164 Map<String, SearchAttributeCriteriaComponent> criteriaComponentsByKey = new HashMap<String, SearchAttributeCriteriaComponent>();
165
166 DocumentType docType = getDocumentType(documentTypeName);
167
168 if (docType != null) {
169
170 DocumentLookupConfiguration lookupConfiguration = KEWServiceLocator.getDocumentLookupCustomizationMediator().getDocumentLookupConfiguration(docType);
171 List<RemotableAttributeField> searchFields = lookupConfiguration.getFlattenedSearchAttributeFields();
172
173 for (RemotableAttributeField searchField : searchFields) {
174 List<SearchAttributeCriteriaComponent> components = DocSearchUtils.translateSearchFieldToCriteriaComponent(searchField);
175 for (SearchAttributeCriteriaComponent searchableAttributeComponent : components) {
176 criteriaComponentsByKey.put(searchField.getName(), searchableAttributeComponent);
177 }
178 }
179
180 }
181
182 Map<String, List<String>> checkForMultiValueSearchableAttributes = new HashMap<String, List<String>>();
183 if ((searchableAttributeString != null) && (searchableAttributeString.trim().length() > 0)) {
184 StringTokenizer tokenizer = new StringTokenizer(searchableAttributeString, ",");
185 while (tokenizer.hasMoreTokens()) {
186 String searchableAttribute = tokenizer.nextToken();
187 int index = searchableAttribute.indexOf(":");
188 if (index != -1) {
189 String key = searchableAttribute.substring(0, index);
190 String value = searchableAttribute.substring(index + 1);
191 if (value.startsWith(CURRENT_USER_PREFIX)) {
192 String idType = value.substring(CURRENT_USER_PREFIX.length());
193 UserSession session = GlobalVariables.getUserSession();
194 String idValue = UserUtils.getIdValue(idType, session.getPerson());
195 if (!StringUtils.isBlank(idValue)) {
196 value = idValue;
197 }
198 }
199 SearchAttributeCriteriaComponent critComponent = criteriaComponentsByKey.get(key);
200 if (critComponent == null) {
201
202
203 continue;
204 }
205 if (critComponent.getSearchableAttributeValue() == null) {
206 String errorMsg = "Cannot find SearchableAttributeValue for given key '" + key + "'";
207 LOG.error("buildSearchableAttributesFromString() " + errorMsg);
208 throw new RuntimeException(errorMsg);
209 }
210 if (critComponent.isCanHoldMultipleValues()) {
211
212 if (checkForMultiValueSearchableAttributes.containsKey(key)) {
213 List<String> keyList = checkForMultiValueSearchableAttributes.get(key);
214 keyList.add(value);
215 checkForMultiValueSearchableAttributes.put(key, keyList);
216 } else {
217 List<String> tempList = new ArrayList<String>();
218 tempList.add(value);
219
220 checkForMultiValueSearchableAttributes.put(key, tempList);
221 searchableAttributes.add(critComponent);
222 }
223 } else {
224
225 if (checkForMultiValueSearchableAttributes.containsKey(key)) {
226
227 String error = "Attempting to add multiple values to a search attribute (key: '" + key + "') that does not suppor them";
228 LOG.error("buildSearchableAttributesFromString() " + error);
229
230
231 }
232 critComponent.setValue(value);
233 searchableAttributes.add(critComponent);
234 }
235
236 }
237 }
238 for (SearchAttributeCriteriaComponent criteriaComponent : searchableAttributes)
239 {
240 if (criteriaComponent.isCanHoldMultipleValues())
241 {
242 List<String> values = checkForMultiValueSearchableAttributes.get(criteriaComponent.getFormKey());
243 criteriaComponent.setValue(null);
244 criteriaComponent.setValues(values);
245 }
246 }
247 }
248
249 return searchableAttributes;
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, String searchAttributesString) {
269 addSearchableAttributesToCriteria(criteria, propertyFields, searchAttributesString, false);
270 }
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, boolean setAttributesStrictly) {
291 addSearchableAttributesToCriteria(criteria, propertyFields, null, setAttributesStrictly);
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311 public static void addSearchableAttributesToCriteria(DocSearchCriteriaDTO criteria, List propertyFields, String searchAttributesString, boolean setAttributesStrictly) {
312 if (criteria != null) {
313 DocumentType docType = getDocumentType(criteria.getDocTypeFullName());
314 if (docType == null) {
315 return;
316 }
317 criteria.getSearchableAttributes().clear();
318 Map<String, SearchAttributeCriteriaComponent> urlParameterSearchAttributesByFormKey = new HashMap<String, SearchAttributeCriteriaComponent>();
319
320 if (!StringUtils.isBlank(searchAttributesString)) {
321 List<SearchAttributeCriteriaComponent> components = buildSearchableAttributesFromString(searchAttributesString, docType.getName());
322 for (SearchAttributeCriteriaComponent component : components) {
323 urlParameterSearchAttributesByFormKey.put(component.getFormKey(), component);
324 criteria.addSearchableAttribute(component);
325 }
326 }
327
328 if (!propertyFields.isEmpty()) {
329 Map<String, SearchAttributeCriteriaComponent> criteriaComponentsByFormKey = new HashMap<String, SearchAttributeCriteriaComponent>();
330
331 DocumentLookupConfiguration lookupConfiguration = KEWServiceLocator.getDocumentLookupCustomizationMediator().getDocumentLookupConfiguration(docType);
332 List<RemotableAttributeField> searchFields = lookupConfiguration.getFlattenedSearchAttributeFields();
333
334 for (RemotableAttributeField searchField : searchFields) {
335 List<SearchAttributeCriteriaComponent> components = DocSearchUtils.translateSearchFieldToCriteriaComponent(searchField);
336 for (SearchAttributeCriteriaComponent searchableAttributeComponent : components) {
337 criteriaComponentsByFormKey.put(searchField.getName(), searchableAttributeComponent);
338 }
339 }
340
341 for (Iterator iterator = propertyFields.iterator(); iterator.hasNext();) {
342 SearchAttributeFormContainer propertyField = (SearchAttributeFormContainer) iterator.next();
343 SearchAttributeCriteriaComponent sacc = criteriaComponentsByFormKey.get(propertyField.getKey());
344 if (sacc != null) {
345 if (sacc.getSearchableAttributeValue() == null) {
346 String errorMsg = "Searchable attribute with form field key " + sacc.getFormKey() + " does not have a valid SearchableAttributeValue";
347 LOG.error("addSearchableAttributesToCriteria() " + errorMsg);
348 throw new RuntimeException(errorMsg);
349 }
350
351 if (urlParameterSearchAttributesByFormKey.containsKey(sacc.getFormKey())) {
352 setupPropertyField(urlParameterSearchAttributesByFormKey.get(sacc.getFormKey()), propertyFields);
353 } else {
354 if (Field.MULTI_VALUE_FIELD_TYPES.contains(sacc.getLookupableFieldType())) {
355
356 sacc.setCanHoldMultipleValues(true);
357 if (propertyField.getValues() == null) {
358 sacc.setValues(new ArrayList<String>());
359 } else {
360 sacc.setValues(Arrays.asList(propertyField.getValues()));
361 }
362 } else {
363 sacc.setValue(propertyField.getValue());
364 }
365 criteria.addSearchableAttribute(sacc);
366 }
367 } else {
368 if (setAttributesStrictly) {
369 String message = "Cannot find matching search attribute with key '" + propertyField.getKey() + "' on document type '" + docType.getName() + "'";
370 LOG.error(message);
371 throw new WorkflowRuntimeException(message);
372 }
373 }
374 }
375 }
376 }
377 }
378
379 public static void setupPropertyField(SearchAttributeCriteriaComponent searchableAttribute, List propertyFields) {
380 SearchAttributeFormContainer propertyField = getPropertyField(searchableAttribute.getFormKey(), propertyFields);
381 if (propertyField != null) {
382 propertyField.setValue(searchableAttribute.getValue());
383 if (searchableAttribute.getValues() != null) {
384 propertyField.setValues(searchableAttribute.getValues().toArray(new String[searchableAttribute.getValues().size()]));
385 }
386 }
387 }
388
389 public static SearchAttributeFormContainer getPropertyField(String key, List propertyFields) {
390 if (StringUtils.isBlank(key)) {
391 return null;
392 }
393 for (Iterator iter = propertyFields.iterator(); iter.hasNext();) {
394 SearchAttributeFormContainer container = (SearchAttributeFormContainer) iter.next();
395 if (key.equals(container.getKey())) {
396 return container;
397 }
398 }
399 return null;
400 }
401
402 private static DocumentType getDocumentType(String docTypeName) {
403 if ((docTypeName != null && !"".equals(docTypeName))) {
404 return ((DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(docTypeName);
405 }
406 return null;
407 }
408
409 }