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