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