001    /**
002     * Copyright (c) 2000-2012 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            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
058                    if (MergeLayoutPrototypesThreadLocal.isInProgress()) {
059                            return methodInvocation.proceed();
060                    }
061    
062                    Method method = methodInvocation.getMethod();
063    
064                    String methodName = method.getName();
065    
066                    Object[] arguments = methodInvocation.getArguments();
067    
068                    Class<?>[] parameterTypes = method.getParameterTypes();
069    
070                    boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
071    
072                    if (methodName.equals("getLayout") &&
073                            (Arrays.equals(parameterTypes, _TYPES_L) ||
074                             Arrays.equals(parameterTypes, _TYPES_L_B_L))) {
075    
076                            Layout layout = (Layout)methodInvocation.proceed();
077    
078                            if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
079                                    Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
080    
081                                    return layout;
082                            }
083    
084                            Group group = layout.getGroup();
085                            LayoutSet layoutSet = layout.getLayoutSet();
086    
087                            try {
088                                    MergeLayoutPrototypesThreadLocal.setInProgress(true);
089                                    WorkflowThreadLocal.setEnabled(false);
090    
091                                    SitesUtil.mergeLayoutProtypeLayout(group, layout);
092    
093                                    if (Validator.isNotNull(
094                                                    layout.getSourcePrototypeLayoutUuid())) {
095    
096                                            if (!SitesUtil.isLayoutModifiedSinceLastMerge(layout)) {
097                                                    SitesUtil.mergeLayoutSetProtypeLayouts(
098                                                            group, layoutSet);
099                                            }
100                                    }
101                            }
102                            finally {
103                                    MergeLayoutPrototypesThreadLocal.setInProgress(false);
104                                    WorkflowThreadLocal.setEnabled(workflowEnabled);
105                            }
106                    }
107                    else if (methodName.equals("getLayouts") &&
108                                     (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
109                                      Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
110    
111                            long groupId = (Long)arguments[0];
112                            boolean privateLayout = (Boolean)arguments[1];
113                            long parentLayoutId = (Long)arguments[2];
114    
115                            try {
116                                    Group group = GroupLocalServiceUtil.getGroup(groupId);
117    
118                                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
119                                            groupId, privateLayout);
120    
121                                    try {
122                                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
123                                            WorkflowThreadLocal.setEnabled(false);
124    
125                                            List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
126                                                    groupId, privateLayout);
127    
128                                            if (layouts.isEmpty()) {
129                                                    SitesUtil.mergeLayoutSetProtypeLayouts(
130                                                            group, layoutSet);
131                                            }
132    
133                                            boolean modified = false;
134    
135                                            for (Layout layout : layouts) {
136                                                    if (SitesUtil.isLayoutModifiedSinceLastMerge(layout)) {
137                                                            modified = true;
138    
139                                                            break;
140                                                    }
141                                            }
142    
143                                            if (!modified) {
144                                                    SitesUtil.mergeLayoutSetProtypeLayouts(
145                                                            group, layoutSet);
146                                            }
147                                    }
148                                    finally {
149                                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
150                                            WorkflowThreadLocal.setEnabled(workflowEnabled);
151                                    }
152    
153                                    List<Layout> layouts = (List<Layout>)methodInvocation.proceed();
154    
155                                    if (PropsValues.
156                                                    USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
157    
158                                            return layouts;
159                                    }
160    
161                                    if (group.isUser()) {
162                                            _virtualLayoutTargetGroupId.set(group.getGroupId());
163    
164                                            if (parentLayoutId ==
165                                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
166    
167                                                    return addUserGroupLayouts(
168                                                            group, layoutSet, layouts, parentLayoutId);
169                                            }
170                                            else {
171                                                    return addChildUserGroupLayouts(group, layouts);
172                                            }
173                                    }
174                                    else if (group.isUserGroup() &&
175                                                     (parentLayoutId !=
176                                                             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
177    
178                                            long targetGroupId = _virtualLayoutTargetGroupId.get();
179    
180                                            if (targetGroupId != GroupConstants.DEFAULT_LIVE_GROUP_ID) {
181                                                    Group targetGroup = GroupLocalServiceUtil.getGroup(
182                                                            targetGroupId);
183    
184                                                    return addChildUserGroupLayouts(targetGroup, layouts);
185                                            }
186                                    }
187    
188                                    return layouts;
189                            }
190                            catch (Exception e) {
191                                    _log.error(e, e);
192    
193                                    throw e;
194                            }
195                    }
196    
197                    return methodInvocation.proceed();
198            }
199    
200            protected List<Layout> addChildUserGroupLayouts(
201                            Group group, List<Layout> layouts)
202                    throws Exception {
203    
204                    layouts = ListUtil.copy(layouts);
205    
206                    List<Layout> childLayouts = new ArrayList<Layout>();
207    
208                    for (Layout layout : layouts) {
209                            Layout childLayout = layout;
210    
211                            Group layoutGroup = layout.getGroup();
212    
213                            if (layoutGroup.isUserGroup()) {
214                                    childLayout = new VirtualLayout(layout, group);
215                            }
216    
217                            childLayouts.add(childLayout);
218                    }
219    
220                    return childLayouts;
221            }
222    
223            protected List<Layout> addUserGroupLayouts(
224                            Group group, LayoutSet layoutSet, List<Layout> layouts,
225                            long parentLayoutId)
226                    throws Exception {
227    
228                    layouts = ListUtil.copy(layouts);
229    
230                    List<UserGroup> userUserGroups =
231                            UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
232    
233                    for (UserGroup userGroup : userUserGroups) {
234                            Group userGroupGroup = userGroup.getGroup();
235    
236                            List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
237                                    userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(),
238                                    parentLayoutId);
239    
240                            for (Layout userGroupLayout : userGroupLayouts) {
241                                    Layout virtualLayout = new VirtualLayout(
242                                            userGroupLayout, group);
243    
244                                    layouts.add(virtualLayout);
245                            }
246                    }
247    
248                    return layouts;
249            }
250    
251            private static final Class<?>[] _TYPES_L = {Long.TYPE};
252    
253            private static final Class<?>[] _TYPES_L_B_L = {
254                    Long.TYPE, Boolean.TYPE, Long.TYPE
255            };
256    
257            private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
258                    Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
259                    Integer.TYPE
260            };
261    
262            private static Log _log = LogFactoryUtil.getLog(
263                    LayoutLocalServiceVirtualLayoutsAdvice.class);
264    
265            private static ThreadLocal<Long> _virtualLayoutTargetGroupId =
266                    new AutoResetThreadLocal<Long>(
267                            LayoutLocalServiceVirtualLayoutsAdvice.class +
268                                    "._virtualLayoutTargetGroupId",
269                            GroupConstants.DEFAULT_LIVE_GROUP_ID);
270    
271    }