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.uuid.PortalUUIDUtil;
042    import com.liferay.portal.kernel.workflow.WorkflowConstants;
043    import com.liferay.portal.model.Group;
044    import com.liferay.portal.model.GroupConstants;
045    import com.liferay.portal.model.Layout;
046    import com.liferay.portal.model.LayoutConstants;
047    import com.liferay.portal.model.LayoutPrototype;
048    import com.liferay.portal.model.LayoutSet;
049    import com.liferay.portal.model.LayoutSetPrototype;
050    import com.liferay.portal.model.LayoutType;
051    import com.liferay.portal.model.LayoutTypePortlet;
052    import com.liferay.portal.model.Organization;
053    import com.liferay.portal.model.PortletConstants;
054    import com.liferay.portal.model.ResourceConstants;
055    import com.liferay.portal.model.Role;
056    import com.liferay.portal.model.RoleConstants;
057    import com.liferay.portal.model.User;
058    import com.liferay.portal.model.UserGroup;
059    import com.liferay.portal.model.impl.VirtualLayout;
060    import com.liferay.portal.security.auth.PrincipalException;
061    import com.liferay.portal.security.auth.PrincipalThreadLocal;
062    import com.liferay.portal.security.permission.ActionKeys;
063    import com.liferay.portal.security.permission.PermissionChecker;
064    import com.liferay.portal.security.permission.PermissionThreadLocal;
065    import com.liferay.portal.security.permission.ResourceActionsUtil;
066    import com.liferay.portal.service.GroupLocalServiceUtil;
067    import com.liferay.portal.service.GroupServiceUtil;
068    import com.liferay.portal.service.LayoutLocalServiceUtil;
069    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
070    import com.liferay.portal.service.LayoutServiceUtil;
071    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
072    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
073    import com.liferay.portal.service.LayoutSetServiceUtil;
074    import com.liferay.portal.service.OrganizationLocalServiceUtil;
075    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
076    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
077    import com.liferay.portal.service.RoleLocalServiceUtil;
078    import com.liferay.portal.service.ServiceContext;
079    import com.liferay.portal.service.ServiceContextFactory;
080    import com.liferay.portal.service.ServiceContextThreadLocal;
081    import com.liferay.portal.service.UserGroupLocalServiceUtil;
082    import com.liferay.portal.service.UserLocalServiceUtil;
083    import com.liferay.portal.service.impl.LayoutLocalServiceVirtualLayoutsAdvice;
084    import com.liferay.portal.service.permission.GroupPermissionUtil;
085    import com.liferay.portal.service.permission.LayoutPermissionUtil;
086    import com.liferay.portal.service.permission.PortalPermissionUtil;
087    import com.liferay.portal.service.permission.PortletPermissionUtil;
088    import com.liferay.portal.service.persistence.LayoutSetUtil;
089    import com.liferay.portal.service.persistence.LayoutUtil;
090    import com.liferay.portal.theme.ThemeDisplay;
091    import com.liferay.portal.util.PortalUtil;
092    import com.liferay.portal.util.PortletKeys;
093    import com.liferay.portal.util.PropsValues;
094    import com.liferay.portal.util.WebKeys;
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             * @throws PortalException if no page was associated with the layout
751             *         prototype or if a portal exception occurred
752             */
753            @Override
754            public int getMergeFailCount(LayoutPrototype layoutPrototype)
755                    throws PortalException {
756    
757                    if ((layoutPrototype == null) ||
758                            (layoutPrototype.getLayoutPrototypeId() == 0)) {
759    
760                            return 0;
761                    }
762    
763                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
764    
765                    UnicodeProperties prototypeTypeSettingsProperties =
766                            layoutPrototypeLayout.getTypeSettingsProperties();
767    
768                    return GetterUtil.getInteger(
769                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
770            }
771    
772            /**
773             * Returns the number of failed merge attempts for the layout set prototype
774             * since its last reset or update.
775             *
776             * @param  layoutSetPrototype the site template being checked for failed
777             *         merge attempts
778             * @return the number of failed merge attempts for the layout set prototype
779             * @throws PortalException if no site was associated with the layout set
780             *         prototype or if a portal exception occurred
781             */
782            @Override
783            public int getMergeFailCount(LayoutSetPrototype layoutSetPrototype)
784                    throws PortalException {
785    
786                    if ((layoutSetPrototype == null) ||
787                            (layoutSetPrototype.getLayoutSetPrototypeId() == 0)) {
788    
789                            return 0;
790                    }
791    
792                    LayoutSet layoutSetPrototypeLayoutSet =
793                            layoutSetPrototype.getLayoutSet();
794    
795                    UnicodeProperties layoutSetPrototypeSettingsProperties =
796                            layoutSetPrototypeLayoutSet.getSettingsProperties();
797    
798                    return GetterUtil.getInteger(
799                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
800            }
801    
802            @Override
803            public List<Layout> getMergeFailFriendlyURLLayouts(LayoutSet layoutSet)
804                    throws PortalException {
805    
806                    if (layoutSet == null) {
807                            return Collections.emptyList();
808                    }
809    
810                    UnicodeProperties settingsProperties =
811                            layoutSet.getSettingsProperties();
812    
813                    String uuids = settingsProperties.getProperty(
814                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
815    
816                    if (Validator.isNotNull(uuids)) {
817                            List<Layout> layouts = new ArrayList<>();
818    
819                            for (String uuid : StringUtil.split(uuids)) {
820                                    Layout layout =
821                                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
822                                                    uuid, layoutSet.getGroupId(),
823                                                    layoutSet.isPrivateLayout());
824    
825                                    layouts.add(layout);
826                            }
827    
828                            return layouts;
829                    }
830    
831                    return Collections.emptyList();
832            }
833    
834            @Override
835            public List<String> getOrganizationNames(Group group, User user)
836                    throws Exception {
837    
838                    List<Organization> organizations =
839                            OrganizationLocalServiceUtil.getGroupUserOrganizations(
840                                    group.getGroupId(), user.getUserId());
841    
842                    return ListUtil.toList(organizations, Organization.NAME_ACCESSOR);
843            }
844    
845            @Override
846            public List<String> getUserGroupNames(Group group, User user)
847                    throws Exception {
848    
849                    List<UserGroup> userGroups =
850                            UserGroupLocalServiceUtil.getGroupUserUserGroups(
851                                    group.getGroupId(), user.getUserId());
852    
853                    return ListUtil.toList(userGroups, UserGroup.NAME_ACCESSOR);
854            }
855    
856            @Override
857            public void importLayoutSetPrototype(
858                            LayoutSetPrototype layoutSetPrototype, InputStream inputStream,
859                            ServiceContext serviceContext)
860                    throws PortalException {
861    
862                    LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
863    
864                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
865                            serviceContext);
866    
867                    setLayoutSetPrototypeLinkEnabledParameter(
868                            parameterMap, layoutSet, serviceContext);
869    
870                    User user = UserLocalServiceUtil.fetchUser(serviceContext.getUserId());
871    
872                    if (user == null) {
873                            BackgroundTask backgroundTask =
874                                    BackgroundTaskManagerUtil.fetchBackgroundTask(
875                                            BackgroundTaskThreadLocal.getBackgroundTaskId());
876    
877                            if (backgroundTask != null) {
878                                    user = UserLocalServiceUtil.getUser(backgroundTask.getUserId());
879                            }
880                    }
881    
882                    if (user == null) {
883                            user = UserLocalServiceUtil.getUser(
884                                    GetterUtil.getLong(PrincipalThreadLocal.getName()));
885                    }
886    
887                    Map<String, Serializable> importLayoutSettingsMap =
888                            ExportImportConfigurationSettingsMapFactory.
889                                    buildImportLayoutSettingsMap(
890                                            user.getUserId(), layoutSet.getGroupId(),
891                                            layoutSet.isPrivateLayout(), null, parameterMap,
892                                            user.getLocale(), user.getTimeZone());
893    
894                    ExportImportConfiguration exportImportConfiguration =
895                            ExportImportConfigurationLocalServiceUtil.
896                                    addDraftExportImportConfiguration(
897                                            user.getUserId(),
898                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
899                                            importLayoutSettingsMap);
900    
901                    ExportImportServiceUtil.importLayouts(
902                            exportImportConfiguration, inputStream);
903            }
904    
905            @Override
906            public boolean isContentSharingWithChildrenEnabled(Group group) {
907                    UnicodeProperties typeSettingsProperties =
908                            group.getParentLiveGroupTypeSettingsProperties();
909    
910                    int companyContentSharingEnabled = PrefsPropsUtil.getInteger(
911                            group.getCompanyId(),
912                            PropsKeys.SITES_CONTENT_SHARING_WITH_CHILDREN_ENABLED);
913    
914                    if (companyContentSharingEnabled ==
915                                    CONTENT_SHARING_WITH_CHILDREN_DISABLED) {
916    
917                            return false;
918                    }
919    
920                    int groupContentSharingEnabled = GetterUtil.getInteger(
921                            typeSettingsProperties.getProperty(
922                                    "contentSharingWithChildrenEnabled"),
923                                    CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE);
924    
925                    if ((groupContentSharingEnabled ==
926                                    CONTENT_SHARING_WITH_CHILDREN_ENABLED) ||
927                            ((companyContentSharingEnabled ==
928                                    CONTENT_SHARING_WITH_CHILDREN_ENABLED_BY_DEFAULT) &&
929                             (groupContentSharingEnabled ==
930                                     CONTENT_SHARING_WITH_CHILDREN_DEFAULT_VALUE))) {
931    
932                            return true;
933                    }
934    
935                    return false;
936            }
937    
938            @Override
939            public boolean isFirstLayout(
940                    long groupId, boolean privateLayout, long layoutId) {
941    
942                    Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout(
943                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
944    
945                    if ((firstLayout != null) && (firstLayout.getLayoutId() == layoutId )) {
946                            return true;
947                    }
948    
949                    return false;
950            }
951    
952            @Override
953            public boolean isLayoutDeleteable(Layout layout) {
954                    try {
955                            if (layout instanceof VirtualLayout) {
956                                    return false;
957                            }
958    
959                            if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
960                                    return true;
961                            }
962    
963                            LayoutSet layoutSet = layout.getLayoutSet();
964    
965                            if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
966                                    return true;
967                            }
968    
969                            if (LayoutLocalServiceUtil.hasLayoutSetPrototypeLayout(
970                                            layoutSet.getLayoutSetPrototypeUuid(),
971                                            layout.getCompanyId(),
972                                            layout.getSourcePrototypeLayoutUuid())) {
973    
974                                    return false;
975                            }
976                    }
977                    catch (Exception e) {
978                            if (_log.isDebugEnabled()) {
979                                    _log.debug(e, e);
980                            }
981                    }
982    
983                    return true;
984            }
985    
986            @Override
987            public boolean isLayoutModifiedSinceLastMerge(Layout layout) {
988                    if ((layout == null) ||
989                            Validator.isNull(layout.getSourcePrototypeLayoutUuid()) ||
990                            layout.isLayoutPrototypeLinkActive() ||
991                            !isLayoutUpdateable(layout)) {
992    
993                            return false;
994                    }
995    
996                    long lastMergeTime = GetterUtil.getLong(
997                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
998    
999                    if (lastMergeTime == 0) {
1000                            return false;
1001                    }
1002    
1003                    Date existingLayoutModifiedDate = layout.getModifiedDate();
1004    
1005                    if ((existingLayoutModifiedDate != null) &&
1006                            (existingLayoutModifiedDate.getTime() > lastMergeTime)) {
1007    
1008                            return true;
1009                    }
1010    
1011                    return false;
1012            }
1013    
1014            /**
1015             * Returns <code>true</code> if the linked site template can be merged into
1016             * the layout set. This method checks the current number of merge fail
1017             * attempts stored for the linked site template and, if greater than the
1018             * merge fail threshold, will return <code>false</code>.
1019             *
1020             * @param  group the site template's group, which is about to be merged into
1021             *         the layout set
1022             * @param  layoutSet the site in which the site template is attempting to
1023             *         merge into
1024             * @return <code>true</code> if the linked site template can be merged into
1025             *         the layout set; <code>false</code> otherwise
1026             * @throws PortalException if no site template was associated with the
1027             *         layout set or if a portal exception occurred
1028             */
1029            @Override
1030            public boolean isLayoutSetMergeable(Group group, LayoutSet layoutSet)
1031                    throws PortalException {
1032    
1033                    if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
1034                            group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
1035    
1036                            return false;
1037                    }
1038    
1039                    UnicodeProperties settingsProperties =
1040                            layoutSet.getSettingsProperties();
1041    
1042                    long lastMergeTime = GetterUtil.getLong(
1043                            settingsProperties.getProperty(LAST_MERGE_TIME));
1044    
1045                    LayoutSetPrototype layoutSetPrototype =
1046                            LayoutSetPrototypeLocalServiceUtil.
1047                                    getLayoutSetPrototypeByUuidAndCompanyId(
1048                                            layoutSet.getLayoutSetPrototypeUuid(),
1049                                            layoutSet.getCompanyId());
1050    
1051                    Date modifiedDate = layoutSetPrototype.getModifiedDate();
1052    
1053                    if (lastMergeTime >= modifiedDate.getTime()) {
1054                            return false;
1055                    }
1056    
1057                    LayoutSet layoutSetPrototypeLayoutSet =
1058                            layoutSetPrototype.getLayoutSet();
1059    
1060                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1061                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1062    
1063                    int mergeFailCount = GetterUtil.getInteger(
1064                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1065    
1066                    if (mergeFailCount >
1067                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1068    
1069                            if (_log.isWarnEnabled()) {
1070                                    StringBundler sb = new StringBundler(6);
1071    
1072                                    sb.append("Merge not performed because the fail threshold ");
1073                                    sb.append("was reached for layoutSetPrototypeId ");
1074                                    sb.append(layoutSetPrototype.getLayoutSetPrototypeId());
1075                                    sb.append(" and layoutId ");
1076                                    sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId());
1077                                    sb.append(". Update the count in the database to try again.");
1078    
1079                                    _log.warn(sb.toString());
1080                            }
1081    
1082                            return false;
1083                    }
1084    
1085                    return true;
1086            }
1087    
1088            @Override
1089            public boolean isLayoutSetPrototypeUpdateable(LayoutSet layoutSet) {
1090                    if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
1091                            return true;
1092                    }
1093    
1094                    try {
1095                            LayoutSetPrototype layoutSetPrototype =
1096                                    LayoutSetPrototypeLocalServiceUtil.
1097                                            getLayoutSetPrototypeByUuidAndCompanyId(
1098                                                    layoutSet.getLayoutSetPrototypeUuid(),
1099                                                    layoutSet.getCompanyId());
1100    
1101                            String layoutsUpdateable = layoutSetPrototype.getSettingsProperty(
1102                                    "layoutsUpdateable");
1103    
1104                            if (Validator.isNotNull(layoutsUpdateable)) {
1105                                    return GetterUtil.getBoolean(layoutsUpdateable, true);
1106                            }
1107                    }
1108                    catch (Exception e) {
1109                            if (_log.isDebugEnabled()) {
1110                                    _log.debug(e, e);
1111                            }
1112                    }
1113    
1114                    return true;
1115            }
1116    
1117            @Override
1118            public boolean isLayoutSortable(Layout layout) {
1119                    return isLayoutDeleteable(layout);
1120            }
1121    
1122            @Override
1123            public boolean isLayoutUpdateable(Layout layout) {
1124                    try {
1125                            if (layout instanceof VirtualLayout) {
1126                                    return false;
1127                            }
1128    
1129                            if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
1130                                    Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
1131    
1132                                    return true;
1133                            }
1134    
1135                            LayoutSet layoutSet = layout.getLayoutSet();
1136    
1137                            if (layoutSet.isLayoutSetPrototypeLinkActive()) {
1138                                    boolean layoutSetPrototypeUpdateable =
1139                                            isLayoutSetPrototypeUpdateable(layoutSet);
1140    
1141                                    if (!layoutSetPrototypeUpdateable) {
1142                                            return false;
1143                                    }
1144    
1145                                    Layout layoutSetPrototypeLayout = getLayoutSetPrototypeLayout(
1146                                            layout);
1147    
1148                                    String layoutUpdateable =
1149                                            layoutSetPrototypeLayout.getTypeSettingsProperty(
1150                                                    LAYOUT_UPDATEABLE);
1151    
1152                                    if (Validator.isNull(layoutUpdateable)) {
1153                                            return true;
1154                                    }
1155    
1156                                    return GetterUtil.getBoolean(layoutUpdateable);
1157                            }
1158                    }
1159                    catch (Exception e) {
1160                            if (_log.isDebugEnabled()) {
1161                                    _log.debug(e, e);
1162                            }
1163                    }
1164    
1165                    return true;
1166            }
1167    
1168            @Override
1169            public boolean isUserGroupLayout(Layout layout) throws PortalException {
1170                    if (!(layout instanceof VirtualLayout)) {
1171                            return false;
1172                    }
1173    
1174                    VirtualLayout virtualLayout = (VirtualLayout)layout;
1175    
1176                    Layout sourceLayout = virtualLayout.getSourceLayout();
1177    
1178                    Group sourceGroup = sourceLayout.getGroup();
1179    
1180                    if (sourceGroup.isUserGroup()) {
1181                            return true;
1182                    }
1183    
1184                    return false;
1185            }
1186    
1187            @Override
1188            public boolean isUserGroupLayoutSetViewable(
1189                            PermissionChecker permissionChecker, Group userGroupGroup)
1190                    throws PortalException {
1191    
1192                    if (!userGroupGroup.isUserGroup()) {
1193                            return false;
1194                    }
1195    
1196                    if (GroupPermissionUtil.contains(
1197                                    permissionChecker, userGroupGroup, ActionKeys.VIEW)) {
1198    
1199                            return true;
1200                    }
1201    
1202                    UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
1203                            userGroupGroup.getClassPK());
1204    
1205                    if (UserLocalServiceUtil.hasUserGroupUser(
1206                                    userGroup.getUserGroupId(), permissionChecker.getUserId())) {
1207    
1208                            return true;
1209                    }
1210                    else {
1211                            return false;
1212                    }
1213            }
1214    
1215            @Override
1216            public void mergeLayoutPrototypeLayout(Group group, Layout layout)
1217                    throws Exception {
1218    
1219                    String sourcePrototypeLayoutUuid =
1220                            layout.getSourcePrototypeLayoutUuid();
1221    
1222                    if (Validator.isNull(sourcePrototypeLayoutUuid)) {
1223                            doMergeLayoutPrototypeLayout(group, layout);
1224    
1225                            return;
1226                    }
1227    
1228                    LayoutSet layoutSet = layout.getLayoutSet();
1229    
1230                    long layoutSetPrototypeId = layoutSet.getLayoutSetPrototypeId();
1231    
1232                    if (layoutSetPrototypeId > 0) {
1233                            Group layoutSetPrototypeGroup =
1234                                    GroupLocalServiceUtil.getLayoutSetPrototypeGroup(
1235                                            layout.getCompanyId(), layoutSetPrototypeId);
1236    
1237                            Layout sourcePrototypeLayout =
1238                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
1239                                            sourcePrototypeLayoutUuid,
1240                                            layoutSetPrototypeGroup.getGroupId(), true);
1241    
1242                            if (sourcePrototypeLayout != null) {
1243                                    doMergeLayoutPrototypeLayout(
1244                                            layoutSetPrototypeGroup, sourcePrototypeLayout);
1245                            }
1246                    }
1247    
1248                    doMergeLayoutPrototypeLayout(group, layout);
1249            }
1250    
1251            /**
1252             * @deprecated As of 6.2.0, replaced by {@link
1253             *             #mergeLayoutPrototypeLayout(Group, Layout)}
1254             */
1255            @Deprecated
1256            @Override
1257            public void mergeLayoutProtypeLayout(Group group, Layout layout)
1258                    throws Exception {
1259    
1260                    mergeLayoutPrototypeLayout(group, layout);
1261            }
1262    
1263            @Override
1264            public void mergeLayoutSetPrototypeLayouts(Group group, LayoutSet layoutSet)
1265                    throws Exception {
1266    
1267                    if (!isLayoutSetMergeable(group, layoutSet)) {
1268                            return;
1269                    }
1270    
1271                    UnicodeProperties settingsProperties =
1272                            layoutSet.getSettingsProperties();
1273    
1274                    long lastMergeTime = GetterUtil.getLong(
1275                            settingsProperties.getProperty(LAST_MERGE_TIME));
1276    
1277                    LayoutSetPrototype layoutSetPrototype =
1278                            LayoutSetPrototypeLocalServiceUtil.
1279                                    getLayoutSetPrototypeByUuidAndCompanyId(
1280                                            layoutSet.getLayoutSetPrototypeUuid(),
1281                                            layoutSet.getCompanyId());
1282    
1283                    LayoutSet layoutSetPrototypeLayoutSet =
1284                            layoutSetPrototype.getLayoutSet();
1285    
1286                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1287                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1288    
1289                    int mergeFailCount = GetterUtil.getInteger(
1290                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1291    
1292                    String owner = PortalUUIDUtil.generate();
1293    
1294                    try {
1295                            Lock lock = LockManagerUtil.lock(
1296                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1297                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1298    
1299                            // Double deep check
1300    
1301                            if (!owner.equals(lock.getOwner())) {
1302                                    Date createDate = lock.getCreateDate();
1303    
1304                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1305                                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1306    
1307                                            // Acquire lock if the lock is older than the lock max time
1308    
1309                                            lock = LockManagerUtil.lock(
1310                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1311                                                    String.valueOf(layoutSet.getLayoutSetId()),
1312                                                    lock.getOwner(), owner);
1313    
1314                                            // Check if acquiring the lock succeeded or if another
1315                                            // process has the lock
1316    
1317                                            if (!owner.equals(lock.getOwner())) {
1318                                                    return;
1319                                            }
1320                                    }
1321                                    else {
1322                                            return;
1323                                    }
1324                            }
1325                    }
1326                    catch (Exception e) {
1327                            return;
1328                    }
1329    
1330                    try {
1331                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1332    
1333                            boolean importData = true;
1334    
1335                            long lastResetTime = GetterUtil.getLong(
1336                                    settingsProperties.getProperty(LAST_RESET_TIME));
1337    
1338                            if ((lastMergeTime > 0) || (lastResetTime > 0)) {
1339                                    importData = false;
1340                            }
1341    
1342                            Map<String, String[]> parameterMap =
1343                                    getLayoutSetPrototypesParameters(importData);
1344    
1345                            layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1346                                    layoutSet.getLayoutSetId());
1347    
1348                            removeMergeFailFriendlyURLLayouts(layoutSet);
1349    
1350                            importLayoutSetPrototype(
1351                                    layoutSetPrototype, layoutSet.getGroupId(),
1352                                    layoutSet.isPrivateLayout(), parameterMap, importData);
1353                    }
1354                    catch (Exception e) {
1355                            _log.error(e, e);
1356    
1357                            layoutSetPrototypeSettingsProperties.setProperty(
1358                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1359    
1360                            // Invoke updateImpl so that we do not trigger the listeners
1361    
1362                            LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet);
1363                    }
1364                    finally {
1365                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1366    
1367                            LockManagerUtil.unlock(
1368                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1369                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1370                    }
1371            }
1372    
1373            /**
1374             * @deprecated As of 6.2.0, replaced by {@link
1375             *             #mergeLayoutSetPrototypeLayouts(Group, LayoutSet)}
1376             */
1377            @Deprecated
1378            @Override
1379            public void mergeLayoutSetProtypeLayouts(Group group, LayoutSet layoutSet)
1380                    throws Exception {
1381    
1382                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
1383            }
1384    
1385            @Override
1386            public void removeMergeFailFriendlyURLLayouts(LayoutSet layoutSet) {
1387                    UnicodeProperties settingsProperties =
1388                            layoutSet.getSettingsProperties();
1389    
1390                    settingsProperties.remove(MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
1391    
1392                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1393            }
1394    
1395            /**
1396             * Checks the permissions necessary for resetting the layout. If sufficient,
1397             * the layout is reset by calling {@link #doResetPrototype(Layout)}.
1398             *
1399             * @param  layout the page being checked for sufficient permissions
1400             * @throws PortalException if no site was associated with the layout, if the
1401             *         user did not have permission to update the layout or the layout's
1402             *         site, or if a portal exception occurred
1403             */
1404            @Override
1405            public void resetPrototype(Layout layout) throws PortalException {
1406                    checkResetPrototypePermissions(layout.getGroup(), layout);
1407    
1408                    doResetPrototype(layout);
1409            }
1410    
1411            /**
1412             * Checks the permissions necessary for resetting the layout set. If
1413             * sufficient, the layout set is reset by calling {@link
1414             * #doResetPrototype(LayoutSet)}.
1415             *
1416             * @param  layoutSet the site being checked for sufficient permissions
1417             * @throws PortalException if the user did not have permission to update the
1418             *         site or if a portal exception occurred
1419             */
1420            @Override
1421            public void resetPrototype(LayoutSet layoutSet) throws PortalException {
1422                    checkResetPrototypePermissions(layoutSet.getGroup(), null);
1423    
1424                    doResetPrototype(layoutSet);
1425            }
1426    
1427            /**
1428             * Sets the number of failed merge attempts for the layout prototype to a
1429             * new value.
1430             *
1431             * @param  layoutPrototype the page template of the counter being updated
1432             * @param  newMergeFailCount the new value of the counter
1433             * @throws PortalException if no page was associated with the layout
1434             *         prototype, if the user did not have permission to update the
1435             *         page, or if a portal exception occurred
1436             */
1437            @Override
1438            public void setMergeFailCount(
1439                            LayoutPrototype layoutPrototype, int newMergeFailCount)
1440                    throws PortalException {
1441    
1442                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1443    
1444                    UnicodeProperties prototypeTypeSettingsProperties =
1445                            layoutPrototypeLayout.getTypeSettingsProperties();
1446    
1447                    if (newMergeFailCount == 0) {
1448                            prototypeTypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1449                    }
1450                    else {
1451                            prototypeTypeSettingsProperties.setProperty(
1452                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1453                    }
1454    
1455                    LayoutServiceUtil.updateLayout(
1456                            layoutPrototypeLayout.getGroupId(),
1457                            layoutPrototypeLayout.getPrivateLayout(),
1458                            layoutPrototypeLayout.getLayoutId(),
1459                            layoutPrototypeLayout.getTypeSettings());
1460            }
1461    
1462            /**
1463             * Sets the number of failed merge attempts for the layout set prototype to
1464             * a new value.
1465             *
1466             * @param  layoutSetPrototype the site template of the counter being updated
1467             * @param  newMergeFailCount the new value of the counter
1468             * @throws PortalException if no site was associated with the layout set
1469             *         prototype, if the user did not have permission to update the
1470             *         layout set prototype, or if a portal exception occurred
1471             */
1472            @Override
1473            public void setMergeFailCount(
1474                            LayoutSetPrototype layoutSetPrototype, int newMergeFailCount)
1475                    throws PortalException {
1476    
1477                    LayoutSet layoutSetPrototypeLayoutSet =
1478                            layoutSetPrototype.getLayoutSet();
1479    
1480                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1481                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1482    
1483                    if (newMergeFailCount == 0) {
1484                            layoutSetPrototypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1485                    }
1486                    else {
1487                            layoutSetPrototypeSettingsProperties.setProperty(
1488                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1489                    }
1490    
1491                    LayoutSetServiceUtil.updateSettings(
1492                            layoutSetPrototypeLayoutSet.getGroupId(),
1493                            layoutSetPrototypeLayoutSet.getPrivateLayout(),
1494                            layoutSetPrototypeLayoutSet.getSettings());
1495            }
1496    
1497            @Override
1498            public void updateLayoutScopes(
1499                            long userId, Layout sourceLayout, Layout targetLayout,
1500                            PortletPreferences sourcePreferences,
1501                            PortletPreferences targetPreferences, String sourcePortletId,
1502                            String languageId)
1503                    throws Exception {
1504    
1505                    String scopeType = GetterUtil.getString(
1506                            sourcePreferences.getValue("lfrScopeType", null));
1507    
1508                    if (Validator.isNull(scopeType) || !scopeType.equals("layout")) {
1509                            return;
1510                    }
1511    
1512                    Layout targetScopeLayout =
1513                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1514                                    targetLayout.getUuid(), targetLayout.getGroupId(),
1515                                    targetLayout.isPrivateLayout());
1516    
1517                    if (!targetScopeLayout.hasScopeGroup()) {
1518                            GroupLocalServiceUtil.addGroup(
1519                                    userId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
1520                                    Layout.class.getName(), targetLayout.getPlid(),
1521                                    GroupConstants.DEFAULT_LIVE_GROUP_ID, targetLayout.getNameMap(),
1522                                    null, 0, true, GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION,
1523                                    null, false, true, null);
1524                    }
1525    
1526                    String portletTitle = PortalUtil.getPortletTitle(
1527                            PortletConstants.getRootPortletId(sourcePortletId), languageId);
1528    
1529                    String newPortletTitle = PortalUtil.getNewPortletTitle(
1530                            portletTitle, String.valueOf(sourceLayout.getLayoutId()),
1531                            targetLayout.getName(languageId));
1532    
1533                    targetPreferences.setValue(
1534                            "groupId", String.valueOf(targetLayout.getGroupId()));
1535                    targetPreferences.setValue("lfrScopeType", "layout");
1536                    targetPreferences.setValue(
1537                            "lfrScopeLayoutUuid", targetLayout.getUuid());
1538                    targetPreferences.setValue(
1539                            "portletSetupTitle_" + languageId, newPortletTitle);
1540                    targetPreferences.setValue(
1541                            "portletSetupUseCustomTitle", Boolean.TRUE.toString());
1542    
1543                    targetPreferences.store();
1544            }
1545    
1546            @Override
1547            public void updateLayoutSetPrototypesLinks(
1548                            Group group, long publicLayoutSetPrototypeId,
1549                            long privateLayoutSetPrototypeId,
1550                            boolean publicLayoutSetPrototypeLinkEnabled,
1551                            boolean privateLayoutSetPrototypeLinkEnabled)
1552                    throws Exception {
1553    
1554                    updateLayoutSetPrototypeLink(
1555                            group.getGroupId(), true, privateLayoutSetPrototypeId,
1556                            privateLayoutSetPrototypeLinkEnabled);
1557                    updateLayoutSetPrototypeLink(
1558                            group.getGroupId(), false, publicLayoutSetPrototypeId,
1559                            publicLayoutSetPrototypeLinkEnabled);
1560            }
1561    
1562            /**
1563             * Checks the permissions necessary for resetting the layout or site. If the
1564             * permissions are not sufficient, a {@link PortalException} is thrown.
1565             *
1566             * @param  group the site being checked for sufficient permissions
1567             * @param  layout the page being checked for sufficient permissions
1568             *         (optionally <code>null</code>). If <code>null</code>, the
1569             *         permissions are only checked for resetting the site.
1570             * @throws PortalException if the user did not have permission to update the
1571             *         layout or site, or if a portal exception occurred
1572             */
1573            protected void checkResetPrototypePermissions(Group group, Layout layout)
1574                    throws PortalException {
1575    
1576                    PermissionChecker permissionChecker =
1577                            PermissionThreadLocal.getPermissionChecker();
1578    
1579                    if ((layout != null) &&
1580                            !LayoutPermissionUtil.contains(
1581                                    permissionChecker, layout, ActionKeys.UPDATE)) {
1582    
1583                            throw new PrincipalException.MustHavePermission(
1584                                    permissionChecker, layout.getName(), layout.getLayoutId(),
1585                                    ActionKeys.UPDATE);
1586                    }
1587                    else if (!group.isUser() &&
1588                                     !GroupPermissionUtil.contains(
1589                                             permissionChecker, group, ActionKeys.UPDATE)) {
1590    
1591                            throw new PrincipalException.MustHavePermission(
1592                                    permissionChecker, group.getName(), group.getGroupId(),
1593                                    ActionKeys.UPDATE);
1594                    }
1595                    else if (group.isUser() &&
1596                                     (permissionChecker.getUserId() != group.getClassPK())) {
1597    
1598                            throw new PrincipalException();
1599                    }
1600            }
1601    
1602            protected void doMergeLayoutPrototypeLayout(Group group, Layout layout)
1603                    throws Exception {
1604    
1605                    if (!layout.isLayoutPrototypeLinkActive() ||
1606                            group.isLayoutPrototype() || group.hasStagingGroup()) {
1607    
1608                            return;
1609                    }
1610    
1611                    long lastMergeTime = GetterUtil.getLong(
1612                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
1613    
1614                    LayoutPrototype layoutPrototype =
1615                            LayoutPrototypeLocalServiceUtil.
1616                                    getLayoutPrototypeByUuidAndCompanyId(
1617                                            layout.getLayoutPrototypeUuid(), layout.getCompanyId());
1618    
1619                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1620    
1621                    Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
1622    
1623                    if (lastMergeTime >= modifiedDate.getTime()) {
1624                            return;
1625                    }
1626    
1627                    UnicodeProperties prototypeTypeSettingsProperties =
1628                            layoutPrototypeLayout.getTypeSettingsProperties();
1629    
1630                    int mergeFailCount = GetterUtil.getInteger(
1631                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1632    
1633                    if (mergeFailCount >
1634                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1635    
1636                            if (_log.isWarnEnabled()) {
1637                                    StringBundler sb = new StringBundler(6);
1638    
1639                                    sb.append("Merge not performed because the fail threshold ");
1640                                    sb.append("was reached for layoutPrototypeId ");
1641                                    sb.append(layoutPrototype.getLayoutPrototypeId());
1642                                    sb.append(" and layoutId ");
1643                                    sb.append(layoutPrototypeLayout.getLayoutId());
1644                                    sb.append(". Update the count in the database to try again.");
1645    
1646                                    _log.warn(sb.toString());
1647                            }
1648    
1649                            return;
1650                    }
1651    
1652                    String owner = PortalUUIDUtil.generate();
1653    
1654                    try {
1655                            Lock lock = LockManagerUtil.lock(
1656                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1657                                    String.valueOf(layout.getPlid()), owner);
1658    
1659                            if (!owner.equals(lock.getOwner())) {
1660                                    Date createDate = lock.getCreateDate();
1661    
1662                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1663                                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1664    
1665                                            // Acquire lock if the lock is older than the lock max time
1666    
1667                                            lock = LockManagerUtil.lock(
1668                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1669                                                    String.valueOf(layout.getPlid()), lock.getOwner(),
1670                                                    owner);
1671    
1672                                            // Check if acquiring the lock succeeded or if another
1673                                            // process has the lock
1674    
1675                                            if (!owner.equals(lock.getOwner())) {
1676                                                    return;
1677                                            }
1678                                    }
1679                                    else {
1680                                            return;
1681                                    }
1682                            }
1683                    }
1684                    catch (Exception e) {
1685                            return;
1686                    }
1687    
1688                    try {
1689                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1690    
1691                            applyLayoutPrototype(layoutPrototype, layout, true);
1692                    }
1693                    catch (Exception e) {
1694                            _log.error(e, e);
1695    
1696                            prototypeTypeSettingsProperties.setProperty(
1697                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1698    
1699                            // Invoke updateImpl so that we do not trigger the listeners
1700    
1701                            LayoutUtil.updateImpl(layoutPrototypeLayout);
1702                    }
1703                    finally {
1704                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1705    
1706                            LockManagerUtil.unlock(
1707                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1708                                    String.valueOf(layout.getPlid()), owner);
1709                    }
1710            }
1711    
1712            /**
1713             * Resets the modified timestamp on the layout, and then calls {@link
1714             * #doResetPrototype(LayoutSet)} to reset the modified timestamp on the
1715             * layout's site.
1716             *
1717             * <p>
1718             * After the timestamps are reset, the modified page template and site
1719             * template are merged into their linked layout and site when they are first
1720             * accessed.
1721             * </p>
1722             *
1723             * @param  layout the page having its timestamp reset
1724             * @throws PortalException if no site was associated with the layout or if a
1725             *         portal exception occurred
1726             */
1727            protected void doResetPrototype(Layout layout) throws PortalException {
1728                    layout.setModifiedDate(null);
1729    
1730                    LayoutLocalServiceUtil.updateLayout(layout);
1731    
1732                    LayoutSet layoutSet = layout.getLayoutSet();
1733    
1734                    doResetPrototype(layoutSet);
1735            }
1736    
1737            /**
1738             * Resets the modified timestamp on the layout set.
1739             *
1740             * <p>
1741             * After the timestamp is reset, the modified site template is merged into
1742             * its linked layout set when it is first accessed.
1743             * </p>
1744             *
1745             * @param layoutSet the site having its timestamp reset
1746             */
1747            protected void doResetPrototype(LayoutSet layoutSet) {
1748                    UnicodeProperties settingsProperties =
1749                            layoutSet.getSettingsProperties();
1750    
1751                    settingsProperties.remove(LAST_MERGE_TIME);
1752    
1753                    settingsProperties.setProperty(
1754                            LAST_RESET_TIME, String.valueOf(System.currentTimeMillis()));
1755    
1756                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1757            }
1758    
1759            protected Map<String, String[]> getLayoutSetPrototypesParameters(
1760                    boolean importData) {
1761    
1762                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
1763    
1764                    parameterMap.put(
1765                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1766                            new String[] {Boolean.FALSE.toString()});
1767                    parameterMap.put(
1768                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1769                            new String[] {Boolean.FALSE.toString()});
1770                    parameterMap.put(
1771                            PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
1772                            new String[] {Boolean.TRUE.toString()});
1773                    parameterMap.put(
1774                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1775                            new String[] {Boolean.TRUE.toString()});
1776                    parameterMap.put(
1777                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1778                            new String[] {Boolean.TRUE.toString()});
1779                    parameterMap.put(
1780                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1781                            new String[] {
1782                                    PortletDataHandlerKeys.
1783                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
1784                            });
1785                    parameterMap.put(
1786                            PortletDataHandlerKeys.PERMISSIONS,
1787                            new String[] {Boolean.TRUE.toString()});
1788                    parameterMap.put(
1789                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
1790                            new String[] {Boolean.TRUE.toString()});
1791                    parameterMap.put(
1792                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
1793                            new String[] {Boolean.TRUE.toString()});
1794                    parameterMap.put(
1795                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1796                            new String[] {Boolean.TRUE.toString()});
1797                    parameterMap.put(
1798                            PortletDataHandlerKeys.THEME_REFERENCE,
1799                            new String[] {Boolean.TRUE.toString()});
1800                    parameterMap.put(
1801                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1802                            new String[] {Boolean.FALSE.toString()});
1803                    parameterMap.put(
1804                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1805                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1806    
1807                    if (importData) {
1808                            parameterMap.put(
1809                                    PortletDataHandlerKeys.DATA_STRATEGY,
1810                                    new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1811                            parameterMap.put(
1812                                    PortletDataHandlerKeys.LOGO,
1813                                    new String[] {Boolean.TRUE.toString()});
1814                            parameterMap.put(
1815                                    PortletDataHandlerKeys.PORTLET_DATA,
1816                                    new String[] {Boolean.TRUE.toString()});
1817                            parameterMap.put(
1818                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1819                                    new String[] {Boolean.TRUE.toString()});
1820                    }
1821                    else {
1822                            if (PropsValues.LAYOUT_SET_PROTOTYPE_PROPAGATE_LOGO) {
1823                                    parameterMap.put(
1824                                            PortletDataHandlerKeys.LOGO,
1825                                            new String[] {Boolean.TRUE.toString()});
1826                            }
1827                            else {
1828                                    parameterMap.put(
1829                                            PortletDataHandlerKeys.LOGO,
1830                                            new String[] {Boolean.FALSE.toString()});
1831                            }
1832    
1833                            parameterMap.put(
1834                                    PortletDataHandlerKeys.PORTLET_DATA,
1835                                    new String[] {Boolean.FALSE.toString()});
1836                            parameterMap.put(
1837                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1838                                    new String[] {Boolean.FALSE.toString()});
1839                    }
1840    
1841                    return parameterMap;
1842            }
1843    
1844            protected void importLayoutSetPrototype(
1845                            LayoutSetPrototype layoutSetPrototype, long groupId,
1846                            boolean privateLayout, Map<String, String[]> parameterMap,
1847                            boolean importData)
1848                    throws PortalException {
1849    
1850                    File file = null;
1851    
1852                    StringBundler sb = new StringBundler(importData ? 4 : 3);
1853    
1854                    sb.append(_TEMP_DIR);
1855                    sb.append(layoutSetPrototype.getUuid());
1856    
1857                    if (importData) {
1858                            sb.append("-data");
1859                    }
1860    
1861                    sb.append(".lar");
1862    
1863                    File cacheFile = new File(sb.toString());
1864    
1865                    if (cacheFile.exists() && !importData) {
1866                            Date modifiedDate = layoutSetPrototype.getModifiedDate();
1867    
1868                            if (cacheFile.lastModified() >= modifiedDate.getTime()) {
1869                                    if (_log.isDebugEnabled()) {
1870                                            _log.debug(
1871                                                    "Using cached layout set prototype LAR file " +
1872                                                            cacheFile.getAbsolutePath());
1873                                    }
1874    
1875                                    file = cacheFile;
1876                            }
1877                    }
1878    
1879                    User user = UserLocalServiceUtil.getDefaultUser(
1880                            layoutSetPrototype.getCompanyId());
1881    
1882                    boolean newFile = false;
1883    
1884                    if (file == null) {
1885                            List<Layout> layoutSetPrototypeLayouts =
1886                                    LayoutLocalServiceUtil.getLayouts(
1887                                            layoutSetPrototype.getGroupId(), true);
1888    
1889                            Map<String, Serializable> exportLayoutSettingsMap =
1890                                    ExportImportConfigurationSettingsMapFactory.
1891                                            buildExportLayoutSettingsMap(
1892                                                    user, layoutSetPrototype.getGroupId(), true,
1893                                                    ExportImportHelperUtil.getLayoutIds(
1894                                                            layoutSetPrototypeLayouts),
1895                                                    parameterMap);
1896    
1897                            ExportImportConfiguration exportImportConfiguration =
1898                                    ExportImportConfigurationLocalServiceUtil.
1899                                            addDraftExportImportConfiguration(
1900                                                    user.getUserId(),
1901                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1902                                                    exportLayoutSettingsMap);
1903    
1904                            file = ExportImportLocalServiceUtil.exportLayoutsAsFile(
1905                                    exportImportConfiguration);
1906    
1907                            newFile = true;
1908                    }
1909    
1910                    Map<String, Serializable> importLayoutSettingsMap =
1911                            ExportImportConfigurationSettingsMapFactory.
1912                                    buildImportLayoutSettingsMap(
1913                                            user.getUserId(), groupId, privateLayout, null,
1914                                            parameterMap, user.getLocale(), user.getTimeZone());
1915    
1916                    ExportImportConfiguration exportImportConfiguration =
1917                            ExportImportConfigurationLocalServiceUtil.
1918                                    addExportImportConfiguration(
1919                                            user.getUserId(), groupId, StringPool.BLANK,
1920                                            StringPool.BLANK,
1921                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1922                                            importLayoutSettingsMap, WorkflowConstants.STATUS_DRAFT,
1923                                            new ServiceContext());
1924    
1925                    ExportImportLocalServiceUtil.importLayouts(
1926                            exportImportConfiguration, file);
1927    
1928                    if (newFile) {
1929                            try {
1930                                    FileUtil.copyFile(file, cacheFile);
1931    
1932                                    if (_log.isDebugEnabled()) {
1933                                            _log.debug(
1934                                                    "Copied " + file.getAbsolutePath() + " to " +
1935                                                            cacheFile.getAbsolutePath());
1936                                    }
1937                            }
1938                            catch (Exception e) {
1939                                    _log.error(
1940                                            "Unable to copy file " + file.getAbsolutePath() + " to " +
1941                                                    cacheFile.getAbsolutePath(),
1942                                            e);
1943                            }
1944                    }
1945            }
1946    
1947            protected void setLayoutSetPrototypeLinkEnabledParameter(
1948                    Map<String, String[]> parameterMap, LayoutSet targetLayoutSet,
1949                    ServiceContext serviceContext) {
1950    
1951                    PermissionChecker permissionChecker =
1952                            PermissionThreadLocal.getPermissionChecker();
1953    
1954                    if ((permissionChecker == null) ||
1955                            !PortalPermissionUtil.contains(
1956                                    permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) {
1957    
1958                            return;
1959                    }
1960    
1961                    if (targetLayoutSet.isPrivateLayout()) {
1962                            boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1963                                    serviceContext, "privateLayoutSetPrototypeLinkEnabled", true);
1964    
1965                            if (!privateLayoutSetPrototypeLinkEnabled) {
1966                                    privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1967                                            serviceContext, "layoutSetPrototypeLinkEnabled");
1968                            }
1969    
1970                            parameterMap.put(
1971                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1972                                    new String[] {
1973                                            String.valueOf(privateLayoutSetPrototypeLinkEnabled)
1974                                    });
1975                    }
1976                    else {
1977                            boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1978                                    serviceContext, "publicLayoutSetPrototypeLinkEnabled");
1979    
1980                            if (!publicLayoutSetPrototypeLinkEnabled) {
1981                                    publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1982                                            serviceContext, "layoutSetPrototypeLinkEnabled", true);
1983                            }
1984    
1985                            parameterMap.put(
1986                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1987                                    new String[] {
1988                                            String.valueOf(publicLayoutSetPrototypeLinkEnabled)
1989                                    });
1990                    }
1991            }
1992    
1993            protected void updateLayoutSetPrototypeLink(
1994                            long groupId, boolean privateLayout, long layoutSetPrototypeId,
1995                            boolean layoutSetPrototypeLinkEnabled)
1996                    throws Exception {
1997    
1998                    String layoutSetPrototypeUuid = null;
1999    
2000                    if (layoutSetPrototypeId > 0) {
2001                            LayoutSetPrototype layoutSetPrototype =
2002                                    LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype(
2003                                            layoutSetPrototypeId);
2004    
2005                            if (layoutSetPrototype != null) {
2006                                    layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
2007    
2008                                    // Merge without enabling the link
2009    
2010                                    if (!layoutSetPrototypeLinkEnabled &&
2011                                            (layoutSetPrototypeId > 0)) {
2012    
2013                                            Map<String, String[]> parameterMap =
2014                                                    getLayoutSetPrototypesParameters(true);
2015    
2016                                            importLayoutSetPrototype(
2017                                                    layoutSetPrototype, groupId, privateLayout,
2018                                                    parameterMap, true);
2019                                    }
2020                            }
2021                    }
2022    
2023                    LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled(
2024                            groupId, privateLayout, layoutSetPrototypeLinkEnabled,
2025                            layoutSetPrototypeUuid);
2026    
2027                    LayoutLocalServiceUtil.updatePriorities(groupId, privateLayout);
2028    
2029                    // Force propagation from site template to site. See LPS-48206.
2030    
2031                    Group group = GroupLocalServiceUtil.getGroup(groupId);
2032    
2033                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
2034                            groupId, privateLayout);
2035    
2036                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
2037            }
2038    
2039            private static final String _TEMP_DIR =
2040                    SystemProperties.get(SystemProperties.TMP_DIR) +
2041                            "/liferay/layout_set_prototype/";
2042    
2043            private static final Log _log = LogFactoryUtil.getLog(SitesImpl.class);
2044    
2045    }