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