View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.rice.core.api.criteria.QueryByCriteria;
29  import org.kuali.rice.core.api.util.RiceConstants;
30  import org.kuali.rice.kim.api.KimConstants.PermissionNames;
31  import org.kuali.rice.kim.api.identity.Person;
32  import org.kuali.rice.kim.api.identity.PersonService;
33  import org.kuali.rice.kim.api.permission.PermissionService;
34  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
35  import org.kuali.rice.kns.authorization.AuthorizationConstants;
36  import org.kuali.rice.krad.data.DataObjectService;
37  import org.kuali.rice.krad.document.Document;
38  import org.kuali.rice.krad.document.authorization.PessimisticLock;
39  import org.kuali.rice.krad.exception.AuthorizationException;
40  import org.kuali.rice.krad.exception.PessimisticLockingException;
41  import org.kuali.rice.krad.service.DataDictionaryService;
42  import org.kuali.rice.krad.service.LegacyDataAdapter;
43  import org.kuali.rice.krad.service.PessimisticLockService;
44  import org.kuali.rice.krad.util.GlobalVariables;
45  import org.kuali.rice.krad.util.KRADConstants;
46  import org.kuali.rice.krad.util.KRADPropertyConstants;
47  import org.springframework.beans.factory.annotation.Required;
48  import org.springframework.transaction.annotation.Transactional;
49  
50  /**
51   * Service implementation for pessimistic locking
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
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      protected DataObjectService dataObjectService;
60      protected DataDictionaryService dataDictionaryService;
61      protected PermissionService permissionService;
62      protected PersonService personService;
63  
64  	/**
65       * @see org.kuali.rice.krad.service.PessimisticLockService#delete(java.lang.String)
66       */
67      @Override
68  	public void delete(String id) {
69          if (StringUtils.isBlank(id)) {
70              throw new IllegalArgumentException("An invalid blank id was passed to delete a Pessimistic Lock.");
71          }
72          PessimisticLock lock = dataObjectService.find(PessimisticLock.class, Long.valueOf(id));
73          if ( lock == null ) {
74              throw new IllegalArgumentException("Pessimistic Lock with id " + id + " cannot be found in the database.");
75          }
76          Person user = GlobalVariables.getUserSession().getPerson();
77          if ( (!lock.isOwnedByUser(user)) && (!isPessimisticLockAdminUser(user)) ) {
78              throw new AuthorizationException(user.getName(),"delete", "Pessimistick Lock (id " + id + ")");
79          }
80          delete(lock);
81      }
82  
83      private void delete(PessimisticLock lock) {
84      	if ( LOG.isDebugEnabled() ) {
85      		LOG.debug("Deleting lock: " + lock);
86      	}
87          dataObjectService.delete(lock);
88      }
89  
90      /**
91       * @see org.kuali.rice.krad.service.PessimisticLockService#generateNewLock(String)
92       */
93      @Override
94  	public PessimisticLock generateNewLock(String documentNumber) {
95          return generateNewLock(documentNumber, GlobalVariables.getUserSession().getPerson());
96      }
97  
98      /**
99       * @see org.kuali.rice.krad.service.PessimisticLockService#generateNewLock(java.lang.String)
100      */
101     @Override
102 	public PessimisticLock generateNewLock(String documentNumber, String lockDescriptor) {
103         return generateNewLock(documentNumber, lockDescriptor, GlobalVariables.getUserSession().getPerson());
104     }
105 
106     /**
107      * @see org.kuali.rice.krad.service.PessimisticLockService#generateNewLock(java.lang.String, org.kuali.rice.kim.api.identity.Person)
108      */
109     @Override
110 	public PessimisticLock generateNewLock(String documentNumber, Person user) {
111         return generateNewLock(documentNumber, PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, user);
112     }
113 
114     /**
115      * @see org.kuali.rice.krad.service.PessimisticLockService#generateNewLock(java.lang.String, java.lang.String, org.kuali.rice.kim.api.identity.Person)
116      */
117     @Override
118 	public PessimisticLock generateNewLock(String documentNumber, String lockDescriptor, Person user) {
119         PessimisticLock lock = new PessimisticLock(documentNumber, lockDescriptor, user, GlobalVariables.getUserSession());
120         lock = save(lock);
121         if ( LOG.isDebugEnabled() ) {
122         	LOG.debug("Generated new lock: " + lock);
123         }
124         return lock;
125     }
126 
127     /**
128      * @see org.kuali.rice.krad.service.PessimisticLockService#getPessimisticLocksForDocument(java.lang.String)
129      */
130     @Override
131 	public List<PessimisticLock> getPessimisticLocksForDocument(String documentNumber) {
132         return new ArrayList<PessimisticLock>( dataObjectService.findMatching(PessimisticLock.class,
133         		QueryByCriteria.Builder.forAttribute(KRADPropertyConstants.DOCUMENT_NUMBER, documentNumber)
134         		.build()).getResults() );
135     }
136 
137     /**
138      * @see org.kuali.rice.krad.service.PessimisticLockService#getPessimisticLocksForSession(java.lang.String)
139      */
140     @Override
141 	public List<PessimisticLock> getPessimisticLocksForSession(String sessionId) {
142         return new ArrayList<PessimisticLock>( dataObjectService.findMatching(PessimisticLock.class,
143         		QueryByCriteria.Builder.forAttribute(KRADPropertyConstants.SESSION_ID, sessionId)
144         		.build()).getResults() );
145     }
146 
147     /**
148      * @see org.kuali.rice.krad.service.PessimisticLockService#isPessimisticLockAdminUser(org.kuali.rice.kim.api.identity.Person)
149      */
150     @Override
151 	public boolean isPessimisticLockAdminUser(Person user) {
152     	return getPermissionService().isAuthorized( user.getPrincipalId(), KRADConstants.KNS_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING,
153                 Collections.<String, String>emptyMap() );
154     }
155 
156     /**
157      * @see org.kuali.rice.krad.service.PessimisticLockService#releaseAllLocksForUser(java.util.List, org.kuali.rice.kim.api.identity.Person)
158      */
159     @Override
160 	public void releaseAllLocksForUser(List<PessimisticLock> locks, Person user) {
161         for (Iterator<PessimisticLock> iterator = locks.iterator(); iterator.hasNext();) {
162             PessimisticLock lock = iterator.next();
163             if (lock.isOwnedByUser(user)) {
164                 try {
165                     delete(lock);
166                 } catch ( RuntimeException ex ) {
167                 	if ( ex.getCause() != null && ex.getCause().getClass().equals( LegacyDataAdapter.OPTIMISTIC_LOCK_OJB_EXCEPTION_CLASS ) ) {
168                         LOG.warn( "Suppressing Optimistic Lock Exception. Document Num: " +  lock.getDocumentNumber());
169                     } else {
170                         throw ex;
171                     }
172                 }
173             }
174         }
175     }
176 
177     /**
178      * @see org.kuali.rice.krad.service.PessimisticLockService#releaseAllLocksForUser(java.util.List, org.kuali.rice.kim.api.identity.Person, java.lang.String)
179      */
180     @Override
181 	public void releaseAllLocksForUser(List<PessimisticLock> locks, Person user, String lockDescriptor) {
182         for (Iterator<PessimisticLock> iterator = locks.iterator(); iterator.hasNext();) {
183             PessimisticLock lock = iterator.next();
184             if ( (lock.isOwnedByUser(user)) && (lockDescriptor.equals(lock.getLockDescriptor())) ) {
185                 try {
186                     delete(lock);
187                 } catch ( RuntimeException ex ) {
188                 	if ( ex.getCause() != null && ex.getCause().getClass().equals( LegacyDataAdapter.OPTIMISTIC_LOCK_OJB_EXCEPTION_CLASS ) ) {
189                         LOG.warn( "Suppressing Optimistic Lock Exception. Document Num: " +  lock.getDocumentNumber());
190                     } else {
191                         throw ex;
192                     }
193                 }
194             }
195         }
196     }
197 
198     /**
199      * @see org.kuali.rice.krad.service.PessimisticLockService#save(org.kuali.rice.krad.document.authorization.PessimisticLock)
200      */
201     @Override
202 	public PessimisticLock save(PessimisticLock lock) {
203     	if ( LOG.isDebugEnabled() ) {
204     		LOG.debug("Saving lock: " + lock);
205     	}
206         return dataObjectService.save(lock);
207     }
208 
209     /**
210      * {@inheritDoc}
211      */
212     @Override
213     public boolean establishPessimisticLocks(Document document, Person user, boolean canEdit) {
214         // establish pessimistic locks if needed
215         if (isPessimisticLockNeeded(document, user, canEdit)) {
216             PessimisticLock pessimisticLock = createNewPessimisticLock(document, user);
217             document.addPessimisticLock(pessimisticLock);
218         }
219 
220         // find if any pessimistic locks are owned by the given user
221         for (PessimisticLock pessimisticLock : document.getPessimisticLocks()) {
222             if (pessimisticLock.isOwnedByUser(user)) {
223                 return true;
224             }
225         }
226 
227         return false;
228     }
229 
230     /**
231      * Determines whether to add a pessimistic lock on the {@code document} for {@code user} based on the current
232      * pessimistic locks and edit modes.
233      *
234      * @param document the document on which the locks will be established
235      * @param user the user for which the locks are being established
236      * @param canEdit whether the user currently can edit the document
237      *
238      * @return true if a pessimistic lock should be added, false otherwise
239      */
240     protected boolean isPessimisticLockNeeded(Document document, Person user, boolean canEdit) {
241         List<String> userOwnedLockDescriptors = new ArrayList<String>();
242         Map<String, Set<String>> otherOwnedLockDescriptors = new HashMap<String,Set<String>>();
243 
244         // create the two lock containers that help determine whether to add a pessimistic lock
245         for (PessimisticLock pessimisticLock : document.getPessimisticLocks()) {
246             if (pessimisticLock.isOwnedByUser(user)) {
247                 userOwnedLockDescriptors.add(pessimisticLock.getLockDescriptor());
248             } else {
249                 if (!otherOwnedLockDescriptors.containsKey(pessimisticLock.getLockDescriptor())) {
250                     otherOwnedLockDescriptors.put(pessimisticLock.getLockDescriptor(), new HashSet<String>());
251                 }
252 
253                 String otherOwnerPrincipalId = pessimisticLock.getOwnedByUser().getPrincipalId();
254                 otherOwnedLockDescriptors.get(pessimisticLock.getLockDescriptor()).add(otherOwnerPrincipalId);
255             }
256         }
257 
258         // double check whether the existing pessimistic locks are sane
259         checkExistingPessimisticLocks(document, userOwnedLockDescriptors, otherOwnedLockDescriptors);
260 
261         // if no one has a lock on this document, then the document can be locked if the user can edit it
262         if (userOwnedLockDescriptors.isEmpty() && otherOwnedLockDescriptors.isEmpty()) {
263             return canEdit;
264         }
265 
266         // if custom locking is turned on, then if the current user doesn't have a custom lock on this document and no
267         // one else has a custom lock on this document, then the document can be locked if the user can edit it
268         if (document.useCustomLockDescriptors()) {
269             String customLockDescriptor = document.getCustomLockDescriptor(user);
270             boolean userOwnsCustomLockDescriptor = userOwnedLockDescriptors.contains(customLockDescriptor);
271             boolean otherOwnsCustomLockDescriptor = otherOwnedLockDescriptors.containsKey(customLockDescriptor);
272 
273             if (!userOwnsCustomLockDescriptor && !otherOwnsCustomLockDescriptor) {
274                 return canEdit;
275             }
276         }
277 
278         return false;
279     }
280 
281     /**
282      * Check to make sure that the current user doesn't erroneously share the same lock with another user.
283      *
284      * @param document the document to check for erroneous locks
285      * @param userOwnedLockDescriptors the list of lock descriptors for the current user
286      * @param otherOwnedLockDescriptors the map of other lock descriptors to all of the other users that own them
287      */
288     protected void checkExistingPessimisticLocks(Document document, List<String> userOwnedLockDescriptors, Map<String, Set<String>> otherOwnedLockDescriptors) {
289         for (String userOwnedLockDescriptor : userOwnedLockDescriptors) {
290             if (otherOwnedLockDescriptors.containsKey(userOwnedLockDescriptor)) {
291                 Set<String> otherOwnerPrincipalIds = otherOwnedLockDescriptors.get(userOwnedLockDescriptor);
292                 String workflowOwnerPrincipalId = getWorkflowPessimisticLockOwnerUser().getPrincipalId();
293                 boolean hasOtherOwners = !otherOwnerPrincipalIds.isEmpty();
294                 boolean hasMoreThanOneOtherOwner = otherOwnerPrincipalIds.size() > 1;
295                 boolean hasWorkflowOwner = otherOwnerPrincipalIds.contains(workflowOwnerPrincipalId);
296 
297                 // if the lock has other owners, then if there is more than one other owner or if the single other owner
298                 // is not the workflow user, then throw an error
299                 if (hasOtherOwners && (hasMoreThanOneOtherOwner || !hasWorkflowOwner)) {
300                     StringBuilder builder = new StringBuilder("Found an invalid lock status on document number ");
301                     builder.append(document.getDocumentNumber());
302                     builder.append(" with current user and other user both having locks concurrently");
303 
304                     if (document.useCustomLockDescriptors()) {
305                         builder.append(" for custom lock descriptor '");
306                         builder.append(userOwnedLockDescriptor);
307                         builder.append("'");
308                     }
309 
310                     builder.append(".");
311 
312                     LOG.debug(builder.toString());
313 
314                     throw new PessimisticLockingException(builder.toString());
315                 }
316             }
317         }
318     }
319 
320     /**
321      * Creates a new {@link PessimisticLock} on a {@code document} for a {@code user}.
322      *
323      * <p>
324      * If the {@code document} uses custom lock descriptors, then the new lock is generated with a custom lock
325      * descriptor for a portion of the document.  Otherwise, it will create a lock over the entire document.
326      * </p>
327      *
328      * @param document the document on which the locks will be established
329      * @param user the user for which the locks are being established
330      *
331      * @return the newly created lock object
332      */
333     protected PessimisticLock createNewPessimisticLock(Document document, Person user) {
334         if (document.useCustomLockDescriptors()) {
335             return generateNewLock(document.getDocumentNumber(), document.getCustomLockDescriptor(user), user);
336         } else {
337             return generateNewLock(document.getDocumentNumber(), user);
338         }
339     }
340 
341     /**
342      * {@inheritDoc}
343      */
344     @Override
345     @Deprecated
346 	public Set getDocumentActions(Document document, Person user, Set<String> documentActions){
347     	if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL) && !hasPreRouteEditAuthorization(document, user) ){
348     		documentActions.remove(KRADConstants.KUALI_ACTION_CAN_CANCEL);
349     	}
350     	if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE)  && !hasPreRouteEditAuthorization(document, user)){
351     		documentActions.remove(KRADConstants.KUALI_ACTION_CAN_SAVE);
352     	}
353         if(documentActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE) && !hasPreRouteEditAuthorization(document, user)){
354         	documentActions.remove(KRADConstants.KUALI_ACTION_CAN_ROUTE);
355         }
356         if (documentActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE) && !hasPreRouteEditAuthorization(document, user)){
357         	documentActions.remove(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE);
358         }
359     	return documentActions;
360     }
361 
362 
363     /**
364      * This method checks to see that the given user has a lock on the document and return true if one is found.
365      *
366      * @param document - document to check
367      * @param user - current user
368      * @return true if the document is using Pessimistic Locking, the user has initiate authorization (see
369      *         {@link #hasInitiateAuthorization(Document, Person)}), and the document has a lock owned by the given
370      *         user. If the document is not using Pessimistic Locking the value returned will be that returned by
371      *         {@link #hasInitiateAuthorization(Document, Person)}.
372      *
373      * @deprecated Different mechanism of obtaining authorization in KRAD
374      */
375     @Deprecated
376     protected boolean hasPreRouteEditAuthorization(Document document, Person user) {
377     	if (document.getPessimisticLocks().isEmpty()) {
378     		return true;
379     	}
380     	for (Iterator<PessimisticLock> iterator = document.getPessimisticLocks().iterator(); iterator.hasNext();) {
381     		PessimisticLock lock = iterator.next();
382     		if (lock.isOwnedByUser(user)) {
383     			return true;
384             }
385         }
386         return false;
387     }
388 
389     @Deprecated
390     protected boolean usesPessimisticLocking(Document document) {
391         return getDataDictionaryService().getDataDictionary().getDocumentEntry(document.getClass().getName()).getUsePessimisticLocking();
392     }
393 
394 
395     /**
396      * This method creates a new {@link PessimisticLock} when Workflow processing requires one
397      *
398      * @param document - the document to create the lock against and add the lock to
399      * @see org.kuali.rice.kns.document.authorization.DocumentAuthorizer#establishWorkflowPessimisticLocking(org.kuali.rice.krad.document.Document)
400      */
401     @Override
402 	public void establishWorkflowPessimisticLocking(Document document) {
403         PessimisticLock lock = createNewPessimisticLock(document, getWorkflowPessimisticLockOwnerUser());
404         document.addPessimisticLock(lock);
405     }
406 
407     /**
408      * This method releases locks created via the {@link #establishWorkflowPessimisticLocking(Document)} method for the given document
409      *
410      * @param document - document to release locks from
411      * @see org.kuali.rice.kns.document.authorization.DocumentAuthorizer#releaseWorkflowPessimisticLocking(org.kuali.rice.krad.document.Document)
412      */
413     @Override
414 	public void releaseWorkflowPessimisticLocking(Document document) {
415         releaseAllLocksForUser(document.getPessimisticLocks(), getWorkflowPessimisticLockOwnerUser());
416         document.refreshPessimisticLocks();
417     }
418 
419     /**
420      * This method identifies the user that should be used to create and clear {@link PessimisticLock} objects required by
421      * Workflow.<br>
422      * <br>
423      * The default is the Kuali system user defined by {@link RiceConstants#SYSTEM_USER}. This method can be overriden by
424      * implementing documents if another user is needed.
425      *
426      * @return a valid {@link Person} object
427      */
428     protected Person getWorkflowPessimisticLockOwnerUser() {
429         String networkId = KRADConstants.SYSTEM_USER;
430         return getPersonService().getPersonByPrincipalName(networkId);
431     }
432 
433     /**
434      * {@inheritDoc}
435      *
436      * This implementation will check the given document, editMode map, and user object to verify Pessimistic Locking. If the
437      * given edit mode map contains an 'entry type' edit mode then the system will check the locks already in existence on
438      * the document. If a valid lock for the given user is found the system will return the given edit mode map. If a valid
439      * lock is found but is owned by another user the edit mode map returned will have any 'entry type' edit modes removed. If the
440      * given document has no locks and the edit mode map passed in has at least one 'entry type' mode then a new
441      * {@link PessimisticLock} object will be created and set on the document for the given user.<br>
442      * <br>
443      * NOTE: This method is only called if the document uses pessimistic locking as described in the data dictionary file.
444      *
445      * @see org.kuali.rice.kns.document.authorization.DocumentAuthorizer#establishLocks(org.kuali.rice.krad.document.Document,
446      *      java.util.Map, org.kuali.rice.kim.api.identity.Person)
447      */
448     @Override
449     @Deprecated
450 	public Map establishLocks(Document document, Map editMode, Person user) {
451         Map editModeMap = new HashMap();
452         // givenUserLockDescriptors is a list of lock descriptors currently held on the document by the given user
453         List<String> givenUserLockDescriptors = new ArrayList<String>();
454         // lockDescriptorUsers is a map with lock descriptors as keys and users other than the given user who hold a lock of each descriptor
455         Map<String,Set<Person>> lockDescriptorUsers = new HashMap<String,Set<Person>>();
456 
457         // build the givenUserLockDescriptors set and the lockDescriptorUsers map
458         for (PessimisticLock lock : document.getPessimisticLocks()) {
459             if (lock.isOwnedByUser(user)) {
460                 // lock is owned by given user
461                 givenUserLockDescriptors.add(lock.getLockDescriptor());
462             } else {
463                 // lock is not owned by the given user
464                 if (!lockDescriptorUsers.containsKey(lock.getLockDescriptor())) {
465                     lockDescriptorUsers.put(lock.getLockDescriptor(), new HashSet<Person>());
466                 }
467                 lockDescriptorUsers.get(lock.getLockDescriptor()).add(lock.getOwnedByUser());
468             }
469         }
470 
471         // verify that no locks held by current user exist for any other user
472         for (String givenUserLockDescriptor : givenUserLockDescriptors) {
473             if ( (lockDescriptorUsers.containsKey(givenUserLockDescriptor)) && (lockDescriptorUsers.get(givenUserLockDescriptor).size() > 0) ) {
474                 Set<Person> users = lockDescriptorUsers.get(givenUserLockDescriptor);
475                 if ( (users.size() != 1) || (!getWorkflowPessimisticLockOwnerUser().getPrincipalId().equals(users.iterator().next().getPrincipalId())) ) {
476                     String descriptorText = (document.useCustomLockDescriptors()) ? " using lock descriptor '" + givenUserLockDescriptor + "'" : "";
477                     String errorMsg = "Found an invalid lock status on document number " + document.getDocumentNumber() + "with current user and other user both having locks" + descriptorText + " concurrently";
478                     LOG.debug(errorMsg);
479                     throw new PessimisticLockingException(errorMsg);
480                 }
481             }
482         }
483 
484         // check to see if the given user has any locks in the system at all
485         if (givenUserLockDescriptors.isEmpty()) {
486             // given user has no locks... check for other user locks
487             if (lockDescriptorUsers.isEmpty()) {
488                 // no other user has any locks... set up locks for given user if user has edit privileges
489                 if (isLockRequiredByUser(document, editMode, user)) {
490                     document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
491                 }
492                 editModeMap.putAll(editMode);
493             } else {
494                 // at least one other user has at least one other lock... adjust edit mode for read only
495                 if (document.useCustomLockDescriptors()) {
496                     // check to see if the custom lock descriptor is already in use
497                     String customLockDescriptor = document.getCustomLockDescriptor(user);
498                     if (lockDescriptorUsers.containsKey(customLockDescriptor)) {
499                         // at least one other user has this descriptor locked... remove editable edit modes
500                         editModeMap = getEditModeWithEditableModesRemoved(editMode);
501                     } else {
502                         // no other user has a lock with this descriptor
503                         if (isLockRequiredByUser(document, editMode, user)) {
504                             document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
505                         }
506                         editModeMap.putAll(editMode);
507                     }
508                 } else {
509                     editModeMap = getEditModeWithEditableModesRemoved(editMode);
510                 }
511             }
512         } else {
513             // given user already has at least one lock descriptor
514             if (document.useCustomLockDescriptors()) {
515                 // get the custom lock descriptor and check to see if if the given user has a lock with that descriptor
516                 String customLockDescriptor = document.getCustomLockDescriptor(user);
517                 if (givenUserLockDescriptors.contains(customLockDescriptor)) {
518                     // user already has lock that is required
519                     editModeMap.putAll(editMode);
520                 } else {
521                     // user does not have lock for descriptor required
522                     if (lockDescriptorUsers.containsKey(customLockDescriptor)) {
523                         // another user has the lock descriptor that the given user requires... disallow lock and alter edit modes to have read only
524                         editModeMap = getEditModeWithEditableModesRemoved(editMode);
525                     } else {
526                         // no other user has a lock with this descriptor... check if this user needs a lock
527                         if (isLockRequiredByUser(document, editMode, user)) {
528                             document.addPessimisticLock(createNewPessimisticLock(document, editMode, user));
529                         }
530                         editModeMap.putAll(editMode);
531                     }
532                 }
533             } else {
534                 // user already has lock and no descriptors are being used... use the existing edit modes
535                 editModeMap.putAll(editMode);
536             }
537         }
538 
539         return editModeMap;
540     }
541 
542     /**
543      * This method is used to check if the given parameters warrant a new lock to be created for the given user. This method
544      * utilizes the {@link #isEntryEditMode(java.util.Map.Entry)} method.
545      *
546      * @param document -
547      *            document to verify lock creation against
548      * @param editMode -
549      *            edit modes list to check for 'entry type' edit modes
550      * @param user -
551      *            user the lock will be 'owned' by
552      * @return true if the given edit mode map has at least one 'entry type' edit mode... false otherwise
553      */
554     @Deprecated
555     protected boolean isLockRequiredByUser(Document document, Map editMode, Person user) {
556         // check for entry edit mode
557         for (Iterator iterator = editMode.entrySet().iterator(); iterator.hasNext();) {
558             Map.Entry entry = (Map.Entry) iterator.next();
559             if (isEntryEditMode(entry)) {
560                 return true;
561             }
562         }
563         return false;
564     }
565 
566    /**
567      * This method is used to remove edit modes from the given map that allow the user to edit data on the document. This
568      * method utilizes the {@link #isEntryEditMode(java.util.Map.Entry)} method to identify if an edit mode is defined as an
569      * 'entry type' edit mode. It also uses the {@link #getEntryEditModeReplacementMode(java.util.Map.Entry)} method to replace
570      * any 'entry type' edit modes it finds.
571      *
572      * @param currentEditMode -
573      *            current set of edit modes the user has assigned to them
574      * @return an adjusted edit mode map where 'entry type' edit modes have been removed or replaced using the
575      *         {@link #getEntryEditModeReplacementMode} method
576      */
577     @Deprecated
578     protected Map getEditModeWithEditableModesRemoved(Map currentEditMode) {
579         Map editModeMap = new HashMap();
580         for (Iterator iterator = currentEditMode.entrySet().iterator(); iterator.hasNext();) {
581             Map.Entry entry = (Map.Entry) iterator.next();
582             if (isEntryEditMode(entry)) {
583                 editModeMap.putAll(getEntryEditModeReplacementMode(entry));
584             } else {
585                 editModeMap.put(entry.getKey(), entry.getValue());
586             }
587         }
588         return editModeMap;
589     }
590 
591     /**
592      * This method is used to check if the given {@link Map.Entry} is an 'entry type' edit mode and that the value is set to
593      * signify that this user has that edit mode available to them
594      *
595      * @param entry -
596      *            the {@link Map.Entry} object that contains an edit mode such as the ones returned but
597      *            {@link #getEditMode(Document, Person)}
598      * @return true if the given entry has a key signifying an 'entry type' edit mode and the value is equal to
599      *         {@link #EDIT_MODE_DEFAULT_TRUE_VALUE}... false if not
600      */
601     @Deprecated
602     protected boolean isEntryEditMode(Map.Entry entry) {
603     	// check for FULL_ENTRY edit mode set to default true value
604     	if (AuthorizationConstants.EditMode.FULL_ENTRY.equals(entry.getKey())) {
605     		String fullEntryEditModeValue = (String)entry.getValue();
606     		return ( StringUtils.equalsIgnoreCase(KRADConstants.KUALI_DEFAULT_TRUE_VALUE, fullEntryEditModeValue) );
607     	}
608     	return false;
609     }
610 
611     /**
612      * This method is used to return values needed to replace the given 'entry type' edit mode {@link Map.Entry} with one that will not allow the user to enter data on the document
613      *
614      * @param entry - the current 'entry type' edit mode to replace
615      * @return a Map of edit modes that will be used to replace this edit mode (represented by the given entry parameter)
616      */
617     protected Map getEntryEditModeReplacementMode(Map.Entry entry) {
618         Map editMode = new HashMap();
619         editMode.put(AuthorizationConstants.EditMode.VIEW_ONLY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
620         return editMode;
621     }
622 
623     /**
624      * This method creates a new {@link PessimisticLock} object using the given document and user. If the document's
625      * useCustomLockDescriptors() method returns true then the new lock will also have a custom lock descriptor
626      * value set to the return value of the document's getCustomLockDescriptor(Person) method.
627      *
628      * @param document -
629      *            document to place the lock on
630      * @param editMode -
631      *            current edit modes for given user
632      * @param user -
633      *            user who will 'own' the new lock object
634      * @return the newly created lock object
635      */
636     @Deprecated
637     protected PessimisticLock createNewPessimisticLock(Document document, Map editMode, Person user) {
638         if (document.useCustomLockDescriptors()) {
639             return generateNewLock(document.getDocumentNumber(), document.getCustomLockDescriptor(user), user);
640         } else {
641             return generateNewLock(document.getDocumentNumber(), user);
642         }
643     }
644 
645     public PersonService getPersonService() {
646         if ( personService == null ) {
647             personService = KimApiServiceLocator.getPersonService();
648         }
649         return personService;
650     }
651 
652 	public DataDictionaryService getDataDictionaryService() {
653 		return dataDictionaryService;
654 	}
655 
656 	@Required
657 	public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
658 		this.dataDictionaryService = dataDictionaryService;
659 	}
660 
661 	public PermissionService getPermissionService() {
662         if ( permissionService == null ) {
663         	permissionService = KimApiServiceLocator.getPermissionService();
664         }
665 		return permissionService;
666 	}
667 
668 
669 	@Required
670     public void setDataObjectService(DataObjectService dataObjectService) {
671 		this.dataObjectService = dataObjectService;
672 	}
673 }
674