001package co.codewizards.cloudstore.ls.core.invoke;
002
003import static java.util.Objects.*;
004
005import java.lang.reflect.InvocationHandler;
006import java.lang.reflect.Method;
007import java.lang.reflect.Proxy;
008
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import co.codewizards.cloudstore.core.Uid;
013
014public class RemoteObjectProxyInvocationHandler implements InvocationHandler {
015
016        private static final Logger logger = LoggerFactory.getLogger(RemoteObjectProxyInvocationHandler.class);
017
018        protected final Uid refId = new Uid();
019        protected final Invoker invoker;
020        protected final ObjectRef objectRef;
021        protected final boolean equalsOverridden;
022
023        public RemoteObjectProxyInvocationHandler(final Invoker invoker, final ObjectRef objectRef) {
024                this.invoker = requireNonNull(invoker, "invoker");
025                this.objectRef = requireNonNull(objectRef, "objectRef");
026
027                if (logger.isDebugEnabled())
028                        logger.debug("[{}]<init>: {} refId={}", getThisId(), objectRef, refId);
029
030                equalsOverridden = invoker.getClassInfoMap().getClassInfoOrFail(objectRef.getClassId()).isEqualsOverridden();
031                invoker.incRefCount(objectRef, refId);
032        }
033
034        @Override
035        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
036                // BEGIN implement RemoteObjectProxy
037                if ("getObjectRef".equals(method.getName()) && method.getParameterTypes().length == 0)
038                        return objectRef;
039                // END implement RemoteObjectProxy
040
041                // BEGIN equals(...) + hashCode()
042                if (! equalsOverridden) {
043                        if ("equals".equals(method.getName()) && method.getParameterTypes().length == 1)
044                                return _equals(proxy, method, args[0]);
045
046                        if ("hashCode".equals(method.getName()) && method.getParameterTypes().length == 0)
047                                return _hashCode(proxy, method);
048                }
049                // END equals(...) + hashCode()
050
051                if (logger.isDebugEnabled())
052                        logger.debug("[{}]invoke: method='{}'", getThisId(), method);
053
054                return invoker.invoke(objectRef, method.getName(), method.getParameterTypes(), args);
055        }
056
057        @Override
058        protected void finalize() throws Throwable {
059                if (logger.isDebugEnabled())
060                        logger.debug("[{}]finalize: {}", getThisId(), objectRef);
061
062                invoker.decRefCount(objectRef, refId);
063                super.finalize();
064        }
065
066        private Object _equals(final Object proxy, final Method method, final Object other) {
067                if (proxy == other)
068                        return true;
069
070                if (null == other)
071                        return false;
072
073                if (proxy.getClass() != other.getClass())
074                        return false;
075
076                final RemoteObjectProxyInvocationHandler otherHandler = (RemoteObjectProxyInvocationHandler) Proxy.getInvocationHandler(other);
077                return this.objectRef.equals(otherHandler.objectRef);
078        }
079
080        private int _hashCode(final Object proxy, final Method method) {
081                return 31 * objectRef.hashCode();
082        }
083
084        protected String getThisId() {
085                return Integer.toHexString(System.identityHashCode(this));
086        }
087}