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