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.security.auth.PrincipalException;
029    import com.liferay.portal.kernel.security.auth.PrincipalThreadLocal;
030    import com.liferay.portal.kernel.security.permission.ActionKeys;
031    import com.liferay.portal.kernel.security.permission.PermissionChecker;
032    import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
033    import com.liferay.portal.kernel.security.permission.ResourceActionsUtil;
034    import com.liferay.portal.kernel.util.ArrayUtil;
035    import com.liferay.portal.kernel.util.FileUtil;
036    import com.liferay.portal.kernel.util.GetterUtil;
037    import com.liferay.portal.kernel.util.ListUtil;
038    import com.liferay.portal.kernel.util.ParamUtil;
039    import com.liferay.portal.kernel.util.PrefsPropsUtil;
040    import com.liferay.portal.kernel.util.PropsKeys;
041    import com.liferay.portal.kernel.util.StringBundler;
042    import com.liferay.portal.kernel.util.StringPool;
043    import com.liferay.portal.kernel.util.StringUtil;
044    import com.liferay.portal.kernel.util.SystemProperties;
045    import com.liferay.portal.kernel.util.UnicodeProperties;
046    import com.liferay.portal.kernel.util.Validator;
047    import com.liferay.portal.kernel.util.WebKeys;
048    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
049    import com.liferay.portal.kernel.workflow.WorkflowConstants;
050    import com.liferay.portal.model.Group;
051    import com.liferay.portal.model.GroupConstants;
052    import com.liferay.portal.model.Layout;
053    import com.liferay.portal.model.LayoutConstants;
054    import com.liferay.portal.model.LayoutPrototype;
055    import com.liferay.portal.model.LayoutSet;
056    import com.liferay.portal.model.LayoutSetPrototype;
057    import com.liferay.portal.model.LayoutType;
058    import com.liferay.portal.model.LayoutTypePortlet;
059    import com.liferay.portal.model.Organization;
060    import com.liferay.portal.model.PortletConstants;
061    import com.liferay.portal.model.ResourceConstants;
062    import com.liferay.portal.model.Role;
063    import com.liferay.portal.model.RoleConstants;
064    import com.liferay.portal.model.User;
065    import com.liferay.portal.model.UserGroup;
066    import com.liferay.portal.model.impl.VirtualLayout;
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 selPlid = ParamUtil.getLong(request, "selPlid");
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 (selPlid <= 0) {
512                            layout = LayoutLocalServiceUtil.getLayout(
513                                    groupId, privateLayout, layoutId);
514                    }
515                    else {
516                            layout = LayoutLocalServiceUtil.getLayout(selPlid);
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            @Override
1247            public void mergeLayoutSetPrototypeLayouts(Group group, LayoutSet layoutSet)
1248                    throws Exception {
1249    
1250                    if (!isLayoutSetMergeable(group, layoutSet)) {
1251                            return;
1252                    }
1253    
1254                    UnicodeProperties settingsProperties =
1255                            layoutSet.getSettingsProperties();
1256    
1257                    long lastMergeTime = GetterUtil.getLong(
1258                            settingsProperties.getProperty(LAST_MERGE_TIME));
1259    
1260                    LayoutSetPrototype layoutSetPrototype =
1261                            LayoutSetPrototypeLocalServiceUtil.
1262                                    getLayoutSetPrototypeByUuidAndCompanyId(
1263                                            layoutSet.getLayoutSetPrototypeUuid(),
1264                                            layoutSet.getCompanyId());
1265    
1266                    LayoutSet layoutSetPrototypeLayoutSet =
1267                            layoutSetPrototype.getLayoutSet();
1268    
1269                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1270                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1271    
1272                    int mergeFailCount = GetterUtil.getInteger(
1273                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1274    
1275                    String owner = PortalUUIDUtil.generate();
1276    
1277                    try {
1278                            Lock lock = LockManagerUtil.lock(
1279                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1280                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1281    
1282                            // Double deep check
1283    
1284                            if (!owner.equals(lock.getOwner())) {
1285                                    Date createDate = lock.getCreateDate();
1286    
1287                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1288                                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1289    
1290                                            // Acquire lock if the lock is older than the lock max time
1291    
1292                                            lock = LockManagerUtil.lock(
1293                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1294                                                    String.valueOf(layoutSet.getLayoutSetId()),
1295                                                    lock.getOwner(), owner);
1296    
1297                                            // Check if acquiring the lock succeeded or if another
1298                                            // process has the lock
1299    
1300                                            if (!owner.equals(lock.getOwner())) {
1301                                                    return;
1302                                            }
1303                                    }
1304                                    else {
1305                                            return;
1306                                    }
1307                            }
1308                    }
1309                    catch (Exception e) {
1310                            return;
1311                    }
1312    
1313                    try {
1314                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1315    
1316                            boolean importData = true;
1317    
1318                            long lastResetTime = GetterUtil.getLong(
1319                                    settingsProperties.getProperty(LAST_RESET_TIME));
1320    
1321                            if ((lastMergeTime > 0) || (lastResetTime > 0)) {
1322                                    importData = false;
1323                            }
1324    
1325                            Map<String, String[]> parameterMap =
1326                                    getLayoutSetPrototypesParameters(importData);
1327    
1328                            layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1329                                    layoutSet.getLayoutSetId());
1330    
1331                            removeMergeFailFriendlyURLLayouts(layoutSet);
1332    
1333                            importLayoutSetPrototype(
1334                                    layoutSetPrototype, layoutSet.getGroupId(),
1335                                    layoutSet.isPrivateLayout(), parameterMap, importData);
1336                    }
1337                    catch (Exception e) {
1338                            _log.error(e, e);
1339    
1340                            layoutSetPrototypeSettingsProperties.setProperty(
1341                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1342    
1343                            // Invoke updateImpl so that we do not trigger the listeners
1344    
1345                            LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet);
1346                    }
1347                    finally {
1348                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1349    
1350                            LockManagerUtil.unlock(
1351                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1352                                    String.valueOf(layoutSet.getLayoutSetId()), owner);
1353                    }
1354            }
1355    
1356            @Override
1357            public void removeMergeFailFriendlyURLLayouts(LayoutSet layoutSet) {
1358                    UnicodeProperties settingsProperties =
1359                            layoutSet.getSettingsProperties();
1360    
1361                    settingsProperties.remove(MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
1362    
1363                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1364            }
1365    
1366            /**
1367             * Checks the permissions necessary for resetting the layout. If sufficient,
1368             * the layout is reset by calling {@link #doResetPrototype(Layout)}.
1369             *
1370             * @param layout the page being checked for sufficient permissions
1371             */
1372            @Override
1373            public void resetPrototype(Layout layout) throws PortalException {
1374                    checkResetPrototypePermissions(layout.getGroup(), layout);
1375    
1376                    doResetPrototype(layout);
1377            }
1378    
1379            /**
1380             * Checks the permissions necessary for resetting the layout set. If
1381             * sufficient, the layout set is reset by calling {@link
1382             * #doResetPrototype(LayoutSet)}.
1383             *
1384             * @param layoutSet the site being checked for sufficient permissions
1385             */
1386            @Override
1387            public void resetPrototype(LayoutSet layoutSet) throws PortalException {
1388                    checkResetPrototypePermissions(layoutSet.getGroup(), null);
1389    
1390                    doResetPrototype(layoutSet);
1391            }
1392    
1393            /**
1394             * Sets the number of failed merge attempts for the layout prototype to a
1395             * new value.
1396             *
1397             * @param layoutPrototype the page template of the counter being updated
1398             * @param newMergeFailCount the new value of the counter
1399             */
1400            @Override
1401            public void setMergeFailCount(
1402                            LayoutPrototype layoutPrototype, int newMergeFailCount)
1403                    throws PortalException {
1404    
1405                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1406    
1407                    UnicodeProperties prototypeTypeSettingsProperties =
1408                            layoutPrototypeLayout.getTypeSettingsProperties();
1409    
1410                    if (newMergeFailCount == 0) {
1411                            prototypeTypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1412                    }
1413                    else {
1414                            prototypeTypeSettingsProperties.setProperty(
1415                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1416                    }
1417    
1418                    LayoutServiceUtil.updateLayout(
1419                            layoutPrototypeLayout.getGroupId(),
1420                            layoutPrototypeLayout.getPrivateLayout(),
1421                            layoutPrototypeLayout.getLayoutId(),
1422                            layoutPrototypeLayout.getTypeSettings());
1423            }
1424    
1425            /**
1426             * Sets the number of failed merge attempts for the layout set prototype to
1427             * a new value.
1428             *
1429             * @param layoutSetPrototype the site template of the counter being updated
1430             * @param newMergeFailCount the new value of the counter
1431             */
1432            @Override
1433            public void setMergeFailCount(
1434                            LayoutSetPrototype layoutSetPrototype, int newMergeFailCount)
1435                    throws PortalException {
1436    
1437                    LayoutSet layoutSetPrototypeLayoutSet =
1438                            layoutSetPrototype.getLayoutSet();
1439    
1440                    UnicodeProperties layoutSetPrototypeSettingsProperties =
1441                            layoutSetPrototypeLayoutSet.getSettingsProperties();
1442    
1443                    if (newMergeFailCount == 0) {
1444                            layoutSetPrototypeSettingsProperties.remove(MERGE_FAIL_COUNT);
1445                    }
1446                    else {
1447                            layoutSetPrototypeSettingsProperties.setProperty(
1448                                    MERGE_FAIL_COUNT, String.valueOf(newMergeFailCount));
1449                    }
1450    
1451                    LayoutSetServiceUtil.updateSettings(
1452                            layoutSetPrototypeLayoutSet.getGroupId(),
1453                            layoutSetPrototypeLayoutSet.getPrivateLayout(),
1454                            layoutSetPrototypeLayoutSet.getSettings());
1455            }
1456    
1457            @Override
1458            public void updateLayoutScopes(
1459                            long userId, Layout sourceLayout, Layout targetLayout,
1460                            PortletPreferences sourcePreferences,
1461                            PortletPreferences targetPreferences, String sourcePortletId,
1462                            String languageId)
1463                    throws Exception {
1464    
1465                    String scopeType = GetterUtil.getString(
1466                            sourcePreferences.getValue("lfrScopeType", null));
1467    
1468                    if (Validator.isNull(scopeType) || !scopeType.equals("layout")) {
1469                            return;
1470                    }
1471    
1472                    Layout targetScopeLayout =
1473                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1474                                    targetLayout.getUuid(), targetLayout.getGroupId(),
1475                                    targetLayout.isPrivateLayout());
1476    
1477                    if (!targetScopeLayout.hasScopeGroup()) {
1478                            GroupLocalServiceUtil.addGroup(
1479                                    userId, GroupConstants.DEFAULT_PARENT_GROUP_ID,
1480                                    Layout.class.getName(), targetLayout.getPlid(),
1481                                    GroupConstants.DEFAULT_LIVE_GROUP_ID, targetLayout.getNameMap(),
1482                                    null, 0, true, GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION,
1483                                    null, false, true, null);
1484                    }
1485    
1486                    String portletTitle = PortalUtil.getPortletTitle(
1487                            PortletConstants.getRootPortletId(sourcePortletId), languageId);
1488    
1489                    String newPortletTitle = PortalUtil.getNewPortletTitle(
1490                            portletTitle, String.valueOf(sourceLayout.getLayoutId()),
1491                            targetLayout.getName(languageId));
1492    
1493                    targetPreferences.setValue(
1494                            "groupId", String.valueOf(targetLayout.getGroupId()));
1495                    targetPreferences.setValue("lfrScopeType", "layout");
1496                    targetPreferences.setValue(
1497                            "lfrScopeLayoutUuid", targetLayout.getUuid());
1498                    targetPreferences.setValue(
1499                            "portletSetupTitle_" + languageId, newPortletTitle);
1500                    targetPreferences.setValue(
1501                            "portletSetupUseCustomTitle", Boolean.TRUE.toString());
1502    
1503                    targetPreferences.store();
1504            }
1505    
1506            @Override
1507            public void updateLayoutSetPrototypesLinks(
1508                            Group group, long publicLayoutSetPrototypeId,
1509                            long privateLayoutSetPrototypeId,
1510                            boolean publicLayoutSetPrototypeLinkEnabled,
1511                            boolean privateLayoutSetPrototypeLinkEnabled)
1512                    throws Exception {
1513    
1514                    updateLayoutSetPrototypeLink(
1515                            group.getGroupId(), true, privateLayoutSetPrototypeId,
1516                            privateLayoutSetPrototypeLinkEnabled);
1517                    updateLayoutSetPrototypeLink(
1518                            group.getGroupId(), false, publicLayoutSetPrototypeId,
1519                            publicLayoutSetPrototypeLinkEnabled);
1520            }
1521    
1522            /**
1523             * Checks the permissions necessary for resetting the layout or site. If the
1524             * permissions are not sufficient, a {@link PortalException} is thrown.
1525             *
1526             * @param group the site being checked for sufficient permissions
1527             * @param layout the page being checked for sufficient permissions
1528             *        (optionally <code>null</code>). If <code>null</code>, the
1529             *        permissions are only checked for resetting the site.
1530             */
1531            protected void checkResetPrototypePermissions(Group group, Layout layout)
1532                    throws PortalException {
1533    
1534                    PermissionChecker permissionChecker =
1535                            PermissionThreadLocal.getPermissionChecker();
1536    
1537                    if ((layout != null) &&
1538                            !LayoutPermissionUtil.contains(
1539                                    permissionChecker, layout, ActionKeys.UPDATE)) {
1540    
1541                            throw new PrincipalException.MustHavePermission(
1542                                    permissionChecker, layout.getName(), layout.getLayoutId(),
1543                                    ActionKeys.UPDATE);
1544                    }
1545                    else if (!group.isUser() &&
1546                                     !GroupPermissionUtil.contains(
1547                                             permissionChecker, group, ActionKeys.UPDATE)) {
1548    
1549                            throw new PrincipalException.MustHavePermission(
1550                                    permissionChecker, group.getName(), group.getGroupId(),
1551                                    ActionKeys.UPDATE);
1552                    }
1553                    else if (group.isUser() &&
1554                                     (permissionChecker.getUserId() != group.getClassPK())) {
1555    
1556                            throw new PrincipalException();
1557                    }
1558            }
1559    
1560            protected void doMergeLayoutPrototypeLayout(Group group, Layout layout)
1561                    throws Exception {
1562    
1563                    if (!layout.isLayoutPrototypeLinkActive() ||
1564                            group.isLayoutPrototype() || group.hasStagingGroup()) {
1565    
1566                            return;
1567                    }
1568    
1569                    long lastMergeTime = GetterUtil.getLong(
1570                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
1571    
1572                    LayoutPrototype layoutPrototype =
1573                            LayoutPrototypeLocalServiceUtil.
1574                                    getLayoutPrototypeByUuidAndCompanyId(
1575                                            layout.getLayoutPrototypeUuid(), layout.getCompanyId());
1576    
1577                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1578    
1579                    Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
1580    
1581                    if (lastMergeTime >= modifiedDate.getTime()) {
1582                            return;
1583                    }
1584    
1585                    UnicodeProperties prototypeTypeSettingsProperties =
1586                            layoutPrototypeLayout.getTypeSettingsProperties();
1587    
1588                    int mergeFailCount = GetterUtil.getInteger(
1589                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1590    
1591                    if (mergeFailCount >
1592                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1593    
1594                            if (_log.isWarnEnabled()) {
1595                                    StringBundler sb = new StringBundler(6);
1596    
1597                                    sb.append("Merge not performed because the fail threshold ");
1598                                    sb.append("was reached for layoutPrototypeId ");
1599                                    sb.append(layoutPrototype.getLayoutPrototypeId());
1600                                    sb.append(" and layoutId ");
1601                                    sb.append(layoutPrototypeLayout.getLayoutId());
1602                                    sb.append(". Update the count in the database to try again.");
1603    
1604                                    _log.warn(sb.toString());
1605                            }
1606    
1607                            return;
1608                    }
1609    
1610                    String owner = PortalUUIDUtil.generate();
1611    
1612                    try {
1613                            Lock lock = LockManagerUtil.lock(
1614                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1615                                    String.valueOf(layout.getPlid()), owner);
1616    
1617                            if (!owner.equals(lock.getOwner())) {
1618                                    Date createDate = lock.getCreateDate();
1619    
1620                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1621                                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1622    
1623                                            // Acquire lock if the lock is older than the lock max time
1624    
1625                                            lock = LockManagerUtil.lock(
1626                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1627                                                    String.valueOf(layout.getPlid()), lock.getOwner(),
1628                                                    owner);
1629    
1630                                            // Check if acquiring the lock succeeded or if another
1631                                            // process has the lock
1632    
1633                                            if (!owner.equals(lock.getOwner())) {
1634                                                    return;
1635                                            }
1636                                    }
1637                                    else {
1638                                            return;
1639                                    }
1640                            }
1641                    }
1642                    catch (Exception e) {
1643                            return;
1644                    }
1645    
1646                    try {
1647                            MergeLayoutPrototypesThreadLocal.setInProgress(true);
1648    
1649                            applyLayoutPrototype(layoutPrototype, layout, true);
1650                    }
1651                    catch (Exception e) {
1652                            _log.error(e, e);
1653    
1654                            prototypeTypeSettingsProperties.setProperty(
1655                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1656    
1657                            // Invoke updateImpl so that we do not trigger the listeners
1658    
1659                            LayoutUtil.updateImpl(layoutPrototypeLayout);
1660                    }
1661                    finally {
1662                            MergeLayoutPrototypesThreadLocal.setInProgress(false);
1663    
1664                            LockManagerUtil.unlock(
1665                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1666                                    String.valueOf(layout.getPlid()), owner);
1667                    }
1668            }
1669    
1670            /**
1671             * Resets the modified timestamp on the layout, and then calls {@link
1672             * #doResetPrototype(LayoutSet)} to reset the modified timestamp on the
1673             * layout's site.
1674             *
1675             * <p>
1676             * After the timestamps are reset, the modified page template and site
1677             * template are merged into their linked layout and site when they are first
1678             * accessed.
1679             * </p>
1680             *
1681             * @param layout the page having its timestamp reset
1682             */
1683            protected void doResetPrototype(Layout layout) throws PortalException {
1684                    layout.setModifiedDate(null);
1685    
1686                    LayoutLocalServiceUtil.updateLayout(layout);
1687    
1688                    LayoutSet layoutSet = layout.getLayoutSet();
1689    
1690                    doResetPrototype(layoutSet);
1691            }
1692    
1693            /**
1694             * Resets the modified timestamp on the layout set.
1695             *
1696             * <p>
1697             * After the timestamp is reset, the modified site template is merged into
1698             * its linked layout set when it is first accessed.
1699             * </p>
1700             *
1701             * @param layoutSet the site having its timestamp reset
1702             */
1703            protected void doResetPrototype(LayoutSet layoutSet) {
1704                    UnicodeProperties settingsProperties =
1705                            layoutSet.getSettingsProperties();
1706    
1707                    settingsProperties.remove(LAST_MERGE_TIME);
1708    
1709                    settingsProperties.setProperty(
1710                            LAST_RESET_TIME, String.valueOf(System.currentTimeMillis()));
1711    
1712                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
1713            }
1714    
1715            protected Map<String, String[]> getLayoutSetPrototypesParameters(
1716                    boolean importData) {
1717    
1718                    Map<String, String[]> parameterMap = new LinkedHashMap<>();
1719    
1720                    parameterMap.put(
1721                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1722                            new String[] {Boolean.FALSE.toString()});
1723                    parameterMap.put(
1724                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1725                            new String[] {Boolean.FALSE.toString()});
1726                    parameterMap.put(
1727                            PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
1728                            new String[] {Boolean.TRUE.toString()});
1729                    parameterMap.put(
1730                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1731                            new String[] {Boolean.TRUE.toString()});
1732                    parameterMap.put(
1733                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1734                            new String[] {Boolean.TRUE.toString()});
1735                    parameterMap.put(
1736                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1737                            new String[] {
1738                                    PortletDataHandlerKeys.
1739                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
1740                            });
1741                    parameterMap.put(
1742                            PortletDataHandlerKeys.PERMISSIONS,
1743                            new String[] {Boolean.TRUE.toString()});
1744                    parameterMap.put(
1745                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
1746                            new String[] {Boolean.TRUE.toString()});
1747                    parameterMap.put(
1748                            PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL,
1749                            new String[] {Boolean.TRUE.toString()});
1750                    parameterMap.put(
1751                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1752                            new String[] {Boolean.TRUE.toString()});
1753                    parameterMap.put(
1754                            PortletDataHandlerKeys.THEME_REFERENCE,
1755                            new String[] {Boolean.TRUE.toString()});
1756                    parameterMap.put(
1757                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1758                            new String[] {Boolean.FALSE.toString()});
1759                    parameterMap.put(
1760                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1761                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1762    
1763                    if (importData) {
1764                            parameterMap.put(
1765                                    PortletDataHandlerKeys.DATA_STRATEGY,
1766                                    new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1767                            parameterMap.put(
1768                                    PortletDataHandlerKeys.LOGO,
1769                                    new String[] {Boolean.TRUE.toString()});
1770                            parameterMap.put(
1771                                    PortletDataHandlerKeys.PORTLET_DATA,
1772                                    new String[] {Boolean.TRUE.toString()});
1773                            parameterMap.put(
1774                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1775                                    new String[] {Boolean.TRUE.toString()});
1776                    }
1777                    else {
1778                            if (PropsValues.LAYOUT_SET_PROTOTYPE_PROPAGATE_LOGO) {
1779                                    parameterMap.put(
1780                                            PortletDataHandlerKeys.LOGO,
1781                                            new String[] {Boolean.TRUE.toString()});
1782                            }
1783                            else {
1784                                    parameterMap.put(
1785                                            PortletDataHandlerKeys.LOGO,
1786                                            new String[] {Boolean.FALSE.toString()});
1787                            }
1788    
1789                            parameterMap.put(
1790                                    PortletDataHandlerKeys.PORTLET_DATA,
1791                                    new String[] {Boolean.FALSE.toString()});
1792                            parameterMap.put(
1793                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1794                                    new String[] {Boolean.FALSE.toString()});
1795                    }
1796    
1797                    return parameterMap;
1798            }
1799    
1800            protected void importLayoutSetPrototype(
1801                            LayoutSetPrototype layoutSetPrototype, long groupId,
1802                            boolean privateLayout, Map<String, String[]> parameterMap,
1803                            boolean importData)
1804                    throws PortalException {
1805    
1806                    File file = null;
1807    
1808                    StringBundler sb = new StringBundler(importData ? 4 : 3);
1809    
1810                    sb.append(_TEMP_DIR);
1811                    sb.append(layoutSetPrototype.getUuid());
1812    
1813                    if (importData) {
1814                            sb.append("-data");
1815                    }
1816    
1817                    sb.append(".lar");
1818    
1819                    File cacheFile = new File(sb.toString());
1820    
1821                    if (cacheFile.exists() && !importData) {
1822                            Date modifiedDate = layoutSetPrototype.getModifiedDate();
1823    
1824                            if (cacheFile.lastModified() >= modifiedDate.getTime()) {
1825                                    if (_log.isDebugEnabled()) {
1826                                            _log.debug(
1827                                                    "Using cached layout set prototype LAR file " +
1828                                                            cacheFile.getAbsolutePath());
1829                                    }
1830    
1831                                    file = cacheFile;
1832                            }
1833                    }
1834    
1835                    User user = UserLocalServiceUtil.getDefaultUser(
1836                            layoutSetPrototype.getCompanyId());
1837    
1838                    boolean newFile = false;
1839    
1840                    if (file == null) {
1841                            List<Layout> layoutSetPrototypeLayouts =
1842                                    LayoutLocalServiceUtil.getLayouts(
1843                                            layoutSetPrototype.getGroupId(), true);
1844    
1845                            Map<String, Serializable> exportLayoutSettingsMap =
1846                                    ExportImportConfigurationSettingsMapFactory.
1847                                            buildExportLayoutSettingsMap(
1848                                                    user, layoutSetPrototype.getGroupId(), true,
1849                                                    ExportImportHelperUtil.getLayoutIds(
1850                                                            layoutSetPrototypeLayouts),
1851                                                    parameterMap);
1852    
1853                            ExportImportConfiguration exportImportConfiguration =
1854                                    ExportImportConfigurationLocalServiceUtil.
1855                                            addDraftExportImportConfiguration(
1856                                                    user.getUserId(),
1857                                                    ExportImportConfigurationConstants.TYPE_EXPORT_LAYOUT,
1858                                                    exportLayoutSettingsMap);
1859    
1860                            file = ExportImportLocalServiceUtil.exportLayoutsAsFile(
1861                                    exportImportConfiguration);
1862    
1863                            newFile = true;
1864                    }
1865    
1866                    Map<String, Serializable> importLayoutSettingsMap =
1867                            ExportImportConfigurationSettingsMapFactory.
1868                                    buildImportLayoutSettingsMap(
1869                                            user.getUserId(), groupId, privateLayout, null,
1870                                            parameterMap, user.getLocale(), user.getTimeZone());
1871    
1872                    ExportImportConfiguration exportImportConfiguration =
1873                            ExportImportConfigurationLocalServiceUtil.
1874                                    addExportImportConfiguration(
1875                                            user.getUserId(), groupId, StringPool.BLANK,
1876                                            StringPool.BLANK,
1877                                            ExportImportConfigurationConstants.TYPE_IMPORT_LAYOUT,
1878                                            importLayoutSettingsMap, WorkflowConstants.STATUS_DRAFT,
1879                                            new ServiceContext());
1880    
1881                    ExportImportLocalServiceUtil.importLayouts(
1882                            exportImportConfiguration, file);
1883    
1884                    if (newFile) {
1885                            try {
1886                                    FileUtil.copyFile(file, cacheFile);
1887    
1888                                    if (_log.isDebugEnabled()) {
1889                                            _log.debug(
1890                                                    "Copied " + file.getAbsolutePath() + " to " +
1891                                                            cacheFile.getAbsolutePath());
1892                                    }
1893                            }
1894                            catch (Exception e) {
1895                                    _log.error(
1896                                            "Unable to copy file " + file.getAbsolutePath() + " to " +
1897                                                    cacheFile.getAbsolutePath(),
1898                                            e);
1899                            }
1900                    }
1901            }
1902    
1903            protected void setLayoutSetPrototypeLinkEnabledParameter(
1904                    Map<String, String[]> parameterMap, LayoutSet targetLayoutSet,
1905                    ServiceContext serviceContext) {
1906    
1907                    PermissionChecker permissionChecker =
1908                            PermissionThreadLocal.getPermissionChecker();
1909    
1910                    if ((permissionChecker == null) ||
1911                            !PortalPermissionUtil.contains(
1912                                    permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) {
1913    
1914                            return;
1915                    }
1916    
1917                    if (targetLayoutSet.isPrivateLayout()) {
1918                            boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1919                                    serviceContext, "privateLayoutSetPrototypeLinkEnabled", true);
1920    
1921                            if (!privateLayoutSetPrototypeLinkEnabled) {
1922                                    privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1923                                            serviceContext, "layoutSetPrototypeLinkEnabled");
1924                            }
1925    
1926                            parameterMap.put(
1927                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1928                                    new String[] {
1929                                            String.valueOf(privateLayoutSetPrototypeLinkEnabled)
1930                                    });
1931                    }
1932                    else {
1933                            boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1934                                    serviceContext, "publicLayoutSetPrototypeLinkEnabled");
1935    
1936                            if (!publicLayoutSetPrototypeLinkEnabled) {
1937                                    publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1938                                            serviceContext, "layoutSetPrototypeLinkEnabled", true);
1939                            }
1940    
1941                            parameterMap.put(
1942                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1943                                    new String[] {
1944                                            String.valueOf(publicLayoutSetPrototypeLinkEnabled)
1945                                    });
1946                    }
1947            }
1948    
1949            protected void updateLayoutSetPrototypeLink(
1950                            long groupId, boolean privateLayout, long layoutSetPrototypeId,
1951                            boolean layoutSetPrototypeLinkEnabled)
1952                    throws Exception {
1953    
1954                    String layoutSetPrototypeUuid = null;
1955    
1956                    if (layoutSetPrototypeId > 0) {
1957                            LayoutSetPrototype layoutSetPrototype =
1958                                    LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype(
1959                                            layoutSetPrototypeId);
1960    
1961                            if (layoutSetPrototype != null) {
1962                                    layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
1963    
1964                                    // Merge without enabling the link
1965    
1966                                    if (!layoutSetPrototypeLinkEnabled &&
1967                                            (layoutSetPrototypeId > 0)) {
1968    
1969                                            Map<String, String[]> parameterMap =
1970                                                    getLayoutSetPrototypesParameters(true);
1971    
1972                                            importLayoutSetPrototype(
1973                                                    layoutSetPrototype, groupId, privateLayout,
1974                                                    parameterMap, true);
1975                                    }
1976                            }
1977                    }
1978    
1979                    LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled(
1980                            groupId, privateLayout, layoutSetPrototypeLinkEnabled,
1981                            layoutSetPrototypeUuid);
1982    
1983                    LayoutLocalServiceUtil.updatePriorities(groupId, privateLayout);
1984    
1985                    // Force propagation from site template to site. See LPS-48206.
1986    
1987                    Group group = GroupLocalServiceUtil.getGroup(groupId);
1988    
1989                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
1990                            groupId, privateLayout);
1991    
1992                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
1993            }
1994    
1995            private static final String _TEMP_DIR =
1996                    SystemProperties.get(SystemProperties.TMP_DIR) +
1997                            "/liferay/layout_set_prototype/";
1998    
1999            private static final Log _log = LogFactoryUtil.getLog(SitesImpl.class);
2000    
2001    }