package co.codewizards.cloudstore.ls.core.invoke;
import static co.codewizards.cloudstore.core.util.AssertUtil.*;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RemoteObjectProxyManager {
private static final Logger logger = LoggerFactory.getLogger(RemoteObjectProxyManager.class);
private final Map<ObjectRef, WeakReference<RemoteObjectProxy>> objectRef2RemoteObjectProxyRef = new HashMap<>();
private final Map<WeakReference<RemoteObjectProxy>, ObjectRef> remoteObjectProxyRef2ObjectRef = new IdentityHashMap<>();
private final ReferenceQueue<RemoteObjectProxy> referenceQueue = new ReferenceQueue<RemoteObjectProxy>();
protected RemoteObjectProxyManager() {
if (logger.isDebugEnabled())
logger.debug("[{}]<init>", getThisId());
}
public synchronized RemoteObjectProxy getRemoteObjectProxy(final ObjectRef objectRef) {
assertNotNull(objectRef, "objectRef");
final WeakReference<RemoteObjectProxy> remoteObjectProxyRef = objectRef2RemoteObjectProxyRef.get(objectRef);
final RemoteObjectProxy remoteObjectProxy = remoteObjectProxyRef == null ? null : remoteObjectProxyRef.get();
evictOrphanedObjectRefs();
return remoteObjectProxy;
}
public synchronized RemoteObjectProxy getRemoteObjectProxyOrCreate(final ObjectRef objectRef, final RemoteObjectProxyFactory remoteObjectProxyFactory) {
assertNotNull(objectRef, "objectRef");
assertNotNull(remoteObjectProxyFactory, "remoteObjectProxyFactory");
final WeakReference<RemoteObjectProxy> remoteObjectProxyRef = objectRef2RemoteObjectProxyRef.get(objectRef);
RemoteObjectProxy remoteObjectProxy = remoteObjectProxyRef == null ? null : remoteObjectProxyRef.get();
if (remoteObjectProxy == null) {
if (logger.isDebugEnabled())
logger.debug("[{}]getRemoteObjectProxy: Creating proxy for {}. remoteObjectProxyRef={}", getThisId(), objectRef, remoteObjectProxyRef);
// We do not need to create the proxy outside of the synchronized block, anymore, because the proxy creation now works without
// immediate inverse-invocation and thus there's no more risk of a deadlock, here. => stay inside single big synchronized-block.
remoteObjectProxy = remoteObjectProxyFactory.createRemoteObjectProxy(objectRef);
assertNotNull(remoteObjectProxy, "remoteObjectProxyFactory.createRemoteObjectProxy(objectRef)");
final WeakReference<RemoteObjectProxy> reference = new WeakReference<>(remoteObjectProxy, referenceQueue);
objectRef2RemoteObjectProxyRef.put(objectRef, reference);
remoteObjectProxyRef2ObjectRef.put(reference, objectRef);
}
evictOrphanedObjectRefs();
return remoteObjectProxy;
}
private String getThisId() {
return Integer.toHexString(System.identityHashCode(this));
}
private synchronized void evictOrphanedObjectRefs() {
Reference<? extends RemoteObjectProxy> reference;
while (null != (reference = referenceQueue.poll())) {
final ObjectRef objectRef = remoteObjectProxyRef2ObjectRef.remove(reference);
objectRef2RemoteObjectProxyRef.remove(objectRef);
}
}
}