1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.util.RiceConstants;
20 import org.kuali.rice.kim.api.KimConstants.PermissionNames;
21 import org.kuali.rice.kim.api.identity.Person;
22 import org.kuali.rice.kim.api.identity.PersonService;
23 import org.kuali.rice.kim.api.permission.PermissionService;
24 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
25 import org.kuali.rice.kns.authorization.AuthorizationConstants;
26 import org.kuali.rice.krad.document.Document;
27 import org.kuali.rice.krad.document.authorization.PessimisticLock;
28 import org.kuali.rice.krad.exception.AuthorizationException;
29 import org.kuali.rice.krad.exception.PessimisticLockingException;
30 import org.kuali.rice.krad.service.BusinessObjectService;
31 import org.kuali.rice.krad.service.DataDictionaryService;
32 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33 import org.kuali.rice.krad.service.PessimisticLockService;
34 import org.kuali.rice.krad.util.GlobalVariables;
35 import org.kuali.rice.krad.util.KRADConstants;
36 import org.kuali.rice.krad.util.KRADPropertyConstants;
37 import org.kuali.rice.krad.util.ObjectUtils;
38 import org.springframework.transaction.annotation.Transactional;
39
40 import java.util.ArrayList;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48
49
50
51
52
53
54
55 @Transactional
56 public class PessimisticLockServiceImpl implements PessimisticLockService {
57 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PessimisticLockServiceImpl.class);
58
59 private PersonService personService;
60 private BusinessObjectService businessObjectService;
61 private DataDictionaryService dataDictionaryService;
62 private PermissionService permissionService;
63
64
65
66
67 public void delete(String id) {
68 if (StringUtils.isBlank(id)) {
69 throw new IllegalArgumentException("An invalid blank id was passed to delete a Pessimistic Lock.");
70 }
71 Map<String,Object> primaryKeys = new HashMap<String,Object>();
72 primaryKeys.put(KRADPropertyConstants.ID, Long.valueOf(id));
73 PessimisticLock lock = (PessimisticLock) getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys);
74 if (ObjectUtils.isNull(lock)) {
75 throw new IllegalArgumentException("Pessimistic Lock with id " + id + " cannot be found in the database.");
76 }
77 Person user = GlobalVariables.getUserSession().getPerson();
78 if ( (!lock.isOwnedByUser(user)) && (!isPessimisticLockAdminUser(user)) ) {
79 throw new AuthorizationException(user.getName(),"delete", "Pessimistick Lock (id " + id + ")");
80 }
81 delete(lock);
82 }
83
84 private void delete(PessimisticLock lock) {
85 if ( LOG.isDebugEnabled() ) {
86 LOG.debug("Deleting lock: " + lock);
87 }
88 getBusinessObjectService().delete(lock);
89 }
90
91
92
93
94 public PessimisticLock generateNewLock(String documentNumber) {
95 return generateNewLock(documentNumber, GlobalVariables.getUserSession().getPerson());
96 }
97
98
99
100
101 public PessimisticLock generateNewLock(String documentNumber, String lockDescriptor) {
102 return generateNewLock(documentNumber, lockDescriptor, GlobalVariables.getUserSession().getPerson());
103 }
104
105
106
107
108 public PessimisticLock generateNewLock(String documentNumber, Person user) {
109 return generateNewLock(documentNumber, PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, user);
110 }
111
112
113
114
115 public PessimisticLock generateNewLock(String documentNumber, String lockDescriptor, Person user) {
116 PessimisticLock lock = new PessimisticLock(documentNumber, lockDescriptor, user);
117 lock = save(lock);
118 if ( LOG.isDebugEnabled() ) {
119 LOG.debug("Generated new lock: " + lock);
120 }
121 return lock;
122 }
123
124
125
126
127 @SuppressWarnings("unchecked")
128 public List<PessimisticLock> getPessimisticLocksForDocument(String documentNumber) {
129 Map fieldValues = new HashMap();
130 fieldValues.put(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber);
131 return (List<PessimisticLock>) getBusinessObjectService().findMatching(PessimisticLock.class, fieldValues);
132 }
133
134
135
136
137 public boolean isPessimisticLockAdminUser(Person user) {
138 return getPermissionService().isAuthorized( user.getPrincipalId(), KRADConstants.KNS_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING,
139 Collections.<String, String>emptyMap() );
140 }
141
142
143
144
145 public void releaseAllLocksForUser(List<PessimisticLock> locks, Person user) {
146 for (Iterator<PessimisticLock> iterator = locks.iterator(); iterator.hasNext();) {
147 PessimisticLock lock = (PessimisticLock) iterator.next();
148 if (lock.isOwnedByUser(user)) {
149 delete(lock);
150 }
151 }
152 }
153
154
155
156
157 public void releaseAllLocksForUser(List<PessimisticLock> locks, Person user, String lockDescriptor) {
158 for (Iterator<PessimisticLock> iterator = locks.iterator(); iterator.hasNext();) {
159 PessimisticLock lock = (PessimisticLock) iterator.next();
160 if ( (lock.isOwnedByUser(user)) && (lockDescriptor.equals(lock.getLockDescriptor())) ) {
161 delete(lock);
162 }
163 }
164 }
165
166
167
168
169 public PessimisticLock save(PessimisticLock lock) {
170 if ( LOG.isDebugEnabled() ) {
171 LOG.debug("Saving lock: " + lock);
172 }
173 return (PessimisticLock)getBusinessObjectService().save(lock);
174 }
175
176 public BusinessObjectService getBusinessObjectService() {
177 return this.businessObjectService;
178 }
179
180 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
181 this.businessObjectService = businessObjectService;
182 }
183
184
185
186
187
188
189 public Set getDocumentActions(Document document, Person user, Set<String> documentActions){
190 if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL) && !hasPreRouteEditAuthorization(document, user) ){
191 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CANCEL);
192 }
193 if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE) && !hasPreRouteEditAuthorization(document, user)){
194 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SAVE);
195 }
196 if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE) && !hasPreRouteEditAuthorization(document, user)){
197 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ROUTE);
198 }
199 if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE) && !hasPreRouteEditAuthorization(document, user)){
200 documentActions.remove(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE);
201 }
202 return documentActions;
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216 protected boolean hasPreRouteEditAuthorization(Document document, Person user) {
217 if (document.getPessimisticLocks().isEmpty()) {
218 return true;
219 }
220 for (Iterator iterator = document.getPessimisticLocks().iterator(); iterator.hasNext();) {
221 PessimisticLock lock = (PessimisticLock) iterator.next();
222 if (lock.isOwnedByUser(user)) {
223 return true;
224 }
225 }
226 return false;
227 }
228
229
230 protected boolean usesPessimisticLocking(Document document) {
231 return getDataDictionaryService().getDataDictionary().getDocumentEntry(document.getClass().getName()).getUsePessimisticLocking();
232 }
233
234
235
236
237
238
239
240
241 public void establishWorkflowPessimisticLocking(Document document) {
242 PessimisticLock lock = createNewPessimisticLock(document, new HashMap(), getWorkflowPessimisticLockOwnerUser());
243 document.addPessimisticLock(lock);
244 }
245
246
247
248
249
250
251
252 public void releaseWorkflowPessimisticLocking(Document document) {
253 releaseAllLocksForUser(document.getPessimisticLocks(), getWorkflowPessimisticLockOwnerUser());
254 document.refreshPessimisticLocks();
255 }
256
257
258
259
260
261
262
263
264
265
266 protected Person getWorkflowPessimisticLockOwnerUser() {
267 String networkId = KRADConstants.SYSTEM_USER;
268 return getPersonService().getPersonByPrincipalName(networkId);
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 public Map establishLocks(Document document, Map editMode, Person user) {
285 Map editModeMap = new HashMap();
286
287 List<String> givenUserLockDescriptors = new ArrayList<String>();
288
289 Map<String,Set<Person>> lockDescriptorUsers = new HashMap<String,Set<Person>>();
290
291
292 for (PessimisticLock lock : document.getPessimisticLocks()) {
293 if (lock.isOwnedByUser(user)) {
294
295 givenUserLockDescriptors.add(lock.getLockDescriptor());
296 } else {
297
298 if (!lockDescriptorUsers.containsKey(lock.getLockDescriptor())) {
299 lockDescriptorUsers.put(lock.getLockDescriptor(), new HashSet<Person>());
300 }
301 ((Set<Person>) lockDescriptorUsers.get(lock.getLockDescriptor())).add(lock.getOwnedByUser());
302 }
303 }
304
305
306 for (String givenUserLockDescriptor : givenUserLockDescriptors) {
307 if ( (lockDescriptorUsers.containsKey(givenUserLockDescriptor)) && (lockDescriptorUsers.get(givenUserLockDescriptor).size() > 0) ) {
308 Set<Person> users = lockDescriptorUsers.get(givenUserLockDescriptor);
309 if ( (users.size() != 1) || (!getWorkflowPessimisticLockOwnerUser().getPrincipalId().equals(users.iterator().next().getPrincipalId())) ) {
310 String descriptorText = (document.useCustomLockDescriptors()) ? " using lock descriptor '" + givenUserLockDescriptor + "'" : "";
311 String errorMsg = "Found an invalid lock status on document number " + document.getDocumentNumber() + "with current user and other user both having locks" + descriptorText + " concurrently";
312 LOG.debug(errorMsg);
313 throw new PessimisticLockingException(errorMsg);
314 }
315 }
316 }
317
318
319 if (givenUserLockDescriptors.isEmpty()) {
320
321 if (lockDescriptorUsers.isEmpty()) {
322
323 if (isLockRequiredByUser(document, editMode, user)) {
324 document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
325 }
326 editModeMap.putAll(editMode);
327 } else {
328
329 if (document.useCustomLockDescriptors()) {
330
331 String customLockDescriptor = document.getCustomLockDescriptor(user);
332 if (lockDescriptorUsers.containsKey(customLockDescriptor)) {
333
334 editModeMap = getEditModeWithEditableModesRemoved(editMode);
335 } else {
336
337 if (isLockRequiredByUser(document, editMode, user)) {
338 document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
339 }
340 editModeMap.putAll(editMode);
341 }
342 } else {
343 editModeMap = getEditModeWithEditableModesRemoved(editMode);
344 }
345 }
346 } else {
347
348 if (document.useCustomLockDescriptors()) {
349
350 String customLockDescriptor = document.getCustomLockDescriptor(user);
351 if (givenUserLockDescriptors.contains(customLockDescriptor)) {
352
353 editModeMap.putAll(editMode);
354 } else {
355
356 if (lockDescriptorUsers.containsKey(customLockDescriptor)) {
357
358 editModeMap = getEditModeWithEditableModesRemoved(editMode);
359 } else {
360
361 if (isLockRequiredByUser(document, editMode, user)) {
362 document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
363 }
364 editModeMap.putAll(editMode);
365 }
366 }
367 } else {
368
369 editModeMap.putAll(editMode);
370 }
371 }
372
373 return editModeMap;
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388 protected boolean isLockRequiredByUser(Document document, Map editMode, Person user) {
389
390 for (Iterator iterator = editMode.entrySet().iterator(); iterator.hasNext();) {
391 Map.Entry entry = (Map.Entry) iterator.next();
392 if (isEntryEditMode(entry)) {
393 return true;
394 }
395 }
396 return false;
397 }
398
399
400
401
402
403
404
405
406
407
408
409
410 protected Map getEditModeWithEditableModesRemoved(Map currentEditMode) {
411 Map editModeMap = new HashMap();
412 for (Iterator iterator = currentEditMode.entrySet().iterator(); iterator.hasNext();) {
413 Map.Entry entry = (Map.Entry) iterator.next();
414 if (isEntryEditMode(entry)) {
415 editModeMap.putAll(getEntryEditModeReplacementMode(entry));
416 } else {
417 editModeMap.put(entry.getKey(), entry.getValue());
418 }
419 }
420 return editModeMap;
421 }
422
423
424
425
426
427
428
429
430
431
432
433 protected boolean isEntryEditMode(Map.Entry entry) {
434
435 if (AuthorizationConstants.EditMode.FULL_ENTRY.equals(entry.getKey())) {
436 String fullEntryEditModeValue = (String)entry.getValue();
437 return ( StringUtils.equalsIgnoreCase(KRADConstants.KUALI_DEFAULT_TRUE_VALUE, fullEntryEditModeValue) );
438 }
439 return false;
440 }
441
442
443
444
445
446
447
448 protected Map getEntryEditModeReplacementMode(Map.Entry entry) {
449 Map editMode = new HashMap();
450 editMode.put(AuthorizationConstants.EditMode.VIEW_ONLY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
451 return editMode;
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467 protected PessimisticLock createNewPessimisticLock(Document document, Map editMode, Person user) {
468 if (document.useCustomLockDescriptors()) {
469 return generateNewLock(document.getDocumentNumber(), document.getCustomLockDescriptor(user), user);
470 } else {
471 return generateNewLock(document.getDocumentNumber(), user);
472 }
473 }
474
475 public PersonService getPersonService() {
476 if ( personService == null ) {
477 personService = KimApiServiceLocator.getPersonService();
478 }
479 return personService;
480 }
481
482 public DataDictionaryService getDataDictionaryService() {
483 if ( dataDictionaryService == null ) {
484 dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
485 }
486 return dataDictionaryService;
487 }
488
489 public PermissionService getPermissionService() {
490 if ( permissionService == null ) {
491 permissionService = KimApiServiceLocator.getPermissionService();
492 }
493 return permissionService;
494 }
495
496
497
498 }
499