1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.workflow.attribute;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.kuali.rice.core.api.CoreApiServiceLocator;
22 import org.kuali.rice.core.api.config.property.ConfigurationService;
23 import org.kuali.rice.core.api.uif.RemotableAttributeError;
24 import org.kuali.rice.core.api.uif.RemotableAttributeField;
25 import org.kuali.rice.kew.api.KewApiConstants;
26 import org.kuali.rice.kew.api.document.DocumentWithContent;
27 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
28 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
29 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeString;
30 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
31 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
32 import org.kuali.rice.kew.api.exception.WorkflowException;
33 import org.kuali.rice.kew.api.extension.ExtensionDefinition;
34 import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
35 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
36 import org.kuali.rice.kns.document.MaintenanceDocument;
37 import org.kuali.rice.kns.lookup.LookupUtils;
38 import org.kuali.rice.kns.maintenance.KualiGlobalMaintainableImpl;
39 import org.kuali.rice.kns.maintenance.Maintainable;
40 import org.kuali.rice.kns.service.DictionaryValidationService;
41 import org.kuali.rice.kns.service.KNSServiceLocator;
42 import org.kuali.rice.kns.util.FieldUtils;
43 import org.kuali.rice.kns.web.ui.Field;
44 import org.kuali.rice.kns.web.ui.Row;
45 import org.kuali.rice.krad.bo.BusinessObject;
46 import org.kuali.rice.krad.bo.DocumentHeader;
47 import org.kuali.rice.krad.bo.GlobalBusinessObject;
48 import org.kuali.rice.krad.bo.PersistableBusinessObject;
49 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
50 import org.kuali.rice.krad.datadictionary.DocumentEntry;
51 import org.kuali.rice.krad.datadictionary.SearchingAttribute;
52 import org.kuali.rice.krad.datadictionary.SearchingTypeDefinition;
53 import org.kuali.rice.krad.datadictionary.WorkflowAttributes;
54 import org.kuali.rice.krad.document.Document;
55 import org.kuali.rice.krad.service.DocumentService;
56 import org.kuali.rice.krad.service.KRADServiceLocator;
57 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
58 import org.kuali.rice.krad.util.ErrorMessage;
59 import org.kuali.rice.krad.util.GlobalVariables;
60 import org.kuali.rice.krad.util.KRADPropertyConstants;
61 import org.kuali.rice.krad.util.MessageMap;
62 import org.kuali.rice.krad.util.ObjectUtils;
63 import org.kuali.rice.kns.service.WorkflowAttributePropertyResolutionService;
64
65 import java.text.MessageFormat;
66 import java.util.ArrayList;
67 import java.util.LinkedHashMap;
68 import java.util.List;
69 import java.util.Map;
70
71 public class DataDictionarySearchableAttribute implements SearchableAttribute {
72
73 private static final long serialVersionUID = 173059488280366451L;
74 private static final Logger LOG = Logger.getLogger(DataDictionarySearchableAttribute.class);
75 public static final String DATA_TYPE_BOOLEAN = "boolean";
76
77 @Override
78 public String generateSearchContent(ExtensionDefinition extensionDefinition,
79 String documentTypeName,
80 WorkflowAttributeDefinition attributeDefinition) {
81 return "";
82 }
83
84 @Override
85 public List<DocumentAttribute> extractDocumentAttributes(ExtensionDefinition extensionDefinition,
86 DocumentWithContent documentWithContent) {
87 List<DocumentAttribute> attributes = new ArrayList<DocumentAttribute>();
88
89 String docId = documentWithContent.getDocument().getDocumentId();
90
91 DocumentService docService = KRADServiceLocatorWeb.getDocumentService();
92 Document doc = null;
93 try {
94 doc = docService.getByDocumentHeaderIdSessionless(docId);
95 } catch (WorkflowException we) {
96 LOG.error( "Unable to retrieve document " + docId + " in getSearchStorageValues()", we);
97 }
98
99 String attributeValue = "";
100 if ( doc != null ) {
101 if ( doc.getDocumentHeader() != null ) {
102 attributeValue = doc.getDocumentHeader().getDocumentDescription();
103 } else {
104 attributeValue = "null document header";
105 }
106 } else {
107 attributeValue = "null document";
108 }
109 DocumentAttributeString attribute = DocumentAttributeFactory.createStringAttribute("documentDescription", attributeValue);
110 attributes.add(attribute);
111
112 attributeValue = "";
113 if ( doc != null ) {
114 if ( doc.getDocumentHeader() != null ) {
115 attributeValue = doc.getDocumentHeader().getOrganizationDocumentNumber();
116 } else {
117 attributeValue = "null document header";
118 }
119 } else {
120 attributeValue = "null document";
121 }
122 attribute = DocumentAttributeFactory.createStringAttribute("organizationDocumentNumber", attributeValue);
123 attributes.add(attribute);
124
125 if ( doc != null && doc instanceof MaintenanceDocument) {
126 final Class<? extends BusinessObject> businessObjectClass = getBusinessObjectClass(
127 documentWithContent.getDocument().getDocumentTypeName());
128 if (businessObjectClass != null) {
129 if (GlobalBusinessObject.class.isAssignableFrom(businessObjectClass)) {
130 final GlobalBusinessObject globalBO = retrieveGlobalBusinessObject(docId, businessObjectClass);
131
132 if (globalBO != null) {
133 attributes.addAll(findAllDocumentAttributesForGlobalBusinessObject(globalBO));
134 }
135 } else {
136 attributes.addAll(parsePrimaryKeyValuesFromDocument(businessObjectClass, (MaintenanceDocument)doc));
137 }
138
139 }
140 }
141 if ( doc != null ) {
142 DocumentEntry docEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(
143 documentWithContent.getDocument().getDocumentTypeName());
144 if ( docEntry != null ) {
145 WorkflowAttributes workflowAttributes = docEntry.getWorkflowAttributes();
146 WorkflowAttributePropertyResolutionService waprs = KNSServiceLocator
147 .getWorkflowAttributePropertyResolutionService();
148 attributes.addAll(waprs.resolveSearchableAttributeValues(doc, workflowAttributes));
149 } else {
150 LOG.error("Unable to find DD document entry for document type: " + documentWithContent.getDocument()
151 .getDocumentTypeName());
152 }
153 }
154 return attributes;
155 }
156
157 @Override
158 public List<RemotableAttributeField> getSearchFields(ExtensionDefinition extensionDefinition, String documentTypeName) {
159 List<Row> searchRows = getSearchingRows(documentTypeName);
160 return FieldUtils.convertRowsToAttributeFields(searchRows);
161 }
162
163
164
165
166
167 protected List<Row> getSearchingRows(String documentTypeName) {
168
169 List<Row> docSearchRows = new ArrayList<Row>();
170
171 Class boClass = DocumentHeader.class;
172
173 Field descriptionField = FieldUtils.getPropertyField(boClass, "documentDescription", true);
174 descriptionField.setFieldDataType(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING);
175
176 Field orgDocNumberField = FieldUtils.getPropertyField(boClass, "organizationDocumentNumber", true);
177 orgDocNumberField.setFieldDataType(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING);
178
179 List<Field> fieldList = new ArrayList<Field>();
180 fieldList.add(descriptionField);
181 docSearchRows.add(new Row(fieldList));
182
183 fieldList = new ArrayList<Field>();
184 fieldList.add(orgDocNumberField);
185 docSearchRows.add(new Row(fieldList));
186
187
188 DocumentEntry entry =
189 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(documentTypeName);
190 if (entry == null)
191 return docSearchRows;
192 if (entry instanceof MaintenanceDocumentEntry) {
193 Class<? extends BusinessObject> businessObjectClass = getBusinessObjectClass(documentTypeName);
194 Class<? extends Maintainable> maintainableClass = getMaintainableClass(documentTypeName);
195
196 KualiGlobalMaintainableImpl globalMaintainable = null;
197 try {
198 globalMaintainable = (KualiGlobalMaintainableImpl)maintainableClass.newInstance();
199 businessObjectClass = globalMaintainable.getPrimaryEditedBusinessObjectClass();
200 } catch (Exception ie) {
201
202 }
203
204 if (businessObjectClass != null)
205 docSearchRows.addAll(createFieldRowsForBusinessObject(businessObjectClass));
206 }
207
208 WorkflowAttributes workflowAttributes = entry.getWorkflowAttributes();
209 if (workflowAttributes != null)
210 docSearchRows.addAll(createFieldRowsForWorkflowAttributes(workflowAttributes));
211
212 return docSearchRows;
213 }
214
215 @Override
216 public List<RemotableAttributeError> validateDocumentAttributeCriteria(ExtensionDefinition extensionDefinition,
217 DocumentSearchCriteria documentSearchCriteria) {
218 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>();
219 DictionaryValidationService validationService = KNSServiceLocator.getKNSDictionaryValidationService();
220
221
222 Map<String, List<String>> documentAttributeValues = documentSearchCriteria.getDocumentAttributeValues();
223 for (String key : documentAttributeValues.keySet()) {
224 List<String> values = documentAttributeValues.get(key);
225 if (CollectionUtils.isNotEmpty(values)) {
226 for (String value : values) {
227 if (StringUtils.isNotBlank(value)) {
228 validationService.validateAttributeFormat(documentSearchCriteria.getDocumentTypeName(), key, value, key);
229 }
230 }
231 }
232 }
233
234 retrieveValidationErrorsFromGlobalVariables(validationErrors);
235
236 return validationErrors;
237 }
238
239
240
241
242
243 protected void retrieveValidationErrorsFromGlobalVariables(List<RemotableAttributeError> validationErrors) {
244
245 ConfigurationService configurationService = CoreApiServiceLocator.getKualiConfigurationService();
246
247 if(GlobalVariables.getMessageMap().hasErrors()){
248 MessageMap deepCopy = (MessageMap)ObjectUtils.deepCopy(GlobalVariables.getMessageMap());
249 for (String errorKey : deepCopy.getErrorMessages().keySet()) {
250 List<ErrorMessage> errorMessages = deepCopy.getErrorMessages().get(errorKey);
251 if (CollectionUtils.isNotEmpty(errorMessages)) {
252 List<String> errors = new ArrayList<String>();
253 for (ErrorMessage errorMessage : errorMessages) {
254
255 String error = MessageFormat.format(configurationService.getPropertyValueAsString(errorMessage.getErrorKey()), errorMessage.getMessageParameters());
256 errors.add(error);
257 }
258 RemotableAttributeError remotableAttributeError = RemotableAttributeError.Builder.create(errorKey, errors).build();
259 validationErrors.add(remotableAttributeError);
260 }
261 }
262
263 GlobalVariables.getMessageMap().clearErrorMessages();
264 }
265 }
266
267 protected List<Row> createFieldRowsForWorkflowAttributes(WorkflowAttributes attrs) {
268 List<Row> searchFields = new ArrayList<Row>();
269
270 List<SearchingTypeDefinition> searchingTypeDefinitions = attrs.getSearchingTypeDefinitions();
271 final WorkflowAttributePropertyResolutionService propertyResolutionService = KNSServiceLocator
272 .getWorkflowAttributePropertyResolutionService();
273 for (SearchingTypeDefinition definition: searchingTypeDefinitions) {
274 SearchingAttribute attr = definition.getSearchingAttribute();
275
276 final String attributeName = attr.getAttributeName();
277 final String businessObjectClassName = attr.getBusinessObjectClassName();
278 Class boClass = null;
279 BusinessObject businessObject = null;
280 try {
281 boClass = Class.forName(businessObjectClassName);
282 businessObject = (BusinessObject)boClass.newInstance();
283 } catch (Exception e) {
284 throw new RuntimeException(e);
285 }
286
287 Field searchField = FieldUtils.getPropertyField(boClass, attributeName, false);
288
289
290 searchField.setColumnVisible(attr.isShowAttributeInResultSet());
291
292
293
294 if (!attr.isShowAttributeInSearchCriteria()){
295 searchField.setFieldType(Field.HIDDEN);
296 }
297 String fieldDataType = propertyResolutionService.determineFieldDataType(boClass, attributeName);
298 if (fieldDataType.equals(DataDictionarySearchableAttribute.DATA_TYPE_BOOLEAN)) {
299 fieldDataType = KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING;
300 }
301
302
303 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT) ||
304 fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_LONG) ||
305 fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_DATE)) {
306
307 searchField.setAllowInlineRange(true);
308 }
309 searchField.setFieldDataType(fieldDataType);
310 List displayedFieldNames = new ArrayList();
311 displayedFieldNames.add(attributeName);
312 LookupUtils.setFieldQuickfinder(businessObject, attributeName, searchField, displayedFieldNames);
313
314 List<Field> fieldList = new ArrayList<Field>();
315 fieldList.add(searchField);
316
317 Row row = new Row(fieldList);
318 if (!attr.isShowAttributeInSearchCriteria()) {
319 row.setHidden(true);
320 }
321 searchFields.add(row);
322 }
323
324 return searchFields;
325 }
326
327 protected List<DocumentAttribute> parsePrimaryKeyValuesFromDocument(Class<? extends BusinessObject> businessObjectClass, MaintenanceDocument document) {
328 List<DocumentAttribute> values = new ArrayList<DocumentAttribute>();
329
330 final List primaryKeyNames = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(businessObjectClass);
331
332 for (Object primaryKeyNameAsObj : primaryKeyNames) {
333 final String primaryKeyName = (String)primaryKeyNameAsObj;
334 final DocumentAttribute searchableValue = parseSearchableAttributeValueForPrimaryKey(primaryKeyName, businessObjectClass, document);
335 if (searchableValue != null) {
336 values.add(searchableValue);
337 }
338 }
339 return values;
340 }
341
342
343
344
345
346
347
348
349 protected DocumentAttribute parseSearchableAttributeValueForPrimaryKey(String propertyName, Class<? extends BusinessObject> businessObjectClass, MaintenanceDocument document) {
350
351 Maintainable maintainable = document.getNewMaintainableObject();
352 PersistableBusinessObject bo = maintainable.getBusinessObject();
353
354 final Object propertyValue = ObjectUtils.getPropertyValue(bo, propertyName);
355 if (propertyValue == null) return null;
356
357 final WorkflowAttributePropertyResolutionService propertyResolutionService = KNSServiceLocator
358 .getWorkflowAttributePropertyResolutionService();
359 DocumentAttribute value = propertyResolutionService.buildSearchableAttribute(businessObjectClass, propertyName, propertyValue);
360 return value;
361 }
362
363
364
365
366
367
368 protected Class<? extends BusinessObject> getBusinessObjectClass(String documentTypeName) {
369 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
370 return (entry == null ? null : (Class<? extends BusinessObject>) entry.getDataObjectClass());
371 }
372
373
374
375
376
377
378 protected Class<? extends Maintainable> getMaintainableClass(String documentTypeName) {
379 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
380 return (entry == null ? null : entry.getMaintainableClass());
381 }
382
383
384
385
386
387
388
389 protected MaintenanceDocumentEntry retrieveMaintenanceDocumentEntry(String documentTypeName) {
390 return (MaintenanceDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(documentTypeName);
391 }
392
393 protected GlobalBusinessObject retrieveGlobalBusinessObject(String documentNumber, Class<? extends BusinessObject> businessObjectClass) {
394 GlobalBusinessObject globalBO = null;
395
396 Map pkMap = new LinkedHashMap();
397 pkMap.put(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber);
398
399 List returnedBOs = (List) KRADServiceLocator.getBusinessObjectService().findMatching(businessObjectClass, pkMap);
400 if (returnedBOs.size() > 0) {
401 globalBO = (GlobalBusinessObject)returnedBOs.get(0);
402 }
403
404 return globalBO;
405 }
406
407 protected List<DocumentAttribute> findAllDocumentAttributesForGlobalBusinessObject(GlobalBusinessObject globalBO) {
408 List<DocumentAttribute> searchValues = new ArrayList<DocumentAttribute>();
409
410 for (PersistableBusinessObject bo : globalBO.generateGlobalChangesToPersist()) {
411 DocumentAttribute value = generateSearchableAttributeFromChange(bo);
412 if (value != null) {
413 searchValues.add(value);
414 }
415 }
416
417 return searchValues;
418 }
419
420 protected DocumentAttribute generateSearchableAttributeFromChange(PersistableBusinessObject changeToPersist) {
421 List<String> primaryKeyNames = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(changeToPersist.getClass());
422
423 for (Object primaryKeyNameAsObject : primaryKeyNames) {
424 String primaryKeyName = (String)primaryKeyNameAsObject;
425 Object value = ObjectUtils.getPropertyValue(changeToPersist, primaryKeyName);
426
427 if (value != null) {
428 final WorkflowAttributePropertyResolutionService propertyResolutionService = KNSServiceLocator
429 .getWorkflowAttributePropertyResolutionService();
430 DocumentAttribute saValue = propertyResolutionService.buildSearchableAttribute(changeToPersist.getClass(), primaryKeyName, value);
431 return saValue;
432 }
433 }
434 return null;
435 }
436
437
438
439
440
441
442 protected List<Row> createFieldRowsForBusinessObject(Class<? extends BusinessObject> businessObjectClass) {
443 List<Row> searchFields = new ArrayList<Row>();
444
445 final List primaryKeyNamesAsObjects = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(businessObjectClass);
446 final BusinessObjectEntry boEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(businessObjectClass.getName());
447 final WorkflowAttributePropertyResolutionService propertyResolutionService = KNSServiceLocator
448 .getWorkflowAttributePropertyResolutionService();
449 for (Object primaryKeyNameAsObject : primaryKeyNamesAsObjects) {
450
451 String attributeName = (String)primaryKeyNameAsObject;
452 BusinessObject businessObject = null;
453 try {
454 businessObject = businessObjectClass.newInstance();
455 } catch (Exception e) {
456 throw new RuntimeException(e);
457 }
458
459 Field searchField = FieldUtils.getPropertyField(businessObjectClass, attributeName, false);
460 String dataType = propertyResolutionService.determineFieldDataType(businessObjectClass, attributeName);
461 searchField.setFieldDataType(dataType);
462 List<Field> fieldList = new ArrayList<Field>();
463
464 List displayedFieldNames = new ArrayList();
465 displayedFieldNames.add(attributeName);
466 LookupUtils.setFieldQuickfinder(businessObject, attributeName, searchField, displayedFieldNames);
467
468 fieldList.add(searchField);
469 searchFields.add(new Row(fieldList));
470 }
471
472 return searchFields;
473 }
474
475 }