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