View Javadoc

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