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