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.util.AutoResetThreadLocal;
024 import com.liferay.portal.kernel.util.ListUtil;
025 import com.liferay.portal.kernel.util.Validator;
026 import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
027 import com.liferay.portal.model.Group;
028 import com.liferay.portal.model.GroupConstants;
029 import com.liferay.portal.model.Layout;
030 import com.liferay.portal.model.LayoutConstants;
031 import com.liferay.portal.model.LayoutSet;
032 import com.liferay.portal.model.UserGroup;
033 import com.liferay.portal.model.impl.VirtualLayout;
034 import com.liferay.portal.service.GroupLocalServiceUtil;
035 import com.liferay.portal.service.LayoutLocalServiceUtil;
036 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
037 import com.liferay.portal.service.UserGroupLocalServiceUtil;
038 import com.liferay.portal.util.PropsValues;
039 import com.liferay.portlet.exportimport.staging.MergeLayoutPrototypesThreadLocal;
040 import com.liferay.sites.kernel.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
091 return layout;
092 }
093
094 LayoutSet layoutSet = layout.getLayoutSet();
095
096 try {
097 WorkflowThreadLocal.setEnabled(false);
098
099 SitesUtil.mergeLayoutPrototypeLayout(group, layout);
100
101 if (Validator.isNotNull(
102 layout.getSourcePrototypeLayoutUuid())) {
103
104 SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
105 }
106 }
107 finally {
108 MergeLayoutPrototypesThreadLocal.setMergeComplete(
109 method, arguments);
110 WorkflowThreadLocal.setEnabled(workflowEnabled);
111 }
112 }
113 else if (methodName.equals("getLayouts") &&
114 (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
115 Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
116
117 long groupId = (Long)arguments[0];
118
119 Group group = GroupLocalServiceUtil.getGroup(groupId);
120
121 if (isMergeComplete(method, arguments, group)) {
122 return methodInvocation.proceed();
123 }
124
125 boolean privateLayout = (Boolean)arguments[1];
126 long parentLayoutId = (Long)arguments[2];
127
128 try {
129 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
130 groupId, privateLayout);
131
132 mergeLayoutSetPrototypeLayouts(
133 method, arguments, group, layoutSet, privateLayout,
134 workflowEnabled);
135
136 List<Layout> layouts = (List<Layout>)methodInvocation.proceed();
137
138 if (PropsValues.
139 USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE) {
140
141 return layouts;
142 }
143
144 if (group.isUser()) {
145 _virtualLayoutTargetGroupId.set(group.getGroupId());
146
147 if (parentLayoutId ==
148 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
149
150 return addUserGroupLayouts(
151 group, layoutSet, layouts, parentLayoutId);
152 }
153 else {
154 return addChildUserGroupLayouts(group, layouts);
155 }
156 }
157 else if (group.isUserGroup() &&
158 (parentLayoutId !=
159 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
160
161 long targetGroupId = _virtualLayoutTargetGroupId.get();
162
163 if (targetGroupId != GroupConstants.DEFAULT_LIVE_GROUP_ID) {
164 Group targetGroup = GroupLocalServiceUtil.getGroup(
165 targetGroupId);
166
167 return addChildUserGroupLayouts(targetGroup, layouts);
168 }
169 }
170
171 return layouts;
172 }
173 catch (Exception e) {
174 _log.error(e, e);
175
176 throw e;
177 }
178 }
179
180 return methodInvocation.proceed();
181 }
182
183 protected List<Layout> addChildUserGroupLayouts(
184 Group group, List<Layout> layouts)
185 throws Exception {
186
187 layouts = ListUtil.copy(layouts);
188
189 List<Layout> childLayouts = new ArrayList<>();
190
191 for (Layout layout : layouts) {
192 Layout childLayout = layout;
193
194 Group layoutGroup = layout.getGroup();
195
196 if (layoutGroup.isUserGroup()) {
197 childLayout = new VirtualLayout(layout, group);
198 }
199
200 childLayouts.add(childLayout);
201 }
202
203 return childLayouts;
204 }
205
206 protected List<Layout> addUserGroupLayouts(
207 Group group, LayoutSet layoutSet, List<Layout> layouts,
208 long parentLayoutId)
209 throws Exception {
210
211 layouts = ListUtil.copy(layouts);
212
213 List<UserGroup> userUserGroups =
214 UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
215
216 for (UserGroup userGroup : userUserGroups) {
217 Group userGroupGroup = userGroup.getGroup();
218
219 List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
220 userGroupGroup.getGroupId(), layoutSet.isPrivateLayout(),
221 parentLayoutId);
222
223 for (Layout userGroupLayout : userGroupLayouts) {
224 Layout virtualLayout = new VirtualLayout(
225 userGroupLayout, group);
226
227 layouts.add(virtualLayout);
228 }
229 }
230
231 return layouts;
232 }
233
234 protected List<Layout> getPrototypeLinkedLayouts(
235 long groupId, boolean privateLayout) {
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 boolean isMergeComplete(
265 Method method, Object[] arguments, Group group) {
266
267 if (MergeLayoutPrototypesThreadLocal.isMergeComplete(
268 method, arguments) &&
269 (!group.isUser() ||
270 PropsValues.USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE)) {
271
272 return true;
273 }
274 else {
275 return false;
276 }
277 }
278
279 protected void mergeLayoutSetPrototypeLayouts(
280 Method method, Object[] arguments, Group group, LayoutSet layoutSet,
281 boolean privateLayout, boolean workflowEnabled) {
282
283 try {
284 if (!SitesUtil.isLayoutSetMergeable(group, layoutSet)) {
285 return;
286 }
287
288 WorkflowThreadLocal.setEnabled(false);
289
290 SitesUtil.mergeLayoutSetPrototypeLayouts(group, layoutSet);
291 }
292 catch (Exception e) {
293 if (_log.isWarnEnabled()) {
294 _log.warn("Unable to merge layouts for site template", e);
295 }
296 }
297 finally {
298 MergeLayoutPrototypesThreadLocal.setMergeComplete(
299 method, arguments);
300 WorkflowThreadLocal.setEnabled(workflowEnabled);
301 }
302 }
303
304 private static final Class<?>[] _TYPES_L = {Long.TYPE};
305
306 private static final Class<?>[] _TYPES_L_B_L = {
307 Long.TYPE, Boolean.TYPE, Long.TYPE
308 };
309
310 private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
311 Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
312 Integer.TYPE
313 };
314
315 private static final Log _log = LogFactoryUtil.getLog(
316 LayoutLocalServiceVirtualLayoutsAdvice.class);
317
318 private static final ThreadLocal<Long> _virtualLayoutTargetGroupId =
319 new AutoResetThreadLocal<Long>(
320 LayoutLocalServiceVirtualLayoutsAdvice.class +
321 "._virtualLayoutTargetGroupId",
322 GroupConstants.DEFAULT_LIVE_GROUP_ID);
323
324 }