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