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.module.framework.service.IdentifiableOSGiServiceInvokerUtil;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.GroupThreadLocal;
020    import com.liferay.portal.kernel.util.LocaleThreadLocal;
021    import com.liferay.portal.kernel.util.MethodHandler;
022    import com.liferay.portal.kernel.util.MethodKey;
023    import com.liferay.portal.kernel.util.PropsKeys;
024    import com.liferay.portal.kernel.util.PropsUtil;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.model.User;
027    import com.liferay.portal.security.auth.CompanyThreadLocal;
028    import com.liferay.portal.security.auth.PrincipalThreadLocal;
029    import com.liferay.portal.security.permission.PermissionChecker;
030    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
031    import com.liferay.portal.security.permission.PermissionThreadLocal;
032    import com.liferay.portal.service.UserLocalServiceUtil;
033    
034    import java.io.Serializable;
035    
036    import java.lang.reflect.Method;
037    
038    import java.util.Locale;
039    import java.util.Map;
040    import java.util.concurrent.Future;
041    import java.util.concurrent.TimeUnit;
042    
043    /**
044     * @author Shuyang Zhou
045     */
046    public class ClusterableInvokerUtil {
047    
048            public static MethodHandler createMethodHandler(
049                    Class<? extends ClusterInvokeAcceptor> clusterInvokeAcceptorClass,
050                    Object targetObject, Method method, Object[] arguments) {
051    
052                    MethodHandler methodHandler =
053                            IdentifiableOSGiServiceInvokerUtil.createMethodHandler(
054                                    targetObject, method, arguments);
055    
056                    Map<String, Serializable> context =
057                            ClusterableContextThreadLocal.collectThreadLocalContext();
058    
059                    _populateContextFromThreadLocals(context);
060    
061                    String clusterInvokeAcceptorClassName =
062                            clusterInvokeAcceptorClass.getName();
063    
064                    if (clusterInvokeAcceptorClass == ClusterInvokeAcceptor.class) {
065                            clusterInvokeAcceptorClassName = null;
066                    }
067    
068                    return new MethodHandler(
069                            _invokeMethodKey, methodHandler, clusterInvokeAcceptorClassName,
070                            context);
071            }
072    
073            public static void invokeOnCluster(
074                            Class<? extends ClusterInvokeAcceptor> clusterInvokeAcceptorClass,
075                            Object targetObject, Method method, Object[] arguments)
076                    throws Throwable {
077    
078                    MethodHandler methodHandler = createMethodHandler(
079                            clusterInvokeAcceptorClass, targetObject, method, arguments);
080    
081                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
082                            methodHandler, true);
083    
084                    clusterRequest.setFireAndForget(true);
085    
086                    ClusterExecutorUtil.execute(clusterRequest);
087            }
088    
089            public static Object invokeOnMaster(
090                            Class<? extends ClusterInvokeAcceptor> clusterInvokeAcceptorClass,
091                            Object targetObject, Method method, Object[] arguments)
092                    throws Throwable {
093    
094                    MethodHandler methodHandler = createMethodHandler(
095                            clusterInvokeAcceptorClass, targetObject, method, arguments);
096    
097                    Future<Object> futureResult = ClusterMasterExecutorUtil.executeOnMaster(
098                            methodHandler);
099    
100                    return futureResult.get(
101                            _CLUSTERABLE_ADVICE_CALL_MASTER_TIMEOUT, TimeUnit.SECONDS);
102            }
103    
104            @SuppressWarnings("unused")
105            private static Object _invoke(
106                            MethodHandler methodHandler, String clusterInvokeAcceptorClassName,
107                            Map<String, Serializable> context)
108                    throws Exception {
109    
110                    if (Validator.isNotNull(clusterInvokeAcceptorClassName)) {
111                            ClusterInvokeAcceptor clusterInvokeAcceptor =
112                                    ClusterInvokeAcceptorUtil.getClusterInvokeAcceptor(
113                                            clusterInvokeAcceptorClassName);
114    
115                            if (!clusterInvokeAcceptor.accept(context)) {
116                                    return null;
117                            }
118                    }
119    
120                    _populateThreadLocalsFromContext(context);
121    
122                    return methodHandler.invoke();
123            }
124    
125            private static void _populateContextFromThreadLocals(
126                    Map<String, Serializable> context) {
127    
128                    if (!context.containsKey("companyId")) {
129                            context.put("companyId", CompanyThreadLocal.getCompanyId());
130                    }
131    
132                    if (!context.containsKey("defaultLocale")) {
133                            context.put("defaultLocale", LocaleThreadLocal.getDefaultLocale());
134                    }
135    
136                    if (!context.containsKey("groupId")) {
137                            context.put("groupId", GroupThreadLocal.getGroupId());
138                    }
139    
140                    if (!context.containsKey("principalName")) {
141                            context.put("principalName", PrincipalThreadLocal.getName());
142                    }
143    
144                    if (!context.containsKey("principalPassword")) {
145                            context.put(
146                                    "principalPassword", PrincipalThreadLocal.getPassword());
147                    }
148    
149                    if (!context.containsKey("siteDefaultLocale")) {
150                            context.put(
151                                    "siteDefaultLocale", LocaleThreadLocal.getSiteDefaultLocale());
152                    }
153    
154                    if (!context.containsKey("themeDisplayLocale")) {
155                            context.put(
156                                    "themeDisplayLocale",
157                                    LocaleThreadLocal.getThemeDisplayLocale());
158                    }
159            }
160    
161            private static void _populateThreadLocalsFromContext(
162                    Map<String, Serializable> context) {
163    
164                    long companyId = GetterUtil.getLong(context.get("companyId"));
165    
166                    if (companyId > 0) {
167                            CompanyThreadLocal.setCompanyId(companyId);
168                    }
169    
170                    Locale defaultLocale = (Locale)context.get("defaultLocale");
171    
172                    if (defaultLocale != null) {
173                            LocaleThreadLocal.setDefaultLocale(defaultLocale);
174                    }
175    
176                    long groupId = GetterUtil.getLong(context.get("groupId"));
177    
178                    if (groupId > 0) {
179                            GroupThreadLocal.setGroupId(groupId);
180                    }
181    
182                    String principalName = GetterUtil.getString(
183                            context.get("principalName"));
184    
185                    if (Validator.isNotNull(principalName)) {
186                            PrincipalThreadLocal.setName(principalName);
187                    }
188    
189                    PermissionChecker permissionChecker = null;
190    
191                    if (Validator.isNotNull(principalName)) {
192                            try {
193                                    User user = UserLocalServiceUtil.fetchUser(
194                                            PrincipalThreadLocal.getUserId());
195    
196                                    permissionChecker = PermissionCheckerFactoryUtil.create(user);
197                            }
198                            catch (Exception e) {
199                                    throw new RuntimeException(e);
200                            }
201                    }
202    
203                    if (permissionChecker != null) {
204                            PermissionThreadLocal.setPermissionChecker(permissionChecker);
205                    }
206    
207                    String principalPassword = GetterUtil.getString(
208                            context.get("principalPassword"));
209    
210                    if (Validator.isNotNull(principalPassword)) {
211                            PrincipalThreadLocal.setPassword(principalPassword);
212                    }
213    
214                    Locale siteDefaultLocale = (Locale)context.get("siteDefaultLocale");
215    
216                    if (siteDefaultLocale != null) {
217                            LocaleThreadLocal.setSiteDefaultLocale(siteDefaultLocale);
218                    }
219    
220                    Locale themeDisplayLocale = (Locale)context.get("themeDisplayLocale");
221    
222                    if (themeDisplayLocale != null) {
223                            LocaleThreadLocal.setThemeDisplayLocale(themeDisplayLocale);
224                    }
225            }
226    
227            private static final long _CLUSTERABLE_ADVICE_CALL_MASTER_TIMEOUT =
228                    GetterUtil.getLong(
229                            PropsUtil.get(PropsKeys.CLUSTERABLE_ADVICE_CALL_MASTER_TIMEOUT));
230    
231            private static final MethodKey _invokeMethodKey = new MethodKey(
232                    ClusterableInvokerUtil.class, "_invoke", MethodHandler.class,
233                    String.class, Map.class);
234    
235    }