package org.ovirt.engine.core.utils.lock;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.enterprise.context.ApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ApplicationScoped
public class LockedObjectFactory {
private static final Logger log = LoggerFactory.getLogger(LockedObjectFactory.class);
/**
* @param instance class to be decorated.
* @param interfaceClass class type of interface implemented by the decorated class.
* @param lock lock used for locking.
* @param <T> <b>type of !INTERFACE!</b>
*/
public <T> T createLockingInstance(T instance,
Class<T> interfaceClass,
ReentrantReadWriteLock lock) {
Objects.requireNonNull(instance);
log.debug("Creating locking proxy for {} using lock: {}", instance, lock);
//noinspection unchecked
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class<?>[] { interfaceClass },
new LockingInvocationHandler(instance, lock));
}
static class LockingInvocationHandler<T> implements InvocationHandler {
private final ReentrantReadWriteLock lockObj;
private final T instance;
public LockingInvocationHandler(T instance, ReentrantReadWriteLock lockObj) {
this.instance = instance;
this.lockObj = lockObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.isAnnotationPresent(AcquireReadLock.class)) {
try (AutoCloseableLock l = new AutoCloseableLock(lockObj.readLock())) {
return method.invoke(instance, args);
}
}
if (method.isAnnotationPresent(AcquireWriteLock.class)) {
try (AutoCloseableLock l = new AutoCloseableLock(lockObj.writeLock())) {
try {
return method.invoke(instance, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
try {
return method.invoke(instance, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
}