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