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                    Class<?>[] parameterTypes = method.getParameterTypes();
072    
073                    Object[] arguments = methodInvocation.getArguments();
074    
075                    boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
076    
077                    if (methodName.equals("getLayout") &&
078                            (Arrays.equals(parameterTypes, _TYPES_L) ||
079                             Arrays.equals(parameterTypes, _TYPES_L_B_L))) {
080    
081                            Layout layout = (Layout)methodInvocation.proceed();
082    
083                            Group group = layout.getGroup();
084    
085                            if (isMergeComplete(method, arguments, group)) {
086                                    return layout;
087                            }
088    
089                            if ((Validator.isNull(layout.getLayoutPrototypeUuid()) &&
090                                     Validator.isNull(layout.getSourcePrototypeLayoutUuid())) ||
091                                    !layout.getLayoutPrototypeLinkEnabled()) {
092    
093                                    return layout;
094                            }
095    
096                            LayoutSet layoutSet = layout.getLayoutSet();
097    
098                            try {
099                                    MergeLayoutPrototypesThreadLocal.setInProgress(true);
100                                    WorkflowThreadLocal.setEnabled(false);
101    
102                                    SitesUtil.mergeLayoutPrototypeLayout(group, layout);
103    
104                                    if (Validator.isNotNull(
105                                                    layout.getSourcePrototypeLayoutUuid())) {
106    
107                                            SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
108                                    }
109                            }
110                            finally {
111                                    MergeLayoutPrototypesThreadLocal.setMergeComplete(
112                                            method, arguments);
113                                    WorkflowThreadLocal.setEnabled(workflowEnabled);
114                            }
115                    }
116                    else if (methodName.equals("getLayouts") &&
117                                     (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
118                                      Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
119    
120                            long groupId = (Long)arguments[0];
121    
122                            Group group = GroupLocalServiceUtil.getGroup(groupId);
123    
124                            if (isMergeComplete(method, arguments, group)) {
125                                    return methodInvocation.proceed();
126                            }
127    
128                            boolean privateLayout = (Boolean)arguments[1];
129                            long parentLayoutId = (Long)arguments[2];
130    
131                            try {
132                                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
133                                            groupId, privateLayout);
134    
135                                    mergeLayoutSetPrototypeLayouts(
136                                            method, arguments, group, layoutSet, privateLayout,
137                                            workflowEnabled);
138    
139                                    List<Layout> layouts = (List<Layout>)methodInvocation.proceed();
140    
141                                    if (PropsValues.
142                                                    USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
143    
144                                            return layouts;
145                                    }
146    
147                                    if (group.isUser()) {
148                                            _virtualLayoutTargetGroupId.set(group.getGroupId());
149    
150                                            if (parentLayoutId ==
151                                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
152    
153                                                    return addUserGroupLayouts(
154                                                            group, layoutSet, layouts, parentLayoutId);
155                                            }
156                                            else {
157                                                    return addChildUserGroupLayouts(group, layouts);
158                                            }
159                                    }
160                                    else if (group.isUserGroup() &&
161                                                     (parentLayoutId !=
162                                                             LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
163    
164                                            long targetGroupId = _virtualLayoutTargetGroupId.get();
165    
166                                            if (targetGroupId != GroupConstants.DEFAULT_LIVE_GROUP_ID) {
167                                                    Group targetGroup = GroupLocalServiceUtil.getGroup(
168                                                            targetGroupId);
169    
170                                                    return addChildUserGroupLayouts(targetGroup, layouts);
171                                            }
172                                    }
173    
174                                    return layouts;
175                            }
176                            catch (Exception e) {
177                                    _log.error(e, e);
178    
179                                    throw e;
180                            }
181                    }
182    
183                    return methodInvocation.proceed();
184            }
185    
186            protected List<Layout> addChildUserGroupLayouts(
187                            Group group, List<Layout> layouts)
188                    throws Exception {
189    
190                    layouts = ListUtil.copy(layouts);
191    
192                    List<Layout> childLayouts = new ArrayList<Layout>();
193    
194                    for (Layout layout : layouts) {
195                            Layout childLayout = layout;
196    
197                            Group layoutGroup = layout.getGroup();
198    
199                            if (layoutGroup.isUserGroup()) {
200                                    childLayout = new VirtualLayout(layout, group);
201                            }
202    
203                            childLayouts.add(childLayout);
204                    }
205    
206                    return childLayouts;
207            }
208    
209            protected List<Layout> addUserGroupLayouts(
210                            Group group, LayoutSet layoutSet, List<Layout> layouts,
211                            long parentLayoutId)
212                    throws Exception {
213    
214                    layouts = ListUtil.copy(layouts);
215    
216                    List<UserGroup> userUserGroups =
217                            UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
218    
219                    for (UserGroup userGroup : userUserGroups) {
220                            Group userGroupGroup = userGroup.getGroup();
221    
222                            List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
223                                    userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(),
224                                    parentLayoutId);
225    
226                            for (Layout userGroupLayout : userGroupLayouts) {
227                                    Layout virtualLayout = new VirtualLayout(
228                                            userGroupLayout, group);
229    
230                                    layouts.add(virtualLayout);
231                            }
232                    }
233    
234                    return layouts;
235            }
236    
237            protected List<Layout> getPrototypeLinkedLayouts(
238                            long groupId, boolean privateLayout)
239                    throws SystemException {
240    
241                    Class<?> clazz = getClass();
242    
243                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
244                            Layout.class, clazz.getClassLoader());
245    
246                    Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
247    
248                    dynamicQuery.add(groupIdProperty.eq(groupId));
249    
250                    Property layoutPrototypeUuidProperty = PropertyFactoryUtil.forName(
251                            "layoutPrototypeUuid");
252    
253                    dynamicQuery.add(layoutPrototypeUuidProperty.isNotNull());
254    
255                    Property privateLayoutProperty = PropertyFactoryUtil.forName(
256                            "privateLayout");
257    
258                    dynamicQuery.add(privateLayoutProperty.eq(privateLayout));
259    
260                    Property sourcePrototypeLayoutUuidProperty =
261                            PropertyFactoryUtil.forName("sourcePrototypeLayoutUuid");
262    
263                    dynamicQuery.add(sourcePrototypeLayoutUuidProperty.isNotNull());
264    
265                    return LayoutLocalServiceUtil.dynamicQuery(dynamicQuery);
266            }
267    
268            protected boolean isMergeComplete(
269                    Method method, Object[] arguments, Group group) {
270    
271                    if (MergeLayoutPrototypesThreadLocal.isMergeComplete(
272                                    method, arguments) &&
273                            (!group.isUser() ||
274                             PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE)) {
275    
276                            return true;
277                    }
278                    else {
279                            return false;
280                    }
281            }
282    
283            protected void mergeLayoutSetPrototypeLayouts(
284                    Method method, Object[] arguments, Group group, LayoutSet layoutSet,
285                    boolean privateLayout, boolean workflowEnabled) {
286    
287                    try {
288                            if (!SitesUtil.isLayoutSetMergeable(group, layoutSet)) {
289                                    return;
290                            }
291    
292                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
293                            WorkflowThreadLocal.setEnabled(false);
294    
295                            SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
296                    }
297                    catch (Exception e) {
298                            if (_log.isWarnEnabled()) {
299                                    _log.warn("Unable to merge layouts for site template", e);
300                            }
301                    }
302                    finally {
303                            MergeLayoutPrototypesThreadLocal.setMergeComplete(
304                                    method, arguments);
305                            WorkflowThreadLocal.setEnabled(workflowEnabled);
306                    }
307            }
308    
309            private static final Class<?>[] _TYPES_L = {Long.TYPE};
310    
311            private static final Class<?>[] _TYPES_L_B_L = {
312                    Long.TYPE, Boolean.TYPE, Long.TYPE
313            };
314    
315            private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
316                    Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
317                    Integer.TYPE
318            };
319    
320            private static Log _log = LogFactoryUtil.getLog(
321                    LayoutLocalServiceVirtualLayoutsAdvice.class);
322    
323            private static ThreadLocal<Long> _virtualLayoutTargetGroupId =
324                    new AutoResetThreadLocal<Long>(
325                            LayoutLocalServiceVirtualLayoutsAdvice.class +
326                                    "._virtualLayoutTargetGroupId",
327                            GroupConstants.DEFAULT_LIVE_GROUP_ID);
328    
329    }