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