@Test public void releaseLocksWhenExistingLocks() { Object[][] testData = { { 1L, "FILE", "READ", "userId", "READ", "userId", 1l, true, null, false }, { 1L, "FILE", "READ", "userId", "READ", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "WRITE", "userId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "WRITE", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "SHARED_WRITE", "userId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "SHARED_WRITE", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "DELETE", "userId", 1l, false, null, false }, { 1L, "FILE", "READ", "userId", "DELETE", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "WRITE", "userId", "READ", "userId", 1l, false, null, false }, { 1L, "FILE", "WRITE", "userId", "READ", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "WRITE", "userId", "WRITE", "userId", 1l, true, null, false }, { 1L, "FILE", "WRITE", "userId", "WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "WRITE", "userId", "SHARED_WRITE", "userId", 1l, false, null, true }, { 1L, "FILE", "WRITE", "userId", "SHARED_WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "WRITE", "userId", "DELETE", "userId", 1l, false, null, true }, { 1L, "FILE", "WRITE", "userId", "DELETE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "READ", "userId", 1l, false, null, false }, { 1L, "FILE", "DELETE", "userId", "READ", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "DELETE", "userId", 1l, true, null, false }, { 1L, "FILE", "DELETE", "userId", "DELETE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "WRITE", "userId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "SHARED_WRITE", "userId", 1l, false, null, true }, { 1L, "FILE", "DELETE", "userId", "SHARED_WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "READ", "userId", 1l, false, null, false }, { 1L, "FILE", "SHARED_WRITE", "userId", "READ", "anotherUserId", 1l, false, null, false }, { 1L, "FILE", "SHARED_WRITE", "userId", "SHARED_WRITE", "userId", 1l, true, 1l, false }, { 1L, "FILE", "SHARED_WRITE", "userId", "SHARED_WRITE", "anotherUserId", 1l, true, 1l, false }, { 1L, "FILE", "SHARED_WRITE", "userId", "SHARED_WRITE", "userId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "SHARED_WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "WRITE", "userId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "WRITE", "anotherUserId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "DELETE", "userId", 1l, false, null, true }, { 1L, "FILE", "SHARED_WRITE", "userId", "DELETE", "anotherUserId", 1l, false, null, true } }; for (Object[] data : testData) { EasyMock.reset(objectLockDaoMock, applicationEventPublisherMock); AcmObjectLock existingObjectLock = new AcmObjectLock(); existingObjectLock.setId((Long) data[6]); existingObjectLock.setObjectId((Long) data[0]); existingObjectLock.setObjectType((String) data[1]); existingObjectLock.setLockType((String) data[4]); existingObjectLock.setCreator((String) data[5]); Date existingLockCreated = new DateTime(new Date()).minusMinutes(5).toDate(); existingObjectLock.setCreated(existingLockCreated); expect(objectLockDaoMock.findLock((Long) data[0], (String) data[1])).andReturn(existingObjectLock).anyTimes(); if ((Boolean) data[7]) { objectLockDaoMock.remove(anyObject(AcmObjectLock.class)); expectLastCall(); applicationEventPublisherMock.publishEvent(anyObject(AcmObjectUnlockEvent.class)); expectLastCall(); } replayAll(); try { System.out.println("Releasing lock with test data: " + Arrays.toString(data)); fileObjectLockingProvider.releaseObjectLock((Long) data[0], (String) data[1], (String) data[2], false, (String) data[3], (Long) data[8]); if ((Boolean) data[9]) { fail("Exception should have been thrown at testData: " + Arrays.toString(data) + "!"); } } catch (AcmObjectLockException e) { if (!(Boolean) data[9]) { fail("Exception should not have been thrown at testData: " + Arrays.toString(data) + "!"); } } verifyAll(); } }
@Override public synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId, Long lockId) throws AcmObjectLockException { log.trace("Releasing object lock[objectId={}, objectType={}, lockType={}] for user: [{}]", objectId, objectType, lockType, userId); FileLockType objectLockType = FileLockType.fromName(lockType); AcmObjectLock existingLock = objectLockService.findLock(objectId, objectType); if (existingLock == null) { return; } if (existingLock.getCreator().equals(userId)) { switch (objectLockType) { case READ: if (!existingLock.getLockType().equals(FileLockType.READ.name())) { return; } break; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } else { switch (objectLockType) { case READ: return; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, true); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[%s] not able to release object lock[objectId=%s, objectType=%s, lockType=%s]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name())) { userId = existingLock.getCreator(); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object already has a lock of type {} by user: [{}]", userId, objectId, objectType, lockType, existingLock.getLockType(), existingLock.getCreator())); default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } objectLockService.removeLock(objectId, objectType, lockType, userId); }
FileLockingProvider implements ObjectLockingProvider { @Override public synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId, Long lockId) throws AcmObjectLockException { log.trace("Releasing object lock[objectId={}, objectType={}, lockType={}] for user: [{}]", objectId, objectType, lockType, userId); FileLockType objectLockType = FileLockType.fromName(lockType); AcmObjectLock existingLock = objectLockService.findLock(objectId, objectType); if (existingLock == null) { return; } if (existingLock.getCreator().equals(userId)) { switch (objectLockType) { case READ: if (!existingLock.getLockType().equals(FileLockType.READ.name())) { return; } break; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } else { switch (objectLockType) { case READ: return; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, true); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[%s] not able to release object lock[objectId=%s, objectType=%s, lockType=%s]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name())) { userId = existingLock.getCreator(); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object already has a lock of type {} by user: [{}]", userId, objectId, objectType, lockType, existingLock.getLockType(), existingLock.getCreator())); default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } objectLockService.removeLock(objectId, objectType, lockType, userId); } }
FileLockingProvider implements ObjectLockingProvider { @Override public synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId, Long lockId) throws AcmObjectLockException { log.trace("Releasing object lock[objectId={}, objectType={}, lockType={}] for user: [{}]", objectId, objectType, lockType, userId); FileLockType objectLockType = FileLockType.fromName(lockType); AcmObjectLock existingLock = objectLockService.findLock(objectId, objectType); if (existingLock == null) { return; } if (existingLock.getCreator().equals(userId)) { switch (objectLockType) { case READ: if (!existingLock.getLockType().equals(FileLockType.READ.name())) { return; } break; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } else { switch (objectLockType) { case READ: return; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, true); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[%s] not able to release object lock[objectId=%s, objectType=%s, lockType=%s]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name())) { userId = existingLock.getCreator(); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object already has a lock of type {} by user: [{}]", userId, objectId, objectType, lockType, existingLock.getLockType(), existingLock.getCreator())); default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } objectLockService.removeLock(objectId, objectType, lockType, userId); }  }
FileLockingProvider implements ObjectLockingProvider { @Override public synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId, Long lockId) throws AcmObjectLockException { log.trace("Releasing object lock[objectId={}, objectType={}, lockType={}] for user: [{}]", objectId, objectType, lockType, userId); FileLockType objectLockType = FileLockType.fromName(lockType); AcmObjectLock existingLock = objectLockService.findLock(objectId, objectType); if (existingLock == null) { return; } if (existingLock.getCreator().equals(userId)) { switch (objectLockType) { case READ: if (!existingLock.getLockType().equals(FileLockType.READ.name())) { return; } break; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } else { switch (objectLockType) { case READ: return; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, true); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[%s] not able to release object lock[objectId=%s, objectType=%s, lockType=%s]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name())) { userId = existingLock.getCreator(); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object already has a lock of type {} by user: [{}]", userId, objectId, objectType, lockType, existingLock.getLockType(), existingLock.getCreator())); default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } objectLockService.removeLock(objectId, objectType, lockType, userId); }  @Override void checkIfObjectLockCanBeAcquired(Long objectId, String objectType, String lockType, boolean checkChildObjects, String userId); @Override synchronized AcmObjectLock acquireObjectLock(Long objectId, String objectType, String lockType, Long expiry,
            boolean lockChildObjects, String userId); @Override synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId,
            Long lockId); @Override Long getExpiryTimeInMilliseconds(); void setExpiryTimeInMilliseconds(Long expiryTimeInMilliseconds); AcmObjectLockService getObjectLockService(); void setObjectLockService(AcmObjectLockService objectLockService); }
FileLockingProvider implements ObjectLockingProvider { @Override public synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId, Long lockId) throws AcmObjectLockException { log.trace("Releasing object lock[objectId={}, objectType={}, lockType={}] for user: [{}]", objectId, objectType, lockType, userId); FileLockType objectLockType = FileLockType.fromName(lockType); AcmObjectLock existingLock = objectLockService.findLock(objectId, objectType); if (existingLock == null) { return; } if (existingLock.getCreator().equals(userId)) { switch (objectLockType) { case READ: if (!existingLock.getLockType().equals(FileLockType.READ.name())) { return; } break; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } else { switch (objectLockType) { case READ: return; case WRITE: throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, true); break; case SHARED_WRITE: if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name()) && !existingLock.getId().equals(lockId)) { throw new AcmObjectLockException(String.format( "[%s] not able to release object lock[objectId=%s, objectType=%s, lockType=%s]. Reason: Object lockId mismatch!", userId, objectId, objectType, lockType, existingLock.getLockType())); } if (existingLock.getLockType().equals(FileLockType.SHARED_WRITE.name())) { userId = existingLock.getCreator(); } throwErrorOnExistingLockExceptForReadLock(objectId, objectType, lockType, userId, existingLock, false); break; case DELETE: throw new AcmObjectLockException(String.format( "[{}] not able to release object lock[objectId={}, objectType={}, lockType={}]. Reason: Object already has a lock of type {} by user: [{}]", userId, objectId, objectType, lockType, existingLock.getLockType(), existingLock.getCreator())); default: throw new AcmObjectLockException("Unimplemented handling of lock type: " + lockType); } } objectLockService.removeLock(objectId, objectType, lockType, userId); }  @Override void checkIfObjectLockCanBeAcquired(Long objectId, String objectType, String lockType, boolean checkChildObjects, String userId); @Override synchronized AcmObjectLock acquireObjectLock(Long objectId, String objectType, String lockType, Long expiry,
            boolean lockChildObjects, String userId); @Override synchronized void releaseObjectLock(Long objectId, String objectType, String lockType, boolean unlockChildObjects, String userId,
            Long lockId); @Override Long getExpiryTimeInMilliseconds(); void setExpiryTimeInMilliseconds(Long expiryTimeInMilliseconds); AcmObjectLockService getObjectLockService(); void setObjectLockService(AcmObjectLockService objectLockService);  }