/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portlet.sites.util; import com.liferay.exportimport.kernel.configuration.ExportImportConfigurationConstants; import com.liferay.exportimport.kernel.configuration.ExportImportConfigurationSettingsMapFactory; import com.liferay.exportimport.kernel.lar.ExportImportHelperUtil; import com.liferay.exportimport.kernel.lar.PortletDataHandlerKeys; import com.liferay.exportimport.kernel.lar.UserIdStrategy; import com.liferay.exportimport.kernel.model.ExportImportConfiguration; import com.liferay.exportimport.kernel.service.ExportImportConfigurationLocalServiceUtil; import com.liferay.exportimport.kernel.service.ExportImportLocalServiceUtil; import com.liferay.exportimport.kernel.service.ExportImportServiceUtil; import com.liferay.exportimport.kernel.staging.MergeLayoutPrototypesThreadLocal; import com.liferay.portal.events.EventsProcessorUtil; import com.liferay.portal.kernel.backgroundtask.BackgroundTask; import com.liferay.portal.kernel.backgroundtask.BackgroundTaskManagerUtil; import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.RequiredLayoutException; import com.liferay.portal.kernel.language.LanguageUtil; import com.liferay.portal.kernel.lock.Lock; import com.liferay.portal.kernel.lock.LockManagerUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.GroupConstants; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.LayoutConstants; import com.liferay.portal.kernel.model.LayoutPrototype; import com.liferay.portal.kernel.model.LayoutSet; import com.liferay.portal.kernel.model.LayoutSetPrototype; import com.liferay.portal.kernel.model.LayoutType; import com.liferay.portal.kernel.model.LayoutTypePortlet; import com.liferay.portal.kernel.model.Organization; import com.liferay.portal.kernel.model.PortletConstants; import com.liferay.portal.kernel.model.ResourceConstants; import com.liferay.portal.kernel.model.Role; import com.liferay.portal.kernel.model.RoleConstants; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.model.UserGroup; import com.liferay.portal.kernel.model.impl.VirtualLayout; import com.liferay.portal.kernel.portlet.PortletPreferencesFactoryUtil; import com.liferay.portal.kernel.security.auth.PrincipalException; import com.liferay.portal.kernel.security.auth.PrincipalThreadLocal; import com.liferay.portal.kernel.security.permission.ActionKeys; import com.liferay.portal.kernel.security.permission.PermissionChecker; import com.liferay.portal.kernel.security.permission.PermissionThreadLocal; import com.liferay.portal.kernel.security.permission.ResourceActionsUtil; import com.liferay.portal.kernel.service.GroupLocalServiceUtil; import com.liferay.portal.kernel.service.GroupServiceUtil; import com.liferay.portal.kernel.service.LayoutLocalServiceUtil; import com.liferay.portal.kernel.service.LayoutPrototypeLocalServiceUtil; import com.liferay.portal.kernel.service.LayoutServiceUtil; import com.liferay.portal.kernel.service.LayoutSetLocalServiceUtil; import com.liferay.portal.kernel.service.LayoutSetPrototypeLocalServiceUtil; import com.liferay.portal.kernel.service.LayoutSetServiceUtil; import com.liferay.portal.kernel.service.OrganizationLocalServiceUtil; import com.liferay.portal.kernel.service.PortletLocalServiceUtil; import com.liferay.portal.kernel.service.PortletPreferencesLocalServiceUtil; import com.liferay.portal.kernel.service.ResourcePermissionLocalServiceUtil; import com.liferay.portal.kernel.service.RoleLocalServiceUtil; import com.liferay.portal.kernel.service.ServiceContext; import com.liferay.portal.kernel.service.ServiceContextFactory; import com.liferay.portal.kernel.service.ServiceContextThreadLocal; import com.liferay.portal.kernel.service.UserGroupLocalServiceUtil; import com.liferay.portal.kernel.service.UserLocalServiceUtil; import com.liferay.portal.kernel.service.permission.GroupPermissionUtil; import com.liferay.portal.kernel.service.permission.LayoutPermissionUtil; import com.liferay.portal.kernel.service.permission.PortalPermissionUtil; import com.liferay.portal.kernel.service.permission.PortletPermissionUtil; import com.liferay.portal.kernel.service.persistence.LayoutSetUtil; import com.liferay.portal.kernel.service.persistence.LayoutUtil; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.LocaleThreadLocal; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.PortalUtil; import com.liferay.portal.kernel.util.PortletKeys; import com.liferay.portal.kernel.util.PrefsPropsUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.SystemProperties; import com.liferay.portal.kernel.util.UnicodeProperties; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.kernel.uuid.PortalUUIDUtil; import com.liferay.portal.kernel.workflow.WorkflowConstants; import com.liferay.portal.util.PropsValues; import com.liferay.portlet.PortletPreferencesImpl; import com.liferay.sites.kernel.util.Sites; import java.io.File; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Raymond Augé * @author Ryan Park * @author Zsolt Berentey */ public class SitesImpl implements Sites { @Override public void addMergeFailFriendlyURLLayout(Layout layout) throws PortalException { LayoutSet layoutSet = layout.getLayoutSet(); layoutSet = LayoutSetLocalServiceUtil.getLayoutSet( layoutSet.getGroupId(), layoutSet.isPrivateLayout()); UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); String mergeFailFriendlyURLLayouts = settingsProperties.getProperty( MERGE_FAIL_FRIENDLY_URL_LAYOUTS, StringPool.BLANK); mergeFailFriendlyURLLayouts = StringUtil.add( mergeFailFriendlyURLLayouts, layout.getUuid()); settingsProperties.setProperty( MERGE_FAIL_FRIENDLY_URL_LAYOUTS, mergeFailFriendlyURLLayouts); LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet); } @Override public void addPortletBreadcrumbEntries( Group group, HttpServletRequest request, PortletURL portletURL) throws Exception { List<Group> ancestorGroups = group.getAncestors(); Collections.reverse(ancestorGroups); for (Group ancestorGroup : ancestorGroups) { portletURL.setParameter( "groupId", String.valueOf(ancestorGroup.getGroupId())); PortalUtil.addPortletBreadcrumbEntry( request, ancestorGroup.getDescriptiveName(), portletURL.toString()); } Group unescapedGroup = group.toUnescapedModel(); portletURL.setParameter( "groupId", String.valueOf(unescapedGroup.getGroupId())); PortalUtil.addPortletBreadcrumbEntry( request, unescapedGroup.getDescriptiveName(), portletURL.toString()); } @Override public void addPortletBreadcrumbEntries( Group group, HttpServletRequest request, RenderResponse renderResponse) throws Exception { PortletURL portletURL = renderResponse.createRenderURL(); addPortletBreadcrumbEntries(group, request, portletURL); } @Override public void addPortletBreadcrumbEntries( Group group, String pagesName, PortletURL redirectURL, HttpServletRequest request, RenderResponse renderResponse) throws Exception { if (renderResponse == null) { return; } ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); Group unescapedGroup = group.toUnescapedModel(); Locale locale = themeDisplay.getLocale(); if (group.isLayoutPrototype()) { PortalUtil.addPortletBreadcrumbEntry( request, LanguageUtil.get(locale, "page-template"), null); PortalUtil.addPortletBreadcrumbEntry( request, unescapedGroup.getDescriptiveName(), redirectURL.toString()); } else { PortalUtil.addPortletBreadcrumbEntry( request, unescapedGroup.getDescriptiveName(), null); } if (!group.isLayoutPrototype()) { PortalUtil.addPortletBreadcrumbEntry( request, LanguageUtil.get(locale, pagesName), redirectURL.toString()); } } @Override public void applyLayoutPrototype( LayoutPrototype layoutPrototype, Layout targetLayout, boolean linkEnabled) throws Exception { Locale siteDefaultLocale = LocaleThreadLocal.getSiteDefaultLocale(); LayoutTypePortlet targetLayoutType = (LayoutTypePortlet)targetLayout.getLayoutType(); List<String> targetLayoutPortletIds = targetLayoutType.getPortletIds(); Layout layoutPrototypeLayout = layoutPrototype.getLayout(); ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext(); serviceContext.setAttribute("layoutPrototypeLinkEnabled", linkEnabled); serviceContext.setAttribute( "layoutPrototypeUuid", layoutPrototype.getUuid()); try { Locale targetSiteDefaultLocale = PortalUtil.getSiteDefaultLocale( targetLayout.getGroupId()); LocaleThreadLocal.setSiteDefaultLocale(targetSiteDefaultLocale); targetLayout = LayoutLocalServiceUtil.updateLayout( targetLayout.getGroupId(), targetLayout.isPrivateLayout(), targetLayout.getLayoutId(), targetLayout.getParentLayoutId(), targetLayout.getNameMap(), targetLayout.getTitleMap(), targetLayout.getDescriptionMap(), targetLayout.getKeywordsMap(), targetLayout.getRobotsMap(), layoutPrototypeLayout.getType(), targetLayout.getHidden(), targetLayout.getFriendlyURLMap(), targetLayout.getIconImage(), null, serviceContext); } finally { LocaleThreadLocal.setSiteDefaultLocale(siteDefaultLocale); } targetLayout = LayoutLocalServiceUtil.updateLayout( targetLayout.getGroupId(), targetLayout.isPrivateLayout(), targetLayout.getLayoutId(), layoutPrototypeLayout.getTypeSettings()); copyPortletPermissions(targetLayout, layoutPrototypeLayout); copyPortletSetups(layoutPrototypeLayout, targetLayout); copyLookAndFeel(targetLayout, layoutPrototypeLayout); deleteUnreferencedPortlets( targetLayoutPortletIds, targetLayout, layoutPrototypeLayout); targetLayout = LayoutLocalServiceUtil.getLayout(targetLayout.getPlid()); UnicodeProperties typeSettingsProperties = targetLayout.getTypeSettingsProperties(); typeSettingsProperties.setProperty( LAST_MERGE_TIME, String.valueOf(targetLayout.getModifiedDate().getTime())); LayoutLocalServiceUtil.updateLayout(targetLayout); UnicodeProperties prototypeTypeSettingsProperties = layoutPrototypeLayout.getTypeSettingsProperties(); prototypeTypeSettingsProperties.setProperty(MERGE_FAIL_COUNT, "0"); LayoutLocalServiceUtil.updateLayout(layoutPrototypeLayout); } @Override public void copyLayout( long userId, Layout sourceLayout, Layout targetLayout, ServiceContext serviceContext) throws Exception { User user = UserLocalServiceUtil.getUser(userId); Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters( serviceContext); parameterMap.put( PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS, new String[] {Boolean.FALSE.toString()}); Map<String, Serializable> exportLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildExportLayoutSettingsMap( user, sourceLayout.getGroupId(), sourceLayout.isPrivateLayout(), new long[] {sourceLayout.getLayoutId()}, parameterMap); ExportImportConfiguration exportConfiguration = ExportImportConfigurationLocalServiceUtil. addDraftExportImportConfiguration( user.getUserId(), ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT, exportLayoutSettingsMap); File file = ExportImportLocalServiceUtil.exportLayoutsAsFile( exportConfiguration); try { Map<String, Serializable> importLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildImportLayoutSettingsMap( userId, targetLayout.getGroupId(), targetLayout.isPrivateLayout(), null, parameterMap, user.getLocale(), user.getTimeZone()); ExportImportConfiguration importConfiguration = ExportImportConfigurationLocalServiceUtil. addDraftExportImportConfiguration( userId, ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT, importLayoutSettingsMap); ExportImportLocalServiceUtil.importLayouts( importConfiguration, file); } finally { file.delete(); } } @Override public void copyLookAndFeel(Layout targetLayout, Layout sourceLayout) throws Exception { LayoutLocalServiceUtil.updateLookAndFeel( targetLayout.getGroupId(), targetLayout.isPrivateLayout(), targetLayout.getLayoutId(), sourceLayout.getThemeId(), sourceLayout.getColorSchemeId(), sourceLayout.getCss()); } @Override public void copyPortletPermissions(Layout targetLayout, Layout sourceLayout) throws Exception { List<Role> roles = RoleLocalServiceUtil.getGroupRelatedRoles( targetLayout.getGroupId()); Group targetGroup = targetLayout.getGroup(); LayoutTypePortlet sourceLayoutTypePortlet = (LayoutTypePortlet)sourceLayout.getLayoutType(); List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds(); for (String sourcePortletId : sourcePortletIds) { String resourceName = PortletConstants.getRootPortletId( sourcePortletId); String sourceResourcePrimKey = PortletPermissionUtil.getPrimaryKey( sourceLayout.getPlid(), sourcePortletId); String targetResourcePrimKey = PortletPermissionUtil.getPrimaryKey( targetLayout.getPlid(), sourcePortletId); List<String> actionIds = ResourceActionsUtil.getPortletResourceActions(resourceName); for (Role role : roles) { String roleName = role.getName(); if (roleName.equals(RoleConstants.ADMINISTRATOR) || (!targetGroup.isLayoutSetPrototype() && targetLayout.isPrivateLayout() && roleName.equals(RoleConstants.GUEST))) { continue; } List<String> actions = ResourcePermissionLocalServiceUtil. getAvailableResourcePermissionActionIds( targetLayout.getCompanyId(), resourceName, ResourceConstants.SCOPE_INDIVIDUAL, sourceResourcePrimKey, role.getRoleId(), actionIds); ResourcePermissionLocalServiceUtil.setResourcePermissions( targetLayout.getCompanyId(), resourceName, ResourceConstants.SCOPE_INDIVIDUAL, targetResourcePrimKey, role.getRoleId(), actions.toArray(new String[actions.size()])); } } } @Override public void copyPortletSetups(Layout sourceLayout, Layout targetLayout) throws Exception { LayoutTypePortlet sourceLayoutTypePortlet = (LayoutTypePortlet)sourceLayout.getLayoutType(); List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds(); for (String sourcePortletId : sourcePortletIds) { PortletPreferences sourcePreferences = PortletPreferencesFactoryUtil.getPortletSetup( sourceLayout, sourcePortletId, null); PortletPreferencesImpl sourcePreferencesImpl = (PortletPreferencesImpl)sourcePreferences; PortletPreferences targetPreferences = PortletPreferencesFactoryUtil.getPortletSetup( targetLayout, sourcePortletId, null); PortletPreferencesImpl targetPreferencesImpl = (PortletPreferencesImpl)targetPreferences; PortletPreferencesLocalServiceUtil.updatePreferences( targetPreferencesImpl.getOwnerId(), targetPreferencesImpl.getOwnerType(), targetPreferencesImpl.getPlid(), sourcePortletId, sourcePreferences); if ((sourcePreferencesImpl.getOwnerId() != PortletKeys.PREFS_OWNER_ID_DEFAULT) && (sourcePreferencesImpl.getOwnerType() != PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) { sourcePreferences = PortletPreferencesFactoryUtil.getLayoutPortletSetup( sourceLayout, sourcePortletId); sourcePreferencesImpl = (PortletPreferencesImpl)sourcePreferences; targetPreferences = PortletPreferencesFactoryUtil.getLayoutPortletSetup( targetLayout, sourcePortletId); targetPreferencesImpl = (PortletPreferencesImpl)targetPreferences; PortletPreferencesLocalServiceUtil.updatePreferences( targetPreferencesImpl.getOwnerId(), targetPreferencesImpl.getOwnerType(), targetPreferencesImpl.getPlid(), sourcePortletId, sourcePreferences); } ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext(); updateLayoutScopes( serviceContext.getUserId(), sourceLayout, targetLayout, sourcePreferences, targetPreferences, sourcePortletId, serviceContext.getLanguageId()); } } @Override public void copyTypeSettings(Group sourceGroup, Group targetGroup) throws Exception { GroupServiceUtil.updateGroup( targetGroup.getGroupId(), sourceGroup.getTypeSettings()); } @Override public Object[] deleteLayout( HttpServletRequest request, HttpServletResponse response) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); PermissionChecker permissionChecker = themeDisplay.getPermissionChecker(); long selPlid = ParamUtil.getLong(request, "selPlid"); long groupId = ParamUtil.getLong(request, "groupId"); boolean privateLayout = ParamUtil.getBoolean(request, "privateLayout"); long layoutId = ParamUtil.getLong(request, "layoutId"); Layout layout = null; if (selPlid <= 0) { layout = LayoutLocalServiceUtil.getLayout( groupId, privateLayout, layoutId); } else { layout = LayoutLocalServiceUtil.getLayout(selPlid); groupId = layout.getGroupId(); privateLayout = layout.isPrivateLayout(); layoutId = layout.getLayoutId(); } Group group = layout.getGroup(); String oldFriendlyURL = themeDisplay.getLayoutFriendlyURL(layout); if (group.isStagingGroup() && !GroupPermissionUtil.contains( permissionChecker, group, ActionKeys.MANAGE_STAGING) && !GroupPermissionUtil.contains( permissionChecker, group, ActionKeys.PUBLISH_STAGING)) { throw new PrincipalException.MustHavePermission( permissionChecker, Group.class.getName(), group.getGroupId(), ActionKeys.MANAGE_STAGING, ActionKeys.PUBLISH_STAGING); } if (LayoutPermissionUtil.contains( permissionChecker, layout, ActionKeys.DELETE)) { LayoutType layoutType = layout.getLayoutType(); EventsProcessorUtil.process( PropsKeys.LAYOUT_CONFIGURATION_ACTION_DELETE, layoutType.getConfigurationActionDelete(), request, response); } if (group.isGuest() && !layout.isPrivateLayout() && layout.isRootLayout() && (LayoutLocalServiceUtil.getLayoutsCount( group, false, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) == 1)) { throw new RequiredLayoutException( RequiredLayoutException.AT_LEAST_ONE); } ServiceContext serviceContext = ServiceContextFactory.getInstance( request); LayoutServiceUtil.deleteLayout( groupId, privateLayout, layoutId, serviceContext); return new Object[] { group, oldFriendlyURL, LayoutConstants.DEFAULT_PLID }; } @Override public Object[] deleteLayout( PortletRequest portletRequest, PortletResponse portletResponse) throws Exception { HttpServletRequest request = PortalUtil.getHttpServletRequest( portletRequest); HttpServletResponse response = PortalUtil.getHttpServletResponse( portletResponse); return deleteLayout(request, response); } @Override public void deleteLayout( RenderRequest renderRequest, RenderResponse renderResponse) throws Exception { HttpServletRequest request = PortalUtil.getHttpServletRequest( renderRequest); HttpServletResponse response = PortalUtil.getHttpServletResponse( renderResponse); deleteLayout(request, response); } @Override public File exportLayoutSetPrototype( LayoutSetPrototype layoutSetPrototype, ServiceContext serviceContext) throws PortalException { User user = UserLocalServiceUtil.fetchUser(serviceContext.getUserId()); if (user == null) { BackgroundTask backgroundTask = BackgroundTaskManagerUtil.fetchBackgroundTask( BackgroundTaskThreadLocal.getBackgroundTaskId()); if (backgroundTask != null) { user = UserLocalServiceUtil.getUser(backgroundTask.getUserId()); } } if (user == null) { user = UserLocalServiceUtil.getUser( GetterUtil.getLong(PrincipalThreadLocal.getName())); } LayoutSet layoutSet = layoutSetPrototype.getLayoutSet(); List<Layout> layoutSetPrototypeLayouts = LayoutLocalServiceUtil.getLayouts( layoutSet.getGroupId(), layoutSet.isPrivateLayout()); Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters( serviceContext); Map<String, Serializable> exportLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildExportLayoutSettingsMap( user, layoutSet.getGroupId(), layoutSet.isPrivateLayout(), ExportImportHelperUtil.getLayoutIds( layoutSetPrototypeLayouts), parameterMap); ExportImportConfiguration exportImportConfiguration = ExportImportConfigurationLocalServiceUtil. addDraftExportImportConfiguration( user.getUserId(), ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT, exportLayoutSettingsMap); return ExportImportLocalServiceUtil.exportLayoutsAsFile( exportImportConfiguration); } @Override public Long[] filterGroups(List<Group> groups, String[] groupKeys) { List<Long> groupIds = new ArrayList<>(); for (Group group : groups) { if (!ArrayUtil.contains(groupKeys, group.getGroupKey())) { groupIds.add(group.getGroupId()); } } return ArrayUtil.toArray(ArrayUtil.toLongArray(groupIds)); } @Override public Layout getLayoutSetPrototypeLayout(Layout layout) { try { LayoutSet layoutSet = layout.getLayoutSet(); if (!layoutSet.isLayoutSetPrototypeLinkActive()) { return null; } LayoutSetPrototype layoutSetPrototype = LayoutSetPrototypeLocalServiceUtil. getLayoutSetPrototypeByUuidAndCompanyId( layoutSet.getLayoutSetPrototypeUuid(), layout.getCompanyId()); return LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId( layout.getSourcePrototypeLayoutUuid(), layoutSetPrototype.getGroupId(), true); } catch (Exception e) { _log.error( "Unable to fetch the the layout set prototype's layout", e); } return null; } @Override public Map<String, String[]> getLayoutSetPrototypeParameters( ServiceContext serviceContext) { Map<String, String[]> parameterMap = new LinkedHashMap<>(); parameterMap.put( PortletDataHandlerKeys.DATA_STRATEGY, new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR}); parameterMap.put( PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.DELETE_PORTLET_DATA, new String[] {Boolean.FALSE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_SETTINGS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_SETTINGS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE, new String[] { PortletDataHandlerKeys. LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE }); parameterMap.put( PortletDataHandlerKeys.LOGO, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PERFORM_DIRECT_BINARY_IMPORT, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PERMISSIONS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_CONFIGURATION, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA_ALL, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_SETUP_ALL, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.THEME_REFERENCE, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.USER_ID_STRATEGY, new String[] {UserIdStrategy.CURRENT_USER_ID}); return parameterMap; } /** * Returns the number of failed merge attempts for the layout prototype * since its last reset or update. * * @param layoutPrototype the page template being checked for failed merge * attempts * @return the number of failed merge attempts for the layout prototype */ @Override public int getMergeFailCount(LayoutPrototype layoutPrototype) throws PortalException { if ((layoutPrototype == null) || (layoutPrototype.getLayoutPrototypeId() == 0)) { return 0; } Layout layoutPrototypeLayout = layoutPrototype.getLayout(); UnicodeProperties prototypeTypeSettingsProperties = layoutPrototypeLayout.getTypeSettingsProperties(); return GetterUtil.getInteger( prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT)); } /** * Returns the number of failed merge attempts for the layout set prototype * since its last reset or update. * * @param layoutSetPrototype the site template being checked for failed * merge attempts * @return the number of failed merge attempts for the layout set prototype */ @Override public int getMergeFailCount(LayoutSetPrototype layoutSetPrototype) throws PortalException { if ((layoutSetPrototype == null) || (layoutSetPrototype.getLayoutSetPrototypeId() == 0)) { return 0; } LayoutSet layoutSetPrototypeLayoutSet = layoutSetPrototype.getLayoutSet(); UnicodeProperties layoutSetPrototypeSettingsProperties = layoutSetPrototypeLayoutSet.getSettingsProperties(); return GetterUtil.getInteger( layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT)); } @Override public List<Layout> getMergeFailFriendlyURLLayouts(LayoutSet layoutSet) throws PortalException { if (layoutSet == null) { return Collections.emptyList(); } UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); String uuids = settingsProperties.getProperty( MERGE_FAIL_FRIENDLY_URL_LAYOUTS); if (Validator.isNotNull(uuids)) { List<Layout> layouts = new ArrayList<>(); for (String uuid : StringUtil.split(uuids)) { Layout layout = LayoutLocalServiceUtil.getLayoutByUuidAndGroupId( uuid, layoutSet.getGroupId(), layoutSet.isPrivateLayout()); layouts.add(layout); } return layouts; } return Collections.emptyList(); } @Override public List<String> getOrganizationNames(Group group, User user) throws Exception { List<Organization> organizations = OrganizationLocalServiceUtil.getGroupUserOrganizations( group.getGroupId(), user.getUserId()); return ListUtil.toList(organizations, Organization.NAME_ACCESSOR); } @Override public List<String> getUserGroupNames(Group group, User user) throws Exception { List<UserGroup> userGroups = UserGroupLocalServiceUtil.getGroupUserUserGroups( group.getGroupId(), user.getUserId()); return ListUtil.toList(userGroups, UserGroup.NAME_ACCESSOR); } @Override public void importLayoutSetPrototype( LayoutSetPrototype layoutSetPrototype, InputStream inputStream, ServiceContext serviceContext) throws PortalException { LayoutSet layoutSet = layoutSetPrototype.getLayoutSet(); Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters( serviceContext); setLayoutSetPrototypeLinkEnabledParameter( parameterMap, layoutSet, serviceContext); User user = UserLocalServiceUtil.fetchUser(serviceContext.getUserId()); if (user == null) { BackgroundTask backgroundTask = BackgroundTaskManagerUtil.fetchBackgroundTask( BackgroundTaskThreadLocal.getBackgroundTaskId()); if (backgroundTask != null) { user = UserLocalServiceUtil.getUser(backgroundTask.getUserId()); } } if (user == null) { user = UserLocalServiceUtil.getUser( GetterUtil.getLong(PrincipalThreadLocal.getName())); } Map<String, Serializable> importLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildImportLayoutSettingsMap( user.getUserId(), layoutSet.getGroupId(), layoutSet.isPrivateLayout(), null, parameterMap, user.getLocale(), user.getTimeZone()); ExportImportConfiguration exportImportConfiguration = ExportImportConfigurationLocalServiceUtil. addDraftExportImportConfiguration( user.getUserId(), ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT, importLayoutSettingsMap); ExportImportServiceUtil.importLayouts( exportImportConfiguration, inputStream); } @Override public boolean isContentSharingWithChildrenEnabled(Group group) { UnicodeProperties typeSettingsProperties = group.getParentLiveGroupTypeSettingsProperties(); int companyContentSharingEnabled = PrefsPropsUtil.getInteger( group.getCompanyId(), PropsKeys.SITES_CONTENT_SHARING_WITH_CHILDREN_ENABLED); if (companyContentSharingEnabled == CONTENT_SHARING_WITH_CHILDREN_DISABLED) { return false; } int groupContentSharingEnabled = GetterUtil.getInteger( typeSettingsProperties.getProperty( "contentSharingWithChildrenEnabled"), CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE); if ((groupContentSharingEnabled == CONTENT_SHARING_WITH_CHILDREN_ENABLED) || ((companyContentSharingEnabled == CONTENT_SHARING_WITH_CHILDREN_ENABLED_BY_DEFAULT) && (groupContentSharingEnabled == CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE))) { return true; } return false; } @Override public boolean isFirstLayout( long groupId, boolean privateLayout, long layoutId) { Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout( groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID); if ((firstLayout != null) && (firstLayout.getLayoutId() == layoutId)) { return true; } return false; } @Override public boolean isLayoutDeleteable(Layout layout) { try { if (layout instanceof VirtualLayout) { return false; } if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) { return true; } LayoutSet layoutSet = layout.getLayoutSet(); if (!layoutSet.isLayoutSetPrototypeLinkActive()) { return true; } if (LayoutLocalServiceUtil.hasLayoutSetPrototypeLayout( layoutSet.getLayoutSetPrototypeUuid(), layout.getCompanyId(), layout.getSourcePrototypeLayoutUuid())) { return false; } } catch (Exception e) { if (_log.isDebugEnabled()) { _log.debug(e, e); } } return true; } @Override public boolean isLayoutModifiedSinceLastMerge(Layout layout) { if ((layout == null) || Validator.isNull(layout.getSourcePrototypeLayoutUuid()) || layout.isLayoutPrototypeLinkActive() || !isLayoutUpdateable(layout)) { return false; } long lastMergeTime = GetterUtil.getLong( layout.getTypeSettingsProperty(LAST_MERGE_TIME)); if (lastMergeTime == 0) { return false; } Date existingLayoutModifiedDate = layout.getModifiedDate(); if ((existingLayoutModifiedDate != null) && (existingLayoutModifiedDate.getTime() > lastMergeTime)) { return true; } return false; } /** * Returns <code>true</code> if the linked site template can be merged into * the layout set. This method checks the current number of merge fail * attempts stored for the linked site template and, if greater than the * merge fail threshold, will return <code>false</code>. * * @param group the site template's group, which is about to be merged into * the layout set * @param layoutSet the site in which the site template is attempting to * merge into * @return <code>true</code> if the linked site template can be merged into * the layout set; <code>false</code> otherwise */ @Override public boolean isLayoutSetMergeable(Group group, LayoutSet layoutSet) throws PortalException { if (!layoutSet.isLayoutSetPrototypeLinkActive() || group.isLayoutPrototype() || group.isLayoutSetPrototype()) { return false; } UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); long lastMergeTime = GetterUtil.getLong( settingsProperties.getProperty(LAST_MERGE_TIME)); LayoutSetPrototype layoutSetPrototype = LayoutSetPrototypeLocalServiceUtil. getLayoutSetPrototypeByUuidAndCompanyId( layoutSet.getLayoutSetPrototypeUuid(), layoutSet.getCompanyId()); Date modifiedDate = layoutSetPrototype.getModifiedDate(); if (lastMergeTime >= modifiedDate.getTime()) { return false; } LayoutSet layoutSetPrototypeLayoutSet = layoutSetPrototype.getLayoutSet(); UnicodeProperties layoutSetPrototypeSettingsProperties = layoutSetPrototypeLayoutSet.getSettingsProperties(); int mergeFailCount = GetterUtil.getInteger( layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT)); if (mergeFailCount > PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) { if (_log.isWarnEnabled()) { StringBundler sb = new StringBundler(6); sb.append("Merge not performed because the fail threshold "); sb.append("was reached for layoutSetPrototypeId "); sb.append(layoutSetPrototype.getLayoutSetPrototypeId()); sb.append(" and layoutId "); sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId()); sb.append(". Update the count in the database to try again."); _log.warn(sb.toString()); } return false; } return true; } @Override public boolean isLayoutSetPrototypeUpdateable(LayoutSet layoutSet) { if (!layoutSet.isLayoutSetPrototypeLinkActive()) { return true; } try { LayoutSetPrototype layoutSetPrototype = LayoutSetPrototypeLocalServiceUtil. getLayoutSetPrototypeByUuidAndCompanyId( layoutSet.getLayoutSetPrototypeUuid(), layoutSet.getCompanyId()); String layoutsUpdateable = layoutSetPrototype.getSettingsProperty( "layoutsUpdateable"); if (Validator.isNotNull(layoutsUpdateable)) { return GetterUtil.getBoolean(layoutsUpdateable, true); } } catch (Exception e) { if (_log.isDebugEnabled()) { _log.debug(e, e); } } return true; } @Override public boolean isLayoutSortable(Layout layout) { return isLayoutDeleteable(layout); } @Override public boolean isLayoutUpdateable(Layout layout) { try { if (layout instanceof VirtualLayout) { return false; } if (Validator.isNull(layout.getLayoutPrototypeUuid()) && Validator.isNull(layout.getSourcePrototypeLayoutUuid())) { return true; } LayoutSet layoutSet = layout.getLayoutSet(); if (layoutSet.isLayoutSetPrototypeLinkActive()) { boolean layoutSetPrototypeUpdateable = isLayoutSetPrototypeUpdateable(layoutSet); if (!layoutSetPrototypeUpdateable) { return false; } Layout layoutSetPrototypeLayout = getLayoutSetPrototypeLayout( layout); String layoutUpdateable = layoutSetPrototypeLayout.getTypeSettingsProperty( LAYOUT_UPDATEABLE); if (Validator.isNull(layoutUpdateable)) { return true; } return GetterUtil.getBoolean(layoutUpdateable); } } catch (Exception e) { if (_log.isDebugEnabled()) { _log.debug(e, e); } } return true; } @Override public boolean isUserGroupLayout(Layout layout) throws PortalException { if (!(layout instanceof VirtualLayout)) { return false; } VirtualLayout virtualLayout = (VirtualLayout)layout; Layout sourceLayout = virtualLayout.getSourceLayout(); Group sourceGroup = sourceLayout.getGroup(); if (sourceGroup.isUserGroup()) { return true; } return false; } @Override public boolean isUserGroupLayoutSetViewable( PermissionChecker permissionChecker, Group userGroupGroup) throws PortalException { if (!userGroupGroup.isUserGroup()) { return false; } if (GroupPermissionUtil.contains( permissionChecker, userGroupGroup, ActionKeys.VIEW)) { return true; } UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup( userGroupGroup.getClassPK()); if (UserLocalServiceUtil.hasUserGroupUser( userGroup.getUserGroupId(), permissionChecker.getUserId())) { return true; } else { return false; } } @Override public void mergeLayoutPrototypeLayout(Group group, Layout layout) throws Exception { String sourcePrototypeLayoutUuid = layout.getSourcePrototypeLayoutUuid(); if (Validator.isNull(sourcePrototypeLayoutUuid)) { doMergeLayoutPrototypeLayout(group, layout); return; } LayoutSet layoutSet = layout.getLayoutSet(); long layoutSetPrototypeId = layoutSet.getLayoutSetPrototypeId(); if (layoutSetPrototypeId > 0) { Group layoutSetPrototypeGroup = GroupLocalServiceUtil.getLayoutSetPrototypeGroup( layout.getCompanyId(), layoutSetPrototypeId); Layout sourcePrototypeLayout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId( sourcePrototypeLayoutUuid, layoutSetPrototypeGroup.getGroupId(), true); if (sourcePrototypeLayout != null) { doMergeLayoutPrototypeLayout( layoutSetPrototypeGroup, sourcePrototypeLayout); } } doMergeLayoutPrototypeLayout(group, layout); } @Override public void mergeLayoutSetPrototypeLayouts(Group group, LayoutSet layoutSet) throws Exception { if (!isLayoutSetMergeable(group, layoutSet)) { return; } UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); long lastMergeTime = GetterUtil.getLong( settingsProperties.getProperty(LAST_MERGE_TIME)); LayoutSetPrototype layoutSetPrototype = LayoutSetPrototypeLocalServiceUtil. getLayoutSetPrototypeByUuidAndCompanyId( layoutSet.getLayoutSetPrototypeUuid(), layoutSet.getCompanyId()); LayoutSet layoutSetPrototypeLayoutSet = layoutSetPrototype.getLayoutSet(); UnicodeProperties layoutSetPrototypeSettingsProperties = layoutSetPrototypeLayoutSet.getSettingsProperties(); int mergeFailCount = GetterUtil.getInteger( layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT)); String owner = PortalUUIDUtil.generate(); try { Lock lock = LockManagerUtil.lock( SitesImpl.class.getName(), String.valueOf(layoutSet.getLayoutSetId()), owner); // Double deep check if (!owner.equals(lock.getOwner())) { Date createDate = lock.getCreateDate(); if ((System.currentTimeMillis() - createDate.getTime()) >= PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) { // Acquire lock if the lock is older than the lock max time lock = LockManagerUtil.lock( SitesImpl.class.getName(), String.valueOf(layoutSet.getLayoutSetId()), lock.getOwner(), owner); // Check if acquiring the lock succeeded or if another // process has the lock if (!owner.equals(lock.getOwner())) { return; } } else { return; } } } catch (Exception e) { return; } try { MergeLayoutPrototypesThreadLocal.setInProgress(true); boolean importData = true; long lastResetTime = GetterUtil.getLong( settingsProperties.getProperty(LAST_RESET_TIME)); if ((lastMergeTime > 0) || (lastResetTime > 0)) { importData = false; } Map<String, String[]> parameterMap = getLayoutSetPrototypesParameters(importData); layoutSet = LayoutSetLocalServiceUtil.getLayoutSet( layoutSet.getLayoutSetId()); removeMergeFailFriendlyURLLayouts(layoutSet); importLayoutSetPrototype( layoutSetPrototype, layoutSet.getGroupId(), layoutSet.isPrivateLayout(), parameterMap, importData); } catch (Exception e) { mergeFailCount++; StringBundler sb = new StringBundler(6); sb.append("Merge fail count increased to "); sb.append(mergeFailCount); sb.append(" for layout set prototype "); sb.append(layoutSetPrototype.getLayoutSetPrototypeId()); sb.append(" and layout set "); sb.append(layoutSet.getLayoutSetId()); _log.error(sb.toString(), e); layoutSetPrototypeSettingsProperties.setProperty( MERGE_FAIL_COUNT, String.valueOf(mergeFailCount)); // Invoke updateImpl so that we do not trigger the listeners LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet); } finally { MergeLayoutPrototypesThreadLocal.setInProgress(false); LockManagerUtil.unlock( SitesImpl.class.getName(), String.valueOf(layoutSet.getLayoutSetId()), owner); } } @Override public void removeMergeFailFriendlyURLLayouts(LayoutSet layoutSet) { UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); settingsProperties.remove(MERGE_FAIL_FRIENDLY_URL_LAYOUTS); LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet); } /** * Checks the permissions necessary for resetting the layout. If sufficient, * the layout is reset by calling {@link #doResetPrototype(Layout)}. * * @param layout the page being checked for sufficient permissions */ @Override public void resetPrototype(Layout layout) throws PortalException { checkResetPrototypePermissions(layout.getGroup(), layout); doResetPrototype(layout); } /** * Checks the permissions necessary for resetting the layout set. If * sufficient, the layout set is reset by calling {@link * #doResetPrototype(LayoutSet)}. * * @param layoutSet the site being checked for sufficient permissions */ @Override public void resetPrototype(LayoutSet layoutSet) throws PortalException { checkResetPrototypePermissions(layoutSet.getGroup(), null); doResetPrototype(layoutSet); } /** * Sets the number of failed merge attempts for the layout prototype to a * new value. * * @param layoutPrototype the page template of the counter being updated * @param newMergeFailCount the new value of the counter */ @Override public void setMergeFailCount( LayoutPrototype layoutPrototype, int newMergeFailCount) throws PortalException { Layout layoutPrototypeLayout = layoutPrototype.getLayout(); UnicodeProperties prototypeTypeSettingsProperties = layoutPrototypeLayout.getTypeSettingsProperties(); if (newMergeFailCount == 0) { prototypeTypeSettingsProperties.remove(MERGE_FAIL_COUNT); } else { prototypeTypeSettingsProperties.setProperty( MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount)); } LayoutServiceUtil.updateLayout( layoutPrototypeLayout.getGroupId(), layoutPrototypeLayout.getPrivateLayout(), layoutPrototypeLayout.getLayoutId(), layoutPrototypeLayout.getTypeSettings()); } /** * Sets the number of failed merge attempts for the layout set prototype to * a new value. * * @param layoutSetPrototype the site template of the counter being updated * @param newMergeFailCount the new value of the counter */ @Override public void setMergeFailCount( LayoutSetPrototype layoutSetPrototype, int newMergeFailCount) throws PortalException { LayoutSet layoutSetPrototypeLayoutSet = layoutSetPrototype.getLayoutSet(); UnicodeProperties layoutSetPrototypeSettingsProperties = layoutSetPrototypeLayoutSet.getSettingsProperties(); if (newMergeFailCount == 0) { layoutSetPrototypeSettingsProperties.remove(MERGE_FAIL_COUNT); } else { layoutSetPrototypeSettingsProperties.setProperty( MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount)); } LayoutSetServiceUtil.updateSettings( layoutSetPrototypeLayoutSet.getGroupId(), layoutSetPrototypeLayoutSet.getPrivateLayout(), layoutSetPrototypeLayoutSet.getSettings()); } @Override public void updateLayoutScopes( long userId, Layout sourceLayout, Layout targetLayout, PortletPreferences sourcePreferences, PortletPreferences targetPreferences, String sourcePortletId, String languageId) throws Exception { String scopeType = GetterUtil.getString( sourcePreferences.getValue("lfrScopeType", null)); if (Validator.isNull(scopeType) || !scopeType.equals("layout")) { return; } Layout targetScopeLayout = LayoutLocalServiceUtil.getLayoutByUuidAndGroupId( targetLayout.getUuid(), targetLayout.getGroupId(), targetLayout.isPrivateLayout()); if (!targetScopeLayout.hasScopeGroup()) { GroupLocalServiceUtil.addGroup( userId, GroupConstants.DEFAULT_PARENT_GROUP_ID, Layout.class.getName(), targetLayout.getPlid(), GroupConstants.DEFAULT_LIVE_GROUP_ID, targetLayout.getNameMap(), null, 0, true, GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, null, false, true, null); } String portletTitle = PortalUtil.getPortletTitle( PortletConstants.getRootPortletId(sourcePortletId), languageId); String newPortletTitle = PortalUtil.getNewPortletTitle( portletTitle, String.valueOf(sourceLayout.getLayoutId()), targetLayout.getName(languageId)); targetPreferences.setValue( "groupId", String.valueOf(targetLayout.getGroupId())); targetPreferences.setValue("lfrScopeType", "layout"); targetPreferences.setValue( "lfrScopeLayoutUuid", targetLayout.getUuid()); targetPreferences.setValue( "portletSetupTitle_" + languageId, newPortletTitle); targetPreferences.setValue( "portletSetupUseCustomTitle", Boolean.TRUE.toString()); targetPreferences.store(); } @Override public void updateLayoutSetPrototypesLinks( Group group, long publicLayoutSetPrototypeId, long privateLayoutSetPrototypeId, boolean publicLayoutSetPrototypeLinkEnabled, boolean privateLayoutSetPrototypeLinkEnabled) throws Exception { updateLayoutSetPrototypeLink( group.getGroupId(), true, privateLayoutSetPrototypeId, privateLayoutSetPrototypeLinkEnabled); updateLayoutSetPrototypeLink( group.getGroupId(), false, publicLayoutSetPrototypeId, publicLayoutSetPrototypeLinkEnabled); } /** * Checks the permissions necessary for resetting the layout or site. If the * permissions are not sufficient, a {@link PortalException} is thrown. * * @param group the site being checked for sufficient permissions * @param layout the page being checked for sufficient permissions * (optionally <code>null</code>). If <code>null</code>, the * permissions are only checked for resetting the site. */ protected void checkResetPrototypePermissions(Group group, Layout layout) throws PortalException { PermissionChecker permissionChecker = PermissionThreadLocal.getPermissionChecker(); if ((layout != null) && !LayoutPermissionUtil.contains( permissionChecker, layout, ActionKeys.UPDATE)) { throw new PrincipalException.MustHavePermission( permissionChecker, layout.getName(), layout.getLayoutId(), ActionKeys.UPDATE); } else if (!GroupPermissionUtil.contains( permissionChecker, group, ActionKeys.UPDATE) && (!group.isUser() || (permissionChecker.getUserId() != group.getClassPK()))) { throw new PrincipalException.MustHavePermission( permissionChecker, group.getName(), group.getGroupId(), ActionKeys.UPDATE); } } protected void deleteUnreferencedPortlets( List<String> targetLayoutPortletIds, Layout targetLayout, Layout sourceLayout) throws Exception { LayoutTypePortlet sourceLayoutType = (LayoutTypePortlet)sourceLayout.getLayoutType(); List<String> unreferencedPortletIds = new ArrayList<>( targetLayoutPortletIds); unreferencedPortletIds.removeAll(sourceLayoutType.getPortletIds()); PortletLocalServiceUtil.deletePortlets( targetLayout.getCompanyId(), unreferencedPortletIds.toArray( new String[unreferencedPortletIds.size()]), targetLayout.getPlid()); } protected void doMergeLayoutPrototypeLayout(Group group, Layout layout) throws Exception { if (!layout.isLayoutPrototypeLinkActive() || group.isLayoutPrototype() || group.hasStagingGroup()) { return; } long lastMergeTime = GetterUtil.getLong( layout.getTypeSettingsProperty(LAST_MERGE_TIME)); LayoutPrototype layoutPrototype = LayoutPrototypeLocalServiceUtil. getLayoutPrototypeByUuidAndCompanyId( layout.getLayoutPrototypeUuid(), layout.getCompanyId()); Layout layoutPrototypeLayout = layoutPrototype.getLayout(); Date modifiedDate = layoutPrototypeLayout.getModifiedDate(); if (lastMergeTime >= modifiedDate.getTime()) { return; } UnicodeProperties prototypeTypeSettingsProperties = layoutPrototypeLayout.getTypeSettingsProperties(); int mergeFailCount = GetterUtil.getInteger( prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT)); if (mergeFailCount > PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) { if (_log.isWarnEnabled()) { StringBundler sb = new StringBundler(6); sb.append("Merge not performed because the fail threshold "); sb.append("was reached for layoutPrototypeId "); sb.append(layoutPrototype.getLayoutPrototypeId()); sb.append(" and layoutId "); sb.append(layoutPrototypeLayout.getLayoutId()); sb.append(". Update the count in the database to try again."); _log.warn(sb.toString()); } return; } String owner = PortalUUIDUtil.generate(); try { Lock lock = LockManagerUtil.lock( SitesImpl.class.getName(), String.valueOf(layout.getPlid()), owner); if (!owner.equals(lock.getOwner())) { Date createDate = lock.getCreateDate(); if ((System.currentTimeMillis() - createDate.getTime()) >= PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME) { // Acquire lock if the lock is older than the lock max time lock = LockManagerUtil.lock( SitesImpl.class.getName(), String.valueOf(layout.getPlid()), lock.getOwner(), owner); // Check if acquiring the lock succeeded or if another // process has the lock if (!owner.equals(lock.getOwner())) { return; } } else { return; } } } catch (Exception e) { return; } try { MergeLayoutPrototypesThreadLocal.setInProgress(true); applyLayoutPrototype(layoutPrototype, layout, true); } catch (Exception e) { _log.error(e, e); prototypeTypeSettingsProperties.setProperty( MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount)); // Invoke updateImpl so that we do not trigger the listeners LayoutUtil.updateImpl(layoutPrototypeLayout); } finally { MergeLayoutPrototypesThreadLocal.setInProgress(false); LockManagerUtil.unlock( SitesImpl.class.getName(), String.valueOf(layout.getPlid()), owner); } } /** * Resets the modified timestamp on the layout, and then calls {@link * #doResetPrototype(LayoutSet)} to reset the modified timestamp on the * layout's site. * * <p> * After the timestamps are reset, the modified page template and site * template are merged into their linked layout and site when they are first * accessed. * </p> * * @param layout the page having its timestamp reset */ protected void doResetPrototype(Layout layout) throws PortalException { layout.setModifiedDate(null); LayoutLocalServiceUtil.updateLayout(layout); LayoutSet layoutSet = layout.getLayoutSet(); doResetPrototype(layoutSet); } /** * Resets the modified timestamp on the layout set. * * <p> * After the timestamp is reset, the modified site template is merged into * its linked layout set when it is first accessed. * </p> * * @param layoutSet the site having its timestamp reset */ protected void doResetPrototype(LayoutSet layoutSet) { UnicodeProperties settingsProperties = layoutSet.getSettingsProperties(); settingsProperties.remove(LAST_MERGE_TIME); settingsProperties.setProperty( LAST_RESET_TIME, String.valueOf(System.currentTimeMillis())); LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet); } protected Map<String, String[]> getLayoutSetPrototypesParameters( boolean importData) { Map<String, String[]> parameterMap = new LinkedHashMap<>(); parameterMap.put( PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS, new String[] {Boolean.FALSE.toString()}); parameterMap.put( PortletDataHandlerKeys.DELETE_PORTLET_DATA, new String[] {Boolean.FALSE.toString()}); parameterMap.put( PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_SETTINGS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_SETTINGS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE, new String[] { PortletDataHandlerKeys. LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE }); parameterMap.put( PortletDataHandlerKeys.PERMISSIONS, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_CONFIGURATION, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_SETUP_ALL, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.THEME_REFERENCE, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE, new String[] {Boolean.FALSE.toString()}); parameterMap.put( PortletDataHandlerKeys.USER_ID_STRATEGY, new String[] {UserIdStrategy.CURRENT_USER_ID}); if (importData) { parameterMap.put( PortletDataHandlerKeys.DATA_STRATEGY, new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR}); parameterMap.put( PortletDataHandlerKeys.LOGO, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA, new String[] {Boolean.TRUE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA_ALL, new String[] {Boolean.TRUE.toString()}); } else { if (PropsValues.LAYOUT_SET_PROTOTYPE_PROPAGATE_LOGO) { parameterMap.put( PortletDataHandlerKeys.LOGO, new String[] {Boolean.TRUE.toString()}); } else { parameterMap.put( PortletDataHandlerKeys.LOGO, new String[] {Boolean.FALSE.toString()}); } parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA, new String[] {Boolean.FALSE.toString()}); parameterMap.put( PortletDataHandlerKeys.PORTLET_DATA_ALL, new String[] {Boolean.FALSE.toString()}); } return parameterMap; } protected void importLayoutSetPrototype( LayoutSetPrototype layoutSetPrototype, long groupId, boolean privateLayout, Map<String, String[]> parameterMap, boolean importData) throws PortalException { File file = null; StringBundler sb = new StringBundler(importData ? 4 : 3); sb.append(_TEMP_DIR); sb.append(layoutSetPrototype.getUuid()); if (importData) { sb.append("-data"); } sb.append(".lar"); File cacheFile = new File(sb.toString()); if (cacheFile.exists() && !importData) { Date modifiedDate = layoutSetPrototype.getModifiedDate(); if (cacheFile.lastModified() >= modifiedDate.getTime()) { if (_log.isDebugEnabled()) { _log.debug( "Using cached layout set prototype LAR file " + cacheFile.getAbsolutePath()); } file = cacheFile; } } User user = UserLocalServiceUtil.getDefaultUser( layoutSetPrototype.getCompanyId()); boolean newFile = false; if (file == null) { List<Layout> layoutSetPrototypeLayouts = LayoutLocalServiceUtil.getLayouts( layoutSetPrototype.getGroupId(), true); Map<String, Serializable> exportLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildExportLayoutSettingsMap( user, layoutSetPrototype.getGroupId(), true, ExportImportHelperUtil.getLayoutIds( layoutSetPrototypeLayouts), parameterMap); ExportImportConfiguration exportImportConfiguration = ExportImportConfigurationLocalServiceUtil. addDraftExportImportConfiguration( user.getUserId(), ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT, exportLayoutSettingsMap); file = ExportImportLocalServiceUtil.exportLayoutsAsFile( exportImportConfiguration); newFile = true; } Map<String, Serializable> importLayoutSettingsMap = ExportImportConfigurationSettingsMapFactory. buildImportLayoutSettingsMap( user.getUserId(), groupId, privateLayout, null, parameterMap, user.getLocale(), user.getTimeZone()); ExportImportConfiguration exportImportConfiguration = ExportImportConfigurationLocalServiceUtil. addExportImportConfiguration( user.getUserId(), groupId, StringPool.BLANK, StringPool.BLANK, ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT, importLayoutSettingsMap, WorkflowConstants.STATUS_DRAFT, new ServiceContext()); ExportImportLocalServiceUtil.importLayouts( exportImportConfiguration, file); if (newFile) { try { FileUtil.copyFile(file, cacheFile); if (_log.isDebugEnabled()) { _log.debug( "Copied " + file.getAbsolutePath() + " to " + cacheFile.getAbsolutePath()); } } catch (Exception e) { _log.error( "Unable to copy file " + file.getAbsolutePath() + " to " + cacheFile.getAbsolutePath(), e); } } } protected void setLayoutSetPrototypeLinkEnabledParameter( Map<String, String[]> parameterMap, LayoutSet targetLayoutSet, ServiceContext serviceContext) { PermissionChecker permissionChecker = PermissionThreadLocal.getPermissionChecker(); if ((permissionChecker == null) || !PortalPermissionUtil.contains( permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) { return; } if (targetLayoutSet.isPrivateLayout()) { boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean( serviceContext, "privateLayoutSetPrototypeLinkEnabled", true); if (!privateLayoutSetPrototypeLinkEnabled) { privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean( serviceContext, "layoutSetPrototypeLinkEnabled"); } parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, new String[] { String.valueOf(privateLayoutSetPrototypeLinkEnabled) }); } else { boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean( serviceContext, "publicLayoutSetPrototypeLinkEnabled"); if (!publicLayoutSetPrototypeLinkEnabled) { publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean( serviceContext, "layoutSetPrototypeLinkEnabled", true); } parameterMap.put( PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, new String[] { String.valueOf(publicLayoutSetPrototypeLinkEnabled) }); } } protected void updateLayoutSetPrototypeLink( long groupId, boolean privateLayout, long layoutSetPrototypeId, boolean layoutSetPrototypeLinkEnabled) throws Exception { String layoutSetPrototypeUuid = null; if (layoutSetPrototypeId > 0) { LayoutSetPrototype layoutSetPrototype = LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype( layoutSetPrototypeId); if (layoutSetPrototype != null) { layoutSetPrototypeUuid = layoutSetPrototype.getUuid(); // Merge without enabling the link if (!layoutSetPrototypeLinkEnabled && (layoutSetPrototypeId > 0)) { Map<String, String[]> parameterMap = getLayoutSetPrototypesParameters(true); importLayoutSetPrototype( layoutSetPrototype, groupId, privateLayout, parameterMap, true); } } } LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled( groupId, privateLayout, layoutSetPrototypeLinkEnabled, layoutSetPrototypeUuid); LayoutLocalServiceUtil.updatePriorities(groupId, privateLayout); // Force propagation from site template to site. See LPS-48206. Group group = GroupLocalServiceUtil.getGroup(groupId); LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet( groupId, privateLayout); mergeLayoutSetPrototypeLayouts(group, layoutSet); } private static final String _TEMP_DIR = SystemProperties.get(SystemProperties.TMP_DIR) + "/liferay/layout_set_prototype/"; private static final Log _log = LogFactoryUtil.getLog(SitesImpl.class); }