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.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
018    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
019    import com.liferay.portal.kernel.dao.orm.Property;
020    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.util.AutoResetThreadLocal;
024    import com.liferay.portal.kernel.util.ListUtil;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
027    import com.liferay.portal.model.Group;
028    import com.liferay.portal.model.GroupConstants;
029    import com.liferay.portal.model.Layout;
030    import com.liferay.portal.model.LayoutConstants;
031    import com.liferay.portal.model.LayoutSet;
032    import com.liferay.portal.model.UserGroup;
033    import com.liferay.portal.model.impl.VirtualLayout;
034    import com.liferay.portal.service.GroupLocalServiceUtil;
035    import com.liferay.portal.service.LayoutLocalServiceUtil;
036    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
037    import com.liferay.portal.service.UserGroupLocalServiceUtil;
038    import com.liferay.portal.util.PropsValues;
039    import com.liferay.portlet.exportimport.staging.MergeLayoutPrototypesThreadLocal;
040    import com.liferay.sites.kernel.util.SitesUtil;
041    
042    import java.lang.reflect.Method;
043    
044    import java.util.ArrayList;
045    import java.util.Arrays;
046    import java.util.List;
047    
048    import org.aopalliance.intercept.MethodInterceptor;
049    import org.aopalliance.intercept.MethodInvocation;
050    
051    import org.springframework.core.annotation.Order;
052    
053    /**
054     * @author Raymond Aug??
055     * @author Jorge Ferrer
056     */
057    @Order(2)
058    public class LayoutLocalServiceVirtualLayoutsAdvice
059            implements MethodInterceptor {
060    
061            @Override
062            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
063                    if (MergeLayoutPrototypesThreadLocal.isInProgress()) {
064                            return methodInvocation.proceed();
065                    }
066    
067                    Method method = methodInvocation.getMethod();
068    
069                    String methodName = method.getName();
070                    Class<?>[] parameterTypes = method.getParameterTypes();
071    
072                    Object[] arguments = methodInvocation.getArguments();
073    
074                    boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
075    
076                    if (methodName.equals("getLayout") &&
077                            (Arrays.equals(parameterTypes, _TYPES_L) ||
078                             Arrays.equals(parameterTypes, _TYPES_L_B_L))) {
079    
080                            Layout layout = (Layout)methodInvocation.proceed();
081    
082                            Group group = layout.getGroup();
083    
084                            if (isMergeComplete(method, arguments, group)) {
085                                    return layout;
086                            }
087    
088                            if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
089                                    Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
090    
091                                    return layout;
092                            }
093    
094                            LayoutSet layoutSet = layout.getLayoutSet();
095    
096                            try {
097                                    WorkflowThreadLocal.setEnabled(false);
098    
099                                    SitesUtil.mergeLayoutPrototypeLayout(group, layout);
100    
101                                    if (Validator.isNotNull(
102                                                    layout.getSourcePrototypeLayoutUuid())) {
103    
104                                            SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
105                                    }
106                            }
107                            finally {
108                                    MergeLayoutPrototypesThreadLocal.setMergeComplete(
109                                            method, arguments);
110                                    WorkflowThreadLocal.setEnabled(workflowEnabled);
111                            }
112                    }
113                    else if (methodName.equals("getLayouts") &&
114                                     (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
115                                      Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
116    
117                            long groupId = (Long)arguments[0];
118    
119                            Group group = GroupLocalServiceUtil.getGroup(groupId);
120    
121                            if (isMergeComplete(method, arguments, group)) {
122                                    return methodInvocation.proceed();
123                            }
124    
125                            boolean privateLayout = (Boolean)arguments[1];
126                            long parentLayoutId = (Long)arguments[2];
127    
128                            try {
129                                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
130                                            groupId, privateLayout);
131    
132                                    mergeLayoutSetPrototypeLayouts(
133                                            method, arguments, group, layoutSet, privateLayout,
134                                            workflowEnabled);
135    
136                                    List<Layout> layouts = (List<Layout>)methodInvocation.proceed();
137    
138                                    if (PropsValues.
139                                                    USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
140    
141                                            return layouts;
142                                    }
143    
144                                    if (group.isUser()) {
145                                            _virtualLayoutTargetGroupId.set(group.getGroupId());
146    
147                                            if (parentLayoutId ==
148                                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
149    
150                                                    return addUserGroupLayouts(
151                                                            group, layoutSet, layouts, parentLayoutId);
152                                            }
153                                            else {
154                                                    return addChildUserGroupLayouts(group, layouts);
155                                            }
156                                    }
157                                    else if (group.isUserGroup() &&
158                                                     (parentLayoutId !=
159                                                             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
160    
161                                            long targetGroupId = _virtualLayoutTargetGroupId.get();
162    
163                                            if (targetGroupId != GroupConstants.DEFAULT_LIVE_GROUP_ID) {
164                                                    Group targetGroup = GroupLocalServiceUtil.getGroup(
165                                                            targetGroupId);
166    
167                                                    return addChildUserGroupLayouts(targetGroup, layouts);
168                                            }
169                                    }
170    
171                                    return layouts;
172                            }
173                            catch (Exception e) {
174                                    _log.error(e, e);
175    
176                                    throw e;
177                            }
178                    }
179    
180                    return methodInvocation.proceed();
181            }
182    
183            protected List<Layout> addChildUserGroupLayouts(
184                            Group group, List<Layout> layouts)
185                    throws Exception {
186    
187                    layouts = ListUtil.copy(layouts);
188    
189                    List<Layout> childLayouts = new ArrayList<>();
190    
191                    for (Layout layout : layouts) {
192                            Layout childLayout = layout;
193    
194                            Group layoutGroup = layout.getGroup();
195    
196                            if (layoutGroup.isUserGroup()) {
197                                    childLayout = new VirtualLayout(layout, group);
198                            }
199    
200                            childLayouts.add(childLayout);
201                    }
202    
203                    return childLayouts;
204            }
205    
206            protected List<Layout> addUserGroupLayouts(
207                            Group group, LayoutSet layoutSet, List<Layout> layouts,
208                            long parentLayoutId)
209                    throws Exception {
210    
211                    layouts = ListUtil.copy(layouts);
212    
213                    List<UserGroup> userUserGroups =
214                            UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
215    
216                    for (UserGroup userGroup : userUserGroups) {
217                            Group userGroupGroup = userGroup.getGroup();
218    
219                            List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
220                                    userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(),
221                                    parentLayoutId);
222    
223                            for (Layout userGroupLayout : userGroupLayouts) {
224                                    Layout virtualLayout = new VirtualLayout(
225                                            userGroupLayout, group);
226    
227                                    layouts.add(virtualLayout);
228                            }
229                    }
230    
231                    return layouts;
232            }
233    
234            protected List<Layout> getPrototypeLinkedLayouts(
235                    long groupId, boolean privateLayout) {
236    
237                    Class<?> clazz = getClass();
238    
239                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
240                            Layout.class, clazz.getClassLoader());
241    
242                    Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
243    
244                    dynamicQuery.add(groupIdProperty.eq(groupId));
245    
246                    Property layoutPrototypeUuidProperty = PropertyFactoryUtil.forName(
247                            "layoutPrototypeUuid");
248    
249                    dynamicQuery.add(layoutPrototypeUuidProperty.isNotNull());
250    
251                    Property privateLayoutProperty = PropertyFactoryUtil.forName(
252                            "privateLayout");
253    
254                    dynamicQuery.add(privateLayoutProperty.eq(privateLayout));
255    
256                    Property sourcePrototypeLayoutUuidProperty =
257                            PropertyFactoryUtil.forName("sourcePrototypeLayoutUuid");
258    
259                    dynamicQuery.add(sourcePrototypeLayoutUuidProperty.isNotNull());
260    
261                    return LayoutLocalServiceUtil.dynamicQuery(dynamicQuery);
262            }
263    
264            protected boolean isMergeComplete(
265                    Method method, Object[] arguments, Group group) {
266    
267                    if (MergeLayoutPrototypesThreadLocal.isMergeComplete(
268                                    method, arguments) &&
269                            (!group.isUser() ||
270                             PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE)) {
271    
272                            return true;
273                    }
274                    else {
275                            return false;
276                    }
277            }
278    
279            protected void mergeLayoutSetPrototypeLayouts(
280                    Method method, Object[] arguments, Group group, LayoutSet layoutSet,
281                    boolean privateLayout, boolean workflowEnabled) {
282    
283                    try {
284                            if (!SitesUtil.isLayoutSetMergeable(group, layoutSet)) {
285                                    return;
286                            }
287    
288                            WorkflowThreadLocal.setEnabled(false);
289    
290                            SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
291                    }
292                    catch (Exception e) {
293                            if (_log.isWarnEnabled()) {
294                                    _log.warn("Unable to merge layouts for site template", e);
295                            }
296                    }
297                    finally {
298                            MergeLayoutPrototypesThreadLocal.setMergeComplete(
299                                    method, arguments);
300                            WorkflowThreadLocal.setEnabled(workflowEnabled);
301                    }
302            }
303    
304            private static final Class<?>[] _TYPES_L = {Long.TYPE};
305    
306            private static final Class<?>[] _TYPES_L_B_L = {
307                    Long.TYPE, Boolean.TYPE, Long.TYPE
308            };
309    
310            private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
311                    Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
312                    Integer.TYPE
313            };
314    
315            private static final Log _log = LogFactoryUtil.getLog(
316                    LayoutLocalServiceVirtualLayoutsAdvice.class);
317    
318            private static final ThreadLocal<Long> _virtualLayoutTargetGroupId =
319                    new AutoResetThreadLocal<Long>(
320                            LayoutLocalServiceVirtualLayoutsAdvice.class +
321                                    "._virtualLayoutTargetGroupId",
322                            GroupConstants.DEFAULT_LIVE_GROUP_ID);
323    
324    }