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