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