1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.workflow.service.impl;
17
18 import org.joda.time.DateTime;
19 import org.kuali.rice.core.api.util.type.KualiDecimal;
20 import org.kuali.rice.kew.api.KewApiConstants;
21 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
22 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDateTime;
23 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDecimal;
24 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
25 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeInteger;
26 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeString;
27 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
28 import org.kuali.rice.kns.service.KNSServiceLocator;
29 import org.kuali.rice.kns.service.WorkflowAttributePropertyResolutionService;
30 import org.kuali.rice.kns.workflow.attribute.DataDictionarySearchableAttribute;
31 import org.kuali.rice.krad.bo.BusinessObject;
32 import org.kuali.rice.krad.bo.PersistableBusinessObject;
33 import org.kuali.rice.krad.datadictionary.DocumentCollectionPath;
34 import org.kuali.rice.krad.datadictionary.DocumentValuePathGroup;
35 import org.kuali.rice.krad.datadictionary.RoutingAttribute;
36 import org.kuali.rice.krad.datadictionary.RoutingTypeDefinition;
37 import org.kuali.rice.krad.datadictionary.SearchingTypeDefinition;
38 import org.kuali.rice.krad.datadictionary.WorkflowAttributes;
39 import org.kuali.rice.krad.document.Document;
40 import org.kuali.rice.krad.service.PersistenceStructureService;
41 import org.kuali.rice.krad.util.DataTypeUtil;
42 import org.kuali.rice.krad.util.ObjectUtils;
43
44 import java.math.BigDecimal;
45 import java.math.BigInteger;
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.List;
51 import java.util.Map;
52 import java.util.Set;
53 import java.util.Stack;
54
55
56
57
58
59
60
61
62 @Deprecated
63 public class WorkflowAttributePropertyResolutionServiceImpl implements WorkflowAttributePropertyResolutionService {
64
65 private PersistenceStructureService persistenceStructureService;
66 private BusinessObjectMetaDataService businessObjectMetaDataService;
67
68
69
70
71 public List<Map<String, String>> resolveRoutingTypeQualifiers(Document document, RoutingTypeDefinition routingTypeDefinition) {
72 List<Map<String, String>> qualifiers = new ArrayList<Map<String, String>>();
73
74 if (routingTypeDefinition != null) {
75 document.populateDocumentForRouting();
76 RoutingAttributeTracker routingAttributeTracker = new RoutingAttributeTracker(routingTypeDefinition.getRoutingAttributes());
77 for (DocumentValuePathGroup documentValuePathGroup : routingTypeDefinition.getDocumentValuePathGroups()) {
78 qualifiers.addAll(resolveDocumentValuePath(document, documentValuePathGroup, routingAttributeTracker));
79 routingAttributeTracker.reset();
80 }
81 }
82 return qualifiers;
83 }
84
85
86
87
88
89
90
91 protected List<Map<String, String>> resolveDocumentValuePath(Object businessObject, DocumentValuePathGroup group, RoutingAttributeTracker routingAttributeTracker) {
92 List<Map<String, String>> qualifiers;
93 Map<String, String> qualifier = new HashMap<String, String>();
94 if (group.getDocumentValues() == null && group.getDocumentCollectionPath() == null) {
95 throw new IllegalStateException("A document value path group must have the documentValues property set, the documentCollectionPath property set, or both.");
96 }
97 if (group.getDocumentValues() != null) {
98 addPathValuesToQualifier(businessObject, group.getDocumentValues(), routingAttributeTracker, qualifier);
99 }
100 if (group.getDocumentCollectionPath() != null) {
101 qualifiers = resolveDocumentCollectionPath(businessObject, group.getDocumentCollectionPath(), routingAttributeTracker);
102 qualifiers = cleanCollectionQualifiers(qualifiers);
103 for (Map<String, String> collectionElementQualifier : qualifiers) {
104 copyQualifications(qualifier, collectionElementQualifier);
105 }
106 } else {
107 qualifiers = new ArrayList<Map<String, String>>();
108 qualifiers.add(qualifier);
109 }
110 return qualifiers;
111 }
112
113
114
115
116
117
118
119 protected List<Map<String, String>> resolveDocumentCollectionPath(Object businessObject, DocumentCollectionPath collectionPath, RoutingAttributeTracker routingAttributeTracker) {
120 List<Map<String, String>> qualifiers = new ArrayList<Map<String, String>>();
121 final Collection collectionByPath = getCollectionByPath(businessObject, collectionPath.getCollectionPath());
122 if (!ObjectUtils.isNull(collectionByPath)) {
123 if (collectionPath.getNestedCollection() != null) {
124
125 for (Object collectionElement : collectionByPath) {
126
127 if (collectionElement instanceof BusinessObject) {
128 List<Map<String, String>> childQualifiers = resolveDocumentCollectionPath((BusinessObject)collectionElement, collectionPath.getNestedCollection(), routingAttributeTracker);
129 for (Map<String, String> childQualifier : childQualifiers) {
130 Map<String, String> qualifier = new HashMap<String, String>();
131 routingAttributeTracker.checkPoint();
132
133 addPathValuesToQualifier(collectionElement, collectionPath.getDocumentValues(), routingAttributeTracker, qualifier);
134
135 copyQualifications(childQualifier, qualifier);
136 qualifiers.add(qualifier);
137 routingAttributeTracker.backUpToCheckPoint();
138 }
139 }
140 }
141 } else {
142
143 for (Object collectionElement : collectionByPath) {
144 Map<String, String> qualifier = new HashMap<String, String>();
145 routingAttributeTracker.checkPoint();
146 addPathValuesToQualifier(collectionElement, collectionPath.getDocumentValues(), routingAttributeTracker, qualifier);
147 qualifiers.add(qualifier);
148 routingAttributeTracker.backUpToCheckPoint();
149 }
150 }
151 }
152 return qualifiers;
153 }
154
155
156
157
158
159
160
161 protected Collection getCollectionByPath(Object businessObject, String collectionPath) {
162 return (Collection)getPropertyByPath(businessObject, collectionPath.trim());
163 }
164
165
166
167
168
169
170
171
172 protected void addPathValuesToQualifier(Object businessObject, List<String> paths, RoutingAttributeTracker routingAttributes, Map<String, String> qualifier) {
173 if (ObjectUtils.isNotNull(paths)) {
174 for (String path : paths) {
175
176 final Object value = getPropertyByPath(businessObject, path.trim());
177 if (value != null) {
178 qualifier.put(routingAttributes.getCurrentRoutingAttribute().getQualificationAttributeName(), value.toString());
179 }
180 routingAttributes.moveToNext();
181 }
182 }
183 }
184
185
186
187
188
189
190 protected void copyQualifications(Map<String, String> source, Map<String, String> target) {
191 for (String key : source.keySet()) {
192 target.put(key, source.get(key));
193 }
194 }
195
196
197
198
199
200 public List<DocumentAttribute> resolveSearchableAttributeValues(Document document, WorkflowAttributes workflowAttributes) {
201 List<DocumentAttribute> valuesToIndex = new ArrayList<DocumentAttribute>();
202 if (workflowAttributes != null && workflowAttributes.getSearchingTypeDefinitions() != null) {
203 for (SearchingTypeDefinition definition : workflowAttributes.getSearchingTypeDefinitions()) {
204 valuesToIndex.addAll(aardvarkValuesForSearchingTypeDefinition(document, definition));
205 }
206 }
207 return valuesToIndex;
208 }
209
210
211
212
213
214
215
216 protected List<DocumentAttribute> aardvarkValuesForSearchingTypeDefinition(Document document, SearchingTypeDefinition searchingTypeDefinition) {
217 List<DocumentAttribute> searchAttributes = new ArrayList<DocumentAttribute>();
218
219 final List<Object> searchValues = aardvarkSearchValuesForPaths(document, searchingTypeDefinition.getDocumentValues());
220 for (Object value : searchValues) {
221 try {
222 final DocumentAttribute searchableAttributeValue = buildSearchableAttribute(((Class<? extends BusinessObject>)Class.forName(searchingTypeDefinition.getSearchingAttribute().getBusinessObjectClassName())), searchingTypeDefinition.getSearchingAttribute().getAttributeName(), value);
223 if (searchableAttributeValue != null) {
224 searchAttributes.add(searchableAttributeValue);
225 }
226 }
227 catch (ClassNotFoundException cnfe) {
228 throw new RuntimeException("Could not find instance of class "+searchingTypeDefinition.getSearchingAttribute().getBusinessObjectClassName(), cnfe);
229 }
230 }
231 return searchAttributes;
232 }
233
234
235
236
237
238
239
240 protected List<Object> aardvarkSearchValuesForPaths(Document document, List<String> paths) {
241 List<Object> searchValues = new ArrayList<Object>();
242 for (String path : paths) {
243 flatAdd(searchValues, getPropertyByPath(document, path.trim()));
244 }
245 return searchValues;
246 }
247
248
249
250
251
252
253 protected List<Map<String, String>> cleanCollectionQualifiers(List<Map<String, String>> qualifiers) {
254 List<Map<String, String>> cleanedQualifiers = new ArrayList<Map<String, String>>();
255 for (Map<String, String> qualifier : qualifiers) {
256 if (qualifier.size() > 0) {
257 cleanedQualifiers.add(qualifier);
258 }
259 }
260 return cleanedQualifiers;
261 }
262
263 public String determineFieldDataType(Class<? extends BusinessObject> businessObjectClass, String attributeName) {
264 return DataTypeUtil.determineFieldDataType(businessObjectClass, attributeName);
265 }
266
267
268
269
270
271
272
273 public DocumentAttribute buildSearchableAttribute(Class<? extends BusinessObject> businessObjectClass, String attributeKey, Object value) {
274 if (value == null) return null;
275 final String fieldDataType = determineFieldDataType(businessObjectClass, attributeKey);
276 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING)) return buildSearchableStringAttribute(attributeKey, value);
277 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT) && DataTypeUtil.isDecimaltastic(value.getClass())) return buildSearchableRealAttribute(attributeKey, value);
278 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_DATE) && DataTypeUtil.isDateLike(value.getClass())) return buildSearchableDateTimeAttribute(attributeKey, value);
279 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_LONG) && DataTypeUtil.isIntsy(value.getClass())) return buildSearchableFixnumAttribute(attributeKey, value);
280 if (fieldDataType.equals(DataDictionarySearchableAttribute.DATA_TYPE_BOOLEAN) && DataTypeUtil.isBooleanable(value.getClass())) return buildSearchableYesNoAttribute(attributeKey, value);
281 return buildSearchableStringAttribute(attributeKey, value);
282 }
283
284
285
286
287
288
289
290 protected DocumentAttributeDateTime buildSearchableDateTimeAttribute(String attributeKey, Object value) {
291 return DocumentAttributeFactory.createDateTimeAttribute(attributeKey, new DateTime(value));
292 }
293
294
295
296
297
298
299
300 protected DocumentAttributeDecimal buildSearchableRealAttribute(String attributeKey, Object value) {
301 BigDecimal decimalValue = null;
302 if (value instanceof BigDecimal) {
303 decimalValue = (BigDecimal)value;
304 } else if (value instanceof KualiDecimal) {
305 decimalValue = ((KualiDecimal)value).bigDecimalValue();
306 } else {
307 decimalValue = new BigDecimal(((Number)value).doubleValue());
308 }
309 return DocumentAttributeFactory.createDecimalAttribute(attributeKey, decimalValue);
310 }
311
312
313
314
315
316
317
318 protected DocumentAttributeInteger buildSearchableFixnumAttribute(String attributeKey, Object value) {
319 BigInteger integerValue = null;
320 if (value instanceof BigInteger) {
321 integerValue = (BigInteger)value;
322 } else {
323 integerValue = BigInteger.valueOf(((Number)value).longValue());
324 }
325 return DocumentAttributeFactory.createIntegerAttribute(attributeKey, integerValue);
326 }
327
328
329
330
331
332
333
334 protected DocumentAttributeString buildSearchableStringAttribute(String attributeKey, Object value) {
335 return DocumentAttributeFactory.createStringAttribute(attributeKey, value.toString());
336 }
337
338
339
340
341
342
343
344 protected DocumentAttributeString buildSearchableYesNoAttribute(String attributeKey, Object value) {
345 final String boolValueAsString = booleanValueAsString((Boolean)value);
346 return DocumentAttributeFactory.createStringAttribute(attributeKey, boolValueAsString);
347 }
348
349
350
351
352
353
354 private String booleanValueAsString(Boolean booleanValue) {
355 if (booleanValue == null) return "";
356 if (booleanValue.booleanValue()) return "Y";
357 return "N";
358 }
359
360 public Object getPropertyByPath(Object object, String path) {
361 if (object instanceof Collection) return getPropertyOfCollectionByPath((Collection)object, path);
362
363 final String[] splitPath = headAndTailPath(path);
364 final String head = splitPath[0];
365 final String tail = splitPath[1];
366
367 if (object instanceof PersistableBusinessObject && tail != null) {
368 if (getBusinessObjectMetaDataService().getBusinessObjectRelationship((BusinessObject) object, head) != null) {
369 ((PersistableBusinessObject)object).refreshReferenceObject(head);
370
371 }
372 }
373 final Object headValue = ObjectUtils.getPropertyValue(object, head);
374 if (!ObjectUtils.isNull(headValue)) {
375 if (tail == null) {
376 return headValue;
377 } else {
378
379 if (headValue instanceof Collection) {
380
381 Collection values = makeNewCollectionOfSameType((Collection)headValue);
382 for (Object currentElement : (Collection)headValue) {
383 flatAdd(values, getPropertyByPath(currentElement, tail));
384 }
385 return values;
386 } else {
387 return getPropertyByPath(headValue, tail);
388 }
389 }
390 }
391 return null;
392 }
393
394
395
396
397
398
399
400 public Collection getPropertyOfCollectionByPath(Collection collection, String path) {
401 Collection values = makeNewCollectionOfSameType(collection);
402 for (Object o : collection) {
403 flatAdd(values, getPropertyByPath(o, path));
404 }
405 return values;
406 }
407
408
409
410
411
412
413 public Collection makeNewCollectionOfSameType(Collection collection) {
414 if (collection instanceof List) return new ArrayList();
415 if (collection instanceof Set) return new HashSet();
416 try {
417 return collection.getClass().newInstance();
418 }
419 catch (InstantiationException ie) {
420 throw new RuntimeException("Couldn't instantiate class of collection we'd already instantiated??", ie);
421 }
422 catch (IllegalAccessException iae) {
423 throw new RuntimeException("Illegal Access on class of collection we'd already accessed??", iae);
424 }
425 }
426
427
428
429
430
431
432 protected String[] headAndTailPath(String path) {
433 final int firstDot = path.indexOf('.');
434 if (firstDot < 0) {
435 return new String[] { path, null };
436 }
437 return new String[] { path.substring(0, firstDot), path.substring(firstDot + 1) };
438 }
439
440
441
442
443
444
445 protected void flatAdd(Collection c, Object o) {
446 if (o instanceof Collection) {
447 c.addAll((Collection) o);
448 } else {
449 c.add(o);
450 }
451 }
452
453
454
455
456
457 public PersistenceStructureService getPersistenceStructureService() {
458 return persistenceStructureService;
459 }
460
461
462
463
464
465 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
466 this.persistenceStructureService = persistenceStructureService;
467 }
468
469
470
471
472 class RoutingAttributeTracker {
473
474 private List<RoutingAttribute> routingAttributes;
475 private int currentRoutingAttributeIndex;
476 private Stack<Integer> checkPoints;
477
478
479
480
481
482 public RoutingAttributeTracker(List<RoutingAttribute> routingAttributes) {
483 this.routingAttributes = routingAttributes;
484 checkPoints = new Stack<Integer>();
485 }
486
487
488
489
490 public RoutingAttribute getCurrentRoutingAttribute() {
491 return routingAttributes.get(currentRoutingAttributeIndex);
492 }
493
494
495
496
497 public void moveToNext() {
498 currentRoutingAttributeIndex += 1;
499 }
500
501
502
503
504 public void checkPoint() {
505 checkPoints.push(new Integer(currentRoutingAttributeIndex));
506 }
507
508
509
510
511 public void backUpToCheckPoint() {
512 currentRoutingAttributeIndex = checkPoints.pop().intValue();
513 }
514
515
516
517
518
519 public void reset() {
520 currentRoutingAttributeIndex = 0;
521 checkPoints.clear();
522 }
523 }
524
525 protected BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
526 if ( businessObjectMetaDataService == null ) {
527 businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService();
528 }
529 return businessObjectMetaDataService;
530 }
531 }