View Javadoc

1   /*
2    * Copyright 2006-2011 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;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.junit.Test;
20  import org.kuali.rice.kew.exception.WorkflowException;
21  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
22  import org.kuali.rice.kim.bo.Person;
23  import org.kuali.rice.kim.util.KimConstants.PermissionNames;
24  import org.kuali.rice.krad.UserSession;
25  import org.kuali.rice.krad.authorization.AuthorizationConstants;
26  import org.kuali.rice.krad.document.Document;
27  import org.kuali.rice.krad.document.MaintenanceDocument;
28  import org.kuali.rice.krad.document.authorization.PessimisticLock;
29  import org.kuali.rice.krad.exception.AuthorizationException;
30  import org.kuali.rice.krad.service.impl.PessimisticLockServiceImpl;
31  import org.kuali.rice.krad.test.document.AccountRequestDocument;
32  import org.kuali.rice.krad.test.document.AccountRequestDocument2;
33  import org.kuali.rice.krad.util.GlobalVariables;
34  import org.kuali.rice.krad.util.KRADConstants;
35  import org.kuali.rice.krad.util.KRADPropertyConstants;
36  import org.kuali.rice.maintainable.AccountType2MaintainableImpl;
37  import org.kuali.rice.test.BaselineTestCase;
38  import org.kuali.rice.test.data.UnitTestData;
39  import org.kuali.rice.test.data.UnitTestSql;
40  import org.kuali.test.KRADTestCase;
41  
42  import java.io.Serializable;
43  import java.util.Arrays;
44  import java.util.HashMap;
45  import java.util.HashSet;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Set;
49  
50  import static org.junit.Assert.*;
51  
52  
53  /**
54   * This class is used to test the {@link PessimisticLockServiceImpl} class
55   *
56   * @author Kuali Rice Team (rice.collab@kuali.org)
57   */
58  @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
59  public class PessimisticLockServiceTest extends KRADTestCase {
60  
61      @Override
62      public void setUp() throws Exception {
63          super.setUp();
64          GlobalVariables.setUserSession(new UserSession("quickstart"));
65      }
66  
67      /**
68       * This method tests deleting {@link PessimisticLock} objects. Tests that invalid deletes throw exceptions and valid
69       * deletes by owner users as well as lock admin users do work as expected
70       *
71       * @throws Exception
72       */
73      @UnitTestData(
74              sqlStatements = {
75                      @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"),
76                      @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1111, '4f6bc9e2-7df8-102c-97b6-ed716fdaf540', 0, NULL, '1234', {d '2007-07-01'}, 'employee')"),
77                      @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1112, '5add9cba-7df8-102c-97b6-ed716fdaf540', 0, NULL, '1235', {d '2007-10-01'}, 'frank')"),
78                      @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1113, '69e42b8e-7df8-102c-97b6-ed716fdaf540', 0, NULL, '1236', {d '2007-08-01'}, 'fred')"),
79                      @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1114, '76504650-7df8-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fred')")
80                      }
81              )
82      @Test
83      public void testDeleteLocks() throws Exception {
84      	
85          List<PessimisticLock> locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
86          assertEquals("Should be 4 locks in DB", 4, locks.size());
87  
88          String userId = "employee";
89          String[] lockIdsToVerify = new String[]{"1112", "1113"};
90          assertFalse("User " + userId + " should not be member of pessimistic lock admin permission", KimApiServiceLocator.getPermissionService().isAuthorized(new UserSession(userId).getPerson().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING, null, null ) );
91          verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true);
92          userId = "frank";
93          lockIdsToVerify = new String[]{"1111", "1113"};
94          assertFalse("User " + userId + " should not be member of pessimistic lock admin permission", KimApiServiceLocator.getPermissionService().isAuthorized(new UserSession(userId).getPerson().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING, null, null ) );
95          verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true);
96          userId = "fred";
97          lockIdsToVerify = new String[]{"1111", "1112"};
98          assertFalse("User " + userId + " should not be member of pessimistic lock admin permission", KimApiServiceLocator.getPermissionService().isAuthorized(new UserSession(userId).getPerson().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING, null, null ) );
99          verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true);
100 
101         verifyDelete("employee", Arrays.asList(new String[]{"1111"}), null, false);
102         verifyDelete("frank", Arrays.asList(new String[]{"1112"}), null, false);
103         verifyDelete("fred", Arrays.asList(new String[]{"1113"}), null, false);
104         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
105         assertEquals("Should be 1 lock left in DB", 1, locks.size());
106 
107         // test admin user can delete any lock
108         userId = "fran";
109         assertTrue("User " + userId + " should be member of pessimistic lock admin permission", KimApiServiceLocator.getPermissionService().isAuthorized(new UserSession(userId).getPerson().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING, null, null ) );
110         userId = "admin";
111         assertTrue("User " + userId + " should be member of pessimistic lock admin permission", KimApiServiceLocator.getPermissionService().isAuthorized(new UserSession(userId).getPerson().getPrincipalId(), KRADConstants.KRAD_NAMESPACE, PermissionNames.ADMIN_PESSIMISTIC_LOCKING, null, null ) );
112         verifyDelete(userId, Arrays.asList(new String[]{"1114"}), null, false);
113         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
114         assertEquals("Should be 0 locks left in DB", 0, locks.size());
115     }
116 
117     private void verifyDelete(String userId, List<String> lockIds, Class expectedException, boolean expectException) throws WorkflowException {
118         GlobalVariables.setUserSession(new UserSession(userId));
119         for (String lockId : lockIds) {
120             try {
121                 KRADServiceLocatorWeb.getPessimisticLockService().delete(lockId);
122                 if (expectException) {
123                     fail("Expected exception when deleting lock with id '" + lockId + "' for user '" + userId + "'");
124                 }
125             } catch (Exception e) {
126                 if (!expectException) {
127                     fail("Did not expect exception when deleting lock with id '" + lockId + "' for user '" + userId + "' but got exception of type '" + e.getClass().getName() + "'");
128                 }
129                 if (expectedException != null) {
130                     // if we have an expected exception
131                     if (!expectedException.isAssignableFrom(e.getClass())) {
132                         fail("Expected exception of type '" + expectedException.getName() + "' when deleting lock with id '" + lockId + "' for user '" + userId + "' but got exception of type '" + e.getClass().getName() + "'");
133                     }
134                 }
135             }
136         }
137     }
138 
139     /**
140      * This method tests the generation of new {@link PessimisticLock} objects
141      *
142      * @throws Exception
143      */
144     @Test
145     public void testGenerateNewLocks() throws Exception {
146         PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService();
147 
148         // test generating lock with no given lock descriptor
149         String documentNumber = "1243";
150         PessimisticLock lock = lockService.generateNewLock(documentNumber);
151         assertNotNull("Generated lock should have id", lock.getId());
152         assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber());
153         assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp());
154         assertEquals("Generated lock should have default lock descriptor", PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, lock.getLockDescriptor());
155         assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName());
156         Map primaryKeys = new HashMap();
157         primaryKeys.put(KRADPropertyConstants.ID, lock.getId());
158         lock = null;
159         lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys);
160         assertNotNull("Generated lock should be available from BO Service", lock);
161         assertNotNull("Generated lock should have id", lock.getId());
162         assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber());
163         assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp());
164         assertEquals("Generated lock should have default lock descriptor", PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, lock.getLockDescriptor());
165         assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName());
166 
167         // test generating lock with given lock descriptor
168         lock = null;
169         documentNumber = "4321";
170         String lockDescriptor = "this is a test lock descriptor";
171         lock = lockService.generateNewLock(documentNumber, lockDescriptor);
172         assertNotNull("Generated lock should have id", lock.getId());
173         assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber());
174         assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp());
175         assertEquals("Generated lock should have lock descriptor set", lockDescriptor, lock.getLockDescriptor());
176         assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName());
177         primaryKeys = new HashMap();
178         primaryKeys.put(KRADPropertyConstants.ID, lock.getId());
179         lock = null;
180         lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys);
181         assertNotNull("Generated lock should be available from BO Service", lock);
182         assertNotNull("Generated lock should have id", lock.getId());
183         assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber());
184         assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp());
185         assertEquals("Generated lock should have lock descriptor set", lockDescriptor, lock.getLockDescriptor());
186         assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName());
187     }
188 
189     /**
190      * This method tests retrieving {@link PessimisticLock} objects by document number
191      *
192      * @throws Exception
193      */
194     @UnitTestData(
195             sqlStatements = {
196                     @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"),
197                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1111, 'fbcb0362-7dfb-102c-97b6-ed716fdaf540', 0, NULL, '1234', {d '2007-07-01'}, 'fran')"),
198                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1112, '055bef4a-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-10-01'}, 'frank')"),
199                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1113, '0e0144ec-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1236', {d '2007-10-01'}, 'frank')"),
200                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1114, '1891526c-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fred')")
201                     }
202             )
203     @Test
204     public void testGetPessimisticLocksForDocument() throws Exception {
205         PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService();
206         String docId = "1234";
207         assertEquals("Document " + docId + " expected lock count incorrect", 1, lockService.getPessimisticLocksForDocument(docId).size());
208         docId = "1237";
209         assertEquals("Document " + docId + " expected lock count incorrect", 2, lockService.getPessimisticLocksForDocument(docId).size());
210         docId = "1236";
211         assertEquals("Document " + docId + " expected lock count incorrect", 1, lockService.getPessimisticLocksForDocument(docId).size());
212         docId = "3948";
213         assertEquals("Document " + docId + " expected lock count incorrect", 0, lockService.getPessimisticLocksForDocument(docId).size());
214     }
215 
216     /**
217      * This method tests releasing {@link PessimisticLock} objects for a specific user
218      *
219      * @throws Exception
220      */
221     @UnitTestData(
222             sqlStatements = {
223                     @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"),
224                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1111, '24c40cd2-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1234', {d '2007-07-01'}, 'fran')"),
225                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1112, '32602e8e-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1235', {d '2007-10-01'}, 'frank')"),
226                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1113, '3acfc1ce-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1236', {d '2007-10-01'}, 'frank')"),
227                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1114, '463cc642-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fred')"),
228                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1115, '4e66c4b2-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1234', {d '2007-07-01'}, 'fran')"),
229                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1116, '55d99b02-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1235', {d '2007-10-01'}, 'frank')"),
230                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1117, '5e47fb26-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1236', {d '2007-10-01'}, 'frank')"),
231                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1118, '65c366d8-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1237', {d '2007-08-01'}, 'fred')")
232                     }
233             )
234     @Test
235     public void testReleaseAllLocksForUser() throws Exception {
236         String lockDescriptor = "Temporary Lock";
237         List<PessimisticLock> locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
238         assertEquals("Should be 8 manually inserted locks", 8, locks.size());
239 
240         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fran"), lockDescriptor);
241         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
242         assertEquals("Should be 7 locks left after releasing locks for fran using lock descriptor " + lockDescriptor, 7, locks.size());
243 
244         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("frank"), lockDescriptor);
245         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
246         assertEquals("Should be 5 locks left after releasing locks for fran and frank using lock descriptor " + lockDescriptor, 5, locks.size());
247 
248         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fred"), lockDescriptor);
249         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
250         assertEquals("Should be 4 locks left after releasing locks for fran, frank, and fred using lock descriptor " + lockDescriptor, 4, locks.size());
251 
252         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fran"));
253         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
254         assertEquals("Should be 3 locks left after releasing locks for fran with no lock descriptor", 3, locks.size());
255 
256         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("frank"));
257         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
258         assertEquals("Should be 1 lock left after releasing locks for fran and frank with no lock descriptor", 1, locks.size());
259 
260         KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fred"));
261         locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class);
262         assertEquals("Should be no locks left after releasing locks for fran, frank, and fred with no lock descriptor", 0, locks.size());
263     }
264 
265     /**
266      * This method tests saving {@link PessimisticLock} objects
267      *
268      * @throws Exception
269      */
270     @UnitTestData(
271             sqlStatements = {
272                     @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"),
273                     @UnitTestSql("INSERT INTO KRNS_PESSIMISTIC_LOCK_T (PESSIMISTIC_LOCK_ID,OBJ_ID,VER_NBR,LOCK_DESC_TXT,DOC_HDR_ID,GNRT_DT,PRNCPL_ID) VALUES (1111, '73f340de-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1234', {d '2007-07-01'}, 'fran')")
274                     }
275             )
276     @Test
277     public void testSaveLock() throws Exception {
278         String lockDescriptor = "new test lock descriptor";
279         // get existing lock and update lock descriptor and save
280         Map primaryKeys = new HashMap();
281         primaryKeys.put(KRADPropertyConstants.ID, Long.valueOf("1111"));
282         PessimisticLock lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys);
283         lock.setLockDescriptor(lockDescriptor);
284         KRADServiceLocatorWeb.getPessimisticLockService().save(lock);
285 
286         // verify retrieved lock has lock descriptor set previously
287         PessimisticLock savedLock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys);
288         assertEquals("Lock descriptor is not correct from lock that was saved", lockDescriptor, savedLock.getLockDescriptor());
289     }
290     
291     /**
292      * This method tests the PessimisticLockService.establishLocks method and the PessimisticLockService.getDocumentActions method.
293      * 
294      * @throws Exception
295      */
296     @Test
297     public void testEstablishLocks() throws Exception {
298     	PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService();
299     	AccountRequestDocument accountDoc = (AccountRequestDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest");
300     	
301     	assertTrue("The AccountRequestDocument should be using pessimistic locking",
302     			KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(accountDoc.getClass().getName()).getUsePessimisticLocking());
303     	
304     	// Have "quickstart" establish a pessimistic lock on the account request document.
305     	UserSession quickstartSession = new UserSession("quickstart");
306     	Person[] quickstartPerson = { quickstartSession.getPerson() };
307     	Map<String,String> editMode = new HashMap<String,String>();
308     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
309     	Map <?,?> finalModes = lockService.establishLocks(accountDoc, editMode, quickstartSession.getPerson());
310     	
311     	// Verify that the lock was actually established.
312     	assertCorrectLocksAreInPlace(true, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null);
313     	
314     	// Now check to make sure that a different user (such as "admin") cannot save, route, cancel, or blanket approve the document.
315     	UserSession adminSession = new UserSession("admin");
316     	Set<String> documentActions = new HashSet<String>(Arrays.asList(new String[] { KRADConstants.KUALI_ACTION_CAN_CANCEL,
317     			KRADConstants.KUALI_ACTION_CAN_SAVE, KRADConstants.KUALI_ACTION_CAN_ROUTE, KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE }));
318     	Set<?> finalActions = lockService.getDocumentActions(accountDoc, adminSession.getPerson(), documentActions);
319     	assertFalse("'admin' should not be able to cancel the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL));
320     	assertFalse("'admin' should not be able to save the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE));
321     	assertFalse("'admin' should not be able to route the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE));
322     	assertFalse("'admin' should not be able to blanket approve the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE));
323     	
324     	// Verify that "quickstart" can save, route, and cancel the document since he is the owner of the lock.
325     	documentActions = new HashSet<String>(Arrays.asList(new String[] {
326     			KRADConstants.KUALI_ACTION_CAN_CANCEL, KRADConstants.KUALI_ACTION_CAN_SAVE, KRADConstants.KUALI_ACTION_CAN_ROUTE }));
327     	finalActions = lockService.getDocumentActions(accountDoc, quickstartSession.getPerson(), documentActions);
328     	assertTrue("'quickstart' should have had cancel privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL));
329     	assertTrue("'quickstart' should have had save privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE));
330     	assertTrue("'quickstart' should have had route privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE));
331     	
332     	// Check that "admin" cannot establish a lock when one is already in place.
333     	editMode = new HashMap<String,String>();
334     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
335     	finalModes = lockService.establishLocks(accountDoc, editMode, adminSession.getPerson());
336     	assertCorrectLocksAreInPlace(false, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null);
337     	
338     	// Make sure that "quickstart" cannot create a second lock if custom lock descriptors are not in use.
339     	editMode = new HashMap<String,String>();
340     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
341     	finalModes = lockService.establishLocks(accountDoc, editMode, quickstartSession.getPerson());
342     	assertCorrectLocksAreInPlace(true, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null);
343     }
344     
345     /**
346      * This method tests the PessimistLockService's workflow pessimistic locking capabilities.
347      * 
348      * @throws Exception
349      */
350     @Test
351     public void testWorkflowPessimisticLocking() throws Exception {
352     	PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService();
353     	AccountRequestDocument accountDoc = (AccountRequestDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest");
354     	assertTrue("The AccountRequestDocument should be using pessimistic locking",
355     			KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(accountDoc.getClass().getName()).getUsePessimisticLocking());
356     	
357     	// Have the system user create a workflow pessimistic lock.
358     	UserSession systemSession = new UserSession(KRADConstants.SYSTEM_USER);
359     	Person[] systemPerson = { systemSession.getPerson() };
360     	lockService.establishWorkflowPessimisticLocking(accountDoc);
361        	assertCorrectLocksAreInPlace(false, null, 1, accountDoc.getPessimisticLocks(), systemPerson, null);
362        	
363        	// Make sure that no other users can lock when the workflow lock is in place.
364        	UserSession adminSession = new UserSession("admin");
365     	Map<String,String> editMode = new HashMap<String,String>();
366     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
367     	Map<?,?> finalModes = lockService.establishLocks(accountDoc, editMode, adminSession.getPerson());
368     	assertCorrectLocksAreInPlace(false, finalModes, 1, accountDoc.getPessimisticLocks(), systemPerson, null);
369        	
370        	// Ensure that workflow pessimistic locks can also be released.
371        	lockService.releaseWorkflowPessimisticLocking(accountDoc);
372        	assertTrue("There should not be any pessimistic locks present on the document", accountDoc.getPessimisticLocks().isEmpty());
373     }
374     
375     /**
376      * This method tests the PessimisticLockService's ability to establish pessimistic locks for documents supporting custom lock descriptors.
377      * 
378      * @throws Exception
379      */
380     @Test
381     public void testPessimisticLockingWithCustomDocumentLockDescriptors() throws Exception {
382        	AccountRequestDocument2 accountDoc2 = (AccountRequestDocument2) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest2");
383        	assertTrue("The AccountRequestDocument2 should be using pessimistic locking", KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary(
384        			).getDocumentEntry(accountDoc2.getClass().getName()).getUsePessimisticLocking());
385        	assertTrue("The AccountRequestDocument2 should be using custom lock descriptors", accountDoc2.useCustomLockDescriptors());
386        	
387        	// Perform the custom lock descriptor unit testing operations.
388        	assertCustomLockDescriptorsAreWorking(accountDoc2, AccountRequestDocument2.ACCT_REQ_DOC_2_EDITABLE_FIELDS,
389        			AccountRequestDocument2.EDIT_ALL_BUT_REASONS, AccountRequestDocument2.EDIT_REASONS_ONLY);
390     }
391     
392     /**
393      * This method tests the PessimisticLockService's ability to establish pessimistic locks for maintenance documents (via maintainables) that
394      * support custom lock descriptors.
395      * 
396      * @throws Exception
397      */
398     @Test
399     public void testPessimisticLockingWithCustomMaintainableLockDescriptors() throws Exception {
400     	MaintenanceDocument maintDoc = (MaintenanceDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountType2MaintenanceDocument");
401     	assertTrue("The AccountType2MaintenanceDocument should be using pessimistic locking", KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary(
402 			).getDocumentEntry(maintDoc.getNewMaintainableObject().getDataObjectClass().getSimpleName() + "MaintenanceDocument").getUsePessimisticLocking());
403     	assertTrue("The AccountType2MaintenanceDocument should be using custom lock descriptors", maintDoc.useCustomLockDescriptors());
404     	assertTrue("The AccountType2MaintenanceDocument's new maintainable uses the wrong class",
405     			maintDoc.getNewMaintainableObject() instanceof AccountType2MaintainableImpl);
406     	AccountType2MaintainableImpl newMaint = (AccountType2MaintainableImpl) maintDoc.getNewMaintainableObject();
407     	assertTrue("The AccountType2MaintainableImpl should be using custom lock descriptors", newMaint.useCustomLockDescriptors());
408     	
409     	// Perform the custom lock descriptor unit testing operations.
410        	assertCustomLockDescriptorsAreWorking(maintDoc, AccountType2MaintainableImpl.ACCT_TYPE_2_MAINT_FIELDS_TO_EDIT,
411        			AccountType2MaintainableImpl.EDIT_CODE_ONLY, AccountType2MaintainableImpl.EDIT_NAME_ONLY);
412     }
413     
414     /**
415      * A convenience method for testing the custom lock descriptors of documents (and on the maintainables of maintenance documents).
416      * 
417      * @param testDoc The document to test pessimistic locking on (or the maintenance document with maintainables to test on).
418      * @param LOCK_KEY The UserSession object key to use for storing the lock descriptor's key.
419      * @param LOCK_VALUE1 One possible object to store in a UserSession for generating lock descriptors on the testDoc.
420      * @param LOCK_VALUE2 Another possible object to store in a UserSession for generating lock descriptors on the testDoc.
421      * 
422      * @throws Exception
423      */
424     private void assertCustomLockDescriptorsAreWorking(Document testDoc, final String LOCK_KEY, final Serializable LOCK_VALUE1,
425     		final Serializable LOCK_VALUE2) throws Exception {
426     	PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService();
427     	
428     	// Have "quickstart" establish a pessimistic lock on the document by using a custom lock descriptor that only locks part of the document.
429        	UserSession quickstartSession = new UserSession("quickstart");
430        	Person[] allPersons = { quickstartSession.getPerson(), null };
431     	Map<String,String> editMode = new HashMap<String,String>();
432     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
433     	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1);
434     	String[] allDescriptors = { testDoc.getCustomLockDescriptor(quickstartSession.getPerson()), null };
435    		assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[0]);
436     	Map <?,?> finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson());
437     	
438     	// Verify that the lock was actually established and that the expected custom lock descriptor was used.
439     	assertCorrectLocksAreInPlace(true, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
440     	
441     	// Attempt to establish the same lock again, which should change nothing since "quickstart" already has the lock.
442     	editMode = new HashMap<String,String>();
443     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
444     	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1);
445     	lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson());
446     	assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
447     	
448     	// Now check to make sure that a different user (such as "admin") cannot establish a lock using the same lock descriptor.
449     	UserSession adminSession = new UserSession("admin");
450     	editMode = new HashMap<String,String>();
451     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
452        	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1);
453     	assertEquals("The document should have generated the same lock descriptors for both 'quickstart' and 'admin'",
454     			allDescriptors[0], testDoc.getCustomLockDescriptor(adminSession.getPerson()));
455     	finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson());
456     	assertCorrectLocksAreInPlace(false, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
457     	
458     	// Ensure that "admin" can establish a lock that has a different lock descriptor.
459     	allPersons[1] = adminSession.getPerson();
460     	editMode = new HashMap<String,String>();
461     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
462     	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2);
463     	allDescriptors[1] = testDoc.getCustomLockDescriptor(adminSession.getPerson());
464     	assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[1]);
465     	assertNotSame("'quickstart' and 'admin' should have different custom lock descriptors now", allDescriptors[0], allDescriptors[1]);
466     	finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson());
467     	assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
468     	
469     	// Verify that "quickstart" cannot acquire the lock owned by "admin".
470     	editMode = new HashMap<String,String>();
471     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
472     	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2);
473     	lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson());
474     	assertCorrectLocksAreInPlace(false, null, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
475     	
476     	// After "admin" releases his lock, check to make sure that "quickstart" can now acquire it.
477     	lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[1], allDescriptors[1]);
478     	testDoc.refreshPessimisticLocks();
479     	assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
480     	allPersons[1] = allPersons[0];
481     	editMode = new HashMap<String,String>();
482     	editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE);
483     	GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2);
484     	finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson());
485     	assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors);
486     	
487     	// Release all the locks when done.
488     	GlobalVariables.getUserSession().removeObject(LOCK_KEY);
489     	lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[0]);
490     	testDoc.refreshPessimisticLocks();
491     	assertTrue("There should not be any pessimistic locks present on the document", testDoc.getPessimisticLocks().isEmpty());
492     }
493     
494     /**
495      * A convenience method for checking to ensure that the proper pessimistic locks are in place.
496      * 
497      * @param latestUserHasFullEntry Indicates if the map returned by PessimisticLockService.establishLocks should have a true "fullEntry" parameter.
498      * @param finalModes The map returned by the call to PessimisticLockService.establishLocks. This parameter can be null if checking it is not needed.
499      * @param expectedLockQuantity The expected number of pessimistic locks.
500      * @param pessimisticLocks The list of pessimistic locks to check for proper quantity and proper state.
501      * @param expectedOwners The users who are expected to own the corresponding locks in the previous list.
502      * @param expectedDescriptors The expected lock descriptors for the corresponding locks in the other list. This parameter can be set to null if
503      * the pessimistic locks are not using custom lock descriptors or if custom lock descriptors are not the concern of the test.
504      * @throws Exception
505      */
506     private void assertCorrectLocksAreInPlace(boolean latestUserHasFullEntry, Map<?,?> finalModes, int expectedLockQuantity,
507     		List<PessimisticLock> pessimisticLocks, Person[] expectedOwners, String[] expectedDescriptors) throws Exception {
508     	// Ensure that the last user to attempt to establish locks has the expected finalModes entry (or lack of it).
509     	if (finalModes != null) {
510     		assertEquals("The last user that tried to establish locks does not have the expected status on their full entry privileges",
511     				latestUserHasFullEntry, StringUtils.equalsIgnoreCase(KRADConstants.KUALI_DEFAULT_TRUE_VALUE, (String)(finalModes.get(AuthorizationConstants.EditMode.FULL_ENTRY))));
512     	}
513     	// Ensure that the expected number of locks are present.
514     	assertEquals("The wrong number of pessimistic locks are in place", expectedLockQuantity, pessimisticLocks.size());
515     	// Verify that each lock has the expected owners.
516     	for (int i = pessimisticLocks.size() - 1; i > -1; i--) {
517     		assertTrue("The lock at index " + i + " did not have the expected owner of " + expectedOwners[i].getPrincipalName(),
518     			pessimisticLocks.get(i).isOwnedByUser(expectedOwners[i]));
519     		if (expectedDescriptors != null) {
520     			assertTrue("The lock at index " + i + " did not have the expected lock descriptor of " + expectedDescriptors[i],
521     					pessimisticLocks.get(i).getLockDescriptor().equals(expectedDescriptors[i]));
522     		}
523     	}
524     }
525 }