001package co.codewizards.cloudstore.ls.core.invoke; 002 003import static java.util.Objects.*; 004 005import java.lang.ref.Reference; 006import java.lang.ref.ReferenceQueue; 007import java.lang.ref.WeakReference; 008import java.util.HashMap; 009import java.util.IdentityHashMap; 010import java.util.Map; 011 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015public class RemoteObjectProxyManager { 016 017 private static final Logger logger = LoggerFactory.getLogger(RemoteObjectProxyManager.class); 018 019 private final Map<ObjectRef, WeakReference<RemoteObjectProxy>> objectRef2RemoteObjectProxyRef = new HashMap<>(); 020 private final Map<WeakReference<RemoteObjectProxy>, ObjectRef> remoteObjectProxyRef2ObjectRef = new IdentityHashMap<>(); 021 private final ReferenceQueue<RemoteObjectProxy> referenceQueue = new ReferenceQueue<RemoteObjectProxy>(); 022 023 protected RemoteObjectProxyManager() { 024 if (logger.isDebugEnabled()) 025 logger.debug("[{}]<init>", getThisId()); 026 } 027 028 public synchronized RemoteObjectProxy getRemoteObjectProxy(final ObjectRef objectRef) { 029 requireNonNull(objectRef, "objectRef"); 030 final WeakReference<RemoteObjectProxy> remoteObjectProxyRef = objectRef2RemoteObjectProxyRef.get(objectRef); 031 final RemoteObjectProxy remoteObjectProxy = remoteObjectProxyRef == null ? null : remoteObjectProxyRef.get(); 032 evictOrphanedObjectRefs(); 033 return remoteObjectProxy; 034 } 035 036 public synchronized RemoteObjectProxy getRemoteObjectProxyOrCreate(final ObjectRef objectRef, final RemoteObjectProxyFactory remoteObjectProxyFactory) { 037 requireNonNull(objectRef, "objectRef"); 038 requireNonNull(remoteObjectProxyFactory, "remoteObjectProxyFactory"); 039 040 final WeakReference<RemoteObjectProxy> remoteObjectProxyRef = objectRef2RemoteObjectProxyRef.get(objectRef); 041 RemoteObjectProxy remoteObjectProxy = remoteObjectProxyRef == null ? null : remoteObjectProxyRef.get(); 042 043 if (remoteObjectProxy == null) { 044 if (logger.isDebugEnabled()) 045 logger.debug("[{}]getRemoteObjectProxy: Creating proxy for {}. remoteObjectProxyRef={}", getThisId(), objectRef, remoteObjectProxyRef); 046 047 // We do not need to create the proxy outside of the synchronized block, anymore, because the proxy creation now works without 048 // immediate inverse-invocation and thus there's no more risk of a deadlock, here. => stay inside single big synchronized-block. 049 remoteObjectProxy = remoteObjectProxyFactory.createRemoteObjectProxy(objectRef); 050 requireNonNull(remoteObjectProxy, "remoteObjectProxyFactory.createRemoteObjectProxy(objectRef)"); 051 052 final WeakReference<RemoteObjectProxy> reference = new WeakReference<>(remoteObjectProxy, referenceQueue); 053 objectRef2RemoteObjectProxyRef.put(objectRef, reference); 054 remoteObjectProxyRef2ObjectRef.put(reference, objectRef); 055 } 056 evictOrphanedObjectRefs(); 057 return remoteObjectProxy; 058 } 059 060 private String getThisId() { 061 return Integer.toHexString(System.identityHashCode(this)); 062 } 063 064 private synchronized void evictOrphanedObjectRefs() { 065 Reference<? extends RemoteObjectProxy> reference; 066 while (null != (reference = referenceQueue.poll())) { 067 final ObjectRef objectRef = remoteObjectProxyRef2ObjectRef.remove(reference); 068 objectRef2RemoteObjectProxyRef.remove(objectRef); 069 } 070 } 071}