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 List<RemotableAttributeField> attributeFields = new ArrayList<RemotableAttributeField>();
162 DataDictionaryRemoteFieldService dataDictionaryRemoteFieldService =
163 KRADServiceLocatorWeb.getDataDictionaryRemoteFieldService();
164 for (Row row : searchRows) {
165 List<RemotableAttributeField> rowAttributeFields = new ArrayList<RemotableAttributeField>();
166 for (Field field : row.getFields()) {
167 RemotableAttributeField remotableAttributeField = dataDictionaryRemoteFieldService.buildRemotableFieldFromAttributeDefinition(field.getBusinessObjectClassName(), field.getPropertyName());
168 if (remotableAttributeField != null) {
169 rowAttributeFields.add(remotableAttributeField);
170 }
171 }
172 attributeFields.addAll(rowAttributeFields);
173 }
174 return attributeFields;
175
176 }
177
178
179
180
181
182 protected List<Row> getSearchingRows(String documentTypeName) {
183
184 List<Row> docSearchRows = new ArrayList<Row>();
185
186 Class boClass = DocumentHeader.class;
187
188 Field descriptionField = FieldUtils.getPropertyField(boClass, "documentDescription", true);
189 descriptionField.setFieldDataType(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING);
190
191 Field orgDocNumberField = FieldUtils.getPropertyField(boClass, "organizationDocumentNumber", true);
192 orgDocNumberField.setFieldDataType(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING);
193
194 List<Field> fieldList = new ArrayList<Field>();
195 fieldList.add(descriptionField);
196 docSearchRows.add(new Row(fieldList));
197
198 fieldList = new ArrayList<Field>();
199 fieldList.add(orgDocNumberField);
200 docSearchRows.add(new Row(fieldList));
201
202
203 DocumentEntry entry =
204 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(documentTypeName);
205 if (entry == null)
206 return docSearchRows;
207 if (entry instanceof MaintenanceDocumentEntry) {
208 Class<? extends BusinessObject> businessObjectClass = getBusinessObjectClass(documentTypeName);
209 Class<? extends Maintainable> maintainableClass = getMaintainableClass(documentTypeName);
210
211 KualiGlobalMaintainableImpl globalMaintainable = null;
212 try {
213 globalMaintainable = (KualiGlobalMaintainableImpl)maintainableClass.newInstance();
214 businessObjectClass = globalMaintainable.getPrimaryEditedBusinessObjectClass();
215 } catch (Exception ie) {
216
217 }
218
219 if (businessObjectClass != null)
220 docSearchRows.addAll(createFieldRowsForBusinessObject(businessObjectClass));
221 }
222
223 WorkflowAttributes workflowAttributes = entry.getWorkflowAttributes();
224 if (workflowAttributes != null)
225 docSearchRows.addAll(createFieldRowsForWorkflowAttributes(workflowAttributes));
226
227 return docSearchRows;
228 }
229
230 @Override
231 public List<RemotableAttributeError> validateDocumentAttributeCriteria(ExtensionDefinition extensionDefinition,
232 DocumentSearchCriteria documentSearchCriteria) {
233 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>();
234 DictionaryValidationService validationService = KNSServiceLocator.getDictionaryValidationService();
235
236
237 Map<String, List<String>> documentAttributeValues = documentSearchCriteria.getDocumentAttributeValues();
238 for (String key : documentAttributeValues.keySet()) {
239 List<String> values = documentAttributeValues.get(key);
240 if (CollectionUtils.isNotEmpty(values)) {
241 for (String value : values) {
242 if (StringUtils.isNotBlank(value)) {
243 validationService.validateAttributeFormat(documentSearchCriteria.getDocumentTypeName(), key, value, key);
244 }
245 }
246 }
247 }
248
249
250 ConfigurationService configurationService = KRADServiceLocator.getKualiConfigurationService();
251
252 if(GlobalVariables.getMessageMap().hasErrors()){
253 validationErrors = new ArrayList<RemotableAttributeError>();
254 MessageMap deepCopy = (MessageMap)ObjectUtils.deepCopy(GlobalVariables.getMessageMap());
255 for (String errorKey : deepCopy.getErrorMessages().keySet()) {
256 List<ErrorMessage> errorMessages = deepCopy.getErrorMessages().get(errorKey);
257 if (CollectionUtils.isNotEmpty(errorMessages)) {
258 List<String> errors = new ArrayList<String>();
259 for (ErrorMessage errorMessage : errorMessages) {
260
261 String error = MessageFormat.format(configurationService.getPropertyValueAsString(errorMessage.getErrorKey()), errorMessage.getMessageParameters());
262 errors.add(error);
263 }
264 RemotableAttributeError remotableAttributeError = RemotableAttributeError.Builder.create(errorKey, errors).build();
265 validationErrors.add(remotableAttributeError);
266 }
267 }
268
269 GlobalVariables.getMessageMap().clearErrorMessages();
270 }
271
272 return validationErrors;
273 }
274
275 protected List<Row> createFieldRowsForWorkflowAttributes(WorkflowAttributes attrs) {
276 List<Row> searchFields = new ArrayList<Row>();
277
278 List<SearchingTypeDefinition> searchingTypeDefinitions = attrs.getSearchingTypeDefinitions();
279 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
280 for (SearchingTypeDefinition definition: searchingTypeDefinitions) {
281 SearchingAttribute attr = definition.getSearchingAttribute();
282
283 final String attributeName = attr.getAttributeName();
284 final String businessObjectClassName = attr.getBusinessObjectClassName();
285 Class boClass = null;
286 BusinessObject businessObject = null;
287 try {
288 boClass = Class.forName(businessObjectClassName);
289 businessObject = (BusinessObject)boClass.newInstance();
290 } catch (Exception e) {
291 throw new RuntimeException(e);
292 }
293
294 Field searchField = FieldUtils.getPropertyField(boClass, attributeName, false);
295 searchField.setColumnVisible(attr.isShowAttributeInResultSet());
296
297
298
299 if (!attr.isShowAttributeInSearchCriteria()){
300 searchField.setFieldType(Field.HIDDEN);
301 }
302 String fieldDataType = propertyResolutionService.determineFieldDataType(boClass, attributeName);
303 if (fieldDataType.equals(DataDictionarySearchableAttribute.DATA_TYPE_BOOLEAN)) {
304 fieldDataType = KewApiConstants.SearchableAttributeConstants.DATA_TYPE_STRING;
305 }
306
307
308 if (fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT) ||
309 fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_LONG) ||
310 fieldDataType.equals(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_DATE)) {
311
312 searchField.setAllowInlineRange(true);
313 }
314 searchField.setFieldDataType(fieldDataType);
315 List displayedFieldNames = new ArrayList();
316 displayedFieldNames.add(attributeName);
317 LookupUtils.setFieldQuickfinder(businessObject, attributeName, searchField, displayedFieldNames);
318
319 List<Field> fieldList = new ArrayList<Field>();
320 fieldList.add(searchField);
321
322 Row row = new Row(fieldList);
323 if (!attr.isShowAttributeInSearchCriteria()) {
324 row.setHidden(true);
325 }
326 searchFields.add(row);
327 }
328
329 return searchFields;
330 }
331
332 protected List<DocumentAttribute> parsePrimaryKeyValuesFromDocument(Class<? extends BusinessObject> businessObjectClass, MaintenanceDocument document) {
333 List<DocumentAttribute> values = new ArrayList<DocumentAttribute>();
334
335 final List primaryKeyNames = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(businessObjectClass);
336
337 for (Object primaryKeyNameAsObj : primaryKeyNames) {
338 final String primaryKeyName = (String)primaryKeyNameAsObj;
339 final DocumentAttribute searchableValue = parseSearchableAttributeValueForPrimaryKey(primaryKeyName, businessObjectClass, document);
340 if (searchableValue != null) {
341 values.add(searchableValue);
342 }
343 }
344 return values;
345 }
346
347
348
349
350
351
352
353
354 protected DocumentAttribute parseSearchableAttributeValueForPrimaryKey(String propertyName, Class<? extends BusinessObject> businessObjectClass, MaintenanceDocument document) {
355
356 Maintainable maintainable = document.getNewMaintainableObject();
357 PersistableBusinessObject bo = maintainable.getBusinessObject();
358
359 final Object propertyValue = ObjectUtils.getPropertyValue(bo, propertyName);
360 if (propertyValue == null) return null;
361
362 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
363 DocumentAttribute value = propertyResolutionService.buildSearchableAttribute(businessObjectClass, propertyName, propertyValue);
364 return value;
365 }
366
367
368
369
370
371
372 protected Class<? extends BusinessObject> getBusinessObjectClass(String documentTypeName) {
373 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
374 return (entry == null ? null : (Class<? extends BusinessObject>) entry.getDataObjectClass());
375 }
376
377
378
379
380
381
382 protected Class<? extends Maintainable> getMaintainableClass(String documentTypeName) {
383 MaintenanceDocumentEntry entry = retrieveMaintenanceDocumentEntry(documentTypeName);
384 return (entry == null ? null : entry.getMaintainableClass());
385 }
386
387
388
389
390
391
392
393 protected MaintenanceDocumentEntry retrieveMaintenanceDocumentEntry(String documentTypeName) {
394 return (MaintenanceDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(documentTypeName);
395 }
396
397 protected GlobalBusinessObject retrieveGlobalBusinessObject(String documentNumber, Class<? extends BusinessObject> businessObjectClass) {
398 GlobalBusinessObject globalBO = null;
399
400 Map pkMap = new LinkedHashMap();
401 pkMap.put(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber);
402
403 List returnedBOs = (List) KRADServiceLocator.getBusinessObjectService().findMatching(businessObjectClass, pkMap);
404 if (returnedBOs.size() > 0) {
405 globalBO = (GlobalBusinessObject)returnedBOs.get(0);
406 }
407
408 return globalBO;
409 }
410
411 protected List<DocumentAttribute> findAllDocumentAttributesForGlobalBusinessObject(GlobalBusinessObject globalBO) {
412 List<DocumentAttribute> searchValues = new ArrayList<DocumentAttribute>();
413
414 for (PersistableBusinessObject bo : globalBO.generateGlobalChangesToPersist()) {
415 DocumentAttribute value = generateSearchableAttributeFromChange(bo);
416 if (value != null) {
417 searchValues.add(value);
418 }
419 }
420
421 return searchValues;
422 }
423
424 protected DocumentAttribute generateSearchableAttributeFromChange(PersistableBusinessObject changeToPersist) {
425 List<String> primaryKeyNames = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(changeToPersist.getClass());
426
427 for (Object primaryKeyNameAsObject : primaryKeyNames) {
428 String primaryKeyName = (String)primaryKeyNameAsObject;
429 Object value = ObjectUtils.getPropertyValue(changeToPersist, primaryKeyName);
430
431 if (value != null) {
432 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
433 DocumentAttribute saValue = propertyResolutionService.buildSearchableAttribute(changeToPersist.getClass(), primaryKeyName, value);
434 return saValue;
435 }
436 }
437 return null;
438 }
439
440
441
442
443
444
445 protected List<Row> createFieldRowsForBusinessObject(Class<? extends BusinessObject> businessObjectClass) {
446 List<Row> searchFields = new ArrayList<Row>();
447
448 final List primaryKeyNamesAsObjects = KNSServiceLocator.getBusinessObjectMetaDataService().listPrimaryKeyFieldNames(businessObjectClass);
449 final BusinessObjectEntry boEntry = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(businessObjectClass.getName());
450 final WorkflowAttributePropertyResolutionService propertyResolutionService = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService();
451 for (Object primaryKeyNameAsObject : primaryKeyNamesAsObjects) {
452
453 String attributeName = (String)primaryKeyNameAsObject;
454 BusinessObject businessObject = null;
455 try {
456 businessObject = businessObjectClass.newInstance();
457 } catch (Exception e) {
458 throw new RuntimeException(e);
459 }
460
461 Field searchField = FieldUtils.getPropertyField(businessObjectClass, attributeName, false);
462 String dataType = propertyResolutionService.determineFieldDataType(businessObjectClass, attributeName);
463 searchField.setFieldDataType(dataType);
464 List<Field> fieldList = new ArrayList<Field>();
465
466 List displayedFieldNames = new ArrayList();
467 displayedFieldNames.add(attributeName);
468 LookupUtils.setFieldQuickfinder(businessObject, attributeName, searchField, displayedFieldNames);
469
470 fieldList.add(searchField);
471 searchFields.add(new Row(fieldList));
472 }
473
474 return searchFields;
475 }
476
477 }