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 @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 }