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                                            else {
133                                                    boolean modified = false;
134    
135                                                    for (Layout layout : layouts) {
136                                                            if (SitesUtil.isLayoutModifiedSinceLastMerge(
137                                                                            layout)) {
138    
139                                                                    modified = true;
140    
141                                                                    break;
142                                                            }
143                                                    }
144    
145                                                    if (!modified) {
146                                                            SitesUtil.mergeLayoutSetProtypeLayouts(
147                                                                    group, layoutSet);
148                                                    }
149                                            }
150                                    }
151                                    finally {
152                                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
153                                            WorkflowThreadLocal.setEnabled(workflowEnabled);
154                                    }
155    
156                                    List<Layout> layouts = (List<Layout>)methodInvocation.proceed();
157    
158                                    if (PropsValues.
159                                                    USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
160    
161                                            return layouts;
162                                    }
163    
164                                    if (group.isUser()) {
165                                            _virtualLayoutTargetGroupId.set(group.getGroupId());
166    
167                                            if (parentLayoutId ==
168                                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
169    
170                                                    return addUserGroupLayouts(
171                                                            group, layoutSet, layouts, parentLayoutId);
172                                            }
173                                            else {
174                                                    return addChildUserGroupLayouts(group, layouts);
175                                            }
176                                    }
177                                    else if (group.isUserGroup() &&
178                                                     (parentLayoutId !=
179                                                             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
180    
181                                            long targetGroupId = _virtualLayoutTargetGroupId.get();
182    
183                                            if (targetGroupId != GroupConstants.DEFAULT_LIVE_GROUP_ID) {
184                                                    Group targetGroup = GroupLocalServiceUtil.getGroup(
185                                                            targetGroupId);
186    
187                                                    return addChildUserGroupLayouts(targetGroup, layouts);
188                                            }
189                                    }
190    
191                                    return layouts;
192                            }
193                            catch (Exception e) {
194                                    _log.error(e, e);
195    
196                                    throw e;
197                            }
198                    }
199    
200                    return methodInvocation.proceed();
201            }
202    
203            protected List<Layout> addChildUserGroupLayouts(
204                            Group group, List<Layout> layouts)
205                    throws Exception {
206    
207                    layouts = ListUtil.copy(layouts);
208    
209                    List<Layout> childLayouts = new ArrayList<Layout>();
210    
211                    for (Layout layout : layouts) {
212                            Layout childLayout = layout;
213    
214                            Group layoutGroup = layout.getGroup();
215    
216                            if (layoutGroup.isUserGroup()) {
217                                    childLayout = new VirtualLayout(layout, group);
218                            }
219    
220                            childLayouts.add(childLayout);
221                    }
222    
223                    return childLayouts;
224            }
225    
226            protected List<Layout> addUserGroupLayouts(
227                            Group group, LayoutSet layoutSet, List<Layout> layouts,
228                            long parentLayoutId)
229                    throws Exception {
230    
231                    layouts = ListUtil.copy(layouts);
232    
233                    List<UserGroup> userUserGroups =
234                            UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
235    
236                    for (UserGroup userGroup : userUserGroups) {
237                            Group userGroupGroup = userGroup.getGroup();
238    
239                            List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
240                                    userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(),
241                                    parentLayoutId);
242    
243                            for (Layout userGroupLayout : userGroupLayouts) {
244                                    Layout virtualLayout = new VirtualLayout(
245                                            userGroupLayout, group);
246    
247                                    layouts.add(virtualLayout);
248                            }
249                    }
250    
251                    return layouts;
252            }
253    
254            private static final Class<?>[] _TYPES_L = {Long.TYPE};
255    
256            private static final Class<?>[] _TYPES_L_B_L = {
257                    Long.TYPE, Boolean.TYPE, Long.TYPE
258            };
259    
260            private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
261                    Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
262                    Integer.TYPE
263            };
264    
265            private static Log _log = LogFactoryUtil.getLog(
266                    LayoutLocalServiceVirtualLayoutsAdvice.class);
267    
268            private static ThreadLocal<Long> _virtualLayoutTargetGroupId =
269                    new AutoResetThreadLocal<Long>(
270                            LayoutLocalServiceVirtualLayoutsAdvice.class +
271                                    "._virtualLayoutTargetGroupId",
272                            GroupConstants.DEFAULT_LIVE_GROUP_ID);
273    
274    }