001
014
015 package com.liferay.portlet.sites.util;
016
017 import com.liferay.portal.events.EventsProcessorUtil;
018 import com.liferay.portal.kernel.exception.PortalException;
019 import com.liferay.portal.kernel.exception.SystemException;
020 import com.liferay.portal.kernel.language.LanguageUtil;
021 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
022 import com.liferay.portal.kernel.lar.UserIdStrategy;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.util.FileUtil;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.ParamUtil;
028 import com.liferay.portal.kernel.util.PropsKeys;
029 import com.liferay.portal.kernel.util.StringBundler;
030 import com.liferay.portal.kernel.util.SystemProperties;
031 import com.liferay.portal.kernel.util.UnicodeProperties;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
034 import com.liferay.portal.model.Group;
035 import com.liferay.portal.model.Layout;
036 import com.liferay.portal.model.LayoutConstants;
037 import com.liferay.portal.model.LayoutPrototype;
038 import com.liferay.portal.model.LayoutSet;
039 import com.liferay.portal.model.LayoutSetPrototype;
040 import com.liferay.portal.model.LayoutTypePortlet;
041 import com.liferay.portal.model.Lock;
042 import com.liferay.portal.model.PortletConstants;
043 import com.liferay.portal.model.ResourceConstants;
044 import com.liferay.portal.model.Role;
045 import com.liferay.portal.model.RoleConstants;
046 import com.liferay.portal.model.UserGroup;
047 import com.liferay.portal.model.impl.VirtualLayout;
048 import com.liferay.portal.security.auth.PrincipalException;
049 import com.liferay.portal.security.permission.ActionKeys;
050 import com.liferay.portal.security.permission.PermissionChecker;
051 import com.liferay.portal.security.permission.PermissionThreadLocal;
052 import com.liferay.portal.security.permission.ResourceActionsUtil;
053 import com.liferay.portal.service.GroupServiceUtil;
054 import com.liferay.portal.service.LayoutLocalServiceUtil;
055 import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
056 import com.liferay.portal.service.LayoutServiceUtil;
057 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
058 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
059 import com.liferay.portal.service.LayoutSetServiceUtil;
060 import com.liferay.portal.service.LockLocalServiceUtil;
061 import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
062 import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
063 import com.liferay.portal.service.RoleLocalServiceUtil;
064 import com.liferay.portal.service.ServiceContext;
065 import com.liferay.portal.service.ServiceContextFactory;
066 import com.liferay.portal.service.ServiceContextThreadLocal;
067 import com.liferay.portal.service.UserGroupLocalServiceUtil;
068 import com.liferay.portal.service.UserLocalServiceUtil;
069 import com.liferay.portal.service.impl.LayoutLocalServiceVirtualLayoutsAdvice;
070 import com.liferay.portal.service.permission.GroupPermissionUtil;
071 import com.liferay.portal.service.permission.LayoutPermissionUtil;
072 import com.liferay.portal.service.permission.PortalPermissionUtil;
073 import com.liferay.portal.service.permission.PortletPermissionUtil;
074 import com.liferay.portal.service.persistence.LayoutSetUtil;
075 import com.liferay.portal.service.persistence.LayoutUtil;
076 import com.liferay.portal.theme.PortletDisplay;
077 import com.liferay.portal.theme.ThemeDisplay;
078 import com.liferay.portal.util.LayoutSettings;
079 import com.liferay.portal.util.PortalUtil;
080 import com.liferay.portal.util.PortletKeys;
081 import com.liferay.portal.util.PropsValues;
082 import com.liferay.portal.util.WebKeys;
083 import com.liferay.portlet.PortletPreferencesFactoryUtil;
084 import com.liferay.portlet.PortletPreferencesImpl;
085
086 import java.io.File;
087 import java.io.InputStream;
088
089 import java.util.Date;
090 import java.util.LinkedHashMap;
091 import java.util.List;
092 import java.util.Locale;
093 import java.util.Map;
094
095 import javax.portlet.ActionRequest;
096 import javax.portlet.ActionResponse;
097 import javax.portlet.PortletPreferences;
098 import javax.portlet.PortletURL;
099 import javax.portlet.RenderRequest;
100 import javax.portlet.RenderResponse;
101
102 import javax.servlet.http.HttpServletRequest;
103 import javax.servlet.http.HttpServletResponse;
104
105
110 public class SitesUtil {
111
112 public static void addPortletBreadcrumbEntries(
113 Group group, String pagesName, PortletURL redirectURL,
114 HttpServletRequest request, RenderResponse renderResponse)
115 throws Exception {
116
117 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
118 com.liferay.portal.kernel.util.WebKeys.THEME_DISPLAY);
119
120 PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
121
122 String portletName = portletDisplay.getPortletName();
123
124 if ((renderResponse == null) ||
125 portletName.equals(PortletKeys.GROUP_PAGES) ||
126 portletName.equals(PortletKeys.MY_PAGES)) {
127
128 return;
129 }
130
131 Locale locale = themeDisplay.getLocale();
132
133 if (group.isLayoutPrototype()) {
134 PortalUtil.addPortletBreadcrumbEntry(
135 request, LanguageUtil.get(locale, "page-template"), null);
136
137 PortalUtil.addPortletBreadcrumbEntry(
138 request, group.getDescriptiveName(), redirectURL.toString());
139 }
140 else {
141 PortalUtil.addPortletBreadcrumbEntry(
142 request, group.getDescriptiveName(), null);
143 }
144
145 if (!group.isLayoutPrototype()) {
146 PortalUtil.addPortletBreadcrumbEntry(
147 request, LanguageUtil.get(locale, pagesName),
148 redirectURL.toString());
149 }
150 }
151
152 public static void applyLayoutPrototype(
153 LayoutPrototype layoutPrototype, Layout targetLayout,
154 boolean linkEnabled)
155 throws Exception {
156
157 Layout layoutPrototypeLayout = layoutPrototype.getLayout();
158
159 ServiceContext serviceContext =
160 ServiceContextThreadLocal.getServiceContext();
161
162 serviceContext.setAttribute("layoutPrototypeLinkEnabled", linkEnabled);
163 serviceContext.setAttribute(
164 "layoutPrototypeUuid", layoutPrototype.getUuid());
165
166 targetLayout = LayoutLocalServiceUtil.updateLayout(
167 targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
168 targetLayout.getLayoutId(), targetLayout.getParentLayoutId(),
169 targetLayout.getNameMap(), targetLayout.getTitleMap(),
170 targetLayout.getDescriptionMap(), targetLayout.getKeywordsMap(),
171 targetLayout.getRobotsMap(), layoutPrototypeLayout.getType(),
172 targetLayout.getHidden(), targetLayout.getFriendlyURL(),
173 targetLayout.getIconImage(), null, serviceContext);
174
175 targetLayout = LayoutLocalServiceUtil.updateLayout(
176 targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
177 targetLayout.getLayoutId(),
178 layoutPrototypeLayout.getTypeSettings());
179
180 copyPortletPermissions(targetLayout, layoutPrototypeLayout);
181
182 copyPortletSetups(layoutPrototypeLayout, targetLayout);
183
184 copyLookAndFeel(targetLayout, layoutPrototypeLayout);
185
186 targetLayout = LayoutLocalServiceUtil.getLayout(targetLayout.getPlid());
187
188 UnicodeProperties typeSettingsProperties =
189 targetLayout.getTypeSettingsProperties();
190
191 typeSettingsProperties.setProperty(
192 "last-merge-time",
193 String.valueOf(targetLayout.getModifiedDate().getTime()));
194
195 LayoutLocalServiceUtil.updateLayout(targetLayout, false);
196
197 UnicodeProperties prototypeTypeSettingsProperties =
198 layoutPrototypeLayout.getTypeSettingsProperties();
199
200 prototypeTypeSettingsProperties.setProperty("merge-fail-count", "0");
201
202 LayoutLocalServiceUtil.updateLayout(layoutPrototypeLayout, false);
203 }
204
205 public static void copyLayout(
206 long userId, Layout sourceLayout, Layout targetLayout,
207 ServiceContext serviceContext)
208 throws Exception {
209
210 Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
211 serviceContext);
212
213 parameterMap.put(
214 PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
215 new String[]{Boolean.FALSE.toString()});
216
217 File file = LayoutLocalServiceUtil.exportLayoutsAsFile(
218 sourceLayout.getGroupId(), sourceLayout.isPrivateLayout(),
219 new long[] {sourceLayout.getLayoutId()}, parameterMap, null, null);
220
221 try {
222 LayoutLocalServiceUtil.importLayouts(
223 userId, targetLayout.getGroupId(),
224 targetLayout.isPrivateLayout(), parameterMap, file);
225 }
226 finally {
227 file.delete();
228 }
229 }
230
231 public static void copyLookAndFeel(Layout targetLayout, Layout sourceLayout)
232 throws Exception {
233
234 LayoutLocalServiceUtil.updateLookAndFeel(
235 targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
236 targetLayout.getLayoutId(), sourceLayout.getThemeId(),
237 sourceLayout.getColorSchemeId(), sourceLayout.getCss(), false);
238
239 LayoutLocalServiceUtil.updateLookAndFeel(
240 targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
241 targetLayout.getLayoutId(), sourceLayout.getWapThemeId(),
242 sourceLayout.getWapColorSchemeId(), sourceLayout.getCss(), true);
243 }
244
245 public static void copyPortletPermissions(
246 Layout targetLayout, Layout sourceLayout)
247 throws Exception {
248
249 long companyId = targetLayout.getCompanyId();
250
251 List<Role> roles = RoleLocalServiceUtil.getRoles(companyId);
252
253 LayoutTypePortlet sourceLayoutTypePortlet =
254 (LayoutTypePortlet)sourceLayout.getLayoutType();
255
256 List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
257
258 for (String sourcePortletId : sourcePortletIds) {
259 String resourceName = PortletConstants.getRootPortletId(
260 sourcePortletId);
261
262 String sourceResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
263 sourceLayout.getPlid(), sourcePortletId);
264
265 String targetResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
266 targetLayout.getPlid(), sourcePortletId);
267
268 List<String> actionIds =
269 ResourceActionsUtil.getPortletResourceActions(resourceName);
270
271 for (Role role : roles) {
272 String roleName = role.getName();
273
274 if (roleName.equals(RoleConstants.ADMINISTRATOR)) {
275 continue;
276 }
277
278 List<String> actions =
279 ResourcePermissionLocalServiceUtil.
280 getAvailableResourcePermissionActionIds(
281 companyId, resourceName,
282 ResourceConstants.SCOPE_INDIVIDUAL,
283 sourceResourcePrimKey, role.getRoleId(), actionIds);
284
285 ResourcePermissionLocalServiceUtil.setResourcePermissions(
286 companyId, resourceName, ResourceConstants.SCOPE_INDIVIDUAL,
287 targetResourcePrimKey, role.getRoleId(),
288 actions.toArray(new String[actions.size()]));
289 }
290 }
291 }
292
293 public static void copyPortletSetups(
294 Layout sourceLayout, Layout targetLayout)
295 throws Exception {
296
297 LayoutTypePortlet sourceLayoutTypePortlet =
298 (LayoutTypePortlet)sourceLayout.getLayoutType();
299
300 List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
301
302 for (String sourcePortletId : sourcePortletIds) {
303 PortletPreferences sourcePreferences =
304 PortletPreferencesFactoryUtil.getPortletSetup(
305 sourceLayout, sourcePortletId, null);
306
307 PortletPreferencesImpl sourcePreferencesImpl =
308 (PortletPreferencesImpl)sourcePreferences;
309
310 PortletPreferences targetPreferences =
311 PortletPreferencesFactoryUtil.getPortletSetup(
312 targetLayout, sourcePortletId, null);
313
314 PortletPreferencesImpl targetPreferencesImpl =
315 (PortletPreferencesImpl)targetPreferences;
316
317 PortletPreferencesLocalServiceUtil.updatePreferences(
318 targetPreferencesImpl.getOwnerId(),
319 targetPreferencesImpl.getOwnerType(),
320 targetPreferencesImpl.getPlid(), sourcePortletId,
321 sourcePreferences);
322
323 if ((sourcePreferencesImpl.getOwnerId() !=
324 PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
325 (sourcePreferencesImpl.getOwnerType() !=
326 PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) {
327
328 sourcePreferences =
329 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
330 sourceLayout, sourcePortletId);
331
332 sourcePreferencesImpl =
333 (PortletPreferencesImpl)sourcePreferences;
334
335 targetPreferences =
336 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
337 targetLayout, sourcePortletId);
338
339 targetPreferencesImpl =
340 (PortletPreferencesImpl)targetPreferences;
341
342 PortletPreferencesLocalServiceUtil.updatePreferences(
343 targetPreferencesImpl.getOwnerId(),
344 targetPreferencesImpl.getOwnerType(),
345 targetPreferencesImpl.getPlid(), sourcePortletId,
346 sourcePreferences);
347 }
348 }
349 }
350
351 public static void copyTypeSettings(Group sourceGroup, Group targetGroup)
352 throws Exception {
353
354 GroupServiceUtil.updateGroup(
355 targetGroup.getGroupId(), sourceGroup.getTypeSettings());
356 }
357
358 public static Object[] deleteLayout(
359 ActionRequest actionRequest, ActionResponse actionResponse)
360 throws Exception {
361
362 HttpServletRequest request = PortalUtil.getHttpServletRequest(
363 actionRequest);
364 HttpServletResponse response = PortalUtil.getHttpServletResponse(
365 actionResponse);
366
367 return deleteLayout(request, response);
368 }
369
370 public static Object[] deleteLayout(
371 HttpServletRequest request, HttpServletResponse response)
372 throws Exception {
373
374 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
375 WebKeys.THEME_DISPLAY);
376
377 PermissionChecker permissionChecker =
378 themeDisplay.getPermissionChecker();
379
380 long plid = ParamUtil.getLong(request, "plid");
381
382 long groupId = ParamUtil.getLong(request, "groupId");
383 boolean privateLayout = ParamUtil.getBoolean(request, "privateLayout");
384 long layoutId = ParamUtil.getLong(request, "layoutId");
385
386 Layout layout = null;
387
388 if (plid <= 0) {
389 layout = LayoutLocalServiceUtil.getLayout(
390 groupId, privateLayout, layoutId);
391 }
392 else {
393 layout = LayoutLocalServiceUtil.getLayout(plid);
394
395 groupId = layout.getGroupId();
396 privateLayout = layout.isPrivateLayout();
397 layoutId = layout.getLayoutId();
398 }
399
400 Group group = layout.getGroup();
401 String oldFriendlyURL = layout.getFriendlyURL();
402
403 if (group.isStagingGroup() &&
404 !GroupPermissionUtil.contains(
405 permissionChecker, groupId, ActionKeys.MANAGE_STAGING) &&
406 !GroupPermissionUtil.contains(
407 permissionChecker, groupId, ActionKeys.PUBLISH_STAGING)) {
408
409 throw new PrincipalException();
410 }
411
412 if (LayoutPermissionUtil.contains(
413 permissionChecker, layout, ActionKeys.DELETE)) {
414
415 LayoutSettings layoutSettings = LayoutSettings.getInstance(layout);
416
417 EventsProcessorUtil.process(
418 PropsKeys.LAYOUT_CONFIGURATION_ACTION_DELETE,
419 layoutSettings.getConfigurationActionDelete(), request,
420 response);
421 }
422
423 LayoutSet layoutSet = layout.getLayoutSet();
424
425 ServiceContext serviceContext = ServiceContextFactory.getInstance(
426 request);
427
428 LayoutServiceUtil.deleteLayout(
429 groupId, privateLayout, layoutId, serviceContext);
430
431 long newPlid = layout.getParentPlid();
432
433 if (newPlid <= 0) {
434 Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout(
435 layoutSet.getGroupId(), layoutSet.getPrivateLayout(),
436 LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
437
438 if (firstLayout != null) {
439 newPlid = firstLayout.getPlid();
440 }
441 }
442
443 return new Object[] {group, oldFriendlyURL, newPlid};
444 }
445
446 public static void deleteLayout(
447 RenderRequest renderRequest, RenderResponse renderResponse)
448 throws Exception {
449
450 HttpServletRequest request = PortalUtil.getHttpServletRequest(
451 renderRequest);
452 HttpServletResponse response = PortalUtil.getHttpServletResponse(
453 renderResponse);
454
455 deleteLayout(request, response);
456 }
457
458 public static File exportLayoutSetPrototype(
459 LayoutSetPrototype layoutSetPrototype,
460 ServiceContext serviceContext)
461 throws PortalException, SystemException {
462
463 LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
464
465 Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
466 serviceContext);
467
468 return LayoutLocalServiceUtil.exportLayoutsAsFile(
469 layoutSet.getGroupId(), layoutSet.isPrivateLayout(), null,
470 parameterMap, null, null);
471 }
472
473 public static Layout getLayoutSetPrototypeLayout(Layout layout) {
474 try {
475 LayoutSet layoutSet = layout.getLayoutSet();
476
477 if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
478 return null;
479 }
480
481 LayoutSetPrototype layoutSetPrototype =
482 LayoutSetPrototypeLocalServiceUtil.
483 getLayoutSetPrototypeByUuid(
484 layoutSet.getLayoutSetPrototypeUuid());
485
486 Group group = layoutSetPrototype.getGroup();
487
488 return LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
489 layout.getSourcePrototypeLayoutUuid(), group.getGroupId());
490 }
491 catch (Exception e) {
492 _log.error(
493 "Unable to fetch the the layout set prototype's layout", e);
494 }
495
496 return null;
497 }
498
499 public static Map<String, String[]> getLayoutSetPrototypeParameters(
500 ServiceContext serviceContext) {
501
502 Map<String, String[]> parameterMap =
503 new LinkedHashMap<String, String[]>();
504
505 parameterMap.put(
506 PortletDataHandlerKeys.CATEGORIES,
507 new String[] {Boolean.TRUE.toString()});
508 parameterMap.put(
509 PortletDataHandlerKeys.DATA_STRATEGY,
510 new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
511 parameterMap.put(
512 PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
513 new String[] {Boolean.TRUE.toString()});
514 parameterMap.put(
515 PortletDataHandlerKeys.DELETE_PORTLET_DATA,
516 new String[] {Boolean.FALSE.toString()});
517 parameterMap.put(
518 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
519 new String[] {Boolean.TRUE.toString()});
520 parameterMap.put(
521 PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
522 new String[] {Boolean.FALSE.toString()});
523 parameterMap.put(
524 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
525 new String[] {
526 PortletDataHandlerKeys.
527 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
528 });
529 parameterMap.put(
530 PortletDataHandlerKeys.LOGO,
531 new String[] {Boolean.FALSE.toString()});
532 parameterMap.put(
533 PortletDataHandlerKeys.PERFORM_DIRECT_BINARY_IMPORT,
534 new String[] {Boolean.TRUE.toString()});
535 parameterMap.put(
536 PortletDataHandlerKeys.PERMISSIONS,
537 new String[] {Boolean.TRUE.toString()});
538 parameterMap.put(
539 PortletDataHandlerKeys.PORTLET_DATA,
540 new String[] {Boolean.TRUE.toString()});
541 parameterMap.put(
542 PortletDataHandlerKeys.PORTLET_DATA_ALL,
543 new String[] {Boolean.TRUE.toString()});
544 parameterMap.put(
545 PortletDataHandlerKeys.PORTLET_SETUP,
546 new String[] {Boolean.TRUE.toString()});
547 parameterMap.put(
548 PortletDataHandlerKeys.PORTLET_USER_PREFERENCES,
549 new String[] {Boolean.TRUE.toString()});
550 parameterMap.put(
551 PortletDataHandlerKeys.THEME,
552 new String[] {Boolean.FALSE.toString()});
553 parameterMap.put(
554 PortletDataHandlerKeys.THEME_REFERENCE,
555 new String[] {Boolean.TRUE.toString()});
556 parameterMap.put(
557 PortletDataHandlerKeys.USER_ID_STRATEGY,
558 new String[] {UserIdStrategy.CURRENT_USER_ID});
559 parameterMap.put(
560 PortletDataHandlerKeys.USER_PERMISSIONS,
561 new String[] {Boolean.FALSE.toString()});
562
563 return parameterMap;
564 }
565
566 public static void importLayoutSetPrototype(
567 LayoutSetPrototype layoutSetPrototype, InputStream inputStream,
568 ServiceContext serviceContext)
569 throws PortalException, SystemException {
570
571 LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
572
573 Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
574 serviceContext);
575
576 setLayoutSetPrototypeLinkEnabledParameter(
577 parameterMap, layoutSet, serviceContext);
578
579 LayoutServiceUtil.importLayouts(
580 layoutSet.getGroupId(), layoutSet.isPrivateLayout(), parameterMap,
581 inputStream);
582 }
583
584 public static boolean isLayoutDeleteable(Layout layout) {
585 try {
586 if (layout instanceof VirtualLayout) {
587 return false;
588 }
589
590 if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
591 return true;
592 }
593
594 LayoutSet layoutSet = layout.getLayoutSet();
595
596 if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
597 return true;
598 }
599
600 if (LayoutLocalServiceUtil.hasLayoutSetPrototypeLayout(
601 layoutSet.getLayoutSetPrototypeUuid(),
602 layout.getSourcePrototypeLayoutUuid())) {
603
604 return false;
605 }
606 }
607 catch (Exception e) {
608 if (_log.isDebugEnabled()) {
609 _log.debug(e, e);
610 }
611 }
612
613 return true;
614 }
615
616 public static boolean isLayoutModifiedSinceLastMerge(Layout layout)
617 throws PortalException, SystemException {
618
619 if ((layout == null) ||
620 Validator.isNull(layout.getSourcePrototypeLayoutUuid()) ||
621 layout.isLayoutPrototypeLinkActive()) {
622
623 return false;
624 }
625
626 LayoutSet existingLayoutSet = layout.getLayoutSet();
627
628 long lastMergeTime = GetterUtil.getLong(
629 existingLayoutSet.getSettingsProperty("last-merge-time"));
630
631 Date existingLayoutModifiedDate = layout.getModifiedDate();
632
633 if ((existingLayoutModifiedDate != null) &&
634 (existingLayoutModifiedDate.getTime() > lastMergeTime) &&
635 isLayoutUpdateable(layout)) {
636
637 return true;
638 }
639
640 return false;
641 }
642
643 public static boolean isLayoutSetPrototypeUpdateable(LayoutSet layoutSet) {
644 if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
645 return true;
646 }
647
648 try {
649 LayoutSetPrototype layoutSetPrototype =
650 LayoutSetPrototypeLocalServiceUtil.
651 getLayoutSetPrototypeByUuid(
652 layoutSet.getLayoutSetPrototypeUuid());
653
654 String layoutsUpdateable = layoutSetPrototype.getSettingsProperty(
655 "layoutsUpdateable");
656
657 if (Validator.isNotNull(layoutsUpdateable)) {
658 return GetterUtil.getBoolean(layoutsUpdateable, true);
659 }
660 }
661 catch (Exception e) {
662 if (_log.isDebugEnabled()) {
663 _log.debug(e, e);
664 }
665 }
666
667 return true;
668 }
669
670 public static boolean isLayoutUpdateable(Layout layout) {
671 try {
672 if (layout instanceof VirtualLayout) {
673 return false;
674 }
675
676 if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
677 Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
678
679 return true;
680 }
681
682 LayoutSet layoutSet = layout.getLayoutSet();
683
684 if (layoutSet.isLayoutSetPrototypeLinkActive()) {
685 boolean layoutSetPrototypeUpdateable =
686 isLayoutSetPrototypeUpdateable(layoutSet);
687
688 if (!layoutSetPrototypeUpdateable) {
689 return false;
690 }
691
692 Layout layoutSetPrototypeLayout = getLayoutSetPrototypeLayout(
693 layout);
694
695 UnicodeProperties typeSettingsProperties =
696 layoutSetPrototypeLayout.getTypeSettingsProperties();
697
698 String layoutUpdateable = typeSettingsProperties.getProperty(
699 "layoutUpdateable");
700
701 if (Validator.isNull(layoutUpdateable)) {
702 return true;
703 }
704
705 return GetterUtil.getBoolean(layoutUpdateable);
706 }
707 }
708 catch (Exception e) {
709 if (_log.isDebugEnabled()) {
710 _log.debug(e, e);
711 }
712 }
713
714 return true;
715 }
716
717 public static boolean isUserGroupLayoutSetViewable(
718 PermissionChecker permissionChecker, Group userGroupGroup)
719 throws PortalException, SystemException {
720
721 if (!userGroupGroup.isUserGroup()) {
722 return false;
723 }
724
725 if (GroupPermissionUtil.contains(
726 permissionChecker, userGroupGroup.getGroupId(),
727 ActionKeys.VIEW)) {
728
729 return true;
730 }
731
732 UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
733 userGroupGroup.getClassPK());
734
735 if (UserLocalServiceUtil.hasUserGroupUser(
736 userGroup.getUserGroupId(), permissionChecker.getUserId())) {
737
738 return true;
739 }
740 else {
741 return false;
742 }
743 }
744
745 public static void mergeLayoutProtypeLayout(Group group, Layout layout)
746 throws Exception {
747
748 if (!layout.isLayoutPrototypeLinkActive() ||
749 group.isLayoutPrototype() || group.hasStagingGroup()) {
750
751 return;
752 }
753
754 UnicodeProperties typeSettingsProperties =
755 layout.getTypeSettingsProperties();
756
757 long lastMergeTime = GetterUtil.getLong(
758 typeSettingsProperties.getProperty("last-merge-time"));
759
760 LayoutPrototype layoutPrototype =
761 LayoutPrototypeLocalServiceUtil.getLayoutPrototypeByUuid(
762 layout.getLayoutPrototypeUuid());
763
764 Layout layoutPrototypeLayout = layoutPrototype.getLayout();
765
766 Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
767
768 if (lastMergeTime >= modifiedDate.getTime()) {
769 return;
770 }
771
772 UnicodeProperties prototypeTypeSettingsProperties =
773 layoutPrototypeLayout.getTypeSettingsProperties();
774
775 int mergeFailCount = GetterUtil.getInteger(
776 prototypeTypeSettingsProperties.getProperty("merge-fail-count"));
777
778 if (mergeFailCount >
779 PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
780
781 return;
782 }
783
784 String owner = PortalUUIDUtil.generate();
785
786 try {
787 Lock lock = LockLocalServiceUtil.lock(
788 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
789 String.valueOf(layout.getPlid()), owner, false);
790
791
792
793 if (!owner.equals(lock.getOwner())) {
794 Date createDate = lock.getCreateDate();
795
796 if (((System.currentTimeMillis() - createDate.getTime()) >=
797 PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME)) {
798
799
800
801 lock = LockLocalServiceUtil.lock(
802 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
803 String.valueOf(layout.getPlid()), lock.getOwner(),
804 owner, false);
805
806
807
808
809 if (!owner.equals(lock.getOwner())) {
810 return;
811 }
812 }
813 else {
814 return;
815 }
816 }
817 }
818 catch (Exception e) {
819 return;
820 }
821
822 try {
823 SitesUtil.applyLayoutPrototype(layoutPrototype, layout, true);
824 }
825 catch (Exception e) {
826 _log.error(e, e);
827
828 prototypeTypeSettingsProperties.setProperty(
829 "merge-fail-count", String.valueOf(++mergeFailCount));
830
831
832
833 LayoutUtil.updateImpl(layoutPrototypeLayout, false);
834 }
835 finally {
836 LockLocalServiceUtil.unlock(
837 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
838 String.valueOf(layout.getPlid()), owner, false);
839 }
840 }
841
842 public static void mergeLayoutSetProtypeLayouts(
843 Group group, LayoutSet layoutSet)
844 throws Exception {
845
846 if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
847 group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
848
849 return;
850 }
851
852 UnicodeProperties settingsProperties =
853 layoutSet.getSettingsProperties();
854
855 long lastMergeTime = GetterUtil.getLong(
856 settingsProperties.getProperty("last-merge-time"));
857
858 LayoutSetPrototype layoutSetPrototype =
859 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
860 layoutSet.getLayoutSetPrototypeUuid());
861
862 Date modifiedDate = layoutSetPrototype.getModifiedDate();
863
864 if (lastMergeTime >= modifiedDate.getTime()) {
865 return;
866 }
867
868 LayoutSet layoutSetPrototypeLayoutSet =
869 layoutSetPrototype.getLayoutSet();
870
871 UnicodeProperties layoutSetPrototypeSettingsProperties =
872 layoutSetPrototypeLayoutSet.getSettingsProperties();
873
874 int mergeFailCount = GetterUtil.getInteger(
875 layoutSetPrototypeSettingsProperties.getProperty(
876 "merge-fail-count"));
877
878 if (mergeFailCount >
879 PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
880
881 if (_log.isWarnEnabled()) {
882 StringBundler sb = new StringBundler(6);
883
884 sb.append("Merge not performed because the fail threshold was");
885 sb.append("reached for layoutSetPrototypeId ");
886 sb.append(layoutSetPrototype.getLayoutSetPrototypeId());
887 sb.append(" and layoutId ");
888 sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId());
889 sb.append(". Update the count in the database to try again.");
890
891 _log.warn(sb.toString());
892 }
893
894 return;
895 }
896
897 String owner = PortalUUIDUtil.generate();
898
899 try {
900 Lock lock = LockLocalServiceUtil.lock(
901 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
902 String.valueOf(layoutSet.getLayoutSetId()), owner, false);
903
904
905
906 if (!owner.equals(lock.getOwner())) {
907 Date createDate = lock.getCreateDate();
908
909 if ((System.currentTimeMillis() - createDate.getTime()) >=
910 PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
911
912
913
914 lock = LockLocalServiceUtil.lock(
915 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
916 String.valueOf(layoutSet.getLayoutSetId()),
917 lock.getOwner(), owner, false);
918
919
920
921
922 if (!owner.equals(lock.getOwner())) {
923 return;
924 }
925 }
926 else {
927 return;
928 }
929 }
930 }
931 catch (Exception e) {
932 return;
933 }
934
935 try {
936 Map<String, String[]> parameterMap = null;
937
938 boolean importData = true;
939
940 if (lastMergeTime > 0) {
941 importData = false;
942 }
943
944 parameterMap = getLayoutSetPrototypesParameters(importData);
945
946 importLayoutSetPrototype(
947 layoutSetPrototype, layoutSet.getGroupId(),
948 layoutSet.isPrivateLayout(), parameterMap, importData);
949
950 layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
951 layoutSet.getGroupId(), layoutSet.isPrivateLayout());
952
953 settingsProperties = layoutSet.getSettingsProperties();
954
955 settingsProperties.setProperty(
956 "last-merge-time", String.valueOf(System.currentTimeMillis()));
957
958 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
959 }
960 catch (Exception e) {
961 _log.error(e, e);
962
963 layoutSetPrototypeSettingsProperties.setProperty(
964 "merge-fail-count", String.valueOf(++mergeFailCount));
965
966
967
968 LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet, false);
969 }
970 finally {
971 LockLocalServiceUtil.unlock(
972 LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
973 String.valueOf(layoutSet.getLayoutSetId()), owner, false);
974 }
975 }
976
977 public static void resetPrototype(Layout layout)
978 throws PortalException, SystemException {
979
980 layout.setModifiedDate(null);
981
982 LayoutLocalServiceUtil.updateLayout(layout, false);
983
984 LayoutSet layoutSet = layout.getLayoutSet();
985 UnicodeProperties settingsProperties =
986 layoutSet.getSettingsProperties();
987
988 settingsProperties.remove("last-merge-time");
989
990 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
991 }
992
993 public static void updateLayoutSetPrototypesLinks(
994 Group group, long publicLayoutSetPrototypeId,
995 long privateLayoutSetPrototypeId,
996 boolean publicLayoutSetPrototypeLinkEnabled,
997 boolean privateLayoutSetPrototypeLinkEnabled)
998 throws Exception {
999
1000 updateLayoutSetPrototypeLink(
1001 group.getGroupId(), true, privateLayoutSetPrototypeId,
1002 privateLayoutSetPrototypeLinkEnabled);
1003 updateLayoutSetPrototypeLink(
1004 group.getGroupId(), false, publicLayoutSetPrototypeId,
1005 publicLayoutSetPrototypeLinkEnabled);
1006 }
1007
1008 protected static Map<String, String[]> getLayoutSetPrototypesParameters(
1009 boolean importData) {
1010
1011 Map<String, String[]> parameterMap =
1012 new LinkedHashMap<String, String[]>();
1013
1014 parameterMap.put(
1015 PortletDataHandlerKeys.CATEGORIES,
1016 new String[] {Boolean.TRUE.toString()});
1017 parameterMap.put(
1018 PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1019 new String[] {Boolean.FALSE.toString()});
1020 parameterMap.put(
1021 PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1022 new String[] {Boolean.FALSE.toString()});
1023 parameterMap.put(
1024 PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
1025 new String[] {Boolean.TRUE.toString()});
1026 parameterMap.put(
1027 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1028 new String[] {Boolean.TRUE.toString()});
1029 parameterMap.put(
1030 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1031 new String[] {
1032 PortletDataHandlerKeys.
1033 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
1034 });
1035 parameterMap.put(
1036 PortletDataHandlerKeys.PERMISSIONS,
1037 new String[] {Boolean.TRUE.toString()});
1038 parameterMap.put(
1039 PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS,
1040 new String[] {Boolean.TRUE.toString()});
1041 parameterMap.put(
1042 PortletDataHandlerKeys.PORTLET_SETUP,
1043 new String[] {Boolean.TRUE.toString()});
1044 parameterMap.put(
1045 PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1046 new String[] {Boolean.TRUE.toString()});
1047 parameterMap.put(
1048 PortletDataHandlerKeys.THEME,
1049 new String[] {Boolean.FALSE.toString()});
1050 parameterMap.put(
1051 PortletDataHandlerKeys.THEME_REFERENCE,
1052 new String[] {Boolean.TRUE.toString()});
1053 parameterMap.put(
1054 PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1055 new String[] {Boolean.FALSE.toString()});
1056 parameterMap.put(
1057 PortletDataHandlerKeys.USER_ID_STRATEGY,
1058 new String[] {UserIdStrategy.CURRENT_USER_ID});
1059
1060 if (importData) {
1061 parameterMap.put(
1062 PortletDataHandlerKeys.DATA_STRATEGY,
1063 new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1064 parameterMap.put(
1065 PortletDataHandlerKeys.PORTLET_DATA,
1066 new String[] {Boolean.TRUE.toString()});
1067 parameterMap.put(
1068 PortletDataHandlerKeys.PORTLET_DATA_ALL,
1069 new String[] {Boolean.TRUE.toString()});
1070 }
1071 else {
1072 parameterMap.put(
1073 PortletDataHandlerKeys.PORTLET_DATA,
1074 new String[] {Boolean.FALSE.toString()});
1075 parameterMap.put(
1076 PortletDataHandlerKeys.PORTLET_DATA_ALL,
1077 new String[] {Boolean.FALSE.toString()});
1078 }
1079
1080 return parameterMap;
1081 }
1082
1083 protected static void importLayoutSetPrototype(
1084 LayoutSetPrototype layoutSetPrototype, long groupId,
1085 boolean privateLayout, Map<String, String[]> parameterMap,
1086 boolean importData)
1087 throws PortalException, SystemException {
1088
1089 File file = null;
1090
1091 StringBundler sb = new StringBundler(importData ? 4 : 4);
1092
1093 sb.append(_TEMP_DIR);
1094 sb.append(layoutSetPrototype.getUuid());
1095
1096 if (importData) {
1097 sb.append("-data");
1098 }
1099
1100 sb.append(".lar");
1101
1102 File cacheFile = new File(sb.toString());
1103
1104 if (cacheFile.exists()) {
1105 Date modifiedDate = layoutSetPrototype.getModifiedDate();
1106
1107 if (cacheFile.lastModified() >= modifiedDate.getTime()) {
1108 if (_log.isDebugEnabled()) {
1109 _log.debug(
1110 "Using cached layout set prototype LAR file " +
1111 cacheFile.getAbsolutePath());
1112 }
1113
1114 file = cacheFile;
1115 }
1116 }
1117
1118 boolean newFile = false;
1119
1120 if (file == null) {
1121 Group layoutSetPrototypeGroup = layoutSetPrototype.getGroup();
1122
1123 file = LayoutLocalServiceUtil.exportLayoutsAsFile(
1124 layoutSetPrototypeGroup.getGroupId(), true, null, parameterMap,
1125 null, null);
1126
1127 newFile = true;
1128 }
1129
1130 long userId = UserLocalServiceUtil.getDefaultUserId(
1131 layoutSetPrototype.getCompanyId());
1132
1133 LayoutLocalServiceUtil.importLayouts(
1134 userId, groupId, privateLayout, parameterMap, file);
1135
1136 if (newFile) {
1137 try {
1138 FileUtil.copyFile(file, cacheFile);
1139
1140 if (_log.isDebugEnabled()) {
1141 _log.debug(
1142 "Copied " + file.getAbsolutePath() + " to " +
1143 cacheFile.getAbsolutePath());
1144 }
1145 }
1146 catch (Exception e) {
1147 _log.error(
1148 "Unable to copy file " + file.getAbsolutePath() + " to " +
1149 cacheFile.getAbsolutePath(),
1150 e);
1151 }
1152 }
1153 }
1154
1155 protected static void setLayoutSetPrototypeLinkEnabledParameter(
1156 Map<String, String[]> parameterMap, LayoutSet targetLayoutSet,
1157 ServiceContext serviceContext) {
1158
1159 PermissionChecker permissionChecker =
1160 PermissionThreadLocal.getPermissionChecker();
1161
1162 if ((permissionChecker == null) ||
1163 !PortalPermissionUtil.contains(
1164 permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) {
1165
1166 return;
1167 }
1168
1169 if (targetLayoutSet.isPrivateLayout()) {
1170 boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1171 serviceContext, "privateLayoutSetPrototypeLinkEnabled", true);
1172
1173 if (!privateLayoutSetPrototypeLinkEnabled) {
1174 privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1175 serviceContext, "layoutSetPrototypeLinkEnabled");
1176 }
1177
1178 parameterMap.put(
1179 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1180 new String[] {
1181 String.valueOf(privateLayoutSetPrototypeLinkEnabled)
1182 });
1183 }
1184 else {
1185 boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1186 serviceContext, "publicLayoutSetPrototypeLinkEnabled");
1187
1188 if (!publicLayoutSetPrototypeLinkEnabled) {
1189 publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1190 serviceContext, "layoutSetPrototypeLinkEnabled", true);
1191 }
1192
1193 parameterMap.put(
1194 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1195 new String[] {
1196 String.valueOf(publicLayoutSetPrototypeLinkEnabled)
1197 });
1198 }
1199 }
1200
1201 protected static void updateLayoutSetPrototypeLink(
1202 long groupId, boolean privateLayout, long layoutSetPrototypeId,
1203 boolean layoutSetPrototypeLinkEnabled)
1204 throws Exception {
1205
1206 String layoutSetPrototypeUuid = null;
1207
1208 if (layoutSetPrototypeId > 0) {
1209 LayoutSetPrototype layoutSetPrototype =
1210 LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype(
1211 layoutSetPrototypeId);
1212
1213 if (layoutSetPrototype != null) {
1214 layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
1215
1216
1217
1218 if (!layoutSetPrototypeLinkEnabled &&
1219 (layoutSetPrototypeId > 0)) {
1220
1221 Map<String, String[]> parameterMap =
1222 getLayoutSetPrototypesParameters(true);
1223
1224 importLayoutSetPrototype(
1225 layoutSetPrototype, groupId, privateLayout,
1226 parameterMap, true);
1227 }
1228 }
1229 }
1230
1231 LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled(
1232 groupId, privateLayout, layoutSetPrototypeLinkEnabled,
1233 layoutSetPrototypeUuid);
1234 }
1235
1236 private static final String _TEMP_DIR =
1237 SystemProperties.get(SystemProperties.TMP_DIR) +
1238 "/liferay/layout_set_prototype/";
1239
1240 private static Log _log = LogFactoryUtil.getLog(SitesUtil.class);
1241
1242 }