001
014
015 package com.liferay.portal.service.impl;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
020 import com.liferay.portal.kernel.lar.UserIdStrategy;
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.FileUtil;
025 import com.liferay.portal.kernel.util.GetterUtil;
026 import com.liferay.portal.kernel.util.ListUtil;
027 import com.liferay.portal.kernel.util.SystemProperties;
028 import com.liferay.portal.kernel.util.UnicodeProperties;
029 import com.liferay.portal.kernel.util.Validator;
030 import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
031 import com.liferay.portal.kernel.workflow.WorkflowThreadLocal;
032 import com.liferay.portal.model.Group;
033 import com.liferay.portal.model.Layout;
034 import com.liferay.portal.model.LayoutConstants;
035 import com.liferay.portal.model.LayoutPrototype;
036 import com.liferay.portal.model.LayoutSet;
037 import com.liferay.portal.model.LayoutSetPrototype;
038 import com.liferay.portal.model.Lock;
039 import com.liferay.portal.model.UserGroup;
040 import com.liferay.portal.model.impl.VirtualLayout;
041 import com.liferay.portal.security.permission.PermissionChecker;
042 import com.liferay.portal.security.permission.PermissionThreadLocal;
043 import com.liferay.portal.service.GroupLocalServiceUtil;
044 import com.liferay.portal.service.LayoutLocalServiceUtil;
045 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
046 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
047 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
048 import com.liferay.portal.service.LockLocalServiceUtil;
049 import com.liferay.portal.service.UserGroupLocalServiceUtil;
050 import com.liferay.portal.service.UserLocalServiceUtil;
051 import com.liferay.portal.service.persistence.LayoutSetUtil;
052 import com.liferay.portal.service.persistence.LayoutUtil;
053 import com.liferay.portal.util.PropsValues;
054 import com.liferay.portlet.sites.util.SitesUtil;
055
056 import java.io.File;
057
058 import java.lang.reflect.Method;
059
060 import java.util.Arrays;
061 import java.util.Date;
062 import java.util.LinkedHashMap;
063 import java.util.List;
064 import java.util.Map;
065
066 import org.aopalliance.intercept.MethodInterceptor;
067 import org.aopalliance.intercept.MethodInvocation;
068
069 import org.springframework.core.annotation.Order;
070
071
075 @Order(2)
076 public class LayoutLocalServiceVirtualLayoutsAdvice
077 implements MethodInterceptor {
078
079 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
080 PermissionChecker permissionChecker =
081 PermissionThreadLocal.getPermissionChecker();
082
083 if (permissionChecker == null) {
084 return methodInvocation.proceed();
085 }
086
087 Method method = methodInvocation.getMethod();
088
089 String methodName = method.getName();
090
091 Object[] arguments = methodInvocation.getArguments();
092
093 Class<?>[] parameterTypes = method.getParameterTypes();
094
095 boolean workflowEnabled = WorkflowThreadLocal.isEnabled();
096
097 if (methodName.equals("getLayout") &&
098 (Arrays.equals(parameterTypes, _TYPES_L) ||
099 Arrays.equals(parameterTypes, _TYPES_L_B_L))) {
100
101 Layout layout = (Layout)methodInvocation.proceed();
102
103 if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
104 return layout;
105 }
106
107 Group group = layout.getGroup();
108 LayoutSet layoutSet = layout.getLayoutSet();
109
110 try {
111 MergeLayoutPrototypesThreadLocal.setInProgress(true);
112 WorkflowThreadLocal.setEnabled(false);
113
114 mergeLayoutProtypeLayout(group, layout);
115 mergeLayoutSetProtypeLayouts(group, layoutSet);
116 }
117 finally {
118 MergeLayoutPrototypesThreadLocal.setInProgress(false);
119 WorkflowThreadLocal.setEnabled(workflowEnabled);
120 }
121 }
122 else if (methodName.equals("getLayouts") &&
123 (Arrays.equals(parameterTypes, _TYPES_L_B_L) ||
124 Arrays.equals(parameterTypes, _TYPES_L_B_L_B_I_I))) {
125
126 long groupId = (Long)arguments[0];
127 boolean privateLayout = (Boolean)arguments[1];
128 long parentLayoutId = (Long)arguments[2];
129
130 try {
131 Group group = GroupLocalServiceUtil.getGroup(groupId);
132
133 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
134 groupId, privateLayout);
135
136 try {
137 MergeLayoutPrototypesThreadLocal.setInProgress(true);
138 WorkflowThreadLocal.setEnabled(false);
139
140 mergeLayoutSetProtypeLayouts(group, layoutSet);
141 }
142 finally {
143 MergeLayoutPrototypesThreadLocal.setInProgress(false);
144 WorkflowThreadLocal.setEnabled(workflowEnabled);
145 }
146
147 if (!PropsValues.
148 USER_GROUPS_COPY_LAYOUTS_TO_USER_PERSONAL_SITE &&
149 group.isUser() &&
150 (parentLayoutId ==
151 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID)) {
152
153 Object returnValue = methodInvocation.proceed();
154
155 return addUserGroupLayouts(
156 group, layoutSet, (List<Layout>)returnValue);
157 }
158 }
159 catch (Exception e) {
160 _log.error(e, e);
161
162 throw e;
163 }
164 }
165
166 return methodInvocation.proceed();
167 }
168
169 protected List<Layout> addUserGroupLayouts(
170 Group group, LayoutSet layoutSet, List<Layout> layouts)
171 throws Exception {
172
173 layouts = ListUtil.copy(layouts);
174
175 List<UserGroup> userUserGroups =
176 UserGroupLocalServiceUtil.getUserUserGroups(group.getClassPK());
177
178 for (UserGroup userGroup : userUserGroups) {
179 Group userGroupGroup = userGroup.getGroup();
180
181 List<Layout> userGroupLayouts = LayoutLocalServiceUtil.getLayouts(
182 userGroupGroup.getGroupId(), layoutSet.isPrivateLayout());
183
184 for (Layout userGroupLayout : userGroupLayouts) {
185 Layout virtualLayout = new VirtualLayout(
186 userGroupLayout, group);
187
188 layouts.add(virtualLayout);
189 }
190 }
191
192 return layouts;
193 }
194
195 protected Map<String, String[]> getLayoutTemplatesParameters(
196 boolean firstTime) {
197
198 Map<String, String[]> parameterMap =
199 new LinkedHashMap<String, String[]>();
200
201 parameterMap.put(
202 PortletDataHandlerKeys.CATEGORIES,
203 new String[] {Boolean.TRUE.toString()});
204 parameterMap.put(
205 PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
206 new String[] {Boolean.FALSE.toString()});
207 parameterMap.put(
208 PortletDataHandlerKeys.DELETE_PORTLET_DATA,
209 new String[] {Boolean.FALSE.toString()});
210 parameterMap.put(
211 PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
212 new String[] {Boolean.TRUE.toString()});
213 parameterMap.put(
214 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
215 new String[] {Boolean.TRUE.toString()});
216 parameterMap.put(
217 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
218 new String[] {
219 PortletDataHandlerKeys.
220 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
221 });
222 parameterMap.put(
223 PortletDataHandlerKeys.PERMISSIONS,
224 new String[] {Boolean.TRUE.toString()});
225 parameterMap.put(
226 PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS,
227 new String[] {Boolean.TRUE.toString()});
228 parameterMap.put(
229 PortletDataHandlerKeys.PORTLET_SETUP,
230 new String[] {Boolean.TRUE.toString()});
231 parameterMap.put(
232 PortletDataHandlerKeys.PORTLET_SETUP_ALL,
233 new String[] {Boolean.TRUE.toString()});
234 parameterMap.put(
235 PortletDataHandlerKeys.THEME,
236 new String[] {Boolean.FALSE.toString()});
237 parameterMap.put(
238 PortletDataHandlerKeys.THEME_REFERENCE,
239 new String[] {Boolean.TRUE.toString()});
240 parameterMap.put(
241 PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
242 new String[] {Boolean.FALSE.toString()});
243 parameterMap.put(
244 PortletDataHandlerKeys.USER_ID_STRATEGY,
245 new String[] {UserIdStrategy.CURRENT_USER_ID});
246
247 if (firstTime) {
248 parameterMap.put(
249 PortletDataHandlerKeys.DATA_STRATEGY,
250 new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
251 parameterMap.put(
252 PortletDataHandlerKeys.PORTLET_DATA,
253 new String[] {Boolean.TRUE.toString()});
254 parameterMap.put(
255 PortletDataHandlerKeys.PORTLET_DATA_ALL,
256 new String[] {Boolean.TRUE.toString()});
257 }
258 else {
259 parameterMap.put(
260 PortletDataHandlerKeys.PORTLET_DATA,
261 new String[] {Boolean.FALSE.toString()});
262 parameterMap.put(
263 PortletDataHandlerKeys.PORTLET_DATA_ALL,
264 new String[] {Boolean.FALSE.toString()});
265 }
266
267 return parameterMap;
268 }
269
270 protected void importLayoutSetPrototype(
271 LayoutSetPrototype layoutSetPrototype, long groupId,
272 boolean privateLayout, Map<String, String[]> parameterMap)
273 throws PortalException, SystemException {
274
275 File file = null;
276
277 File cacheFile = new File(
278 _TEMP_DIR.concat(layoutSetPrototype.getUuid()).concat(".lar"));
279
280 if (cacheFile.exists()) {
281 Date modifiedDate = layoutSetPrototype.getModifiedDate();
282
283 if (cacheFile.lastModified() >= modifiedDate.getTime()) {
284 if (_log.isDebugEnabled()) {
285 _log.debug(
286 "Using cached layout set prototype LAR file " +
287 cacheFile.getAbsolutePath());
288 }
289
290 file = cacheFile;
291 }
292 }
293
294 boolean newFile = false;
295
296 if (file == null) {
297 Group layoutSetPrototypeGroup = layoutSetPrototype.getGroup();
298
299 file = LayoutLocalServiceUtil.exportLayoutsAsFile(
300 layoutSetPrototypeGroup.getGroupId(), true, null,
301 parameterMap, null, null);
302
303 newFile = true;
304 }
305
306 long userId = UserLocalServiceUtil.getDefaultUserId(
307 layoutSetPrototype.getCompanyId());
308
309 LayoutLocalServiceUtil.importLayouts(
310 userId, groupId, privateLayout, parameterMap, file);
311
312 if (newFile) {
313 try {
314 FileUtil.copyFile(file, cacheFile);
315
316 if (_log.isDebugEnabled()) {
317 _log.debug(
318 "Copied " + file.getAbsolutePath() + " to " +
319 cacheFile.getAbsolutePath());
320 }
321 }
322 catch (Exception e) {
323 _log.error(
324 "Unable to copy file " + file.getAbsolutePath() + " to " +
325 cacheFile.getAbsolutePath(),
326 e);
327 }
328 }
329 }
330
331 protected void mergeLayoutProtypeLayout(Group group, Layout layout)
332 throws Exception {
333
334 if (!layout.isLayoutPrototypeLinkActive() ||
335 group.isLayoutPrototype() || group.isLayoutSetPrototype() ||
336 group.hasStagingGroup()) {
337
338 return;
339 }
340
341 UnicodeProperties typeSettingsProperties =
342 layout.getTypeSettingsProperties();
343
344 long lastMergeTime = GetterUtil.getLong(
345 typeSettingsProperties.getProperty("last-merge-time"));
346
347 LayoutPrototype layoutPrototype =
348 LayoutPrototypeLocalServiceUtil.getLayoutPrototypeByUuid(
349 layout.getLayoutPrototypeUuid());
350
351 Layout layoutPrototypeLayout = layoutPrototype.getLayout();
352
353 Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
354
355 if (lastMergeTime >= modifiedDate.getTime()) {
356 return;
357 }
358
359 UnicodeProperties prototypeTypeSettingsProperties =
360 layoutPrototypeLayout.getTypeSettingsProperties();
361
362 int mergeFailCount = GetterUtil.getInteger(
363 prototypeTypeSettingsProperties.getProperty("merge-fail-count"));
364
365 if (mergeFailCount >
366 PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
367
368 return;
369 }
370
371 String owner = PortalUUIDUtil.generate();
372
373 try {
374 Lock lock = LockLocalServiceUtil.lock(
375 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
376 String.valueOf(layout.getPlid()), owner, false);
377
378
379
380 if (!owner.equals(lock.getOwner())) {
381 Date createDate = lock.getCreateDate();
382
383 if (((System.currentTimeMillis() - createDate.getTime()) >=
384 PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME)) {
385
386
387
388 lock = LockLocalServiceUtil.lock(
389 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
390 String.valueOf(layout.getPlid()), lock.getOwner(),
391 owner, false);
392
393
394
395
396 if (!owner.equals(lock.getOwner())) {
397 return;
398 }
399 }
400 else {
401 return;
402 }
403 }
404 }
405 catch (Exception e) {
406 return;
407 }
408
409 try {
410 SitesUtil.applyLayoutPrototype(layoutPrototype, layout, true);
411 }
412 catch (Exception e) {
413 _log.error(e, e);
414
415 prototypeTypeSettingsProperties.setProperty(
416 "merge-fail-count", String.valueOf(++mergeFailCount));
417
418
419
420 LayoutUtil.updateImpl(layoutPrototypeLayout, false);
421 }
422 finally {
423 LockLocalServiceUtil.unlock(
424 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
425 String.valueOf(layout.getPlid()), owner, false);
426 }
427 }
428
429 protected void mergeLayoutSetProtypeLayouts(
430 Group group, LayoutSet layoutSet)
431 throws Exception {
432
433 if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
434 group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
435
436 return;
437 }
438
439 UnicodeProperties settingsProperties =
440 layoutSet.getSettingsProperties();
441
442 long lastMergeTime = GetterUtil.getLong(
443 settingsProperties.getProperty("last-merge-time"));
444
445 LayoutSetPrototype layoutSetPrototype =
446 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
447 layoutSet.getLayoutSetPrototypeUuid());
448
449 Date modifiedDate = layoutSetPrototype.getModifiedDate();
450
451 if (lastMergeTime >= modifiedDate.getTime()) {
452 return;
453 }
454
455 LayoutSet layoutSetPrototypeLayoutSet =
456 layoutSetPrototype.getLayoutSet();
457
458 UnicodeProperties layoutSetPrototypeSettingsProperties =
459 layoutSetPrototypeLayoutSet.getSettingsProperties();
460
461 int mergeFailCount = GetterUtil.getInteger(
462 layoutSetPrototypeSettingsProperties.getProperty(
463 "merge-fail-count"));
464
465 if (mergeFailCount >
466 PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
467
468 return;
469 }
470
471 String owner = PortalUUIDUtil.generate();
472
473 try {
474 Lock lock = LockLocalServiceUtil.lock(
475 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
476 String.valueOf(layoutSet.getLayoutSetId()), owner, false);
477
478
479
480 if (!owner.equals(lock.getOwner())) {
481 Date createDate = lock.getCreateDate();
482
483 if (((System.currentTimeMillis() - createDate.getTime()) >=
484 PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME)) {
485
486
487
488 lock = LockLocalServiceUtil.lock(
489 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
490 String.valueOf(layoutSet.getLayoutSetId()),
491 lock.getOwner(), owner, false);
492
493
494
495
496 if (!owner.equals(lock.getOwner())) {
497 return;
498 }
499 }
500 else {
501 return;
502 }
503 }
504 }
505 catch (Exception e) {
506 return;
507 }
508
509 try {
510 Map<String, String[]> parameterMap = null;
511
512 if (lastMergeTime > 0) {
513 parameterMap = getLayoutTemplatesParameters(false);
514 }
515 else {
516 parameterMap = getLayoutTemplatesParameters(true);
517 }
518
519 importLayoutSetPrototype(
520 layoutSetPrototype, layoutSet.getGroupId(),
521 layoutSet.isPrivateLayout(), parameterMap);
522
523 settingsProperties.setProperty(
524 "last-merge-time", String.valueOf(modifiedDate.getTime()));
525
526 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
527 }
528 catch (Exception e) {
529 _log.error(e, e);
530
531 layoutSetPrototypeSettingsProperties.setProperty(
532 "merge-fail-count", String.valueOf(++mergeFailCount));
533
534
535
536 LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet, false);
537 }
538 finally {
539 LockLocalServiceUtil.unlock(
540 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
541 String.valueOf(layoutSet.getLayoutSetId()), owner, false);
542 }
543 }
544
545 private static final String _TEMP_DIR =
546 SystemProperties.get(SystemProperties.TMP_DIR) +
547 "/liferay/layout_set_prototype/";
548
549 private static final Class<?>[] _TYPES_L = {Long.TYPE};
550
551 private static final Class<?>[] _TYPES_L_B_L = {
552 Long.TYPE, Boolean.TYPE, Long.TYPE
553 };
554
555 private static final Class<?>[] _TYPES_L_B_L_B_I_I = {
556 Long.TYPE, Boolean.TYPE, Long.TYPE, Boolean.TYPE, Integer.TYPE,
557 Integer.TYPE
558 };
559
560 private static Log _log = LogFactoryUtil.getLog(
561 LayoutLocalServiceVirtualLayoutsAdvice.class);
562
563 }