package com.renxo.cms.util;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* An abstract LockManager
implementation based on standard JDK
* {@link Lock}s.
*
* @param
* the type of the lock key.
*/
public abstract class AbstractJdkLockManager implements LockManager {
// ----------------------------------------------------------------------
// Fields
// ----------------------------------------------------------------------
private final ConcurrentMap locks = CollectionFactory
.newConcurrentMap();
// ----------------------------------------------------------------------
// LockManager implementations
// ----------------------------------------------------------------------
@Override
public void ensureLock(K key) {
Lock lock = cachedLock(key);
lock.lock();
}
@Override
public void ensureLockInterruptibly(K key) throws InterruptedException {
Lock lock = cachedLock(key);
lock.lockInterruptibly();
}
@Override
public boolean acquireLock(K key) {
long defaultTryLockTimeout = defaultTryLockTimeout();
if (defaultTryLockTimeout > 0L) {
try {
return acquireLock(key, defaultTryLockTimeout);
} catch (InterruptedException e) {
return false;
}
} else {
Lock lock = cachedLock(key);
return lock.tryLock();
}
}
@Override
public boolean acquireLock(K key, long timeout) throws InterruptedException {
Lock lock = cachedLock(key);
return lock.tryLock(timeout, TimeUnit.MILLISECONDS);
}
@Override
public void releaseLock(K key) {
Lock lock = cachedLock(key);
try {
lock.unlock();
} catch (Exception e) {
throw new IllegalMonitorStateException(e.getMessage());
}
}
@Override
public void clearUnusedLocks() {
Map acquiredLocks = new HashMap();
for (Entry entry : locks.entrySet()) {
K key = entry.getKey();
Lock lock = entry.getValue();
if (lock.tryLock()) {
acquiredLocks.put(key, lock);
}
}
for (Entry entry : acquiredLocks.entrySet()) {
K key = entry.getKey();
Lock lock = entry.getValue();
locks.remove(key);
lock.unlock();
}
}
// ----------------------------------------------------------------------
// Private helper methods
// ----------------------------------------------------------------------
private Lock cachedLock(K key) {
Lock lock = locks.get(key);
if (lock == null) {
lock = getLock(key);
Lock prevLock = locks.putIfAbsent(key, lock);
if (prevLock != null) {
lock = prevLock;
}
}
return lock;
}
// ----------------------------------------------------------------------
// Template methods
// ----------------------------------------------------------------------
/**
* Gets a lock instance for the given key.
*
* @param key
* the key for which to obtain the lock instance.
* @return the requested lock instance.
*/
protected abstract Lock getLock(K key);
/**
* Returns the default {@link #acquireLock(Object)} timeout to use.
* Implementations that do not require a default timeout should return zero.
*
* @return the default {@link #acquireLock(Object)} timeout to use.
*/
protected abstract long defaultTryLockTimeout();
}