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