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 retrieveValidationErrorsFromGlobalVariables(validationErrors);
236
237 return validationErrors;
238 }
239
240
241
242
243
244 protected void retrieveValidationErrorsFromGlobalVariables(List<RemotableAttributeError> validationErrors) {
245
246 ConfigurationService configurationService = KRADServiceLocator.getKualiConfigurationService();
247
248 if(GlobalVariables.getMessageMap().hasErrors()){
249 MessageMap deepCopy = (MessageMap)ObjectUtils.deepCopy(GlobalVariables.getMessageMap());
250 for (String errorKey : deepCopy.getErrorMessages().keySet()) {
251 List<ErrorMessage> errorMessages = deepCopy.getErrorMessages().get(errorKey);
252 if (CollectionUtils.isNotEmpty(errorMessages)) {
253 List<String> errors = new ArrayList<String>();
254 for (ErrorMessage errorMessage : errorMessages) {
255
256 String error = MessageFormat.format(configurationService.getPropertyValueAsString(errorMessage.getErrorKey()), errorMessage.getMessageParameters());
257 errors.add(error);
258 }
259 RemotableAttributeError remotableAttributeError = RemotableAttributeError.Builder.create(errorKey, errors).build();
260 validationErrors.add(remotableAttributeError);
261 }
262 }
263
264 GlobalVariables.getMessageMap().clearErrorMessages();
265 }
266 }
267
268 protected List<Row> createFieldRowsForWorkflowAttributes(WorkflowAttributes attrs) {
269 List<Row> searchFields = new ArrayList<Row>();
270
271 List<SearchingTypeDefinition> searchingTypeDefinitions = attrs.getSearchingTypeDefinitions();
272 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.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 = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
358 DocumentAttribute value = propertyResolutionService.buildSearchableAttribute(businessObjectClass, propertyName, propertyValue);
359 return value;
360 }
361
362
363
364
365
366
367 protected Class<? extends BusinessObject> getBusinessObjectClass(String documentTypeName) {
368 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
369 return (entry == null ? null : (Class<? extends BusinessObject>) entry.getDataObjectClass());
370 }
371
372
373
374
375
376
377 protected Class<? extends Maintainable> getMaintainableClass(String documentTypeName) {
378 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
379 return (entry == null ? null : entry.getMaintainableClass());
380 }
381
382
383
384
385
386
387
388 protected MaintenanceDocumentEntry retrieveMaintenanceDocumentEntry(String documentTypeName) {
389 return (MaintenanceDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(documentTypeName);
390 }
391
392 protected GlobalBusinessObject retrieveGlobalBusinessObject(String documentNumber, Class<? extends BusinessObject> businessObjectClass) {
393 GlobalBusinessObject globalBO = null;
394
395 Map pkMap = new LinkedHashMap();
396 pkMap.put(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber);
397
398 List returnedBOs = (List) KRADServiceLocator.getBusinessObjectService().findMatching(businessObjectClass, pkMap);
399 if (returnedBOs.size() > 0) {
400 globalBO = (GlobalBusinessObject)returnedBOs.get(0);
401 }
402
403 return globalBO;
404 }
405
406 protected List<DocumentAttribute> findAllDocumentAttributesForGlobalBusinessObject(GlobalBusinessObject globalBO) {
407 List<DocumentAttribute> searchValues = new ArrayList<DocumentAttribute>();
408
409 for (PersistableBusinessObject bo : globalBO.generateGlobalChangesToPersist()) {
410 DocumentAttribute value = generateSearchableAttributeFromChange(bo);
411 if (value != null) {
412 searchValues.add(value);
413 }
414 }
415
416 return searchValues;
417 }
418
419 protected DocumentAttribute generateSearchableAttributeFromChange(PersistableBusinessObject changeToPersist) {
420 List<String> primaryKeyNames = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(changeToPersist.getClass());
421
422 for (Object primaryKeyNameAsObject : primaryKeyNames) {
423 String primaryKeyName = (String)primaryKeyNameAsObject;
424 Object value = ObjectUtils.getPropertyValue(changeToPersist, primaryKeyName);
425
426 if (value != null) {
427 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
428 DocumentAttribute saValue = propertyResolutionService.buildSearchableAttribute(changeToPersist.getClass(), primaryKeyName, value);
429 return saValue;
430 }
431 }
432 return null;
433 }
434
435
436
437
438
439
440 protected List<Row> createFieldRowsForBusinessObject(Class<? extends BusinessObject> businessObjectClass) {
441 List<Row> searchFields = new ArrayList<Row>();
442
443 final List primaryKeyNamesAsObjects = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(businessObjectClass);
444 final BusinessObjectEntry boEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(businessObjectClass.getName());
445 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
446 for (Object primaryKeyNameAsObject : primaryKeyNamesAsObjects) {
447
448 String attributeName = (String)primaryKeyNameAsObject;
449 BusinessObject businessObject = null;
450 try {
451 businessObject = businessObjectClass.newInstance();
452 } catch (Exception e) {
453 throw new RuntimeException(e);
454 }
455
456 Field searchField = FieldUtils.getPropertyField(businessObjectClass, attributeName, false);
457 String dataType = propertyResolutionService.determineFieldDataType(businessObjectClass, attributeName);
458 searchField.setFieldDataType(dataType);
459 List<Field> fieldList = new ArrayList<Field>();
460
461 List displayedFieldNames = new ArrayList();
462 displayedFieldNames.add(attributeName);
463 LookupUtils.setFieldQuickfinder(businessObject, attributeName, searchField, displayedFieldNames);
464
465 fieldList.add(searchField);
466 searchFields.add(new Row(fieldList));
467 }
468
469 return searchFields;
470 }
471
472 }