1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.util;
17
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Properties;
25 import java.util.Set;
26 import java.util.StringTokenizer;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.kuali.rice.kew.exception.WorkflowException;
30 import org.kuali.rice.kns.bo.BusinessObject;
31 import org.kuali.rice.kns.datadictionary.AttributeSecurity;
32 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
33 import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
34 import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
35 import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
36 import org.kuali.rice.kns.datadictionary.MaintenanceDocumentEntry;
37 import org.kuali.rice.kns.document.MaintenanceDocument;
38 import org.kuali.rice.kns.exception.KualiExceptionIncident;
39 import org.kuali.rice.kns.exception.ValidationException;
40 import org.kuali.rice.kns.lookup.LookupUtils;
41 import org.kuali.rice.kns.lookup.SelectiveReferenceRefresher;
42 import org.kuali.rice.kns.maintenance.Maintainable;
43 import org.kuali.rice.kns.service.DataDictionaryService;
44 import org.kuali.rice.kns.service.KNSServiceLocator;
45 import org.kuali.rice.kns.service.KualiConfigurationService;
46 import org.kuali.rice.kns.service.KualiExceptionIncidentService;
47 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
48 import org.kuali.rice.kns.service.MaintenanceDocumentService;
49 import org.kuali.rice.kns.web.ui.Field;
50 import org.kuali.rice.kns.web.ui.Row;
51 import org.kuali.rice.kns.web.ui.Section;
52 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
53 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
54
55 public class MaintenanceUtils {
56 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceUtils.class);
57
58 private static MaintenanceDocumentService maintenanceDocumentService;
59 private static WorkflowDocumentService workflowDocumentService;
60 private static KualiConfigurationService kualiConfigurationService;
61 private static KualiExceptionIncidentService kualiExceptionIncidentService;
62 private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
63 private static DataDictionaryService dataDictionaryService;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 public static Map<String, String> generateMultipleValueLookupBOTemplate(List<MaintainableSectionDefinition> sections, String collectionName) {
79 MaintainableCollectionDefinition definition = findMaintainableCollectionDefinition(sections, collectionName);
80 if (definition == null) {
81 return null;
82 }
83 Map<String, String> template = null;
84
85 for (MaintainableFieldDefinition maintainableField : definition.getMaintainableFields()) {
86 String templateString = maintainableField.getTemplate();
87 if (StringUtils.isNotBlank(templateString)) {
88 if (template == null) {
89 template = new HashMap<String, String>();
90 }
91 template.put(maintainableField.getName(), templateString);
92 }
93 }
94 return template;
95 }
96
97
98
99
100
101
102
103
104
105
106
107 public static MaintainableCollectionDefinition findMaintainableCollectionDefinition(List<MaintainableSectionDefinition> sections, String collectionName) {
108 String[] collectionNameParts = StringUtils.split(collectionName, ".");
109 for (MaintainableSectionDefinition section : sections) {
110 MaintainableCollectionDefinition collDefinition = findMaintainableCollectionDefinitionHelper(section.getMaintainableItems(), collectionNameParts, 0);
111 if (collDefinition != null) {
112 return collDefinition;
113 }
114 }
115 return null;
116 }
117
118 private static <E extends MaintainableItemDefinition> MaintainableCollectionDefinition findMaintainableCollectionDefinitionHelper(Collection<E> items, String[] collectionNameParts, int collectionNameIndex) {
119 if (collectionNameParts.length <= collectionNameIndex) {
120
121 return null;
122 }
123
124
125
126 String collectionToFind = StringUtils.substringBefore(collectionNameParts[collectionNameIndex], "[");
127 for (MaintainableItemDefinition item : items) {
128 if (item instanceof MaintainableCollectionDefinition) {
129 MaintainableCollectionDefinition collection = (MaintainableCollectionDefinition) item;
130 if (collection.getName().equals(collectionToFind)) {
131
132
133 if (collectionNameIndex == collectionNameParts.length - 1) {
134
135 return collection;
136 }
137 else {
138
139 return findMaintainableCollectionDefinitionHelper(collection.getMaintainableCollections(), collectionNameParts, collectionNameIndex + 1);
140 }
141 }
142 }
143 }
144 return null;
145 }
146
147
148
149
150
151
152
153
154 public static final Field setFieldQuickfinder(BusinessObject businessObject, String attributeName, MaintainableFieldDefinition maintainableFieldDefinition, Field field, List<String> displayedFieldNames, SelectiveReferenceRefresher srr) {
155 if (maintainableFieldDefinition.getOverrideLookupClass() != null && StringUtils.isNotBlank(maintainableFieldDefinition.getOverrideFieldConversions())) {
156 field.setQuickFinderClassNameImpl(maintainableFieldDefinition.getOverrideLookupClass().getName());
157 field.setFieldConversions(maintainableFieldDefinition.getOverrideFieldConversions());
158 field.setBaseLookupUrl(LookupUtils.getBaseLookupUrl(false));
159 field.setReferencesToRefresh(LookupUtils.convertReferencesToSelectCollectionToString(
160 srr.getAffectedReferencesFromLookup(businessObject, attributeName, "")));
161 return field;
162 }
163 if (maintainableFieldDefinition.isNoLookup()){
164 return field;
165 }
166 return LookupUtils.setFieldQuickfinder(businessObject, null, false, 0, attributeName, field, displayedFieldNames, maintainableFieldDefinition.isNoLookup());
167 }
168
169 public static final Field setFieldQuickfinder(BusinessObject businessObject, String collectionName, boolean addLine, int index,
170 String attributeName, Field field, List<String> displayedFieldNames, Maintainable maintainable, MaintainableFieldDefinition maintainableFieldDefinition) {
171 if (maintainableFieldDefinition.getOverrideLookupClass() != null && StringUtils.isNotBlank(maintainableFieldDefinition.getOverrideFieldConversions())) {
172 if (maintainable != null) {
173 String collectionPrefix = "";
174 if ( collectionName != null ) {
175 if (addLine) {
176 collectionPrefix = KNSConstants.MAINTENANCE_ADD_PREFIX + collectionName + ".";
177 }
178 else {
179 collectionPrefix = collectionName + "[" + index + "].";
180 }
181 }
182 field.setQuickFinderClassNameImpl(maintainableFieldDefinition.getOverrideLookupClass().getName());
183
184 String prefixedFieldConversions = prefixFieldConversionsDestinationsWithCollectionPrefix(maintainableFieldDefinition.getOverrideFieldConversions(), collectionPrefix);
185 field.setFieldConversions(prefixedFieldConversions);
186 field.setBaseLookupUrl(LookupUtils.getBaseLookupUrl(false));
187 field.setReferencesToRefresh(LookupUtils.convertReferencesToSelectCollectionToString(
188 maintainable.getAffectedReferencesFromLookup(businessObject, attributeName, collectionPrefix)));
189 }
190 return field;
191 }
192 if(maintainableFieldDefinition.isNoLookup()){
193 return field;
194 }
195 return LookupUtils.setFieldQuickfinder(businessObject, collectionName, addLine, index,
196 attributeName, field, displayedFieldNames, maintainable);
197 }
198
199 private static String prefixFieldConversionsDestinationsWithCollectionPrefix(String originalFieldConversions, String collectionPrefix) {
200 StringBuilder buf = new StringBuilder();
201 StringTokenizer tok = new StringTokenizer(originalFieldConversions, KNSConstants.FIELD_CONVERSIONS_SEPARATOR);
202 boolean needsSeparator = false;
203 while (tok.hasMoreTokens()) {
204 String conversionPair = tok.nextToken();
205 if (StringUtils.isBlank(conversionPair)) {
206 continue;
207 }
208
209 String fromValue = StringUtils.substringBefore(conversionPair, KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
210 String toValue = StringUtils.substringAfter(conversionPair, KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR);
211
212 if (needsSeparator) {
213 buf.append(KNSConstants.FIELD_CONVERSIONS_SEPARATOR);
214 }
215 needsSeparator = true;
216
217 buf.append(fromValue).append(KNSConstants.FIELD_CONVERSION_PAIR_SEPARATOR).append(collectionPrefix).append(toValue);
218 }
219 return buf.toString();
220 }
221
222 public static final void setFieldDirectInquiry(BusinessObject businessObject, String attributeName, MaintainableFieldDefinition maintainableFieldDefinition, Field field, List<String> displayedFieldNames) {
223 LookupUtils.setFieldDirectInquiry(businessObject, attributeName, field);
224 }
225
226 public static final void setFieldDirectInquiry(BusinessObject businessObject, String collectionName, boolean addLine, int index,
227 String attributeName, Field field, List<String> displayedFieldNames, Maintainable maintainable, MaintainableFieldDefinition maintainableFieldDefinition) {
228 LookupUtils.setFieldDirectInquiry(businessObject, attributeName, field);
229 }
230
231
232
233
234
235
236 public static String generateErrorKeyForSection(Section section) {
237 Set<String> fieldPropertyNames = new HashSet<String>();
238 addRowsToErrorKeySet(section.getRows(), fieldPropertyNames);
239
240 StringBuilder buf = new StringBuilder();
241 buf.append(section.getSectionId()).append(",");
242
243 Iterator<String> nameIter = fieldPropertyNames.iterator();
244 while (nameIter.hasNext()) {
245 buf.append(nameIter.next());
246 if (nameIter.hasNext()) {
247 buf.append(",");
248 }
249 }
250
251 if (section.getContainedCollectionNames() != null && section.getContainedCollectionNames().size() > 0) {
252 buf.append(",");
253
254 Iterator<String> collectionIter = section.getContainedCollectionNames().iterator();
255 while (collectionIter.hasNext()) {
256 buf.append(KNSConstants.MAINTENANCE_NEW_MAINTAINABLE + collectionIter.next());
257 if (collectionIter.hasNext()) {
258 buf.append(",");
259 }
260 }
261 }
262
263 return buf.toString();
264 }
265
266
267
268
269
270
271
272
273
274 protected static void addRowsToErrorKeySet(List<Row> listOfRows, Set<String> errorKeys) {
275 if (listOfRows == null) {
276 return;
277 }
278 for (Row row : listOfRows) {
279 List<Field> fields = row.getFields();
280 if (fields == null) {
281 continue;
282 }
283 for (Field field : fields) {
284 String fieldPropertyName = field.getPropertyName();
285 if (fieldPropertyName != null && fieldPropertyName.startsWith(KNSConstants.MAINTENANCE_NEW_MAINTAINABLE)) {
286 errorKeys.add(field.getPropertyName());
287 }
288 addRowsToErrorKeySet(field.getContainerRows(), errorKeys);
289 }
290 }
291 }
292
293 public static boolean isMaintenanceDocumentCreatingNewRecord(String maintenanceAction) {
294 if (KNSConstants.MAINTENANCE_EDIT_ACTION.equalsIgnoreCase(maintenanceAction)) {
295 return false;
296 }
297 else if (KNSConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equalsIgnoreCase(maintenanceAction)) {
298 return false;
299 }
300 else if (KNSConstants.MAINTENANCE_DELETE_ACTION.equalsIgnoreCase(maintenanceAction)) {
301 return false;
302 }
303
304 else if (KNSConstants.MAINTENANCE_NEW_ACTION.equalsIgnoreCase(maintenanceAction)) {
305 return true;
306 }
307 else if (KNSConstants.MAINTENANCE_COPY_ACTION.equalsIgnoreCase(maintenanceAction)) {
308 return true;
309 }
310 else {
311 return true;
312 }
313 }
314
315
316
317
318 public static void checkForLockingDocument(MaintenanceDocument document, boolean throwExceptionIfLocked) {
319 LOG.info("starting checkForLockingDocument (by MaintenanceDocument)");
320
321
322
323 String blockingDocId = document.getNewMaintainableObject().getLockingDocumentId();
324 checkDocumentBlockingDocumentId(blockingDocId, throwExceptionIfLocked);
325 }
326
327
328
329
330 public static void checkForLockingDocument(Maintainable maintainable, boolean throwExceptionIfLocked) {
331 LOG.info("starting checkForLockingDocument (by Maintainable)");
332
333
334
335 String blockingDocId = maintainable.getLockingDocumentId();
336 checkDocumentBlockingDocumentId(blockingDocId, throwExceptionIfLocked);
337 }
338
339 private static void checkDocumentBlockingDocumentId(String blockingDocId, boolean throwExceptionIfLocked) {
340
341 if (StringUtils.isBlank(blockingDocId)) {
342 return;
343 }
344
345 if ( LOG.isInfoEnabled() ) {
346 LOG.info("Locking document found: docId = " + blockingDocId + ".");
347 }
348
349
350 KualiWorkflowDocument lockedDocument = null;
351 try {
352
353
354
355 if ( getWorkflowDocumentService().workflowDocumentExists(blockingDocId) ) {
356 lockedDocument = getWorkflowDocumentService().createWorkflowDocument(Long.valueOf(blockingDocId), GlobalVariables.getUserSession().getPerson() );
357 }
358 } catch (Exception ex) {
359
360 LOG.error("Unable to retrieve locking document specified in the maintenance lock table: " + blockingDocId, ex);
361
362 cleanOrphanLocks(blockingDocId, ex);
363 return;
364 }
365 if ( lockedDocument == null ) {
366 LOG.warn( "Locking document header for " + blockingDocId + "came back null." );
367 cleanOrphanLocks(blockingDocId, null);
368 }
369
370
371 if (lockCanBeIgnored(lockedDocument)) {
372 return;
373 }
374
375
376 Properties parameters = new Properties();
377 parameters.put(KNSConstants.PARAMETER_DOC_ID, blockingDocId);
378 parameters.put(KNSConstants.PARAMETER_COMMAND, KNSConstants.METHOD_DISPLAY_DOC_SEARCH_VIEW);
379 String blockingUrl = UrlFactory.parameterizeUrl(getKualiConfigurationService().getPropertyString(KNSConstants.WORKFLOW_URL_KEY) + "/" + KNSConstants.DOC_HANDLER_ACTION, parameters);
380 if ( LOG.isDebugEnabled() ) {
381 LOG.debug("blockingUrl = '" + blockingUrl + "'");
382 LOG.debug("Maintenance record: " + lockedDocument.getAppDocId() + "is locked.");
383 }
384 String[] errorParameters = { blockingUrl, blockingDocId };
385
386
387 if (throwExceptionIfLocked) {
388
389 GlobalVariables.getMessageMap().putError(KNSConstants.GLOBAL_ERRORS, RiceKeyConstants.ERROR_MAINTENANCE_LOCKED, errorParameters);
390 throw new ValidationException("Maintenance Record is locked by another document.");
391 }
392 else {
393
394 GlobalVariables.getMessageMap().putWarning(KNSConstants.GLOBAL_MESSAGES, RiceKeyConstants.WARNING_MAINTENANCE_LOCKED, errorParameters);
395 }
396 }
397
398
399
400
401
402
403
404
405
406 private static boolean lockCanBeIgnored(KualiWorkflowDocument lockedDocument) {
407
408 if ( lockedDocument == null ) {
409 return true;
410 }
411
412
413 String userId = GlobalVariables.getUserSession().getPrincipalId().trim();
414 if (StringUtils.isBlank(userId)) {
415 return false;
416 }
417
418
419 if (!userId.equalsIgnoreCase(lockedDocument.getRouteHeader().getInitiatorPrincipalId().trim())) {
420 return false;
421 }
422
423
424 return lockedDocument.stateIsInitiated();
425 }
426
427 private static void cleanOrphanLocks( String lockingDocumentNumber, Exception workflowException ) {
428
429
430 try {
431
432 getMaintenanceDocumentService().deleteLocks(lockingDocumentNumber);
433
434 Map<String, String> parameters = new HashMap<String, String>(1);
435 parameters.put(KNSConstants.PARAMETER_DOC_ID, lockingDocumentNumber);
436 KualiExceptionIncident kei = getKualiExceptionIncidentService().getExceptionIncident(workflowException, parameters);
437 getKualiExceptionIncidentService().report(kei);
438 } catch ( Exception ex ) {
439 LOG.error("Unable to delete and notify upon locking document retrieval failure.", ex);
440 }
441 }
442
443 private static MaintenanceDocumentService getMaintenanceDocumentService() {
444 if ( maintenanceDocumentService == null ) {
445 maintenanceDocumentService = KNSServiceLocator.getMaintenanceDocumentService();
446 }
447 return maintenanceDocumentService;
448 }
449
450 private static WorkflowDocumentService getWorkflowDocumentService() {
451 if ( workflowDocumentService == null ) {
452 workflowDocumentService = KNSServiceLocator.getWorkflowDocumentService();
453 }
454 return workflowDocumentService;
455 }
456
457 private static KualiConfigurationService getKualiConfigurationService() {
458 if ( kualiConfigurationService == null ) {
459 kualiConfigurationService = KNSServiceLocator.getKualiConfigurationService();
460 }
461 return kualiConfigurationService;
462 }
463
464 private static KualiExceptionIncidentService getKualiExceptionIncidentService() {
465 if ( kualiExceptionIncidentService == null ) {
466 kualiExceptionIncidentService = KNSServiceLocator.getKualiExceptionIncidentService();
467 }
468 return kualiExceptionIncidentService;
469 }
470
471 private static MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
472 if ( maintenanceDocumentDictionaryService == null ) {
473 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
474 }
475 return maintenanceDocumentDictionaryService;
476 }
477
478 private static DataDictionaryService getDataDictionaryService() {
479 if ( dataDictionaryService == null ) {
480 dataDictionaryService = KNSServiceLocator.getDataDictionaryService();
481 }
482 return dataDictionaryService;
483 }
484 public static Map<String, AttributeSecurity> retrievePropertyPathToAttributeSecurityMappings(String docTypeName) {
485 Map<String, AttributeSecurity> results = new HashMap<String, AttributeSecurity>();
486 MaintenanceDocumentEntry entry = getMaintenanceDocumentDictionaryService().getMaintenanceDocumentEntry(docTypeName);
487 String className = entry.getBusinessObjectClass().getName();
488
489 for (MaintainableSectionDefinition section : entry.getMaintainableSections()) {
490 for (MaintainableItemDefinition item : section.getMaintainableItems()) {
491 if (item instanceof MaintainableFieldDefinition) {
492 MaintainableFieldDefinition field = (MaintainableFieldDefinition) item;
493 AttributeSecurity attributeSecurity = getDataDictionaryService().getAttributeSecurity(className, field.getName());
494 if (attributeSecurity != null) {
495 results.put(field.getName(), attributeSecurity);
496 }
497 }
498 else if (item instanceof MaintainableCollectionDefinition) {
499 addMaintenanceDocumentCollectionPathToSecurityMappings(results, "", (MaintainableCollectionDefinition) item);
500 }
501 }
502 }
503 return results;
504 }
505
506 private static void addMaintenanceDocumentCollectionPathToSecurityMappings(Map<String, AttributeSecurity> mappings, String propertyPathPrefix, MaintainableCollectionDefinition collectionDefinition) {
507 propertyPathPrefix = propertyPathPrefix + collectionDefinition.getName() + ".";
508 String boClassName = collectionDefinition.getBusinessObjectClass().getName();
509 for (MaintainableFieldDefinition field : collectionDefinition.getMaintainableFields()) {
510 AttributeSecurity attributeSecurity = getDataDictionaryService().getAttributeSecurity(boClassName, field.getName());
511 if (attributeSecurity != null) {
512 mappings.put(propertyPathPrefix + field.getName(), attributeSecurity);
513 }
514 }
515 for (MaintainableCollectionDefinition nestedCollection : collectionDefinition.getMaintainableCollections()) {
516 addMaintenanceDocumentCollectionPathToSecurityMappings(mappings, propertyPathPrefix, nestedCollection);
517 }
518 }
519 }