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