001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.sites.util;
016    
017    import com.liferay.portal.RequiredLayoutException;
018    import com.liferay.portal.events.EventsProcessorUtil;
019    import com.liferay.portal.kernel.backgroundtask.BackgroundTask;
020    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskManagerUtil;
021    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
022    import com.liferay.portal.kernel.exception.PortalException;
023    import com.liferay.portal.kernel.language.LanguageUtil;
024    import com.liferay.portal.kernel.lock.Lock;
025    import com.liferay.portal.kernel.lock.LockManagerUtil;
026    import com.liferay.portal.kernel.log.Log;
027    import com.liferay.portal.kernel.log.LogFactoryUtil;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.GetterUtil;
031    import com.liferay.portal.kernel.util.ListUtil;
032    import com.liferay.portal.kernel.util.ParamUtil;
033    import com.liferay.portal.kernel.util.PrefsPropsUtil;
034    import com.liferay.portal.kernel.util.PropsKeys;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.SystemProperties;
039    import com.liferay.portal.kernel.util.UnicodeProperties;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.kernel.util.WebKeys;
042    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.model.Group;
045    import com.liferay.portal.model.GroupConstants;
046    import com.liferay.portal.model.Layout;
047    import com.liferay.portal.model.LayoutConstants;
048    import com.liferay.portal.model.LayoutPrototype;
049    import com.liferay.portal.model.LayoutSet;
050    import com.liferay.portal.model.LayoutSetPrototype;
051    import com.liferay.portal.model.LayoutType;
052    import com.liferay.portal.model.LayoutTypePortlet;
053    import com.liferay.portal.model.Organization;
054    import com.liferay.portal.model.PortletConstants;
055    import com.liferay.portal.model.ResourceConstants;
056    import com.liferay.portal.model.Role;
057    import com.liferay.portal.model.RoleConstants;
058    import com.liferay.portal.model.User;
059    import com.liferay.portal.model.UserGroup;
060    import com.liferay.portal.model.impl.VirtualLayout;
061    import com.liferay.portal.security.auth.PrincipalException;
062    import com.liferay.portal.security.auth.PrincipalThreadLocal;
063    import com.liferay.portal.security.permission.ActionKeys;
064    import com.liferay.portal.security.permission.PermissionChecker;
065    import com.liferay.portal.security.permission.PermissionThreadLocal;
066    import com.liferay.portal.security.permission.ResourceActionsUtil;
067    import com.liferay.portal.service.GroupLocalServiceUtil;
068    import com.liferay.portal.service.GroupServiceUtil;
069    import com.liferay.portal.service.LayoutLocalServiceUtil;
070    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
071    import com.liferay.portal.service.LayoutServiceUtil;
072    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
073    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
074    import com.liferay.portal.service.LayoutSetServiceUtil;
075    import com.liferay.portal.service.OrganizationLocalServiceUtil;
076    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
077    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
078    import com.liferay.portal.service.RoleLocalServiceUtil;
079    import com.liferay.portal.service.ServiceContext;
080    import com.liferay.portal.service.ServiceContextFactory;
081    import com.liferay.portal.service.ServiceContextThreadLocal;
082    import com.liferay.portal.service.UserGroupLocalServiceUtil;
083    import com.liferay.portal.service.UserLocalServiceUtil;
084    import com.liferay.portal.service.impl.LayoutLocalServiceVirtualLayoutsAdvice;
085    import com.liferay.portal.service.permission.GroupPermissionUtil;
086    import com.liferay.portal.service.permission.LayoutPermissionUtil;
087    import com.liferay.portal.service.permission.PortalPermissionUtil;
088    import com.liferay.portal.service.permission.PortletPermissionUtil;
089    import com.liferay.portal.service.persistence.LayoutSetUtil;
090    import com.liferay.portal.service.persistence.LayoutUtil;
091    import com.liferay.portal.theme.ThemeDisplay;
092    import com.liferay.portal.util.PortalUtil;
093    import com.liferay.portal.util.PortletKeys;
094    import com.liferay.portal.util.PropsValues;
095    import com.liferay.portlet.PortletPreferencesFactoryUtil;
096    import com.liferay.portlet.PortletPreferencesImpl;
097    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationConstants;
098    import com.liferay.portlet.exportimport.configuration.ExportImportConfigurationSettingsMapFactory;
099    import com.liferay.portlet.exportimport.lar.ExportImportHelperUtil;
100    import com.liferay.portlet.exportimport.lar.PortletDataHandlerKeys;
101    import com.liferay.portlet.exportimport.lar.UserIdStrategy;
102    import com.liferay.portlet.exportimport.model.ExportImportConfiguration;
103    import com.liferay.portlet.exportimport.service.ExportImportConfigurationLocalServiceUtil;
104    import com.liferay.portlet.exportimport.service.ExportImportLocalServiceUtil;
105    import com.liferay.portlet.exportimport.service.ExportImportServiceUtil;
106    import com.liferay.portlet.exportimport.staging.MergeLayoutPrototypesThreadLocal;
107    
108    import java.io.File;
109    import java.io.InputStream;
110    import java.io.Serializable;
111    
112    import java.util.ArrayList;
113    import java.util.Collections;
114    import java.util.Date;
115    import java.util.LinkedHashMap;
116    import java.util.List;
117    import java.util.Locale;
118    import java.util.Map;
119    
120    import javax.portlet.ActionRequest;
121    import javax.portlet.ActionResponse;
122    import javax.portlet.PortletPreferences;
123    import javax.portlet.PortletURL;
124    import javax.portlet.RenderRequest;
125    import javax.portlet.RenderResponse;
126    
127    import javax.servlet.http.HttpServletRequest;
128    import javax.servlet.http.HttpServletResponse;
129    
130    /**
131     * @author Raymond Aug??
132     * @author Ryan Park
133     * @author Zsolt Berentey
134     */
135    public class SitesImpl implements Sites {
136    
137            @Override
138            public void addMergeFailFriendlyURLLayout(Layout layout)
139                    throws PortalException {
140    
141                    LayoutSet layoutSet = layout.getLayoutSet();
142    
143                    layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
144                            layoutSet.getGroupId(), layoutSet.isPrivateLayout());
145    
146                    UnicodeProperties settingsProperties =
147                            layoutSet.getSettingsProperties();
148    
149                    String mergeFailFriendlyURLLayouts = settingsProperties.getProperty(
150                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS, StringPool.BLANK);
151    
152                    mergeFailFriendlyURLLayouts = StringUtil.add(
153                            mergeFailFriendlyURLLayouts, layout.getUuid());
154    
155                    settingsProperties.setProperty(
156                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS, mergeFailFriendlyURLLayouts);
157    
158                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
159            }
160    
161            @Override
162            public void addPortletBreadcrumbEntries(
163                            Group group, HttpServletRequest request,
164                            RenderResponse renderResponse)
165                    throws Exception {
166    
167                    PortletURL portletURL = renderResponse.createRenderURL();
168    
169                    List<Group> ancestorGroups = group.getAncestors();
170    
171                    Collections.reverse(ancestorGroups);
172    
173                    for (Group ancestorGroup : ancestorGroups) {
174                            portletURL.setParameter(
175                                    "groupId", String.valueOf(ancestorGroup.getGroupId()));
176    
177                            PortalUtil.addPortletBreadcrumbEntry(
178                                    request, ancestorGroup.getDescriptiveName(),
179                                    portletURL.toString());
180                    }
181    
182                    Group unescapedGroup = group.toUnescapedModel();
183    
184                    portletURL.setParameter(
185                            "groupId", String.valueOf(unescapedGroup.getGroupId()));
186    
187                    PortalUtil.addPortletBreadcrumbEntry(
188                            request, unescapedGroup.getDescriptiveName(),
189                            portletURL.toString());
190            }
191    
192            @Override
193            public void addPortletBreadcrumbEntries(
194                            Group group, String pagesName, PortletURL redirectURL,
195                            HttpServletRequest request, RenderResponse renderResponse)
196                    throws Exception {
197    
198                    if (renderResponse == null) {
199                            return;
200                    }
201    
202                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
203                            com.liferay.portal.kernel.util.WebKeys.THEME_DISPLAY);
204    
205                    Group unescapedGroup = group.toUnescapedModel();
206    
207                    Locale locale = themeDisplay.getLocale();
208    
209                    if (group.isLayoutPrototype()) {
210                            PortalUtil.addPortletBreadcrumbEntry(
211                                    request, LanguageUtil.get(locale, "page-template"), null);
212    
213                            PortalUtil.addPortletBreadcrumbEntry(
214                                    request, unescapedGroup.getDescriptiveName(),
215                                    redirectURL.toString());
216                    }
217                    else {
218                            PortalUtil.addPortletBreadcrumbEntry(
219                                    request, unescapedGroup.getDescriptiveName(), null);
220                    }
221    
222                    if (!group.isLayoutPrototype()) {
223                            PortalUtil.addPortletBreadcrumbEntry(
224                                    request, LanguageUtil.get(locale, pagesName),
225                                    redirectURL.toString());
226                    }
227            }
228    
229            @Override
230            public void applyLayoutPrototype(
231                            LayoutPrototype layoutPrototype, Layout targetLayout,
232                            boolean linkEnabled)
233                    throws Exception {
234    
235                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
236    
237                    ServiceContext serviceContext =
238                            ServiceContextThreadLocal.getServiceContext();
239    
240                    serviceContext.setAttribute("layoutPrototypeLinkEnabled", linkEnabled);
241                    serviceContext.setAttribute(
242                            "layoutPrototypeUuid", layoutPrototype.getUuid());
243    
244                    targetLayout = LayoutLocalServiceUtil.updateLayout(
245                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
246                            targetLayout.getLayoutId(), targetLayout.getParentLayoutId(),
247                            targetLayout.getNameMap(), targetLayout.getTitleMap(),
248                            targetLayout.getDescriptionMap(), targetLayout.getKeywordsMap(),
249                            targetLayout.getRobotsMap(), layoutPrototypeLayout.getType(),
250                            targetLayout.getHidden(), targetLayout.getFriendlyURLMap(),
251                            targetLayout.getIconImage(), null, serviceContext);
252    
253                    targetLayout = LayoutLocalServiceUtil.updateLayout(
254                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
255                            targetLayout.getLayoutId(),
256                            layoutPrototypeLayout.getTypeSettings());
257    
258                    copyPortletPermissions(targetLayout, layoutPrototypeLayout);
259    
260                    copyPortletSetups(layoutPrototypeLayout, targetLayout);
261    
262                    copyLookAndFeel(targetLayout, layoutPrototypeLayout);
263    
264                    targetLayout = LayoutLocalServiceUtil.getLayout(targetLayout.getPlid());
265    
266                    UnicodeProperties typeSettingsProperties =
267                            targetLayout.getTypeSettingsProperties();
268    
269                    typeSettingsProperties.setProperty(
270                            LAST_MERGE_TIME,
271                            String.valueOf(targetLayout.getModifiedDate().getTime()));
272    
273                    LayoutLocalServiceUtil.updateLayout(targetLayout);
274    
275                    UnicodeProperties prototypeTypeSettingsProperties =
276                            layoutPrototypeLayout.getTypeSettingsProperties();
277    
278                    prototypeTypeSettingsProperties.setProperty(MERGE_FAIL_COUNT, "0");
279    
280                    LayoutLocalServiceUtil.updateLayout(layoutPrototypeLayout);
281            }
282    
283            @Override
284            public void copyLayout(
285                            long userId, Layout sourceLayout, Layout targetLayout,
286                            ServiceContext serviceContext)
287                    throws Exception {
288    
289                    User user = UserLocalServiceUtil.getUser(userId);
290    
291                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
292                            serviceContext);
293    
294                    parameterMap.put(
295                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
296                            new String[] {Boolean.FALSE.toString()});
297    
298                    Map<String, Serializable> exportLayoutSettingsMap =
299                            ExportImportConfigurationSettingsMapFactory.
300                                    buildExportLayoutSettingsMap(
301                                            user, sourceLayout.getGroupId(),
302                                            sourceLayout.isPrivateLayout(),
303                                            new long[] {sourceLayout.getLayoutId()}, parameterMap);
304    
305                    ExportImportConfiguration exportConfiguration =
306                            ExportImportConfigurationLocalServiceUtil.
307                                    addDraftExportImportConfiguration(
308                                            user.getUserId(),
309                                            ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
310                                            exportLayoutSettingsMap);
311    
312                    File file = ExportImportLocalServiceUtil.exportLayoutsAsFile(
313                            exportConfiguration);
314    
315                    try {
316                            Map<String, Serializable> importLayoutSettingsMap =
317                                    ExportImportConfigurationSettingsMapFactory.
318                                            buildImportLayoutSettingsMap(
319                                                    userId, targetLayout.getGroupId(),
320                                                    targetLayout.isPrivateLayout(), null, parameterMap,
321                                                    user.getLocale(), user.getTimeZone());
322    
323                            ExportImportConfiguration importConfiguration =
324                                    ExportImportConfigurationLocalServiceUtil.
325                                            addDraftExportImportConfiguration(
326                                                    userId,
327                                                    ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
328                                                    importLayoutSettingsMap);
329    
330                            ExportImportLocalServiceUtil.importLayouts(
331                                    importConfiguration, file);
332                    }
333                    finally {
334                            file.delete();
335                    }
336            }
337    
338            @Override
339            public void copyLookAndFeel(Layout targetLayout, Layout sourceLayout)
340                    throws Exception {
341    
342                    LayoutLocalServiceUtil.updateLookAndFeel(
343                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
344                            targetLayout.getLayoutId(), sourceLayout.getThemeId(),
345                            sourceLayout.getColorSchemeId(), sourceLayout.getCss(), false);
346    
347                    LayoutLocalServiceUtil.updateLookAndFeel(
348                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
349                            targetLayout.getLayoutId(), sourceLayout.getWapThemeId(),
350                            sourceLayout.getWapColorSchemeId(), sourceLayout.getCss(), true);
351            }
352    
353            @Override
354            public void copyPortletPermissions(Layout targetLayout, Layout sourceLayout)
355                    throws Exception {
356    
357                    List<Role> roles = RoleLocalServiceUtil.getGroupRelatedRoles(
358                            targetLayout.getGroupId());
359    
360                    LayoutTypePortlet sourceLayoutTypePortlet =
361                            (LayoutTypePortlet)sourceLayout.getLayoutType();
362    
363                    List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
364    
365                    for (String sourcePortletId : sourcePortletIds) {
366                            String resourceName = PortletConstants.getRootPortletId(
367                                    sourcePortletId);
368    
369                            String sourceResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
370                                    sourceLayout.getPlid(), sourcePortletId);
371    
372                            String targetResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
373                                    targetLayout.getPlid(), sourcePortletId);
374    
375                            List<String> actionIds =
376                                    ResourceActionsUtil.getPortletResourceActions(resourceName);
377    
378                            for (Role role : roles) {
379                                    String roleName = role.getName();
380    
381                                    if (roleName.equals(RoleConstants.ADMINISTRATOR) ||
382                                            (targetLayout.isPrivateLayout() &&
383                                             roleName.equals(RoleConstants.GUEST))) {
384    
385                                            continue;
386                                    }
387    
388                                    List<String> actions =
389                                            ResourcePermissionLocalServiceUtil.
390                                                    getAvailableResourcePermissionActionIds(
391                                                            targetLayout.getCompanyId(), resourceName,
392                                                            ResourceConstants.SCOPE_INDIVIDUAL,
393                                                            sourceResourcePrimKey, role.getRoleId(), actionIds);
394    
395                                    ResourcePermissionLocalServiceUtil.setResourcePermissions(
396                                            targetLayout.getCompanyId(), resourceName,
397                                            ResourceConstants.SCOPE_INDIVIDUAL, targetResourcePrimKey,
398                                            role.getRoleId(),
399                                            actions.toArray(new String[actions.size()]));
400                            }
401                    }
402            }
403    
404            @Override
405            public void copyPortletSetups(Layout sourceLayout, Layout targetLayout)
406                    throws Exception {
407    
408                    LayoutTypePortlet sourceLayoutTypePortlet =
409                            (LayoutTypePortlet)sourceLayout.getLayoutType();
410    
411                    List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
412    
413                    for (String sourcePortletId : sourcePortletIds) {
414                            PortletPreferences sourcePreferences =
415                                    PortletPreferencesFactoryUtil.getPortletSetup(
416                                            sourceLayout, sourcePortletId, null);
417    
418                            PortletPreferencesImpl sourcePreferencesImpl =
419                                    (PortletPreferencesImpl)sourcePreferences;
420    
421                            PortletPreferences targetPreferences =
422                                    PortletPreferencesFactoryUtil.getPortletSetup(
423                                            targetLayout, sourcePortletId, null);
424    
425                            PortletPreferencesImpl targetPreferencesImpl =
426                                    (PortletPreferencesImpl)targetPreferences;
427    
428                            PortletPreferencesLocalServiceUtil.updatePreferences(
429                                    targetPreferencesImpl.getOwnerId(),
430                                    targetPreferencesImpl.getOwnerType(),
431                                    targetPreferencesImpl.getPlid(), sourcePortletId,
432                                    sourcePreferences);
433    
434                            if ((sourcePreferencesImpl.getOwnerId() !=
435                                            PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
436                                    (sourcePreferencesImpl.getOwnerType() !=
437                                            PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) {
438    
439                                    sourcePreferences =
440                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
441                                                    sourceLayout, sourcePortletId);
442    
443                                    sourcePreferencesImpl =
444                                            (PortletPreferencesImpl)sourcePreferences;
445    
446                                    targetPreferences =
447                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
448                                                    targetLayout, sourcePortletId);
449    
450                                    targetPreferencesImpl =
451                                            (PortletPreferencesImpl)targetPreferences;
452    
453                                    PortletPreferencesLocalServiceUtil.updatePreferences(
454                                            targetPreferencesImpl.getOwnerId(),
455                                            targetPreferencesImpl.getOwnerType(),
456                                            targetPreferencesImpl.getPlid(), sourcePortletId,
457                                            sourcePreferences);
458                            }
459    
460                            ServiceContext serviceContext =
461                                    ServiceContextThreadLocal.getServiceContext();
462    
463                            updateLayoutScopes(
464                                    serviceContext.getUserId(), sourceLayout, targetLayout,
465                                    sourcePreferences, targetPreferences, sourcePortletId,
466                                    serviceContext.getLanguageId());
467                    }
468            }
469    
470            @Override
471            public void copyTypeSettings(Group sourceGroup, Group targetGroup)
472                    throws Exception {
473    
474                    GroupServiceUtil.updateGroup(
475                            targetGroup.getGroupId(), sourceGroup.getTypeSettings());
476            }
477    
478            @Override
479            public Object[] deleteLayout(
480                            ActionRequest actionRequest, ActionResponse actionResponse)
481                    throws Exception {
482    
483                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
484                            actionRequest);
485                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
486                            actionResponse);
487    
488                    return deleteLayout(request, response);
489            }
490    
491            @Override
492            public Object[] deleteLayout(
493                            HttpServletRequest request, HttpServletResponse response)
494                    throws Exception {
495    
496                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
497                            WebKeys.THEME_DISPLAY);
498    
499                    PermissionChecker permissionChecker =
500                            themeDisplay.getPermissionChecker();
501    
502                    long plid = ParamUtil.getLong(request, "plid");
503    
504                    long groupId = ParamUtil.getLong(request, "groupId");
505                    boolean privateLayout = ParamUtil.getBoolean(request, "privateLayout");
506                    long layoutId = ParamUtil.getLong(request, "layoutId");
507    
508                    Layout layout = null;
509    
510                    if (plid <= 0) {
511                            layout = LayoutLocalServiceUtil.getLayout(
512                                    groupId, privateLayout, layoutId);
513                    }
514                    else {
515                            layout = LayoutLocalServiceUtil.getLayout(plid);
516    
517                            groupId = layout.getGroupId();
518                            privateLayout = layout.isPrivateLayout();
519                            layoutId = layout.getLayoutId();
520                    }
521    
522                    Group group = layout.getGroup();
523                    String oldFriendlyURL = layout.getFriendlyURL(themeDisplay.getLocale());
524    
525                    if (group.isStagingGroup() &&
526                            !GroupPermissionUtil.contains(
527                                    permissionChecker, group, ActionKeys.MANAGE_STAGING) &&
528                            !GroupPermissionUtil.contains(
529                                    permissionChecker, group, ActionKeys.PUBLISH_STAGING)) {
530    
531                            throw new PrincipalException.MustHavePermission(
532                                    permissionChecker, Group.class.getName(), group.getGroupId(),
533                                    ActionKeys.MANAGE_STAGING, ActionKeys.PUBLISH_STAGING);
534                    }
535    
536                    if (LayoutPermissionUtil.contains(
537                                    permissionChecker, layout, ActionKeys.DELETE)) {
538    
539                            LayoutType layoutType = layout.getLayoutType();
540    
541                            EventsProcessorUtil.process(
542                                    PropsKeys.LAYOUT_CONFIGURATION_ACTION_DELETE,
543                                    layoutType.getConfigurationActionDelete(), request, response);
544                    }
545    
546                    if (group.isGuest() && !layout.isPrivateLayout() &&
547                            layout.isRootLayout() &&
548                            (LayoutLocalServiceUtil.getLayoutsCount(
549                                    group, false, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) == 1)) {
550    
551                            throw new RequiredLayoutException(
552                                    RequiredLayoutException.AT_LEAST_ONE);
553                    }
554    
555                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
556                            request);
557    
558                    LayoutServiceUtil.deleteLayout(
559                            groupId, privateLayout, layoutId, serviceContext);
560    
561                    long newPlid = layout.getParentPlid();
562    
563                    if (newPlid <= 0) {
564                            LayoutSet layoutSet = layout.getLayoutSet();
565    
566                            Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout(
567                                    layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
568                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
569    
570                            if (firstLayout != null) {
571                                    newPlid = firstLayout.getPlid();
572                            }
573                    }
574    
575                    return new Object[] {group, oldFriendlyURL, newPlid};
576            }
577    
578            @Override
579            public void deleteLayout(
580                            RenderRequest renderRequest, RenderResponse renderResponse)
581                    throws Exception {
582    
583                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
584                            renderRequest);
585                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
586                            renderResponse);
587    
588                    deleteLayout(request, response);
589            }
590    
591            @Override
592            public File exportLayoutSetPrototype(
593                            LayoutSetPrototype layoutSetPrototype,
594                            ServiceContext serviceContext)
595                    throws PortalException {
596    
597                    User user = UserLocalServiceUtil.fetchUser(serviceContext.getUserId());
598    
599                    if (user == null) {
600                            BackgroundTask backgroundTask =
601                                    BackgroundTaskManagerUtil.fetchBackgroundTask(
602                                            BackgroundTaskThreadLocal.getBackgroundTaskId());
603    
604                            if (backgroundTask != null) {
605                                    user = UserLocalServiceUtil.getUser(backgroundTask.getUserId());
606                            }
607                    }
608    
609                    if (user == null) {
610                            user = UserLocalServiceUtil.getUser(
611                                    GetterUtil.getLong(PrincipalThreadLocal.getName()));
612                    }
613    
614                    LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
615    
616                    List<Layout> layoutSetPrototypeLayouts =
617                            LayoutLocalServiceUtil.getLayouts(
618                                    layoutSet.getGroupId(), layoutSet.isPrivateLayout());
619    
620                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
621                            serviceContext);
622    
623                    Map<String, Serializable> exportLayoutSettingsMap =
624                            ExportImportConfigurationSettingsMapFactory.
625                                    buildExportLayoutSettingsMap(
626                                            user, layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
627                                            ExportImportHelperUtil.getLayoutIds(
628                                                    layoutSetPrototypeLayouts),
629                                            parameterMap);
630    
631                    ExportImportConfiguration exportImportConfiguration =
632                            ExportImportConfigurationLocalServiceUtil.
633                                    addDraftExportImportConfiguration(
634                                            user.getUserId(),
635                                            ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
636                                            exportLayoutSettingsMap);
637    
638                    return ExportImportLocalServiceUtil.exportLayoutsAsFile(
639                            exportImportConfiguration);
640            }
641    
642            @Override
643            public Long[] filterGroups(List<Group> groups, String[] groupKeys) {
644                    List<Long> groupIds = new ArrayList<>();
645    
646                    for (Group group : groups) {
647                            if (!ArrayUtil.contains(groupKeys, group.getGroupKey())) {
648                                    groupIds.add(group.getGroupId());
649                            }
650                    }
651    
652                    return ArrayUtil.toArray(ArrayUtil.toLongArray(groupIds));
653            }
654    
655            @Override
656            public Layout getLayoutSetPrototypeLayout(Layout layout) {
657                    try {
658                            LayoutSet layoutSet = layout.getLayoutSet();
659    
660                            if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
661                                    return null;
662                            }
663    
664                            LayoutSetPrototype layoutSetPrototype =
665                                    LayoutSetPrototypeLocalServiceUtil.
666                                            getLayoutSetPrototypeByUuidAndCompanyId(
667                                                    layoutSet.getLayoutSetPrototypeUuid(),
668                                                    layout.getCompanyId());
669    
670                            return LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
671                                    layout.getSourcePrototypeLayoutUuid(),
672                                    layoutSetPrototype.getGroupId(), true);
673                    }
674                    catch (Exception e) {
675                            _log.error(
676                                    "Unable to fetch the the layout set prototype's layout", e);
677                    }
678    
679                    return null;
680            }
681    
682            @Override
683            public Map<String, String[]> getLayoutSetPrototypeParameters(
684                    ServiceContext serviceContext) {
685    
686                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
687    
688                    parameterMap.put(
689                            PortletDataHandlerKeys.DATA_STRATEGY,
690                            new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
691                    parameterMap.put(
692                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
693                            new String[] {Boolean.TRUE.toString()});
694                    parameterMap.put(
695                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
696                            new String[] {Boolean.FALSE.toString()});
697                    parameterMap.put(
698                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
699                            new String[] {Boolean.TRUE.toString()});
700                    parameterMap.put(
701                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
702                            new String[] {Boolean.TRUE.toString()});
703                    parameterMap.put(
704                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
705                            new String[] {
706                                    PortletDataHandlerKeys.
707                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
708                            });
709                    parameterMap.put(
710                            PortletDataHandlerKeys.LOGO,
711                            new String[] {Boolean.TRUE.toString()});
712                    parameterMap.put(
713                            PortletDataHandlerKeys.PERFORM_DIRECT_BINARY_IMPORT,
714                            new String[] {Boolean.TRUE.toString()});
715                    parameterMap.put(
716                            PortletDataHandlerKeys.PERMISSIONS,
717                            new String[] {Boolean.TRUE.toString()});
718                    parameterMap.put(
719                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
720                            new String[] {Boolean.TRUE.toString()});
721                    parameterMap.put(
722                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
723                            new String[] {Boolean.TRUE.toString()});
724                    parameterMap.put(
725                            PortletDataHandlerKeys.PORTLET_DATA,
726                            new String[] {Boolean.TRUE.toString()});
727                    parameterMap.put(
728                            PortletDataHandlerKeys.PORTLET_DATA_ALL,
729                            new String[] {Boolean.TRUE.toString()});
730                    parameterMap.put(
731                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
732                            new String[] {Boolean.TRUE.toString()});
733                    parameterMap.put(
734                            PortletDataHandlerKeys.THEME_REFERENCE,
735                            new String[] {Boolean.TRUE.toString()});
736                    parameterMap.put(
737                            PortletDataHandlerKeys.USER_ID_STRATEGY,
738                            new String[] {UserIdStrategy.CURRENT_USER_ID});
739    
740                    return parameterMap;
741            }
742    
743            /**
744             * Returns the number of failed merge attempts for the layout prototype
745             * since its last reset or update.
746             *
747             * @param  layoutPrototype the page template being checked for failed merge
748             *         attempts
749             * @return the number of failed merge attempts for the layout prototype
750             */
751            @Override
752            public int getMergeFailCount(LayoutPrototype layoutPrototype)
753                    throws PortalException {
754    
755                    if ((layoutPrototype == null) ||
756                            (layoutPrototype.getLayoutPrototypeId() == 0)) {
757    
758                            return 0;
759                    }
760    
761                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
762    
763                    UnicodeProperties prototypeTypeSettingsProperties =
764                            layoutPrototypeLayout.getTypeSettingsProperties();
765    
766                    return GetterUtil.getInteger(
767                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
768            }
769    
770            /**
771             * Returns the number of failed merge attempts for the layout set prototype
772             * since its last reset or update.
773             *
774             * @param  layoutSetPrototype the site template being checked for failed
775             *         merge attempts
776             * @return the number of failed merge attempts for the layout set prototype
777             */
778            @Override
779            public int getMergeFailCount(LayoutSetPrototype layoutSetPrototype)
780                    throws PortalException {
781    
782                    if ((layoutSetPrototype == null) ||
783                            (layoutSetPrototype.getLayoutSetPrototypeId() == 0)) {
784    
785                            return 0;
786                    }
787    
788                    LayoutSet layoutSetPrototypeLayoutSet =
789                            layoutSetPrototype.getLayoutSet();
790    
791                    UnicodeProperties layoutSetPrototypeSettingsProperties =
792                            layoutSetPrototypeLayoutSet.getSettingsProperties();
793    
794                    return GetterUtil.getInteger(
795                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
796            }
797    
798            @Override
799            public List<Layout> getMergeFailFriendlyURLLayouts(LayoutSet layoutSet)
800                    throws PortalException {
801    
802                    if (layoutSet == null) {
803                            return Collections.emptyList();
804                    }
805    
806                    UnicodeProperties settingsProperties =
807                            layoutSet.getSettingsProperties();
808    
809                    String uuids = settingsProperties.getProperty(
810                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
811    
812                    if (Validator.isNotNull(uuids)) {
813                            List<Layout> layouts = new ArrayList<>();
814    
815                            for (String uuid : StringUtil.split(uuids)) {
816                                    Layout layout =
817                                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
818                                                    uuid, layoutSet.getGroupId(),
819                                                    layoutSet.isPrivateLayout());
820    
821                                    layouts.add(layout);
822                            }
823    
824                            return layouts;
825                    }
826    
827                    return Collections.emptyList();
828            }
829    
830            @Override
831            public List<String> getOrganizationNames(Group group, User user)
832                    throws Exception {
833    
834                    List<Organization> organizations =
835                            OrganizationLocalServiceUtil.getGroupUserOrganizations(
836                                    group.getGroupId(), user.getUserId());
837    
838                    return ListUtil.toList(organizations, Organization.NAME_ACCESSOR);
839            }
840    
841            @Override
842            public List<String> getUserGroupNames(Group group, User user)
843                    throws Exception {
844    
845                    List<UserGroup> userGroups =
846                            UserGroupLocalServiceUtil.getGroupUserUserGroups(
847                                    group.getGroupId(), user.getUserId());
848    
849                    return ListUtil.toList(userGroups, UserGroup.NAME_ACCESSOR);
850            }
851    
852            @Override
853            public void importLayoutSetPrototype(
854                            LayoutSetPrototype layoutSetPrototype, InputStream inputStream,
855                            ServiceContext serviceContext)
856                    throws PortalException {
857    
858                    LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
859    
860                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
861                            serviceContext);
862    
863                    setLayoutSetPrototypeLinkEnabledParameter(
864                            parameterMap, layoutSet, serviceContext);
865    
866                    User user = UserLocalServiceUtil.fetchUser(serviceContext.getUserId());
867    
868                    if (user == null) {
869                            BackgroundTask backgroundTask =
870                                    BackgroundTaskManagerUtil.fetchBackgroundTask(
871                                            BackgroundTaskThreadLocal.getBackgroundTaskId());
872    
873                            if (backgroundTask != null) {
874                                    user = UserLocalServiceUtil.getUser(backgroundTask.getUserId());
875                            }
876                    }
877    
878                    if (user == null) {
879                            user = UserLocalServiceUtil.getUser(
880                                    GetterUtil.getLong(PrincipalThreadLocal.getName()));
881                    }
882    
883                    Map<String, Serializable> importLayoutSettingsMap =
884                            ExportImportConfigurationSettingsMapFactory.
885                                    buildImportLayoutSettingsMap(
886                                            user.getUserId(), layoutSet.getGroupId(),
887                                            layoutSet.isPrivateLayout(), null, parameterMap,
888                                            user.getLocale(), user.getTimeZone());
889    
890                    ExportImportConfiguration exportImportConfiguration =
891                            ExportImportConfigurationLocalServiceUtil.
892                                    addDraftExportImportConfiguration(
893                                            user.getUserId(),
894                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
895                                            importLayoutSettingsMap);
896    
897                    ExportImportServiceUtil.importLayouts(
898                            exportImportConfiguration, inputStream);
899            }
900    
901            @Override
902            public boolean isContentSharingWithChildrenEnabled(Group group) {
903                    UnicodeProperties typeSettingsProperties =
904                            group.getParentLiveGroupTypeSettingsProperties();
905    
906                    int companyContentSharingEnabled = PrefsPropsUtil.getInteger(
907                            group.getCompanyId(),
908                            PropsKeys.SITES_CONTENT_SHARING_WITH_CHILDREN_ENABLED);
909    
910                    if (companyContentSharingEnabled ==
911                                    CONTENT_SHARING_WITH_CHILDREN_DISABLED) {
912    
913                            return false;
914                    }
915    
916                    int groupContentSharingEnabled = GetterUtil.getInteger(
917                            typeSettingsProperties.getProperty(
918                                    "contentSharingWithChildrenEnabled"),
919                                    CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE);
920    
921                    if ((groupContentSharingEnabled ==
922                                    CONTENT_SHARING_WITH_CHILDREN_ENABLED) ||
923                            ((companyContentSharingEnabled ==
924                                    CONTENT_SHARING_WITH_CHILDREN_ENABLED_BY_DEFAULT) &&
925                             (groupContentSharingEnabled ==
926                                     CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE))) {
927    
928                            return true;
929                    }
930    
931                    return false;
932            }
933    
934            @Override
935            public boolean isFirstLayout(
936                    long groupId, boolean privateLayout, long layoutId) {
937    
938                    Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout(
939                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
940    
941                    if ((firstLayout != null) && (firstLayout.getLayoutId() == layoutId )) {
942                            return true;
943                    }
944    
945                    return false;
946            }
947    
948            @Override
949            public boolean isLayoutDeleteable(Layout layout) {
950                    try {
951                            if (layout instanceof VirtualLayout) {
952                                    return false;
953                            }
954    
955                            if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
956                                    return true;
957                            }
958    
959                            LayoutSet layoutSet = layout.getLayoutSet();
960    
961                            if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
962                                    return true;
963                            }
964    
965                            if (LayoutLocalServiceUtil.hasLayoutSetPrototypeLayout(
966                                            layoutSet.getLayoutSetPrototypeUuid(),
967                                            layout.getCompanyId(),
968                                            layout.getSourcePrototypeLayoutUuid())) {
969    
970                                    return false;
971                            }
972                    }
973                    catch (Exception e) {
974                            if (_log.isDebugEnabled()) {
975                                    _log.debug(e, e);
976                            }
977                    }
978    
979                    return true;
980            }
981    
982            @Override
983            public boolean isLayoutModifiedSinceLastMerge(Layout layout) {
984                    if ((layout == null) ||
985                            Validator.isNull(layout.getSourcePrototypeLayoutUuid()) ||
986                            layout.isLayoutPrototypeLinkActive() ||
987                            !isLayoutUpdateable(layout)) {
988    
989                            return false;
990                    }
991    
992                    long lastMergeTime = GetterUtil.getLong(
993                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
994    
995                    if (lastMergeTime == 0) {
996                            return false;
997                    }
998    
999                    Date existingLayoutModifiedDate = layout.getModifiedDate();
1000    
1001                    if ((existingLayoutModifiedDate != null) &&
1002                            (existingLayoutModifiedDate.getTime() > lastMergeTime)) {
1003    
1004                            return true;
1005                    }
1006    
1007                    return false;
1008            }
1009    
1010            /**
1011             * Returns <code>true</code> if the linked site template can be merged into
1012             * the layout set. This method checks the current number of merge fail
1013             * attempts stored for the linked site template and, if greater than the
1014             * merge fail threshold, will return <code>false</code>.
1015             *
1016             * @param  group the site template's group, which is about to be merged into
1017             *         the layout set
1018             * @param  layoutSet the site in which the site template is attempting to
1019             *         merge into
1020             * @return <code>true</code> if the linked site template can be merged into
1021             *         the layout set; <code>false</code> otherwise
1022             */
1023            @Override
1024            public boolean isLayoutSetMergeable(Group group, LayoutSet layoutSet)
1025                    throws PortalException {
1026    
1027                    if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
1028                            group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
1029    
1030                            return false;
1031                    }
1032    
1033                    UnicodeProperties settingsProperties =
1034                            layoutSet.getSettingsProperties();
1035    
1036                    long lastMergeTime = GetterUtil.getLong(
1037                            settingsProperties.getProperty(LAST_MERGE_TIME));
1038    
1039                    LayoutSetPrototype layoutSetPrototype =
1040                            LayoutSetPrototypeLocalServiceUtil.
1041                                    getLayoutSetPrototypeByUuidAndCompanyId(
1042                                            layoutSet.getLayoutSetPrototypeUuid(),
1043                                            layoutSet.getCompanyId());
1044    
1045                    Date modifiedDate = layoutSetPrototype.getModifiedDate();
1046    
1047                    if (lastMergeTime >= modifiedDate.getTime()) {
1048                            return false;
1049                    }
1050    
1051                    LayoutSet layoutSetPrototypeLayoutSet =
1052                            layoutSetPrototype.getLayoutSet();
1053    
1054                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1055                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1056    
1057                    int mergeFailCount = GetterUtil.getInteger(
1058                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1059    
1060                    if (mergeFailCount >
1061                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1062    
1063                            if (_log.isWarnEnabled()) {
1064                                    StringBundler sb = new StringBundler(6);
1065    
1066                                    sb.append("Merge not performed because the fail threshold ");
1067                                    sb.append("was reached for layoutSetPrototypeId ");
1068                                    sb.append(layoutSetPrototype.getLayoutSetPrototypeId());
1069                                    sb.append(" and layoutId ");
1070                                    sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId());
1071                                    sb.append(". Update the count in the database to try again.");
1072    
1073                                    _log.warn(sb.toString());
1074                            }
1075    
1076                            return false;
1077                    }
1078    
1079                    return true;
1080            }
1081    
1082            @Override
1083            public boolean isLayoutSetPrototypeUpdateable(LayoutSet layoutSet) {
1084                    if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
1085                            return true;
1086                    }
1087    
1088                    try {
1089                            LayoutSetPrototype layoutSetPrototype =
1090                                    LayoutSetPrototypeLocalServiceUtil.
1091                                            getLayoutSetPrototypeByUuidAndCompanyId(
1092                                                    layoutSet.getLayoutSetPrototypeUuid(),
1093                                                    layoutSet.getCompanyId());
1094    
1095                            String layoutsUpdateable = layoutSetPrototype.getSettingsProperty(
1096                                    "layoutsUpdateable");
1097    
1098                            if (Validator.isNotNull(layoutsUpdateable)) {
1099                                    return GetterUtil.getBoolean(layoutsUpdateable, true);
1100                            }
1101                    }
1102                    catch (Exception e) {
1103                            if (_log.isDebugEnabled()) {
1104                                    _log.debug(e, e);
1105                            }
1106                    }
1107    
1108                    return true;
1109            }
1110    
1111            @Override
1112            public boolean isLayoutSortable(Layout layout) {
1113                    return isLayoutDeleteable(layout);
1114            }
1115    
1116            @Override
1117            public boolean isLayoutUpdateable(Layout layout) {
1118                    try {
1119                            if (layout instanceof VirtualLayout) {
1120                                    return false;
1121                            }
1122    
1123                            if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
1124                                    Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
1125    
1126                                    return true;
1127                            }
1128    
1129                            LayoutSet layoutSet = layout.getLayoutSet();
1130    
1131                            if (layoutSet.isLayoutSetPrototypeLinkActive()) {
1132                                    boolean layoutSetPrototypeUpdateable =
1133                                            isLayoutSetPrototypeUpdateable(layoutSet);
1134    
1135                                    if (!layoutSetPrototypeUpdateable) {
1136                                            return false;
1137                                    }
1138    
1139                                    Layout layoutSetPrototypeLayout = getLayoutSetPrototypeLayout(
1140                                            layout);
1141    
1142                                    String layoutUpdateable =
1143                                            layoutSetPrototypeLayout.getTypeSettingsProperty(
1144                                                    LAYOUT_UPDATEABLE);
1145    
1146                                    if (Validator.isNull(layoutUpdateable)) {
1147                                            return true;
1148                                    }
1149    
1150                                    return GetterUtil.getBoolean(layoutUpdateable);
1151                            }
1152                    }
1153                    catch (Exception e) {
1154                            if (_log.isDebugEnabled()) {
1155                                    _log.debug(e, e);
1156                            }
1157                    }
1158    
1159                    return true;
1160            }
1161    
1162            @Override
1163            public boolean isUserGroupLayout(Layout layout) throws PortalException {
1164                    if (!(layout instanceof VirtualLayout)) {
1165                            return false;
1166                    }
1167    
1168                    VirtualLayout virtualLayout = (VirtualLayout)layout;
1169    
1170                    Layout sourceLayout = virtualLayout.getSourceLayout();
1171    
1172                    Group sourceGroup = sourceLayout.getGroup();
1173    
1174                    if (sourceGroup.isUserGroup()) {
1175                            return true;
1176                    }
1177    
1178                    return false;
1179            }
1180    
1181            @Override
1182            public boolean isUserGroupLayoutSetViewable(
1183                            PermissionChecker permissionChecker, Group userGroupGroup)
1184                    throws PortalException {
1185    
1186                    if (!userGroupGroup.isUserGroup()) {
1187                            return false;
1188                    }
1189    
1190                    if (GroupPermissionUtil.contains(
1191                                    permissionChecker, userGroupGroup, ActionKeys.VIEW)) {
1192    
1193                            return true;
1194                    }
1195    
1196                    UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
1197                            userGroupGroup.getClassPK());
1198    
1199                    if (UserLocalServiceUtil.hasUserGroupUser(
1200                                    userGroup.getUserGroupId(), permissionChecker.getUserId())) {
1201    
1202                            return true;
1203                    }
1204                    else {
1205                            return false;
1206                    }
1207            }
1208    
1209            @Override
1210            public void mergeLayoutPrototypeLayout(Group group, Layout layout)
1211                    throws Exception {
1212    
1213                    String sourcePrototypeLayoutUuid =
1214                            layout.getSourcePrototypeLayoutUuid();
1215    
1216                    if (Validator.isNull(sourcePrototypeLayoutUuid)) {
1217                            doMergeLayoutPrototypeLayout(group, layout);
1218    
1219                            return;
1220                    }
1221    
1222                    LayoutSet layoutSet = layout.getLayoutSet();
1223    
1224                    long layoutSetPrototypeId = layoutSet.getLayoutSetPrototypeId();
1225    
1226                    if (layoutSetPrototypeId > 0) {
1227                            Group layoutSetPrototypeGroup =
1228                                    GroupLocalServiceUtil.getLayoutSetPrototypeGroup(
1229                                            layout.getCompanyId(), layoutSetPrototypeId);
1230    
1231                            Layout sourcePrototypeLayout =
1232                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
1233                                            sourcePrototypeLayoutUuid,
1234                                            layoutSetPrototypeGroup.getGroupId(), true);
1235    
1236                            if (sourcePrototypeLayout != null) {
1237                                    doMergeLayoutPrototypeLayout(
1238                                            layoutSetPrototypeGroup, sourcePrototypeLayout);
1239                            }
1240                    }
1241    
1242                    doMergeLayoutPrototypeLayout(group, layout);
1243            }
1244    
1245            /**
1246             * @deprecated As of 6.2.0, replaced by {@link
1247             *             #mergeLayoutPrototypeLayout(Group, Layout)}
1248             */
1249            @Deprecated
1250            @Override
1251            public void mergeLayoutProtypeLayout(Group group, Layout layout)
1252                    throws Exception {
1253    
1254                    mergeLayoutPrototypeLayout(group, layout);
1255            }
1256    
1257            @Override
1258            public void mergeLayoutSetPrototypeLayouts(Group group, LayoutSet layoutSet)
1259                    throws Exception {
1260    
1261                    if (!isLayoutSetMergeable(group, layoutSet)) {
1262                            return;
1263                    }
1264    
1265                    UnicodeProperties settingsProperties =
1266                            layoutSet.getSettingsProperties();
1267    
1268                    long lastMergeTime = GetterUtil.getLong(
1269                            settingsProperties.getProperty(LAST_MERGE_TIME));
1270    
1271                    LayoutSetPrototype layoutSetPrototype =
1272                            LayoutSetPrototypeLocalServiceUtil.
1273                                    getLayoutSetPrototypeByUuidAndCompanyId(
1274                                            layoutSet.getLayoutSetPrototypeUuid(),
1275                                            layoutSet.getCompanyId());
1276    
1277                    LayoutSet layoutSetPrototypeLayoutSet =
1278                            layoutSetPrototype.getLayoutSet();
1279    
1280                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1281                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1282    
1283                    int mergeFailCount = GetterUtil.getInteger(
1284                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1285    
1286                    String owner = PortalUUIDUtil.generate();
1287    
1288                    try {
1289                            Lock lock = LockManagerUtil.lock(
1290                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1291                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1292    
1293                            // Double deep check
1294    
1295                            if (!owner.equals(lock.getOwner())) {
1296                                    Date createDate = lock.getCreateDate();
1297    
1298                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1299                                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1300    
1301                                            // Acquire lock if the lock is older than the lock max time
1302    
1303                                            lock = LockManagerUtil.lock(
1304                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1305                                                    String.valueOf(layoutSet.getLayoutSetId()),
1306                                                    lock.getOwner(), owner);
1307    
1308                                            // Check if acquiring the lock succeeded or if another
1309                                            // process has the lock
1310    
1311                                            if (!owner.equals(lock.getOwner())) {
1312                                                    return;
1313                                            }
1314                                    }
1315                                    else {
1316                                            return;
1317                                    }
1318                            }
1319                    }
1320                    catch (Exception e) {
1321                            return;
1322                    }
1323    
1324                    try {
1325                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1326    
1327                            boolean importData = true;
1328    
1329                            long lastResetTime = GetterUtil.getLong(
1330                                    settingsProperties.getProperty(LAST_RESET_TIME));
1331    
1332                            if ((lastMergeTime > 0) || (lastResetTime > 0)) {
1333                                    importData = false;
1334                            }
1335    
1336                            Map<String, String[]> parameterMap =
1337                                    getLayoutSetPrototypesParameters(importData);
1338    
1339                            layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1340                                    layoutSet.getLayoutSetId());
1341    
1342                            removeMergeFailFriendlyURLLayouts(layoutSet);
1343    
1344                            importLayoutSetPrototype(
1345                                    layoutSetPrototype, layoutSet.getGroupId(),
1346                                    layoutSet.isPrivateLayout(), parameterMap, importData);
1347                    }
1348                    catch (Exception e) {
1349                            _log.error(e, e);
1350    
1351                            layoutSetPrototypeSettingsProperties.setProperty(
1352                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1353    
1354                            // Invoke updateImpl so that we do not trigger the listeners
1355    
1356                            LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet);
1357                    }
1358                    finally {
1359                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1360    
1361                            LockManagerUtil.unlock(
1362                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1363                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1364                    }
1365            }
1366    
1367            /**
1368             * @deprecated As of 6.2.0, replaced by {@link
1369             *             #mergeLayoutSetPrototypeLayouts(Group, LayoutSet)}
1370             */
1371            @Deprecated
1372            @Override
1373            public void mergeLayoutSetProtypeLayouts(Group group, LayoutSet layoutSet)
1374                    throws Exception {
1375    
1376                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
1377            }
1378    
1379            @Override
1380            public void removeMergeFailFriendlyURLLayouts(LayoutSet layoutSet) {
1381                    UnicodeProperties settingsProperties =
1382                            layoutSet.getSettingsProperties();
1383    
1384                    settingsProperties.remove(MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
1385    
1386                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1387            }
1388    
1389            /**
1390             * Checks the permissions necessary for resetting the layout. If sufficient,
1391             * the layout is reset by calling {@link #doResetPrototype(Layout)}.
1392             *
1393             * @param layout the page being checked for sufficient permissions
1394             */
1395            @Override
1396            public void resetPrototype(Layout layout) throws PortalException {
1397                    checkResetPrototypePermissions(layout.getGroup(), layout);
1398    
1399                    doResetPrototype(layout);
1400            }
1401    
1402            /**
1403             * Checks the permissions necessary for resetting the layout set. If
1404             * sufficient, the layout set is reset by calling {@link
1405             * #doResetPrototype(LayoutSet)}.
1406             *
1407             * @param layoutSet the site being checked for sufficient permissions
1408             */
1409            @Override
1410            public void resetPrototype(LayoutSet layoutSet) throws PortalException {
1411                    checkResetPrototypePermissions(layoutSet.getGroup(), null);
1412    
1413                    doResetPrototype(layoutSet);
1414            }
1415    
1416            /**
1417             * Sets the number of failed merge attempts for the layout prototype to a
1418             * new value.
1419             *
1420             * @param layoutPrototype the page template of the counter being updated
1421             * @param newMergeFailCount the new value of the counter
1422             */
1423            @Override
1424            public void setMergeFailCount(
1425                            LayoutPrototype layoutPrototype, int newMergeFailCount)
1426                    throws PortalException {
1427    
1428                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1429    
1430                    UnicodeProperties prototypeTypeSettingsProperties =
1431                            layoutPrototypeLayout.getTypeSettingsProperties();
1432    
1433                    if (newMergeFailCount == 0) {
1434                            prototypeTypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1435                    }
1436                    else {
1437                            prototypeTypeSettingsProperties.setProperty(
1438                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1439                    }
1440    
1441                    LayoutServiceUtil.updateLayout(
1442                            layoutPrototypeLayout.getGroupId(),
1443                            layoutPrototypeLayout.getPrivateLayout(),
1444                            layoutPrototypeLayout.getLayoutId(),
1445                            layoutPrototypeLayout.getTypeSettings());
1446            }
1447    
1448            /**
1449             * Sets the number of failed merge attempts for the layout set prototype to
1450             * a new value.
1451             *
1452             * @param layoutSetPrototype the site template of the counter being updated
1453             * @param newMergeFailCount the new value of the counter
1454             */
1455            @Override
1456            public void setMergeFailCount(
1457                            LayoutSetPrototype layoutSetPrototype, int newMergeFailCount)
1458                    throws PortalException {
1459    
1460                    LayoutSet layoutSetPrototypeLayoutSet =
1461                            layoutSetPrototype.getLayoutSet();
1462    
1463                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1464                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1465    
1466                    if (newMergeFailCount == 0) {
1467                            layoutSetPrototypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1468                    }
1469                    else {
1470                            layoutSetPrototypeSettingsProperties.setProperty(
1471                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1472                    }
1473    
1474                    LayoutSetServiceUtil.updateSettings(
1475                            layoutSetPrototypeLayoutSet.getGroupId(),
1476                            layoutSetPrototypeLayoutSet.getPrivateLayout(),
1477                            layoutSetPrototypeLayoutSet.getSettings());
1478            }
1479    
1480            @Override
1481            public void updateLayoutScopes(
1482                            long userId, Layout sourceLayout, Layout targetLayout,
1483                            PortletPreferences sourcePreferences,
1484                            PortletPreferences targetPreferences, String sourcePortletId,
1485                            String languageId)
1486                    throws Exception {
1487    
1488                    String scopeType = GetterUtil.getString(
1489                            sourcePreferences.getValue("lfrScopeType", null));
1490    
1491                    if (Validator.isNull(scopeType) || !scopeType.equals("layout")) {
1492                            return;
1493                    }
1494    
1495                    Layout targetScopeLayout =
1496                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1497                                    targetLayout.getUuid(), targetLayout.getGroupId(),
1498                                    targetLayout.isPrivateLayout());
1499    
1500                    if (!targetScopeLayout.hasScopeGroup()) {
1501                            GroupLocalServiceUtil.addGroup(
1502                                    userId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
1503                                    Layout.class.getName(), targetLayout.getPlid(),
1504                                    GroupConstants.DEFAULT_LIVE_GROUP_ID, targetLayout.getNameMap(),
1505                                    null, 0, true, GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION,
1506                                    null, false, true, null);
1507                    }
1508    
1509                    String portletTitle = PortalUtil.getPortletTitle(
1510                            PortletConstants.getRootPortletId(sourcePortletId), languageId);
1511    
1512                    String newPortletTitle = PortalUtil.getNewPortletTitle(
1513                            portletTitle, String.valueOf(sourceLayout.getLayoutId()),
1514                            targetLayout.getName(languageId));
1515    
1516                    targetPreferences.setValue(
1517                            "groupId", String.valueOf(targetLayout.getGroupId()));
1518                    targetPreferences.setValue("lfrScopeType", "layout");
1519                    targetPreferences.setValue(
1520                            "lfrScopeLayoutUuid", targetLayout.getUuid());
1521                    targetPreferences.setValue(
1522                            "portletSetupTitle_" + languageId, newPortletTitle);
1523                    targetPreferences.setValue(
1524                            "portletSetupUseCustomTitle", Boolean.TRUE.toString());
1525    
1526                    targetPreferences.store();
1527            }
1528    
1529            @Override
1530            public void updateLayoutSetPrototypesLinks(
1531                            Group group, long publicLayoutSetPrototypeId,
1532                            long privateLayoutSetPrototypeId,
1533                            boolean publicLayoutSetPrototypeLinkEnabled,
1534                            boolean privateLayoutSetPrototypeLinkEnabled)
1535                    throws Exception {
1536    
1537                    updateLayoutSetPrototypeLink(
1538                            group.getGroupId(), true, privateLayoutSetPrototypeId,
1539                            privateLayoutSetPrototypeLinkEnabled);
1540                    updateLayoutSetPrototypeLink(
1541                            group.getGroupId(), false, publicLayoutSetPrototypeId,
1542                            publicLayoutSetPrototypeLinkEnabled);
1543            }
1544    
1545            /**
1546             * Checks the permissions necessary for resetting the layout or site. If the
1547             * permissions are not sufficient, a {@link PortalException} is thrown.
1548             *
1549             * @param group the site being checked for sufficient permissions
1550             * @param layout the page being checked for sufficient permissions
1551             *        (optionally <code>null</code>). If <code>null</code>, the
1552             *        permissions are only checked for resetting the site.
1553             */
1554            protected void checkResetPrototypePermissions(Group group, Layout layout)
1555                    throws PortalException {
1556    
1557                    PermissionChecker permissionChecker =
1558                            PermissionThreadLocal.getPermissionChecker();
1559    
1560                    if ((layout != null) &&
1561                            !LayoutPermissionUtil.contains(
1562                                    permissionChecker, layout, ActionKeys.UPDATE)) {
1563    
1564                            throw new PrincipalException.MustHavePermission(
1565                                    permissionChecker, layout.getName(), layout.getLayoutId(),
1566                                    ActionKeys.UPDATE);
1567                    }
1568                    else if (!group.isUser() &&
1569                                     !GroupPermissionUtil.contains(
1570                                             permissionChecker, group, ActionKeys.UPDATE)) {
1571    
1572                            throw new PrincipalException.MustHavePermission(
1573                                    permissionChecker, group.getName(), group.getGroupId(),
1574                                    ActionKeys.UPDATE);
1575                    }
1576                    else if (group.isUser() &&
1577                                     (permissionChecker.getUserId() != group.getClassPK())) {
1578    
1579                            throw new PrincipalException();
1580                    }
1581            }
1582    
1583            protected void doMergeLayoutPrototypeLayout(Group group, Layout layout)
1584                    throws Exception {
1585    
1586                    if (!layout.isLayoutPrototypeLinkActive() ||
1587                            group.isLayoutPrototype() || group.hasStagingGroup()) {
1588    
1589                            return;
1590                    }
1591    
1592                    long lastMergeTime = GetterUtil.getLong(
1593                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
1594    
1595                    LayoutPrototype layoutPrototype =
1596                            LayoutPrototypeLocalServiceUtil.
1597                                    getLayoutPrototypeByUuidAndCompanyId(
1598                                            layout.getLayoutPrototypeUuid(), layout.getCompanyId());
1599    
1600                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1601    
1602                    Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
1603    
1604                    if (lastMergeTime >= modifiedDate.getTime()) {
1605                            return;
1606                    }
1607    
1608                    UnicodeProperties prototypeTypeSettingsProperties =
1609                            layoutPrototypeLayout.getTypeSettingsProperties();
1610    
1611                    int mergeFailCount = GetterUtil.getInteger(
1612                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1613    
1614                    if (mergeFailCount >
1615                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1616    
1617                            if (_log.isWarnEnabled()) {
1618                                    StringBundler sb = new StringBundler(6);
1619    
1620                                    sb.append("Merge not performed because the fail threshold ");
1621                                    sb.append("was reached for layoutPrototypeId ");
1622                                    sb.append(layoutPrototype.getLayoutPrototypeId());
1623                                    sb.append(" and layoutId ");
1624                                    sb.append(layoutPrototypeLayout.getLayoutId());
1625                                    sb.append(". Update the count in the database to try again.");
1626    
1627                                    _log.warn(sb.toString());
1628                            }
1629    
1630                            return;
1631                    }
1632    
1633                    String owner = PortalUUIDUtil.generate();
1634    
1635                    try {
1636                            Lock lock = LockManagerUtil.lock(
1637                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1638                                    String.valueOf(layout.getPlid()), owner);
1639    
1640                            if (!owner.equals(lock.getOwner())) {
1641                                    Date createDate = lock.getCreateDate();
1642    
1643                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1644                                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1645    
1646                                            // Acquire lock if the lock is older than the lock max time
1647    
1648                                            lock = LockManagerUtil.lock(
1649                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1650                                                    String.valueOf(layout.getPlid()), lock.getOwner(),
1651                                                    owner);
1652    
1653                                            // Check if acquiring the lock succeeded or if another
1654                                            // process has the lock
1655    
1656                                            if (!owner.equals(lock.getOwner())) {
1657                                                    return;
1658                                            }
1659                                    }
1660                                    else {
1661                                            return;
1662                                    }
1663                            }
1664                    }
1665                    catch (Exception e) {
1666                            return;
1667                    }
1668    
1669                    try {
1670                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1671    
1672                            applyLayoutPrototype(layoutPrototype, layout, true);
1673                    }
1674                    catch (Exception e) {
1675                            _log.error(e, e);
1676    
1677                            prototypeTypeSettingsProperties.setProperty(
1678                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1679    
1680                            // Invoke updateImpl so that we do not trigger the listeners
1681    
1682                            LayoutUtil.updateImpl(layoutPrototypeLayout);
1683                    }
1684                    finally {
1685                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1686    
1687                            LockManagerUtil.unlock(
1688                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1689                                    String.valueOf(layout.getPlid()), owner);
1690                    }
1691            }
1692    
1693            /**
1694             * Resets the modified timestamp on the layout, and then calls {@link
1695             * #doResetPrototype(LayoutSet)} to reset the modified timestamp on the
1696             * layout's site.
1697             *
1698             * <p>
1699             * After the timestamps are reset, the modified page template and site
1700             * template are merged into their linked layout and site when they are first
1701             * accessed.
1702             * </p>
1703             *
1704             * @param layout the page having its timestamp reset
1705             */
1706            protected void doResetPrototype(Layout layout) throws PortalException {
1707                    layout.setModifiedDate(null);
1708    
1709                    LayoutLocalServiceUtil.updateLayout(layout);
1710    
1711                    LayoutSet layoutSet = layout.getLayoutSet();
1712    
1713                    doResetPrototype(layoutSet);
1714            }
1715    
1716            /**
1717             * Resets the modified timestamp on the layout set.
1718             *
1719             * <p>
1720             * After the timestamp is reset, the modified site template is merged into
1721             * its linked layout set when it is first accessed.
1722             * </p>
1723             *
1724             * @param layoutSet the site having its timestamp reset
1725             */
1726            protected void doResetPrototype(LayoutSet layoutSet) {
1727                    UnicodeProperties settingsProperties =
1728                            layoutSet.getSettingsProperties();
1729    
1730                    settingsProperties.remove(LAST_MERGE_TIME);
1731    
1732                    settingsProperties.setProperty(
1733                            LAST_RESET_TIME, String.valueOf(System.currentTimeMillis()));
1734    
1735                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1736            }
1737    
1738            protected Map<String, String[]> getLayoutSetPrototypesParameters(
1739                    boolean importData) {
1740    
1741                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
1742    
1743                    parameterMap.put(
1744                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1745                            new String[] {Boolean.FALSE.toString()});
1746                    parameterMap.put(
1747                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1748                            new String[] {Boolean.FALSE.toString()});
1749                    parameterMap.put(
1750                            PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
1751                            new String[] {Boolean.TRUE.toString()});
1752                    parameterMap.put(
1753                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1754                            new String[] {Boolean.TRUE.toString()});
1755                    parameterMap.put(
1756                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1757                            new String[] {Boolean.TRUE.toString()});
1758                    parameterMap.put(
1759                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1760                            new String[] {
1761                                    PortletDataHandlerKeys.
1762                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
1763                            });
1764                    parameterMap.put(
1765                            PortletDataHandlerKeys.PERMISSIONS,
1766                            new String[] {Boolean.TRUE.toString()});
1767                    parameterMap.put(
1768                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
1769                            new String[] {Boolean.TRUE.toString()});
1770                    parameterMap.put(
1771                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
1772                            new String[] {Boolean.TRUE.toString()});
1773                    parameterMap.put(
1774                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1775                            new String[] {Boolean.TRUE.toString()});
1776                    parameterMap.put(
1777                            PortletDataHandlerKeys.THEME_REFERENCE,
1778                            new String[] {Boolean.TRUE.toString()});
1779                    parameterMap.put(
1780                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1781                            new String[] {Boolean.FALSE.toString()});
1782                    parameterMap.put(
1783                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1784                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1785    
1786                    if (importData) {
1787                            parameterMap.put(
1788                                    PortletDataHandlerKeys.DATA_STRATEGY,
1789                                    new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1790                            parameterMap.put(
1791                                    PortletDataHandlerKeys.LOGO,
1792                                    new String[] {Boolean.TRUE.toString()});
1793                            parameterMap.put(
1794                                    PortletDataHandlerKeys.PORTLET_DATA,
1795                                    new String[] {Boolean.TRUE.toString()});
1796                            parameterMap.put(
1797                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1798                                    new String[] {Boolean.TRUE.toString()});
1799                    }
1800                    else {
1801                            if (PropsValues.LAYOUT_SET_PROTOTYPE_PROPAGATE_LOGO) {
1802                                    parameterMap.put(
1803                                            PortletDataHandlerKeys.LOGO,
1804                                            new String[] {Boolean.TRUE.toString()});
1805                            }
1806                            else {
1807                                    parameterMap.put(
1808                                            PortletDataHandlerKeys.LOGO,
1809                                            new String[] {Boolean.FALSE.toString()});
1810                            }
1811    
1812                            parameterMap.put(
1813                                    PortletDataHandlerKeys.PORTLET_DATA,
1814                                    new String[] {Boolean.FALSE.toString()});
1815                            parameterMap.put(
1816                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1817                                    new String[] {Boolean.FALSE.toString()});
1818                    }
1819    
1820                    return parameterMap;
1821            }
1822    
1823            protected void importLayoutSetPrototype(
1824                            LayoutSetPrototype layoutSetPrototype, long groupId,
1825                            boolean privateLayout, Map<String, String[]> parameterMap,
1826                            boolean importData)
1827                    throws PortalException {
1828    
1829                    File file = null;
1830    
1831                    StringBundler sb = new StringBundler(importData ? 4 : 3);
1832    
1833                    sb.append(_TEMP_DIR);
1834                    sb.append(layoutSetPrototype.getUuid());
1835    
1836                    if (importData) {
1837                            sb.append("-data");
1838                    }
1839    
1840                    sb.append(".lar");
1841    
1842                    File cacheFile = new File(sb.toString());
1843    
1844                    if (cacheFile.exists() && !importData) {
1845                            Date modifiedDate = layoutSetPrototype.getModifiedDate();
1846    
1847                            if (cacheFile.lastModified() >= modifiedDate.getTime()) {
1848                                    if (_log.isDebugEnabled()) {
1849                                            _log.debug(
1850                                                    "Using cached layout set prototype LAR file " +
1851                                                            cacheFile.getAbsolutePath());
1852                                    }
1853    
1854                                    file = cacheFile;
1855                            }
1856                    }
1857    
1858                    User user = UserLocalServiceUtil.getDefaultUser(
1859                            layoutSetPrototype.getCompanyId());
1860    
1861                    boolean newFile = false;
1862    
1863                    if (file == null) {
1864                            List<Layout> layoutSetPrototypeLayouts =
1865                                    LayoutLocalServiceUtil.getLayouts(
1866                                            layoutSetPrototype.getGroupId(), true);
1867    
1868                            Map<String, Serializable> exportLayoutSettingsMap =
1869                                    ExportImportConfigurationSettingsMapFactory.
1870                                            buildExportLayoutSettingsMap(
1871                                                    user, layoutSetPrototype.getGroupId(), true,
1872                                                    ExportImportHelperUtil.getLayoutIds(
1873                                                            layoutSetPrototypeLayouts),
1874                                                    parameterMap);
1875    
1876                            ExportImportConfiguration exportImportConfiguration =
1877                                    ExportImportConfigurationLocalServiceUtil.
1878                                            addDraftExportImportConfiguration(
1879                                                    user.getUserId(),
1880                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1881                                                    exportLayoutSettingsMap);
1882    
1883                            file = ExportImportLocalServiceUtil.exportLayoutsAsFile(
1884                                    exportImportConfiguration);
1885    
1886                            newFile = true;
1887                    }
1888    
1889                    Map<String, Serializable> importLayoutSettingsMap =
1890                            ExportImportConfigurationSettingsMapFactory.
1891                                    buildImportLayoutSettingsMap(
1892                                            user.getUserId(), groupId, privateLayout, null,
1893                                            parameterMap, user.getLocale(), user.getTimeZone());
1894    
1895                    ExportImportConfiguration exportImportConfiguration =
1896                            ExportImportConfigurationLocalServiceUtil.
1897                                    addExportImportConfiguration(
1898                                            user.getUserId(), groupId, StringPool.BLANK,
1899                                            StringPool.BLANK,
1900                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1901                                            importLayoutSettingsMap, WorkflowConstants.STATUS_DRAFT,
1902                                            new ServiceContext());
1903    
1904                    ExportImportLocalServiceUtil.importLayouts(
1905                            exportImportConfiguration, file);
1906    
1907                    if (newFile) {
1908                            try {
1909                                    FileUtil.copyFile(file, cacheFile);
1910    
1911                                    if (_log.isDebugEnabled()) {
1912                                            _log.debug(
1913                                                    "Copied " + file.getAbsolutePath() + " to " +
1914                                                            cacheFile.getAbsolutePath());
1915                                    }
1916                            }
1917                            catch (Exception e) {
1918                                    _log.error(
1919                                            "Unable to copy file " + file.getAbsolutePath() + " to " +
1920                                                    cacheFile.getAbsolutePath(),
1921                                            e);
1922                            }
1923                    }
1924            }
1925    
1926            protected void setLayoutSetPrototypeLinkEnabledParameter(
1927                    Map<String, String[]> parameterMap, LayoutSet targetLayoutSet,
1928                    ServiceContext serviceContext) {
1929    
1930                    PermissionChecker permissionChecker =
1931                            PermissionThreadLocal.getPermissionChecker();
1932    
1933                    if ((permissionChecker == null) ||
1934                            !PortalPermissionUtil.contains(
1935                                    permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) {
1936    
1937                            return;
1938                    }
1939    
1940                    if (targetLayoutSet.isPrivateLayout()) {
1941                            boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1942                                    serviceContext, "privateLayoutSetPrototypeLinkEnabled", true);
1943    
1944                            if (!privateLayoutSetPrototypeLinkEnabled) {
1945                                    privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1946                                            serviceContext, "layoutSetPrototypeLinkEnabled");
1947                            }
1948    
1949                            parameterMap.put(
1950                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1951                                    new String[] {
1952                                            String.valueOf(privateLayoutSetPrototypeLinkEnabled)
1953                                    });
1954                    }
1955                    else {
1956                            boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1957                                    serviceContext, "publicLayoutSetPrototypeLinkEnabled");
1958    
1959                            if (!publicLayoutSetPrototypeLinkEnabled) {
1960                                    publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1961                                            serviceContext, "layoutSetPrototypeLinkEnabled", true);
1962                            }
1963    
1964                            parameterMap.put(
1965                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1966                                    new String[] {
1967                                            String.valueOf(publicLayoutSetPrototypeLinkEnabled)
1968                                    });
1969                    }
1970            }
1971    
1972            protected void updateLayoutSetPrototypeLink(
1973                            long groupId, boolean privateLayout, long layoutSetPrototypeId,
1974                            boolean layoutSetPrototypeLinkEnabled)
1975                    throws Exception {
1976    
1977                    String layoutSetPrototypeUuid = null;
1978    
1979                    if (layoutSetPrototypeId > 0) {
1980                            LayoutSetPrototype layoutSetPrototype =
1981                                    LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype(
1982                                            layoutSetPrototypeId);
1983    
1984                            if (layoutSetPrototype != null) {
1985                                    layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
1986    
1987                                    // Merge without enabling the link
1988    
1989                                    if (!layoutSetPrototypeLinkEnabled &&
1990                                            (layoutSetPrototypeId > 0)) {
1991    
1992                                            Map<String, String[]> parameterMap =
1993                                                    getLayoutSetPrototypesParameters(true);
1994    
1995                                            importLayoutSetPrototype(
1996                                                    layoutSetPrototype, groupId, privateLayout,
1997                                                    parameterMap, true);
1998                                    }
1999                            }
2000                    }
2001    
2002                    LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled(
2003                            groupId, privateLayout, layoutSetPrototypeLinkEnabled,
2004                            layoutSetPrototypeUuid);
2005    
2006                    LayoutLocalServiceUtil.updatePriorities(groupId, privateLayout);
2007    
2008                    // Force propagation from site template to site. See LPS-48206.
2009    
2010                    Group group = GroupLocalServiceUtil.getGroup(groupId);
2011    
2012                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
2013                            groupId, privateLayout);
2014    
2015                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
2016            }
2017    
2018            private static final String _TEMP_DIR =
2019                    SystemProperties.get(SystemProperties.TMP_DIR) +
2020                            "/liferay/layout_set_prototype/";
2021    
2022            private static final Log _log = LogFactoryUtil.getLog(SitesImpl.class);
2023    
2024    }