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.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.staging.MergeLayoutPrototypesThreadLocal;
024 import com.liferay.portal.kernel.util.AutoResetThreadLocal;
025 import com.liferay.portal.kernel.util.ListUtil;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
028 import com.liferay.portal.model.Group;
029 import com.liferay.portal.model.GroupConstants;
030 import com.liferay.portal.model.Layout;
031 import com.liferay.portal.model.LayoutConstants;
032 import com.liferay.portal.model.LayoutSet;
033 import com.liferay.portal.model.UserGroup;
034 import com.liferay.portal.model.impl.VirtualLayout;
035 import com.liferay.portal.service.GroupLocalServiceUtil;
036 import com.liferay.portal.service.LayoutLocalServiceUtil;
037 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
038 import com.liferay.portal.service.UserGroupLocalServiceUtil;
039 import com.liferay.portal.util.PropsValues;
040 import com.liferay.portlet.sites.util.SitesUtil;
041
042 import java.lang.reflect.Method;
043
044 import java.util.ArrayList;
045 import java.util.Arrays;
046 import java.util.List;
047
048 import org.aopalliance.intercept.MethodInterceptor;
049 import org.aopalliance.intercept.MethodInvocation;
050
051 import org.springframework.core.annotation.Order;
052
053
057 @Order(2)
058 public class LayoutLocalServiceVirtualLayoutsAdvice
059 implements MethodInterceptor {
060
061 @Override
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 Class<?>[] parameterTypes = method.getParameterTypes();
071
072 Object[] arguments = methodInvocation.getArguments();
073
074 boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
075
076 if (methodName.equals("getLayout") &&
077 (Arrays.equals(parameterTypes, _TYPES_L) ||
078 Arrays.equals(parameterTypes, _TYPES_L_B_L))) {
079
080 Layout layout = (Layout)methodInvocation.proceed();
081
082 Group group = layout.getGroup();
083
084 if (isMergeComplete(method, arguments, group)) {
085 return layout;
086 }
087
088 if ((Validator.isNull(layout.getLayoutPrototypeUuid()) &&
089 Validator.isNull(layout.getSourcePrototypeLayoutUuid())) ||
090 !layout.getLayoutPrototypeLinkEnabled()) {
091
092 return layout;
093 }
094
095 LayoutSet layoutSet = layout.getLayoutSet();
096
097 try {
098 WorkflowThreadLocal.setEnabled(false);
099
100 SitesUtil.mergeLayoutPrototypeLayout(group, layout);
101
102 if (Validator.isNotNull(
103 layout.getSourcePrototypeLayoutUuid())) {
104
105 SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
106 }
107 }
108 finally {
109 MergeLayoutPrototypesThreadLocal.setMergeComplete(
110 method, arguments);
111 WorkflowThreadLocal.setEnabled(workflowEnabled);
112 }
113 }
114 else if (methodName.equals("getLayouts") &&
115 (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
116 Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
117
118 long groupId = (Long)arguments[0];
119
120 Group group = GroupLocalServiceUtil.getGroup(groupId);
121
122 if (isMergeComplete(method, arguments, group)) {
123 return methodInvocation.proceed();
124 }
125
126 boolean privateLayout = (Boolean)arguments[1];
127 long parentLayoutId = (Long)arguments[2];
128
129 try {
130 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
131 groupId, privateLayout);
132
133 mergeLayoutSetPrototypeLayouts(
134 method, arguments, group, layoutSet, privateLayout,
135 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
238 Class<?> clazz = getClass();
239
240 DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
241 Layout.class, clazz.getClassLoader());
242
243 Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
244
245 dynamicQuery.add(groupIdProperty.eq(groupId));
246
247 Property layoutPrototypeUuidProperty = PropertyFactoryUtil.forName(
248 "layoutPrototypeUuid");
249
250 dynamicQuery.add(layoutPrototypeUuidProperty.isNotNull());
251
252 Property privateLayoutProperty = PropertyFactoryUtil.forName(
253 "privateLayout");
254
255 dynamicQuery.add(privateLayoutProperty.eq(privateLayout));
256
257 Property sourcePrototypeLayoutUuidProperty =
258 PropertyFactoryUtil.forName("sourcePrototypeLayoutUuid");
259
260 dynamicQuery.add(sourcePrototypeLayoutUuidProperty.isNotNull());
261
262 return LayoutLocalServiceUtil.dynamicQuery(dynamicQuery);
263 }
264
265 protected boolean isMergeComplete(
266 Method method, Object[] arguments, Group group) {
267
268 if (MergeLayoutPrototypesThreadLocal.isMergeComplete(
269 method, arguments) &&
270 (!group.isUser() ||
271 PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE)) {
272
273 return true;
274 }
275 else {
276 return false;
277 }
278 }
279
280 protected void mergeLayoutSetPrototypeLayouts(
281 Method method, Object[] arguments, Group group, LayoutSet layoutSet,
282 boolean privateLayout, boolean workflowEnabled) {
283
284 try {
285 if (!SitesUtil.isLayoutSetMergeable(group, layoutSet)) {
286 return;
287 }
288
289 WorkflowThreadLocal.setEnabled(false);
290
291 SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
292 }
293 catch (Exception e) {
294 if (_log.isWarnEnabled()) {
295 _log.warn("Unable to merge layouts for site template", e);
296 }
297 }
298 finally {
299 MergeLayoutPrototypesThreadLocal.setMergeComplete(
300 method, arguments);
301 WorkflowThreadLocal.setEnabled(workflowEnabled);
302 }
303 }
304
305 private static final Class<?>[] _TYPES_L = {Long.TYPE};
306
307 private static final Class<?>[] _TYPES_L_B_L = {
308 Long.TYPE, Boolean.TYPE, Long.TYPE
309 };
310
311 private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
312 Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
313 Integer.TYPE
314 };
315
316 private static final Log _log = LogFactoryUtil.getLog(
317 LayoutLocalServiceVirtualLayoutsAdvice.class);
318
319 private static final ThreadLocal<Long> _virtualLayoutTargetGroupId =
320 new AutoResetThreadLocal<Long>(
321 LayoutLocalServiceVirtualLayoutsAdvice.class +
322 "._virtualLayoutTargetGroupId",
323 GroupConstants.DEFAULT_LIVE_GROUP_ID);
324
325 }