001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.cluster;
016    
017    import com.liferay.portal.kernel.annotation.AnnotationLocator;
018    import com.liferay.portal.kernel.util.MethodKey;
019    import com.liferay.portal.kernel.util.ProxyUtil;
020    
021    import java.lang.reflect.InvocationHandler;
022    import java.lang.reflect.Method;
023    
024    import java.util.Map;
025    import java.util.concurrent.ConcurrentHashMap;
026    
027    /**
028     * @author Tina Tian
029     */
030    public class ClusterableProxyFactory {
031    
032            public static <T> T createClusterableProxy(T targetObject) {
033                    Class<?> targetClass = targetObject.getClass();
034    
035                    return (T)ProxyUtil.newProxyInstance(
036                            targetClass.getClassLoader(), targetClass.getInterfaces(),
037                            new ClusterableInvocationHandler<>(targetObject));
038            }
039    
040            private static class ClusterableInvocationHandler<T>
041                    implements InvocationHandler {
042    
043                    @Override
044                    public Object invoke(Object proxy, Method method, Object[] arguments)
045                            throws Throwable {
046    
047                            if (!ClusterInvokeThreadLocal.isEnabled()) {
048                                    return method.invoke(_targetObject, arguments);
049                            }
050    
051                            Clusterable clusterable = _getClusterable(
052                                    method, _targetObject.getClass());
053    
054                            if (clusterable == NullClusterable.NULL_CLUSTERABLE) {
055                                    return method.invoke(_targetObject, arguments);
056                            }
057    
058                            if (clusterable.onMaster()) {
059                                    if (ClusterMasterExecutorUtil.isMaster()) {
060                                            return method.invoke(_targetObject, arguments);
061                                    }
062    
063                                    return ClusterableInvokerUtil.invokeOnMaster(
064                                            clusterable.acceptor(), _targetObject, method, arguments);
065                            }
066    
067                            Object result = method.invoke(_targetObject, arguments);
068    
069                            ClusterableInvokerUtil.invokeOnCluster(
070                                    clusterable.acceptor(), _targetObject, method, arguments);
071    
072                            return result;
073                    }
074    
075                    private ClusterableInvocationHandler(T targetObject) {
076                            _targetObject = targetObject;
077                    }
078    
079                    private Clusterable _getClusterable(
080                            Method method, Class<?> targetClass) {
081    
082                            MethodKey methodKey = new MethodKey(
083                                    targetClass, method.getName(), method.getParameterTypes());
084    
085                            Clusterable clusterable = _clusterables.get(methodKey);
086    
087                            if (clusterable != null) {
088                                    return clusterable;
089                            }
090    
091                            clusterable = AnnotationLocator.locate(
092                                    method, _targetObject.getClass(), Clusterable.class);
093    
094                            if (clusterable == null) {
095                                    clusterable = NullClusterable.NULL_CLUSTERABLE;
096                            }
097    
098                            _clusterables.put(methodKey, clusterable);
099    
100                            return clusterable;
101                    }
102    
103                    private static final Map<MethodKey, Clusterable> _clusterables =
104                            new ConcurrentHashMap<>();
105    
106                    private final T _targetObject;
107    
108            }
109    
110    }