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