001/** 002 * Copyright 2005-2013 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.service; 017 018import org.apache.commons.lang.StringUtils; 019import org.junit.Test; 020import org.kuali.rice.kew.api.exception.WorkflowException; 021import org.kuali.rice.kim.api.KimConstants.PermissionNames; 022import org.kuali.rice.kim.api.identity.Person; 023import org.kuali.rice.kim.api.services.KimApiServiceLocator; 024import org.kuali.rice.kns.authorization.AuthorizationConstants; 025import org.kuali.rice.krad.UserSession; 026import org.kuali.rice.krad.document.Document; 027import org.kuali.rice.krad.maintenance.MaintenanceDocument; 028import org.kuali.rice.krad.document.authorization.PessimisticLock; 029import org.kuali.rice.krad.exception.AuthorizationException; 030import org.kuali.rice.krad.service.impl.PessimisticLockServiceImpl; 031import org.kuali.rice.krad.test.document.AccountRequestDocument; 032import org.kuali.rice.krad.test.document.AccountRequestDocument2; 033import org.kuali.rice.krad.util.GlobalVariables; 034import org.kuali.rice.krad.util.KRADConstants; 035import org.kuali.rice.krad.util.KRADPropertyConstants; 036import org.kuali.rice.test.BaselineTestCase; 037import org.kuali.rice.test.data.UnitTestData; 038import org.kuali.rice.test.data.UnitTestSql; 039import org.kuali.rice.krad.test.KRADTestCase; 040 041import java.io.Serializable; 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.Collections; 045import java.util.HashMap; 046import java.util.HashSet; 047import java.util.List; 048import java.util.Map; 049import java.util.Set; 050 051import static org.junit.Assert.*; 052 053 054/** 055 * PessimisticLockServiceTest tests {@link PessimisticLockServiceImpl} 056 * 057 * @author Kuali Rice Team (rice.collab@kuali.org) 058 */ 059@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE) 060public class PessimisticLockServiceTest extends KRADTestCase { 061 062 String sessionId = "ad4d6c83-4d0f-4309-a528-c2f81ec00396"; 063 064 @Override 065 public void setUp() throws Exception { 066 super.setUp(); 067 GlobalVariables.setUserSession(new UserSession("quickstart")); 068 GlobalVariables.getUserSession().setKualiSessionId(sessionId); 069 } 070 071 /** 072 * tests deleting {@link PessimisticLock} objects. Tests that invalid deletes throw exceptions and valid 073 * deletes by owner users as well as lock admin users do work as expected 074 * 075 * @throws Exception 076 */ 077 @UnitTestData( 078 sqlStatements = { 079 @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"), 080 @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')"), 081 @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')"), 082 @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')"), 083 @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')") 084 } 085 ) 086 @Test 087 public void testDeleteLocks() throws Exception { 088 089 List<PessimisticLock> locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 090 assertEquals("Should be 4 locks in DB", 4, locks.size()); 091 092 String userId = "employee"; 093 String[] lockIdsToVerify = new String[]{"1112", "1113"}; 094 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, 095 Collections.<String, String>emptyMap() ) ); 096 verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true); 097 userId = "frank"; 098 lockIdsToVerify = new String[]{"1111", "1113"}; 099 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() ) ); 100 verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true); 101 userId = "fred"; 102 lockIdsToVerify = new String[]{"1111", "1112"}; 103 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() ) ); 104 verifyDelete(userId, Arrays.asList(lockIdsToVerify), AuthorizationException.class, true); 105 106 verifyDelete("employee", Arrays.asList(new String[]{"1111"}), null, false); 107 verifyDelete("frank", Arrays.asList(new String[]{"1112"}), null, false); 108 verifyDelete("fred", Arrays.asList(new String[]{"1113"}), null, false); 109 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 110 assertEquals("Should be 1 lock left in DB", 1, locks.size()); 111 112 // test admin user can delete any lock 113 userId = "fran"; 114 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() ) ); 115 userId = "admin"; 116 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() ) ); 117 verifyDelete(userId, Arrays.asList(new String[]{"1114"}), null, false); 118 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 119 assertEquals("Should be 0 locks left in DB", 0, locks.size()); 120 } 121 122 /** 123 * deletes the provided locks while checking for error conditions 124 * 125 * @param userId - the user id to use in creating a session 126 * @param lockIds - a list lock ids to delete 127 * @param expectedException - the expected exception's class 128 * @param expectException - true if an exception is expected on delete 129 * @see PessimisticLockService#delete(String) 130 * @throws WorkflowException 131 */ 132 private void verifyDelete(String userId, List<String> lockIds, Class expectedException, boolean expectException) throws WorkflowException { 133 GlobalVariables.setUserSession(new UserSession(userId)); 134 for (String lockId : lockIds) { 135 try { 136 KRADServiceLocatorWeb.getPessimisticLockService().delete(lockId); 137 if (expectException) { 138 fail("Expected exception when deleting lock with id '" + lockId + "' for user '" + userId + "'"); 139 } 140 } catch (Exception e) { 141 if (!expectException) { 142 fail("Did not expect exception when deleting lock with id '" + lockId + "' for user '" + userId + "' but got exception of type '" + e.getClass().getName() + "'"); 143 } 144 if (expectedException != null) { 145 // if we have an expected exception 146 if (!expectedException.isAssignableFrom(e.getClass())) { 147 fail("Expected exception of type '" + expectedException.getName() + "' when deleting lock with id '" + lockId + "' for user '" + userId + "' but got exception of type '" + e.getClass().getName() + "'"); 148 } 149 } 150 } 151 } 152 } 153 154 /** 155 * tests the generation of new {@link PessimisticLock} objects 156 * 157 * @throws Exception 158 */ 159 @Test 160 public void testGenerateNewLocks() throws Exception { 161 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 162 163 // test generating lock with no given lock descriptor 164 String documentNumber = "1243"; 165 PessimisticLock lock = lockService.generateNewLock(documentNumber); 166 assertNotNull("Generated lock should have id", lock.getId()); 167 assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber()); 168 assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp()); 169 assertEquals("Generated lock should have default lock descriptor", PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, lock.getLockDescriptor()); 170 assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName()); 171 Map primaryKeys = new HashMap(); 172 primaryKeys.put(KRADPropertyConstants.ID, lock.getId()); 173 lock = null; 174 lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys); 175 assertNotNull("Generated lock should be available from BO Service", lock); 176 assertNotNull("Generated lock should have id", lock.getId()); 177 assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber()); 178 assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp()); 179 assertEquals("Generated lock should have default lock descriptor", PessimisticLock.DEFAULT_LOCK_DESCRIPTOR, lock.getLockDescriptor()); 180 assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName()); 181 182 // test generating lock with given lock descriptor 183 lock = null; 184 documentNumber = "4321"; 185 String lockDescriptor = "this is a test lock descriptor"; 186 lock = lockService.generateNewLock(documentNumber, lockDescriptor); 187 assertNotNull("Generated lock should have id", lock.getId()); 188 assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber()); 189 assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp()); 190 assertEquals("Generated lock should have lock descriptor set", lockDescriptor, lock.getLockDescriptor()); 191 assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName()); 192 primaryKeys = new HashMap(); 193 primaryKeys.put(KRADPropertyConstants.ID, lock.getId()); 194 lock = null; 195 lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys); 196 assertNotNull("Generated lock should be available from BO Service", lock); 197 assertNotNull("Generated lock should have id", lock.getId()); 198 assertEquals("Document Number should match", documentNumber, lock.getDocumentNumber()); 199 assertNotNull("Generated lock should have a generated timestamp ", lock.getGeneratedTimestamp()); 200 assertEquals("Generated lock should have lock descriptor set", lockDescriptor, lock.getLockDescriptor()); 201 assertEquals("Generated lock should be owned by current user", GlobalVariables.getUserSession().getPerson().getPrincipalName(), lock.getOwnedByUser().getPrincipalName()); 202 } 203 204 /** 205 * tests retrieving {@link PessimisticLock} objects by document number 206 * 207 * @throws Exception 208 */ 209 @UnitTestData( 210 sqlStatements = { 211 @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"), 212 @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')"), 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 (1112, '055bef4a-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-10-01'}, 'frank', 'dd5d6c83-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 (1113, '0e0144ec-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1236', {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 (1114, '1891526c-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fred', 'ab4d6c83-4d0f-4309-a528-c2f81ec00396')") 216 } 217 ) 218 @Test 219 public void testGetPessimisticLocksForDocument() throws Exception { 220 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 221 String docId = "1234"; 222 assertEquals("Document " + docId + " expected lock count incorrect", 1, lockService.getPessimisticLocksForDocument(docId).size()); 223 docId = "1237"; 224 assertEquals("Document " + docId + " expected lock count incorrect", 2, lockService.getPessimisticLocksForDocument(docId).size()); 225 docId = "1236"; 226 assertEquals("Document " + docId + " expected lock count incorrect", 1, lockService.getPessimisticLocksForDocument(docId).size()); 227 docId = "3948"; 228 assertEquals("Document " + docId + " expected lock count incorrect", 0, lockService.getPessimisticLocksForDocument(docId).size()); 229 } 230 231 /** 232 * This method tests retrieving {@link PessimisticLock} objects by session id 233 * 234 * @throws Exception 235 */ 236 @UnitTestData( 237 sqlStatements = { 238 @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"), 239 @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')"), 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 (1112, '32602e8e-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1235', {d '2007-10-01'}, 'fran', 'bc5d6c66-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 (1113, '3acfc1ce-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1236', {d '2007-10-01'}, 'fran', 'ad4d6c83-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 (1114, '463cc642-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fran', 'bc5d6c66-4d0f-4309-a528-c2f81ec00396')") 243 } 244 ) 245 @Test 246 public void testGetPessimisticLocksForSession() throws Exception { 247 List<PessimisticLock> locks = KRADServiceLocatorWeb.getPessimisticLockService().getPessimisticLocksForSession(sessionId); 248 assertEquals("Should return 2 locks for session " + sessionId, 2, locks.size()); 249 250 ArrayList<String> documentNumbers = new ArrayList<String>(); 251 for (PessimisticLock lock : locks) { 252 documentNumbers.add(lock.getDocumentNumber()); 253 } 254 assertTrue("Locks should contain a lock for document number 1234 but contained " + documentNumbers, documentNumbers.contains("1234")); 255 assertTrue("Locks should contain a lock for document number 1236 but contained " + documentNumbers, documentNumbers.contains("1236")); 256 } 257 258 /** 259 * This method tests releasing {@link PessimisticLock} objects for a specific user 260 * 261 * @throws Exception 262 */ 263 @UnitTestData( 264 sqlStatements = { 265 @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"), 266 @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')"), 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 (1112, '32602e8e-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1235', {d '2007-10-01'}, 'frank', 'bc5d6c66-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 (1113, '3acfc1ce-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1236', {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 (1114, '463cc642-7dfc-102c-97b6-ed716fdaf540', 0, NULL, '1237', {d '2007-08-01'}, 'fred', 'dd5d6c66-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 (1115, '4e66c4b2-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1234', {d '2007-07-01'}, 'fran', 'ad4d6c83-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 (1116, '55d99b02-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1235', {d '2007-10-01'}, 'frank', 'bc5d6c66-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 (1117, '5e47fb26-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1236', {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 (1118, '65c366d8-7dfc-102c-97b6-ed716fdaf540', 0, 'Temporary Lock', '1237', {d '2007-08-01'}, 'fred', 'dd5d6c66-4d0f-4309-a528-c2f81ec00396')") 274 } 275 ) 276 @Test 277 public void testReleaseAllLocksForUser() throws Exception { 278 String lockDescriptor = "Temporary Lock"; 279 List<PessimisticLock> locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 280 assertEquals("Should be 8 manually inserted locks", 8, locks.size()); 281 282 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fran"), lockDescriptor); 283 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 284 assertEquals("Should be 7 locks left after releasing locks for fran using lock descriptor " + lockDescriptor, 7, locks.size()); 285 286 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("frank"), lockDescriptor); 287 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 288 assertEquals("Should be 5 locks left after releasing locks for fran and frank using lock descriptor " + lockDescriptor, 5, locks.size()); 289 290 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fred"), lockDescriptor); 291 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 292 assertEquals("Should be 4 locks left after releasing locks for fran, frank, and fred using lock descriptor " + lockDescriptor, 4, locks.size()); 293 294 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fran")); 295 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 296 assertEquals("Should be 3 locks left after releasing locks for fran with no lock descriptor", 3, locks.size()); 297 298 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("frank")); 299 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 300 assertEquals("Should be 1 lock left after releasing locks for fran and frank with no lock descriptor", 1, locks.size()); 301 302 KRADServiceLocatorWeb.getPessimisticLockService().releaseAllLocksForUser(locks, KimApiServiceLocator.getPersonService().getPerson("fred")); 303 locks = (List<PessimisticLock>) KRADServiceLocator.getBusinessObjectService().findAll(PessimisticLock.class); 304 assertEquals("Should be no locks left after releasing locks for fran, frank, and fred with no lock descriptor", 0, locks.size()); 305 } 306 307 /** 308 * tests saving {@link PessimisticLock} objects 309 * 310 * @throws Exception 311 */ 312 @UnitTestData( 313 sqlStatements = { 314 @UnitTestSql("DELETE FROM KRNS_PESSIMISTIC_LOCK_T"), 315 @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')") 316 } 317 ) 318 @Test 319 public void testSaveLock() throws Exception { 320 String lockDescriptor = "new test lock descriptor"; 321 // get existing lock and update lock descriptor and save 322 Map primaryKeys = new HashMap(); 323 primaryKeys.put(KRADPropertyConstants.ID, Long.valueOf("1111")); 324 PessimisticLock lock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys); 325 lock.setLockDescriptor(lockDescriptor); 326 KRADServiceLocatorWeb.getPessimisticLockService().save(lock); 327 328 // verify retrieved lock has lock descriptor set previously 329 PessimisticLock savedLock = (PessimisticLock) KRADServiceLocator.getBusinessObjectService().findByPrimaryKey(PessimisticLock.class, primaryKeys); 330 assertEquals("Lock descriptor is not correct from lock that was saved", lockDescriptor, savedLock.getLockDescriptor()); 331 } 332 333 /** 334 * tests the PessimisticLockService.establishLocks method and the PessimisticLockService.getDocumentActions method 335 * 336 * @throws Exception 337 */ 338 @Test 339 public void testEstablishLocks() throws Exception { 340 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 341 AccountRequestDocument accountDoc = (AccountRequestDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest"); 342 343 assertTrue("The AccountRequestDocument should be using pessimistic locking", 344 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(accountDoc.getClass().getName()).getUsePessimisticLocking()); 345 346 // Have "quickstart" establish a pessimistic lock on the account request document. 347 UserSession quickstartSession = new UserSession("quickstart"); 348 Person[] quickstartPerson = { quickstartSession.getPerson() }; 349 Map<String,String> editMode = new HashMap<String,String>(); 350 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 351 Map <?,?> finalModes = lockService.establishLocks(accountDoc, editMode, quickstartSession.getPerson()); 352 353 // Verify that the lock was actually established. 354 assertCorrectLocksAreInPlace(true, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null); 355 356 // Now check to make sure that a different user (such as "admin") cannot save, route, cancel, or blanket approve the document. 357 UserSession adminSession = new UserSession("admin"); 358 Set<String> documentActions = new HashSet<String>(Arrays.asList(new String[] { KRADConstants.KUALI_ACTION_CAN_CANCEL, 359 KRADConstants.KUALI_ACTION_CAN_SAVE, KRADConstants.KUALI_ACTION_CAN_ROUTE, KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE })); 360 Set<?> finalActions = lockService.getDocumentActions(accountDoc, adminSession.getPerson(), documentActions); 361 assertFalse("'admin' should not be able to cancel the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL)); 362 assertFalse("'admin' should not be able to save the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE)); 363 assertFalse("'admin' should not be able to route the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE)); 364 assertFalse("'admin' should not be able to blanket approve the locked document", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_BLANKET_APPROVE)); 365 366 // Verify that "quickstart" can save, route, and cancel the document since he is the owner of the lock. 367 documentActions = new HashSet<String>(Arrays.asList(new String[] { 368 KRADConstants.KUALI_ACTION_CAN_CANCEL, KRADConstants.KUALI_ACTION_CAN_SAVE, KRADConstants.KUALI_ACTION_CAN_ROUTE })); 369 finalActions = lockService.getDocumentActions(accountDoc, quickstartSession.getPerson(), documentActions); 370 assertTrue("'quickstart' should have had cancel privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_CANCEL)); 371 assertTrue("'quickstart' should have had save privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_SAVE)); 372 assertTrue("'quickstart' should have had route privileges", finalActions.contains(KRADConstants.KUALI_ACTION_CAN_ROUTE)); 373 374 // Check that "admin" cannot establish a lock when one is already in place. 375 editMode = new HashMap<String,String>(); 376 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 377 finalModes = lockService.establishLocks(accountDoc, editMode, adminSession.getPerson()); 378 assertCorrectLocksAreInPlace(false, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null); 379 380 // Make sure that "quickstart" cannot create a second lock if custom lock descriptors are not in use. 381 editMode = new HashMap<String,String>(); 382 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 383 finalModes = lockService.establishLocks(accountDoc, editMode, quickstartSession.getPerson()); 384 assertCorrectLocksAreInPlace(true, finalModes, 1, accountDoc.getPessimisticLocks(), quickstartPerson, null); 385 } 386 387 /** 388 * tests the PessimistLockService's workflow pessimistic locking capabilities 389 * 390 * @throws Exception 391 */ 392 @Test 393 public void testWorkflowPessimisticLocking() throws Exception { 394 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 395 AccountRequestDocument accountDoc = (AccountRequestDocument) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest"); 396 assertTrue("The AccountRequestDocument should be using pessimistic locking", 397 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(accountDoc.getClass().getName()).getUsePessimisticLocking()); 398 399 // Have the system user create a workflow pessimistic lock. 400 UserSession systemSession = new UserSession(KRADConstants.SYSTEM_USER); 401 Person[] systemPerson = { systemSession.getPerson() }; 402 lockService.establishWorkflowPessimisticLocking(accountDoc); 403 assertCorrectLocksAreInPlace(false, null, 1, accountDoc.getPessimisticLocks(), systemPerson, null); 404 405 // Make sure that no other users can lock when the workflow lock is in place. 406 UserSession adminSession = new UserSession("admin"); 407 Map<String,String> editMode = new HashMap<String,String>(); 408 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 409 Map<?,?> finalModes = lockService.establishLocks(accountDoc, editMode, adminSession.getPerson()); 410 assertCorrectLocksAreInPlace(false, finalModes, 1, accountDoc.getPessimisticLocks(), systemPerson, null); 411 412 // Ensure that workflow pessimistic locks can also be released. 413 lockService.releaseWorkflowPessimisticLocking(accountDoc); 414 assertTrue("There should not be any pessimistic locks present on the document", accountDoc.getPessimisticLocks().isEmpty()); 415 } 416 417 /** 418 * tests the PessimisticLockService's ability to establish pessimistic locks for documents supporting custom lock descriptors 419 * 420 * @throws Exception 421 */ 422 @Test 423 public void testPessimisticLockingWithCustomDocumentLockDescriptors() throws Exception { 424 AccountRequestDocument2 accountDoc2 = (AccountRequestDocument2) KRADServiceLocatorWeb.getDocumentService().getNewDocument("AccountRequest2"); 425 assertTrue("The AccountRequestDocument2 should be using pessimistic locking", KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary( 426 ).getDocumentEntry(accountDoc2.getClass().getName()).getUsePessimisticLocking()); 427 assertTrue("The AccountRequestDocument2 should be using custom lock descriptors", accountDoc2.useCustomLockDescriptors()); 428 429 // Perform the custom lock descriptor unit testing operations. 430 assertCustomLockDescriptorsAreWorking(accountDoc2, AccountRequestDocument2.ACCT_REQ_DOC_2_EDITABLE_FIELDS, 431 AccountRequestDocument2.EDIT_ALL_BUT_REASONS, AccountRequestDocument2.EDIT_REASONS_ONLY); 432 } 433 434 /** 435 * A convenience method for testing the custom lock descriptors of documents (and on the maintainables of maintenance documents). 436 * 437 * @param testDoc The document to test pessimistic locking on (or the maintenance document with maintainables to test on). 438 * @param LOCK_KEY The UserSession object key to use for storing the lock descriptor's key. 439 * @param LOCK_VALUE1 One possible object to store in a UserSession for generating lock descriptors on the testDoc. 440 * @param LOCK_VALUE2 Another possible object to store in a UserSession for generating lock descriptors on the testDoc. 441 * 442 * @throws Exception 443 */ 444 private void assertCustomLockDescriptorsAreWorking(Document testDoc, final String LOCK_KEY, final Serializable LOCK_VALUE1, 445 final Serializable LOCK_VALUE2) throws Exception { 446 PessimisticLockService lockService = KRADServiceLocatorWeb.getPessimisticLockService(); 447 448 // Have "quickstart" establish a pessimistic lock on the document by using a custom lock descriptor that only locks part of the document. 449 UserSession quickstartSession = new UserSession("quickstart"); 450 Person[] allPersons = { quickstartSession.getPerson(), null }; 451 Map<String,String> editMode = new HashMap<String,String>(); 452 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 453 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1); 454 String[] allDescriptors = { testDoc.getCustomLockDescriptor(quickstartSession.getPerson()), null }; 455 assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[0]); 456 Map <?,?> finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 457 458 // Verify that the lock was actually established and that the expected custom lock descriptor was used. 459 assertCorrectLocksAreInPlace(true, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 460 461 // Attempt to establish the same lock again, which should change nothing since "quickstart" already has the lock. 462 editMode = new HashMap<String,String>(); 463 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 464 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE1); 465 lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 466 assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 467 468 // Now check to make sure that a different user (such as "admin") cannot establish a lock using the same lock descriptor. 469 UserSession adminSession = new UserSession("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_VALUE1); 473 assertEquals("The document should have generated the same lock descriptors for both 'quickstart' and 'admin'", 474 allDescriptors[0], testDoc.getCustomLockDescriptor(adminSession.getPerson())); 475 finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson()); 476 assertCorrectLocksAreInPlace(false, finalModes, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 477 478 // Ensure that "admin" can establish a lock that has a different lock descriptor. 479 allPersons[1] = adminSession.getPerson(); 480 editMode = new HashMap<String,String>(); 481 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 482 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 483 allDescriptors[1] = testDoc.getCustomLockDescriptor(adminSession.getPerson()); 484 assertNotNull("The document should have generated a custom lock descriptor", allDescriptors[1]); 485 assertNotSame("'quickstart' and 'admin' should have different custom lock descriptors now", allDescriptors[0], allDescriptors[1]); 486 finalModes = lockService.establishLocks(testDoc, editMode, adminSession.getPerson()); 487 assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 488 489 // Verify that "quickstart" cannot acquire the lock owned by "admin". 490 editMode = new HashMap<String,String>(); 491 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 492 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 493 lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 494 assertCorrectLocksAreInPlace(false, null, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 495 496 // After "admin" releases his lock, check to make sure that "quickstart" can now acquire it. 497 lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[1], allDescriptors[1]); 498 testDoc.refreshPessimisticLocks(); 499 assertCorrectLocksAreInPlace(false, null, 1, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 500 allPersons[1] = allPersons[0]; 501 editMode = new HashMap<String,String>(); 502 editMode.put(AuthorizationConstants.EditMode.FULL_ENTRY, KRADConstants.KUALI_DEFAULT_TRUE_VALUE); 503 GlobalVariables.getUserSession().addObject(LOCK_KEY, LOCK_VALUE2); 504 finalModes = lockService.establishLocks(testDoc, editMode, quickstartSession.getPerson()); 505 assertCorrectLocksAreInPlace(true, finalModes, 2, testDoc.getPessimisticLocks(), allPersons, allDescriptors); 506 507 // Release all the locks when done. 508 GlobalVariables.getUserSession().removeObject(LOCK_KEY); 509 lockService.releaseAllLocksForUser(testDoc.getPessimisticLocks(), allPersons[0]); 510 testDoc.refreshPessimisticLocks(); 511 assertTrue("There should not be any pessimistic locks present on the document", testDoc.getPessimisticLocks().isEmpty()); 512 } 513 514 /** 515 * A convenience method for checking to ensure that the proper pessimistic locks are in place. 516 * 517 * @param latestUserHasFullEntry Indicates if the map returned by PessimisticLockService.establishLocks should have a true "fullEntry" parameter. 518 * @param finalModes The map returned by the call to PessimisticLockService.establishLocks. This parameter can be null if checking it is not needed. 519 * @param expectedLockQuantity The expected number of pessimistic locks. 520 * @param pessimisticLocks The list of pessimistic locks to check for proper quantity and proper state. 521 * @param expectedOwners The users who are expected to own the corresponding locks in the previous list. 522 * @param expectedDescriptors The expected lock descriptors for the corresponding locks in the other list. This parameter can be set to null if 523 * the pessimistic locks are not using custom lock descriptors or if custom lock descriptors are not the concern of the test. 524 * @throws Exception 525 */ 526 private void assertCorrectLocksAreInPlace(boolean latestUserHasFullEntry, Map<?,?> finalModes, int expectedLockQuantity, 527 List<PessimisticLock> pessimisticLocks, Person[] expectedOwners, String[] expectedDescriptors) throws Exception { 528 // Ensure that the last user to attempt to establish locks has the expected finalModes entry (or lack of it). 529 if (finalModes != null) { 530 assertEquals("The last user that tried to establish locks does not have the expected status on their full entry privileges", 531 latestUserHasFullEntry, StringUtils.equalsIgnoreCase(KRADConstants.KUALI_DEFAULT_TRUE_VALUE, (String)(finalModes.get( 532 AuthorizationConstants.EditMode.FULL_ENTRY)))); 533 } 534 // Ensure that the expected number of locks are present. 535 assertEquals("The wrong number of pessimistic locks are in place", expectedLockQuantity, pessimisticLocks.size()); 536 // Verify that each lock has the expected owners. 537 for (int i = pessimisticLocks.size() - 1; i > -1; i--) { 538 assertTrue("The lock at index " + i + " did not have the expected owner of " + expectedOwners[i].getPrincipalName(), 539 pessimisticLocks.get(i).isOwnedByUser(expectedOwners[i])); 540 if (expectedDescriptors != null) { 541 assertTrue("The lock at index " + i + " did not have the expected lock descriptor of " + expectedDescriptors[i], 542 pessimisticLocks.get(i).getLockDescriptor().equals(expectedDescriptors[i])); 543 } 544 } 545 } 546}