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