001    /**
002     * Copyright (c) 2000-2013 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.exception.SystemException;
021    import com.liferay.portal.kernel.language.LanguageUtil;
022    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
023    import com.liferay.portal.kernel.lar.UserIdStrategy;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.util.FileUtil;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.ParamUtil;
029    import com.liferay.portal.kernel.util.PropsKeys;
030    import com.liferay.portal.kernel.util.StringBundler;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.SystemProperties;
034    import com.liferay.portal.kernel.util.UnicodeProperties;
035    import com.liferay.portal.kernel.util.Validator;
036    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
037    import com.liferay.portal.model.Group;
038    import com.liferay.portal.model.Layout;
039    import com.liferay.portal.model.LayoutConstants;
040    import com.liferay.portal.model.LayoutPrototype;
041    import com.liferay.portal.model.LayoutSet;
042    import com.liferay.portal.model.LayoutSetPrototype;
043    import com.liferay.portal.model.LayoutTypePortlet;
044    import com.liferay.portal.model.Lock;
045    import com.liferay.portal.model.PortletConstants;
046    import com.liferay.portal.model.ResourceConstants;
047    import com.liferay.portal.model.Role;
048    import com.liferay.portal.model.RoleConstants;
049    import com.liferay.portal.model.UserGroup;
050    import com.liferay.portal.model.impl.VirtualLayout;
051    import com.liferay.portal.security.auth.PrincipalException;
052    import com.liferay.portal.security.permission.ActionKeys;
053    import com.liferay.portal.security.permission.PermissionChecker;
054    import com.liferay.portal.security.permission.PermissionThreadLocal;
055    import com.liferay.portal.security.permission.ResourceActionsUtil;
056    import com.liferay.portal.service.GroupLocalServiceUtil;
057    import com.liferay.portal.service.GroupServiceUtil;
058    import com.liferay.portal.service.LayoutLocalServiceUtil;
059    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
060    import com.liferay.portal.service.LayoutServiceUtil;
061    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
062    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
063    import com.liferay.portal.service.LayoutSetServiceUtil;
064    import com.liferay.portal.service.LockLocalServiceUtil;
065    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
066    import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
067    import com.liferay.portal.service.RoleLocalServiceUtil;
068    import com.liferay.portal.service.ServiceContext;
069    import com.liferay.portal.service.ServiceContextFactory;
070    import com.liferay.portal.service.ServiceContextThreadLocal;
071    import com.liferay.portal.service.UserGroupLocalServiceUtil;
072    import com.liferay.portal.service.UserLocalServiceUtil;
073    import com.liferay.portal.service.impl.LayoutLocalServiceVirtualLayoutsAdvice;
074    import com.liferay.portal.service.permission.GroupPermissionUtil;
075    import com.liferay.portal.service.permission.LayoutPermissionUtil;
076    import com.liferay.portal.service.permission.PortalPermissionUtil;
077    import com.liferay.portal.service.permission.PortletPermissionUtil;
078    import com.liferay.portal.service.persistence.LayoutSetUtil;
079    import com.liferay.portal.service.persistence.LayoutUtil;
080    import com.liferay.portal.theme.PortletDisplay;
081    import com.liferay.portal.theme.ThemeDisplay;
082    import com.liferay.portal.util.LayoutSettings;
083    import com.liferay.portal.util.PortalUtil;
084    import com.liferay.portal.util.PortletKeys;
085    import com.liferay.portal.util.PropsValues;
086    import com.liferay.portal.util.WebKeys;
087    import com.liferay.portlet.PortletPreferencesFactoryUtil;
088    import com.liferay.portlet.PortletPreferencesImpl;
089    
090    import java.io.File;
091    import java.io.InputStream;
092    
093    import java.util.ArrayList;
094    import java.util.Collections;
095    import java.util.Date;
096    import java.util.LinkedHashMap;
097    import java.util.List;
098    import java.util.Locale;
099    import java.util.Map;
100    
101    import javax.portlet.ActionRequest;
102    import javax.portlet.ActionResponse;
103    import javax.portlet.PortletPreferences;
104    import javax.portlet.PortletURL;
105    import javax.portlet.RenderRequest;
106    import javax.portlet.RenderResponse;
107    
108    import javax.servlet.http.HttpServletRequest;
109    import javax.servlet.http.HttpServletResponse;
110    
111    /**
112     * @author Raymond Aug??
113     * @author Ryan Park
114     * @author Zsolt Berentey
115     */
116    public class SitesUtil {
117    
118            public static final String LAST_MERGE_TIME = "last-merge-time";
119    
120            public static final String LAST_RESET_TIME = "last-reset-time";
121    
122            public static final String LAYOUT_UPDATEABLE = "layoutUpdateable";
123    
124            public static final String MERGE_FAIL_COUNT = "merge-fail-count";
125    
126            public static final String MERGE_FAIL_FRIENDLY_URL_LAYOUTS =
127                    "merge-fail-friendly-url-layouts";
128    
129            public static void addMergeFailFriendlyURLLayout(Layout layout)
130                    throws PortalException, SystemException {
131    
132                    LayoutSet layoutSet = layout.getLayoutSet();
133    
134                    layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
135                            layoutSet.getGroupId(), layoutSet.isPrivateLayout());
136    
137                    UnicodeProperties settingsProperties =
138                            layoutSet.getSettingsProperties();
139    
140                    String mergeFailFriendlyURLLayouts =
141                            settingsProperties.getProperty(
142                                    MERGE_FAIL_FRIENDLY_URL_LAYOUTS, StringPool.BLANK);
143    
144                    mergeFailFriendlyURLLayouts = StringUtil.add(
145                            mergeFailFriendlyURLLayouts, layout.getUuid());
146    
147                    settingsProperties.setProperty(
148                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS, mergeFailFriendlyURLLayouts);
149    
150                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
151            }
152    
153            public static void addPortletBreadcrumbEntries(
154                            Group group, String pagesName, PortletURL redirectURL,
155                            HttpServletRequest request, RenderResponse renderResponse)
156                    throws Exception {
157    
158                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
159                            com.liferay.portal.kernel.util.WebKeys.THEME_DISPLAY);
160    
161                    PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();
162    
163                    String portletName = portletDisplay.getPortletName();
164    
165                    if ((renderResponse == null) ||
166                            portletName.equals(PortletKeys.GROUP_PAGES) ||
167                            portletName.equals(PortletKeys.MY_PAGES)) {
168    
169                            return;
170                    }
171    
172                    Locale locale = themeDisplay.getLocale();
173    
174                    if (group.isLayoutPrototype()) {
175                            PortalUtil.addPortletBreadcrumbEntry(
176                                    request, LanguageUtil.get(locale, "page-template"), null);
177    
178                            PortalUtil.addPortletBreadcrumbEntry(
179                                    request, group.getDescriptiveName(), redirectURL.toString());
180                    }
181                    else {
182                            PortalUtil.addPortletBreadcrumbEntry(
183                                    request, group.getDescriptiveName(), null);
184                    }
185    
186                    if (!group.isLayoutPrototype()) {
187                            PortalUtil.addPortletBreadcrumbEntry(
188                                    request, LanguageUtil.get(locale, pagesName),
189                                    redirectURL.toString());
190                    }
191            }
192    
193            public static void applyLayoutPrototype(
194                            LayoutPrototype layoutPrototype, Layout targetLayout,
195                            boolean linkEnabled)
196                    throws Exception {
197    
198                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
199    
200                    ServiceContext serviceContext =
201                            ServiceContextThreadLocal.getServiceContext();
202    
203                    serviceContext.setAttribute("layoutPrototypeLinkEnabled", linkEnabled);
204                    serviceContext.setAttribute(
205                            "layoutPrototypeUuid", layoutPrototype.getUuid());
206    
207                    targetLayout = LayoutLocalServiceUtil.updateLayout(
208                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
209                            targetLayout.getLayoutId(), targetLayout.getParentLayoutId(),
210                            targetLayout.getNameMap(), targetLayout.getTitleMap(),
211                            targetLayout.getDescriptionMap(), targetLayout.getKeywordsMap(),
212                            targetLayout.getRobotsMap(), layoutPrototypeLayout.getType(),
213                            targetLayout.getHidden(), targetLayout.getFriendlyURL(),
214                            targetLayout.getIconImage(), null, serviceContext);
215    
216                    targetLayout = LayoutLocalServiceUtil.updateLayout(
217                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
218                            targetLayout.getLayoutId(),
219                            layoutPrototypeLayout.getTypeSettings());
220    
221                    copyPortletPermissions(targetLayout, layoutPrototypeLayout);
222    
223                    copyPortletSetups(layoutPrototypeLayout, targetLayout);
224    
225                    copyLookAndFeel(targetLayout, layoutPrototypeLayout);
226    
227                    targetLayout = LayoutLocalServiceUtil.getLayout(targetLayout.getPlid());
228    
229                    UnicodeProperties typeSettingsProperties =
230                            targetLayout.getTypeSettingsProperties();
231    
232                    typeSettingsProperties.setProperty(
233                            LAST_MERGE_TIME,
234                            String.valueOf(targetLayout.getModifiedDate().getTime()));
235    
236                    LayoutLocalServiceUtil.updateLayout(targetLayout, false);
237    
238                    UnicodeProperties prototypeTypeSettingsProperties =
239                            layoutPrototypeLayout.getTypeSettingsProperties();
240    
241                    prototypeTypeSettingsProperties.setProperty(MERGE_FAIL_COUNT, "0");
242    
243                    LayoutLocalServiceUtil.updateLayout(layoutPrototypeLayout, false);
244            }
245    
246            public static void copyLayout(
247                            long userId, Layout sourceLayout, Layout targetLayout,
248                            ServiceContext serviceContext)
249                    throws Exception {
250    
251                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
252                            serviceContext);
253    
254                    parameterMap.put(
255                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
256                            new String[] {Boolean.FALSE.toString()});
257    
258                    File file = LayoutLocalServiceUtil.exportLayoutsAsFile(
259                            sourceLayout.getGroupId(), sourceLayout.isPrivateLayout(),
260                            new long[] {sourceLayout.getLayoutId()}, parameterMap, null, null);
261    
262                    try {
263                            LayoutLocalServiceUtil.importLayouts(
264                                    userId, targetLayout.getGroupId(),
265                                    targetLayout.isPrivateLayout(), parameterMap, file);
266                    }
267                    finally {
268                            file.delete();
269                    }
270            }
271    
272            public static void copyLookAndFeel(Layout targetLayout, Layout sourceLayout)
273                    throws Exception {
274    
275                    LayoutLocalServiceUtil.updateLookAndFeel(
276                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
277                            targetLayout.getLayoutId(), sourceLayout.getThemeId(),
278                            sourceLayout.getColorSchemeId(), sourceLayout.getCss(), false);
279    
280                    LayoutLocalServiceUtil.updateLookAndFeel(
281                            targetLayout.getGroupId(), targetLayout.isPrivateLayout(),
282                            targetLayout.getLayoutId(), sourceLayout.getWapThemeId(),
283                            sourceLayout.getWapColorSchemeId(), sourceLayout.getCss(), true);
284            }
285    
286            public static void copyPortletPermissions(
287                            Layout targetLayout, Layout sourceLayout)
288                    throws Exception {
289    
290                    long companyId = targetLayout.getCompanyId();
291    
292                    List<Role> roles = RoleLocalServiceUtil.getRoles(companyId);
293    
294                    LayoutTypePortlet sourceLayoutTypePortlet =
295                            (LayoutTypePortlet)sourceLayout.getLayoutType();
296    
297                    List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
298    
299                    for (String sourcePortletId : sourcePortletIds) {
300                            String resourceName = PortletConstants.getRootPortletId(
301                                    sourcePortletId);
302    
303                            String sourceResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
304                                    sourceLayout.getPlid(), sourcePortletId);
305    
306                            String targetResourcePrimKey = PortletPermissionUtil.getPrimaryKey(
307                                    targetLayout.getPlid(), sourcePortletId);
308    
309                            List<String> actionIds =
310                                    ResourceActionsUtil.getPortletResourceActions(resourceName);
311    
312                            for (Role role : roles) {
313                                    String roleName = role.getName();
314    
315                                    if (roleName.equals(RoleConstants.ADMINISTRATOR) ||
316                                            (targetLayout.isPrivateLayout() &&
317                                             roleName.equals(RoleConstants.GUEST))) {
318    
319                                            continue;
320                                    }
321    
322                                    List<String> actions =
323                                            ResourcePermissionLocalServiceUtil.
324                                                    getAvailableResourcePermissionActionIds(
325                                                            companyId, resourceName,
326                                                            ResourceConstants.SCOPE_INDIVIDUAL,
327                                                            sourceResourcePrimKey, role.getRoleId(), actionIds);
328    
329                                    ResourcePermissionLocalServiceUtil.setResourcePermissions(
330                                            companyId, resourceName, ResourceConstants.SCOPE_INDIVIDUAL,
331                                            targetResourcePrimKey, role.getRoleId(),
332                                            actions.toArray(new String[actions.size()]));
333                            }
334                    }
335            }
336    
337            public static void copyPortletSetups(
338                            Layout sourceLayout, Layout targetLayout)
339                    throws Exception {
340    
341                    LayoutTypePortlet sourceLayoutTypePortlet =
342                            (LayoutTypePortlet)sourceLayout.getLayoutType();
343    
344                    List<String> sourcePortletIds = sourceLayoutTypePortlet.getPortletIds();
345    
346                    for (String sourcePortletId : sourcePortletIds) {
347                            PortletPreferences sourcePreferences =
348                                    PortletPreferencesFactoryUtil.getPortletSetup(
349                                            sourceLayout, sourcePortletId, null);
350    
351                            PortletPreferencesImpl sourcePreferencesImpl =
352                                    (PortletPreferencesImpl)sourcePreferences;
353    
354                            PortletPreferences targetPreferences =
355                                    PortletPreferencesFactoryUtil.getPortletSetup(
356                                            targetLayout, sourcePortletId, null);
357    
358                            PortletPreferencesImpl targetPreferencesImpl =
359                                    (PortletPreferencesImpl)targetPreferences;
360    
361                            PortletPreferencesLocalServiceUtil.updatePreferences(
362                                    targetPreferencesImpl.getOwnerId(),
363                                    targetPreferencesImpl.getOwnerType(),
364                                    targetPreferencesImpl.getPlid(), sourcePortletId,
365                                    sourcePreferences);
366    
367                            if ((sourcePreferencesImpl.getOwnerId() !=
368                                            PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
369                                    (sourcePreferencesImpl.getOwnerType() !=
370                                            PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) {
371    
372                                    sourcePreferences =
373                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
374                                                    sourceLayout, sourcePortletId);
375    
376                                    sourcePreferencesImpl =
377                                            (PortletPreferencesImpl)sourcePreferences;
378    
379                                    targetPreferences =
380                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
381                                                    targetLayout, sourcePortletId);
382    
383                                    targetPreferencesImpl =
384                                            (PortletPreferencesImpl)targetPreferences;
385    
386                                    PortletPreferencesLocalServiceUtil.updatePreferences(
387                                            targetPreferencesImpl.getOwnerId(),
388                                            targetPreferencesImpl.getOwnerType(),
389                                            targetPreferencesImpl.getPlid(), sourcePortletId,
390                                            sourcePreferences);
391                            }
392    
393                            ServiceContext serviceContext =
394                                    ServiceContextThreadLocal.getServiceContext();
395    
396                            updateLayoutScopes(
397                                    serviceContext.getUserId(), sourceLayout, targetLayout,
398                                    sourcePreferences, targetPreferences, sourcePortletId,
399                                    serviceContext.getLanguageId());
400                    }
401            }
402    
403            public static void copyTypeSettings(Group sourceGroup, Group targetGroup)
404                    throws Exception {
405    
406                    GroupServiceUtil.updateGroup(
407                            targetGroup.getGroupId(), sourceGroup.getTypeSettings());
408            }
409    
410            public static Object[] deleteLayout(
411                            ActionRequest actionRequest, ActionResponse actionResponse)
412                    throws Exception {
413    
414                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
415                            actionRequest);
416                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
417                            actionResponse);
418    
419                    return deleteLayout(request, response);
420            }
421    
422            public static Object[] deleteLayout(
423                            HttpServletRequest request, HttpServletResponse response)
424                    throws Exception {
425    
426                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
427                            WebKeys.THEME_DISPLAY);
428    
429                    PermissionChecker permissionChecker =
430                            themeDisplay.getPermissionChecker();
431    
432                    long plid = ParamUtil.getLong(request, "plid");
433    
434                    long groupId = ParamUtil.getLong(request, "groupId");
435                    boolean privateLayout = ParamUtil.getBoolean(request, "privateLayout");
436                    long layoutId = ParamUtil.getLong(request, "layoutId");
437    
438                    Layout layout = null;
439    
440                    if (plid <= 0) {
441                            layout = LayoutLocalServiceUtil.getLayout(
442                                    groupId, privateLayout, layoutId);
443                    }
444                    else {
445                            layout = LayoutLocalServiceUtil.getLayout(plid);
446    
447                            groupId = layout.getGroupId();
448                            privateLayout = layout.isPrivateLayout();
449                            layoutId = layout.getLayoutId();
450                    }
451    
452                    Group group = layout.getGroup();
453                    String oldFriendlyURL = layout.getFriendlyURL();
454    
455                    if (group.isStagingGroup() &&
456                            !GroupPermissionUtil.contains(
457                                    permissionChecker, groupId, ActionKeys.MANAGE_STAGING) &&
458                            !GroupPermissionUtil.contains(
459                                    permissionChecker, groupId, ActionKeys.PUBLISH_STAGING)) {
460    
461                            throw new PrincipalException();
462                    }
463    
464                    if (LayoutPermissionUtil.contains(
465                                    permissionChecker, layout, ActionKeys.DELETE)) {
466    
467                            LayoutSettings layoutSettings = LayoutSettings.getInstance(layout);
468    
469                            EventsProcessorUtil.process(
470                                    PropsKeys.LAYOUT_CONFIGURATION_ACTION_DELETE,
471                                    layoutSettings.getConfigurationActionDelete(), request,
472                                    response);
473                    }
474    
475                    LayoutSet layoutSet = layout.getLayoutSet();
476    
477                    if (group.isGuest() && (layoutSet.getPageCount() == 1)) {
478                            throw new RequiredLayoutException(
479                                    RequiredLayoutException.AT_LEAST_ONE);
480                    }
481    
482                    ServiceContext serviceContext = ServiceContextFactory.getInstance(
483                            request);
484    
485                    LayoutServiceUtil.deleteLayout(
486                            groupId, privateLayout, layoutId, serviceContext);
487    
488                    long newPlid = layout.getParentPlid();
489    
490                    if (newPlid <= 0) {
491                            Layout firstLayout = LayoutLocalServiceUtil.fetchFirstLayout(
492                                    layoutSet.getGroupId(), layoutSet.getPrivateLayout(),
493                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
494    
495                            if (firstLayout != null) {
496                                    newPlid = firstLayout.getPlid();
497                            }
498                    }
499    
500                    return new Object[] {group, oldFriendlyURL, newPlid};
501            }
502    
503            public static void deleteLayout(
504                            RenderRequest renderRequest, RenderResponse renderResponse)
505                    throws Exception {
506    
507                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
508                            renderRequest);
509                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
510                            renderResponse);
511    
512                    deleteLayout(request, response);
513            }
514    
515            public static File exportLayoutSetPrototype(
516                            LayoutSetPrototype layoutSetPrototype,
517                            ServiceContext serviceContext)
518                    throws PortalException, SystemException {
519    
520                    LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
521    
522                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
523                            serviceContext);
524    
525                    return LayoutLocalServiceUtil.exportLayoutsAsFile(
526                            layoutSet.getGroupId(), layoutSet.isPrivateLayout(), null,
527                            parameterMap, null, null);
528            }
529    
530            public static Layout getLayoutSetPrototypeLayout(Layout layout) {
531                    try {
532                            LayoutSet layoutSet = layout.getLayoutSet();
533    
534                            if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
535                                    return null;
536                            }
537    
538                            LayoutSetPrototype layoutSetPrototype =
539                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
540                                            layoutSet.getLayoutSetPrototypeUuid());
541    
542                            Group group = layoutSetPrototype.getGroup();
543    
544                            return LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
545                                    layout.getSourcePrototypeLayoutUuid(), group.getGroupId(),
546                                    true);
547                    }
548                    catch (Exception e) {
549                            _log.error(
550                                    "Unable to fetch the the layout set prototype's layout", e);
551                    }
552    
553                    return null;
554            }
555    
556            public static Map<String, String[]> getLayoutSetPrototypeParameters(
557                    ServiceContext serviceContext) {
558    
559                    Map<String, String[]> parameterMap =
560                            new LinkedHashMap<String, String[]>();
561    
562                    parameterMap.put(
563                            PortletDataHandlerKeys.CATEGORIES,
564                            new String[] {Boolean.TRUE.toString()});
565                    parameterMap.put(
566                            PortletDataHandlerKeys.DATA_STRATEGY,
567                            new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
568                    parameterMap.put(
569                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
570                            new String[] {Boolean.TRUE.toString()});
571                    parameterMap.put(
572                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
573                            new String[] {Boolean.FALSE.toString()});
574                    parameterMap.put(
575                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
576                            new String[] {Boolean.TRUE.toString()});
577                    parameterMap.put(
578                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
579                            new String[] {Boolean.TRUE.toString()});
580                    parameterMap.put(
581                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
582                            new String[] {
583                                    PortletDataHandlerKeys.
584                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
585                            });
586                    parameterMap.put(
587                            PortletDataHandlerKeys.LOGO,
588                            new String[] {Boolean.TRUE.toString()});
589                    parameterMap.put(
590                            PortletDataHandlerKeys.PERFORM_DIRECT_BINARY_IMPORT,
591                            new String[] {Boolean.TRUE.toString()});
592                    parameterMap.put(
593                            PortletDataHandlerKeys.PERMISSIONS,
594                            new String[] {Boolean.TRUE.toString()});
595                    parameterMap.put(
596                            PortletDataHandlerKeys.PORTLET_DATA,
597                            new String[] {Boolean.TRUE.toString()});
598                    parameterMap.put(
599                            PortletDataHandlerKeys.PORTLET_DATA_ALL,
600                            new String[] {Boolean.TRUE.toString()});
601                    parameterMap.put(
602                            PortletDataHandlerKeys.PORTLET_SETUP,
603                            new String[] {Boolean.TRUE.toString()});
604                    parameterMap.put(
605                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES,
606                            new String[] {Boolean.TRUE.toString()});
607                    parameterMap.put(
608                            PortletDataHandlerKeys.THEME,
609                            new String[] {Boolean.FALSE.toString()});
610                    parameterMap.put(
611                            PortletDataHandlerKeys.THEME_REFERENCE,
612                            new String[] {Boolean.TRUE.toString()});
613                    parameterMap.put(
614                            PortletDataHandlerKeys.USER_ID_STRATEGY,
615                            new String[] {UserIdStrategy.CURRENT_USER_ID});
616                    parameterMap.put(
617                            PortletDataHandlerKeys.USER_PERMISSIONS,
618                            new String[] {Boolean.FALSE.toString()});
619    
620                    return parameterMap;
621            }
622    
623            public static List<Layout> getMergeFailFriendlyURLLayouts(
624                            LayoutSet layoutSet)
625                    throws PortalException, SystemException {
626    
627                    if (layoutSet == null) {
628                            return Collections.emptyList();
629                    }
630    
631                    UnicodeProperties settingsProperties =
632                            layoutSet.getSettingsProperties();
633    
634                    String uuids = settingsProperties.getProperty(
635                            MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
636    
637                    if (Validator.isNotNull(uuids)) {
638                            List<Layout> layouts = new ArrayList<Layout>();
639    
640                            for (String uuid : StringUtil.split(uuids)) {
641                                    Layout layout =
642                                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
643                                                    uuid, layoutSet.getGroupId(),
644                                                    layoutSet.isPrivateLayout());
645    
646                                    layouts.add(layout);
647                            }
648    
649                            return layouts;
650                    }
651    
652                    return Collections.emptyList();
653            }
654    
655            public static void importLayoutSetPrototype(
656                            LayoutSetPrototype layoutSetPrototype, InputStream inputStream,
657                            ServiceContext serviceContext)
658                    throws PortalException, SystemException {
659    
660                    LayoutSet layoutSet = layoutSetPrototype.getLayoutSet();
661    
662                    Map<String, String[]> parameterMap = getLayoutSetPrototypeParameters(
663                            serviceContext);
664    
665                    setLayoutSetPrototypeLinkEnabledParameter(
666                            parameterMap, layoutSet, serviceContext);
667    
668                    LayoutServiceUtil.importLayouts(
669                            layoutSet.getGroupId(), layoutSet.isPrivateLayout(), parameterMap,
670                            inputStream);
671            }
672    
673            public static boolean isLayoutDeleteable(Layout layout) {
674                    try {
675                            if (layout instanceof VirtualLayout) {
676                                    return false;
677                            }
678    
679                            if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
680                                    return true;
681                            }
682    
683                            LayoutSet layoutSet = layout.getLayoutSet();
684    
685                            if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
686                                    return true;
687                            }
688    
689                            if (LayoutLocalServiceUtil.hasLayoutSetPrototypeLayout(
690                                            layoutSet.getLayoutSetPrototypeUuid(),
691                                            layout.getSourcePrototypeLayoutUuid())) {
692    
693                                    return false;
694                            }
695                    }
696                    catch (Exception e) {
697                            if (_log.isDebugEnabled()) {
698                                    _log.debug(e, e);
699                            }
700                    }
701    
702                    return true;
703            }
704    
705            public static boolean isLayoutModifiedSinceLastMerge(Layout layout) {
706                    if ((layout == null) ||
707                            Validator.isNull(layout.getSourcePrototypeLayoutUuid()) ||
708                            layout.isLayoutPrototypeLinkActive() ||
709                            !isLayoutUpdateable(layout)) {
710    
711                            return false;
712                    }
713    
714                    long lastMergeTime = GetterUtil.getLong(
715                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
716    
717                    Date existingLayoutModifiedDate = layout.getModifiedDate();
718    
719                    if ((existingLayoutModifiedDate != null) &&
720                            (existingLayoutModifiedDate.getTime() > lastMergeTime)) {
721    
722                            return true;
723                    }
724    
725                    return false;
726            }
727    
728            public static boolean isLayoutSetMergeable(Group group, LayoutSet layoutSet)
729                    throws PortalException, SystemException {
730    
731                    if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
732                            group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
733    
734                            return false;
735                    }
736    
737                    UnicodeProperties settingsProperties =
738                            layoutSet.getSettingsProperties();
739    
740                    long lastMergeTime = GetterUtil.getLong(
741                            settingsProperties.getProperty(LAST_MERGE_TIME));
742    
743                    LayoutSetPrototype layoutSetPrototype =
744                            LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
745                                    layoutSet.getLayoutSetPrototypeUuid());
746    
747                    Date modifiedDate = layoutSetPrototype.getModifiedDate();
748    
749                    if (lastMergeTime >= modifiedDate.getTime()) {
750                            return false;
751                    }
752    
753                    LayoutSet layoutSetPrototypeLayoutSet =
754                            layoutSetPrototype.getLayoutSet();
755    
756                    UnicodeProperties layoutSetPrototypeSettingsProperties =
757                            layoutSetPrototypeLayoutSet.getSettingsProperties();
758    
759                    int mergeFailCount = GetterUtil.getInteger(
760                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
761    
762                    if (mergeFailCount >
763                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
764    
765                            if (_log.isWarnEnabled()) {
766                                    StringBundler sb = new StringBundler(6);
767    
768                                    sb.append("Merge not performed because the fail threshold ");
769                                    sb.append("was reached for layoutSetPrototypeId ");
770                                    sb.append(layoutSetPrototype.getLayoutSetPrototypeId());
771                                    sb.append(" and layoutId ");
772                                    sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId());
773                                    sb.append(". Update the count in the database to try again.");
774    
775                                    _log.warn(sb.toString());
776                            }
777    
778                            return false;
779                    }
780    
781                    return true;
782            }
783    
784            public static boolean isLayoutSetPrototypeUpdateable(LayoutSet layoutSet) {
785                    if (!layoutSet.isLayoutSetPrototypeLinkActive()) {
786                            return true;
787                    }
788    
789                    try {
790                            LayoutSetPrototype layoutSetPrototype =
791                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
792                                            layoutSet.getLayoutSetPrototypeUuid());
793    
794                            String layoutsUpdateable = layoutSetPrototype.getSettingsProperty(
795                                    "layoutsUpdateable");
796    
797                            if (Validator.isNotNull(layoutsUpdateable)) {
798                                    return GetterUtil.getBoolean(layoutsUpdateable, true);
799                            }
800                    }
801                    catch (Exception e) {
802                            if (_log.isDebugEnabled()) {
803                                    _log.debug(e, e);
804                            }
805                    }
806    
807                    return true;
808            }
809    
810            public static boolean isLayoutSortable(Layout layout) {
811                    return isLayoutDeleteable(layout);
812            }
813    
814            public static boolean isLayoutUpdateable(Layout layout) {
815                    try {
816                            if (layout instanceof VirtualLayout) {
817                                    return false;
818                            }
819    
820                            if (Validator.isNull(layout.getLayoutPrototypeUuid()) &&
821                                    Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
822    
823                                    return true;
824                            }
825    
826                            LayoutSet layoutSet = layout.getLayoutSet();
827    
828                            if (layoutSet.isLayoutSetPrototypeLinkActive()) {
829                                    boolean layoutSetPrototypeUpdateable =
830                                            isLayoutSetPrototypeUpdateable(layoutSet);
831    
832                                    if (!layoutSetPrototypeUpdateable) {
833                                            return false;
834                                    }
835    
836                                    Layout layoutSetPrototypeLayout = getLayoutSetPrototypeLayout(
837                                            layout);
838    
839                                    String layoutUpdateable =
840                                            layoutSetPrototypeLayout.getTypeSettingsProperty(
841                                                    LAYOUT_UPDATEABLE);
842    
843                                    if (Validator.isNull(layoutUpdateable)) {
844                                            return true;
845                                    }
846    
847                                    return GetterUtil.getBoolean(layoutUpdateable);
848                            }
849                    }
850                    catch (Exception e) {
851                            if (_log.isDebugEnabled()) {
852                                    _log.debug(e, e);
853                            }
854                    }
855    
856                    return true;
857            }
858    
859            public static boolean isUserGroupLayoutSetViewable(
860                            PermissionChecker permissionChecker, Group userGroupGroup)
861                    throws PortalException, SystemException {
862    
863                    if (!userGroupGroup.isUserGroup()) {
864                            return false;
865                    }
866    
867                    if (GroupPermissionUtil.contains(
868                                    permissionChecker, userGroupGroup.getGroupId(),
869                                    ActionKeys.VIEW)) {
870    
871                            return true;
872                    }
873    
874                    UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
875                            userGroupGroup.getClassPK());
876    
877                    if (UserLocalServiceUtil.hasUserGroupUser(
878                                    userGroup.getUserGroupId(), permissionChecker.getUserId())) {
879    
880                            return true;
881                    }
882                    else {
883                            return false;
884                    }
885            }
886    
887            public static void mergeLayoutPrototypeLayout(Group group, Layout layout)
888                    throws Exception {
889    
890                    String sourcePrototypeLayoutUuid =
891                            layout.getSourcePrototypeLayoutUuid();
892    
893                    if (Validator.isNull(sourcePrototypeLayoutUuid)) {
894                            doMergeLayoutPrototypeLayout(group, layout);
895    
896                            return;
897                    }
898    
899                    LayoutSet layoutSet = layout.getLayoutSet();
900    
901                    long layoutSetPrototypeId = layoutSet.getLayoutSetPrototypeId();
902    
903                    if (layoutSetPrototypeId > 0) {
904                            Group layoutSetPrototypeGroup =
905                                    GroupLocalServiceUtil.getLayoutSetPrototypeGroup(
906                                            layout.getCompanyId(), layoutSetPrototypeId);
907    
908                            Layout sourcePrototypeLayout =
909                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
910                                            sourcePrototypeLayoutUuid,
911                                            layoutSetPrototypeGroup.getGroupId(), true);
912    
913                            doMergeLayoutPrototypeLayout(
914                                    layoutSetPrototypeGroup, sourcePrototypeLayout);
915                    }
916    
917                    doMergeLayoutPrototypeLayout(group, layout);
918            }
919    
920            /**
921             * @deprecated {@link #mergeLayoutPrototypeLayout(Group, Layout)}
922             */
923            public static void mergeLayoutProtypeLayout(Group group, Layout layout)
924                    throws Exception {
925    
926                    mergeLayoutPrototypeLayout(group, layout);
927            }
928    
929            public static void mergeLayoutSetPrototypeLayouts(
930                            Group group, LayoutSet layoutSet)
931                    throws Exception {
932    
933                    if (!layoutSet.isLayoutSetPrototypeLinkActive() ||
934                            group.isLayoutPrototype() || group.isLayoutSetPrototype()) {
935    
936                            return;
937                    }
938    
939                    UnicodeProperties settingsProperties =
940                            layoutSet.getSettingsProperties();
941    
942                    long lastMergeTime = GetterUtil.getLong(
943                            settingsProperties.getProperty(LAST_MERGE_TIME));
944    
945                    LayoutSetPrototype layoutSetPrototype =
946                            LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
947                                    layoutSet.getLayoutSetPrototypeUuid());
948    
949                    Date modifiedDate = layoutSetPrototype.getModifiedDate();
950    
951                    if (lastMergeTime >= modifiedDate.getTime()) {
952                            return;
953                    }
954    
955                    LayoutSet layoutSetPrototypeLayoutSet =
956                            layoutSetPrototype.getLayoutSet();
957    
958                    UnicodeProperties layoutSetPrototypeSettingsProperties =
959                            layoutSetPrototypeLayoutSet.getSettingsProperties();
960    
961                    int mergeFailCount = GetterUtil.getInteger(
962                            layoutSetPrototypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
963    
964                    if (mergeFailCount >
965                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
966    
967                            if (_log.isWarnEnabled()) {
968                                    StringBundler sb = new StringBundler(6);
969    
970                                    sb.append("Merge not performed because the fail threshold ");
971                                    sb.append("was reached for layoutSetPrototypeId ");
972                                    sb.append(layoutSetPrototype.getLayoutSetPrototypeId());
973                                    sb.append(" and layoutId ");
974                                    sb.append(layoutSetPrototypeLayoutSet.getLayoutSetId());
975                                    sb.append(". Update the count in the database to try again.");
976    
977                                    _log.warn(sb.toString());
978                            }
979    
980                            return;
981                    }
982    
983                    String owner = PortalUUIDUtil.generate();
984    
985                    try {
986                            Lock lock = LockLocalServiceUtil.lock(
987                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
988                                    String.valueOf(layoutSet.getLayoutSetId()), owner, false);
989    
990                            // Double deep check
991    
992                            if (!owner.equals(lock.getOwner())) {
993                                    Date createDate = lock.getCreateDate();
994    
995                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
996                                                    PropsValues.LAYOUT_SET_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
997    
998                                            // Acquire lock if the lock is older than the lock max time
999    
1000                                            lock = LockLocalServiceUtil.lock(
1001                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1002                                                    String.valueOf(layoutSet.getLayoutSetId()),
1003                                                    lock.getOwner(), owner, false);
1004    
1005                                            // Check if acquiring the lock succeeded or if another
1006                                            // process has the lock
1007    
1008                                            if (!owner.equals(lock.getOwner())) {
1009                                                    return;
1010                                            }
1011                                    }
1012                                    else {
1013                                            return;
1014                                    }
1015                            }
1016                    }
1017                    catch (Exception e) {
1018                            return;
1019                    }
1020    
1021                    try {
1022                            boolean importData = true;
1023    
1024                            long lastResetTime = GetterUtil.getLong(
1025                                    settingsProperties.getProperty(LAST_RESET_TIME));
1026    
1027                            if ((lastMergeTime > 0) || (lastResetTime > 0)) {
1028                                    importData = false;
1029                            }
1030    
1031                            Map<String, String[]> parameterMap =
1032                                    getLayoutSetPrototypesParameters(importData);
1033    
1034                            removeMergeFailFriendlyURLLayouts(layoutSet);
1035    
1036                            importLayoutSetPrototype(
1037                                    layoutSetPrototype, layoutSet.getGroupId(),
1038                                    layoutSet.isPrivateLayout(), parameterMap, importData);
1039                    }
1040                    catch (Exception e) {
1041                            _log.error(e, e);
1042    
1043                            layoutSetPrototypeSettingsProperties.setProperty(
1044                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1045    
1046                            // Invoke updateImpl so that we do not trigger the listeners
1047    
1048                            LayoutSetUtil.updateImpl(layoutSetPrototypeLayoutSet, false);
1049                    }
1050                    finally {
1051                            LockLocalServiceUtil.unlock(
1052                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1053                                    String.valueOf(layoutSet.getLayoutSetId()), owner, false);
1054                    }
1055            }
1056    
1057            /**
1058             * @deprecated {@link #mergeLayoutSetPrototypeLayouts(Group, LayoutSet)}
1059             */
1060            public static void mergeLayoutSetProtypeLayouts(
1061                            Group group, LayoutSet layoutSet)
1062                    throws Exception {
1063    
1064                    mergeLayoutSetPrototypeLayouts(group, layoutSet);
1065            }
1066    
1067            public static void removeMergeFailFriendlyURLLayouts(LayoutSet layoutSet)
1068                    throws PortalException, SystemException {
1069    
1070                    UnicodeProperties settingsProperties =
1071                            layoutSet.getSettingsProperties();
1072    
1073                    settingsProperties.remove(MERGE_FAIL_FRIENDLY_URL_LAYOUTS);
1074    
1075                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
1076            }
1077    
1078            public static void resetPrototype(Layout layout)
1079                    throws PortalException, SystemException {
1080    
1081                    layout.setModifiedDate(null);
1082    
1083                    LayoutLocalServiceUtil.updateLayout(layout, false);
1084    
1085                    LayoutSet layoutSet = layout.getLayoutSet();
1086                    UnicodeProperties settingsProperties =
1087                            layoutSet.getSettingsProperties();
1088    
1089                    settingsProperties.remove(LAST_MERGE_TIME);
1090    
1091                    settingsProperties.setProperty(
1092                            LAST_RESET_TIME, String.valueOf(System.currentTimeMillis()));
1093    
1094                    LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet, false);
1095            }
1096    
1097            public static void updateLayoutScopes(
1098                            long userId, Layout sourceLayout, Layout targetLayout,
1099                            PortletPreferences sourcePreferences,
1100                            PortletPreferences targetPreferences, String sourcePortletId,
1101                            String languageId)
1102                    throws Exception {
1103    
1104                    String scopeType = GetterUtil.getString(
1105                            sourcePreferences.getValue("lfrScopeType", null));
1106    
1107                    if (Validator.isNull(scopeType) || !scopeType.equals("layout")) {
1108                            return;
1109                    }
1110    
1111                    Layout targetScopeLayout =
1112                            LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
1113                                    targetLayout.getUuid(), targetLayout.getGroupId(),
1114                                    targetLayout.isPrivateLayout());
1115    
1116                    if (!targetScopeLayout.hasScopeGroup()) {
1117                            GroupLocalServiceUtil.addGroup(
1118                                    userId, Layout.class.getName(), targetLayout.getPlid(),
1119                                    targetLayout.getName(languageId), null, 0, null, false, true,
1120                                    null);
1121                    }
1122    
1123                    String portletTitle = PortalUtil.getPortletTitle(
1124                            sourcePortletId, languageId);
1125    
1126                    String newPortletTitle = PortalUtil.getNewPortletTitle(
1127                            portletTitle, String.valueOf(sourceLayout.getLayoutId()),
1128                            targetLayout.getName(languageId));
1129    
1130                    targetPreferences.setValue(
1131                            "groupId", String.valueOf(targetLayout.getGroupId()));
1132                    targetPreferences.setValue("lfrScopeType", "layout");
1133                    targetPreferences.setValue(
1134                            "lfrScopeLayoutUuid", targetLayout.getUuid());
1135                    targetPreferences.setValue(
1136                            "portletSetupTitle_" + languageId, newPortletTitle);
1137                    targetPreferences.setValue(
1138                            "portletSetupUseCustomTitle", Boolean.TRUE.toString());
1139    
1140                    targetPreferences.store();
1141            }
1142    
1143            public static void updateLayoutSetPrototypesLinks(
1144                            Group group, long publicLayoutSetPrototypeId,
1145                            long privateLayoutSetPrototypeId,
1146                            boolean publicLayoutSetPrototypeLinkEnabled,
1147                            boolean privateLayoutSetPrototypeLinkEnabled)
1148                    throws Exception {
1149    
1150                    updateLayoutSetPrototypeLink(
1151                            group.getGroupId(), true, privateLayoutSetPrototypeId,
1152                            privateLayoutSetPrototypeLinkEnabled);
1153                    updateLayoutSetPrototypeLink(
1154                            group.getGroupId(), false, publicLayoutSetPrototypeId,
1155                            publicLayoutSetPrototypeLinkEnabled);
1156            }
1157    
1158            protected static void doMergeLayoutPrototypeLayout(
1159                            Group group, Layout layout)
1160                    throws Exception {
1161    
1162                    if (!layout.isLayoutPrototypeLinkActive() ||
1163                            group.isLayoutPrototype() || group.hasStagingGroup()) {
1164    
1165                            return;
1166                    }
1167    
1168                    long lastMergeTime = GetterUtil.getLong(
1169                            layout.getTypeSettingsProperty(LAST_MERGE_TIME));
1170    
1171                    LayoutPrototype layoutPrototype =
1172                            LayoutPrototypeLocalServiceUtil.getLayoutPrototypeByUuid(
1173                                    layout.getLayoutPrototypeUuid());
1174    
1175                    Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1176    
1177                    Date modifiedDate = layoutPrototypeLayout.getModifiedDate();
1178    
1179                    if (lastMergeTime >= modifiedDate.getTime()) {
1180                            return;
1181                    }
1182    
1183                    UnicodeProperties prototypeTypeSettingsProperties =
1184                            layoutPrototypeLayout.getTypeSettingsProperties();
1185    
1186                    int mergeFailCount = GetterUtil.getInteger(
1187                            prototypeTypeSettingsProperties.getProperty(MERGE_FAIL_COUNT));
1188    
1189                    if (mergeFailCount >
1190                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_FAIL_THRESHOLD) {
1191    
1192                            if (_log.isWarnEnabled()) {
1193                                    StringBundler sb = new StringBundler(6);
1194    
1195                                    sb.append("Merge not performed because the fail threshold ");
1196                                    sb.append("was reached for layoutPrototypeId ");
1197                                    sb.append(layoutPrototype.getLayoutPrototypeId());
1198                                    sb.append(" and layoutId ");
1199                                    sb.append(layoutPrototypeLayout.getLayoutId());
1200                                    sb.append(". Update the count in the database to try again.");
1201    
1202                                    _log.warn(sb.toString());
1203                            }
1204    
1205                            return;
1206                    }
1207    
1208                    String owner = PortalUUIDUtil.generate();
1209    
1210                    try {
1211                            Lock lock = LockLocalServiceUtil.lock(
1212                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1213                                    String.valueOf(layout.getPlid()), owner, false);
1214    
1215                            if (!owner.equals(lock.getOwner())) {
1216                                    Date createDate = lock.getCreateDate();
1217    
1218                                    if ((System.currentTimeMillis() - createDate.getTime()) >=
1219                                                    PropsValues.LAYOUT_PROTOTYPE_MERGE_LOCK_MAX_TIME) {
1220    
1221                                            // Acquire lock if the lock is older than the lock max time
1222    
1223                                            lock = LockLocalServiceUtil.lock(
1224                                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1225                                                    String.valueOf(layout.getPlid()), lock.getOwner(),
1226                                                    owner, false);
1227    
1228                                            // Check if acquiring the lock succeeded or if another
1229                                            // process has the lock
1230    
1231                                            if (!owner.equals(lock.getOwner())) {
1232                                                    return;
1233                                            }
1234                                    }
1235                                    else {
1236                                            return;
1237                                    }
1238                            }
1239                    }
1240                    catch (Exception e) {
1241                            return;
1242                    }
1243    
1244                    try {
1245                            SitesUtil.applyLayoutPrototype(layoutPrototype, layout, true);
1246                    }
1247                    catch (Exception e) {
1248                            _log.error(e, e);
1249    
1250                            prototypeTypeSettingsProperties.setProperty(
1251                                    MERGE_FAIL_COUNT, String.valueOf(++mergeFailCount));
1252    
1253                            // Invoke updateImpl so that we do not trigger the listeners
1254    
1255                            LayoutUtil.updateImpl(layoutPrototypeLayout, false);
1256                    }
1257                    finally {
1258                            LockLocalServiceUtil.unlock(
1259                                    LayoutLocalServiceVirtualLayoutsAdvice.class.getName(),
1260                                    String.valueOf(layout.getPlid()), owner, false);
1261                    }
1262            }
1263    
1264            protected static Map<String, String[]> getLayoutSetPrototypesParameters(
1265                    boolean importData) {
1266    
1267                    Map<String, String[]> parameterMap =
1268                            new LinkedHashMap<String, String[]>();
1269    
1270                    parameterMap.put(
1271                            PortletDataHandlerKeys.CATEGORIES,
1272                            new String[] {Boolean.TRUE.toString()});
1273                    parameterMap.put(
1274                            PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
1275                            new String[] {Boolean.FALSE.toString()});
1276                    parameterMap.put(
1277                            PortletDataHandlerKeys.DELETE_PORTLET_DATA,
1278                            new String[] {Boolean.FALSE.toString()});
1279                    parameterMap.put(
1280                            PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE,
1281                            new String[] {Boolean.TRUE.toString()});
1282                    parameterMap.put(
1283                            PortletDataHandlerKeys.LAYOUT_SET_SETTINGS,
1284                            new String[] {Boolean.TRUE.toString()});
1285                    parameterMap.put(
1286                            PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1287                            new String[] {Boolean.TRUE.toString()});
1288                    parameterMap.put(
1289                            PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
1290                            new String[] {
1291                                    PortletDataHandlerKeys.
1292                                            LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE
1293                            });
1294                    parameterMap.put(
1295                            PortletDataHandlerKeys.LOGO,
1296                            new String[] {Boolean.TRUE.toString()});
1297                    parameterMap.put(
1298                            PortletDataHandlerKeys.PERMISSIONS,
1299                            new String[] {Boolean.TRUE.toString()});
1300                    parameterMap.put(
1301                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS,
1302                            new String[] {Boolean.TRUE.toString()});
1303                    parameterMap.put(
1304                            PortletDataHandlerKeys.PORTLET_SETUP,
1305                            new String[] {Boolean.TRUE.toString()});
1306                    parameterMap.put(
1307                            PortletDataHandlerKeys.PORTLET_SETUP_ALL,
1308                            new String[] {Boolean.TRUE.toString()});
1309                    parameterMap.put(
1310                            PortletDataHandlerKeys.THEME,
1311                            new String[] {Boolean.FALSE.toString()});
1312                    parameterMap.put(
1313                            PortletDataHandlerKeys.THEME_REFERENCE,
1314                            new String[] {Boolean.TRUE.toString()});
1315                    parameterMap.put(
1316                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE,
1317                            new String[] {Boolean.FALSE.toString()});
1318                    parameterMap.put(
1319                            PortletDataHandlerKeys.USER_ID_STRATEGY,
1320                            new String[] {UserIdStrategy.CURRENT_USER_ID});
1321    
1322                    if (importData) {
1323                            parameterMap.put(
1324                                    PortletDataHandlerKeys.DATA_STRATEGY,
1325                                    new String[] {PortletDataHandlerKeys.DATA_STRATEGY_MIRROR});
1326                            parameterMap.put(
1327                                    PortletDataHandlerKeys.PORTLET_DATA,
1328                                    new String[] {Boolean.TRUE.toString()});
1329                            parameterMap.put(
1330                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1331                                    new String[] {Boolean.TRUE.toString()});
1332                    }
1333                    else {
1334                            parameterMap.put(
1335                                    PortletDataHandlerKeys.PORTLET_DATA,
1336                                    new String[] {Boolean.FALSE.toString()});
1337                            parameterMap.put(
1338                                    PortletDataHandlerKeys.PORTLET_DATA_ALL,
1339                                    new String[] {Boolean.FALSE.toString()});
1340                    }
1341    
1342                    return parameterMap;
1343            }
1344    
1345            protected static void importLayoutSetPrototype(
1346                            LayoutSetPrototype layoutSetPrototype, long groupId,
1347                            boolean privateLayout, Map<String, String[]> parameterMap,
1348                            boolean importData)
1349                    throws PortalException, SystemException {
1350    
1351                    File file = null;
1352    
1353                    StringBundler sb = new StringBundler(importData ? 4 : 3);
1354    
1355                    sb.append(_TEMP_DIR);
1356                    sb.append(layoutSetPrototype.getUuid());
1357    
1358                    if (importData) {
1359                            sb.append("-data");
1360                    }
1361    
1362                    sb.append(".lar");
1363    
1364                    File cacheFile = new File(sb.toString());
1365    
1366                    if (cacheFile.exists()) {
1367                            Date modifiedDate = layoutSetPrototype.getModifiedDate();
1368    
1369                            if (cacheFile.lastModified() >= modifiedDate.getTime()) {
1370                                    if (_log.isDebugEnabled()) {
1371                                            _log.debug(
1372                                                    "Using cached layout set prototype LAR file " +
1373                                                            cacheFile.getAbsolutePath());
1374                                    }
1375    
1376                                    file = cacheFile;
1377                            }
1378                    }
1379    
1380                    boolean newFile = false;
1381    
1382                    if (file == null) {
1383                            Group layoutSetPrototypeGroup = layoutSetPrototype.getGroup();
1384    
1385                            file = LayoutLocalServiceUtil.exportLayoutsAsFile(
1386                                    layoutSetPrototypeGroup.getGroupId(), true, null, parameterMap,
1387                                    null, null);
1388    
1389                            newFile = true;
1390                    }
1391    
1392                    long userId = UserLocalServiceUtil.getDefaultUserId(
1393                            layoutSetPrototype.getCompanyId());
1394    
1395                    LayoutLocalServiceUtil.importLayouts(
1396                            userId, groupId, privateLayout, parameterMap, file);
1397    
1398                    if (newFile) {
1399                            try {
1400                                    FileUtil.copyFile(file, cacheFile);
1401    
1402                                    if (_log.isDebugEnabled()) {
1403                                            _log.debug(
1404                                                    "Copied " + file.getAbsolutePath() + " to " +
1405                                                            cacheFile.getAbsolutePath());
1406                                    }
1407                            }
1408                            catch (Exception e) {
1409                                    _log.error(
1410                                            "Unable to copy file " + file.getAbsolutePath() + " to " +
1411                                                    cacheFile.getAbsolutePath(),
1412                                            e);
1413                            }
1414                    }
1415            }
1416    
1417            protected static void setLayoutSetPrototypeLinkEnabledParameter(
1418                    Map<String, String[]> parameterMap, LayoutSet targetLayoutSet,
1419                    ServiceContext serviceContext) {
1420    
1421                    PermissionChecker permissionChecker =
1422                            PermissionThreadLocal.getPermissionChecker();
1423    
1424                    if ((permissionChecker == null) ||
1425                            !PortalPermissionUtil.contains(
1426                                    permissionChecker, ActionKeys.UNLINK_LAYOUT_SET_PROTOTYPE)) {
1427    
1428                            return;
1429                    }
1430    
1431                    if (targetLayoutSet.isPrivateLayout()) {
1432                            boolean privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1433                                    serviceContext, "privateLayoutSetPrototypeLinkEnabled", true);
1434    
1435                            if (!privateLayoutSetPrototypeLinkEnabled) {
1436                                    privateLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1437                                            serviceContext, "layoutSetPrototypeLinkEnabled");
1438                            }
1439    
1440                            parameterMap.put(
1441                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1442                                    new String[] {
1443                                            String.valueOf(privateLayoutSetPrototypeLinkEnabled)
1444                                    });
1445                    }
1446                    else {
1447                            boolean publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1448                                    serviceContext, "publicLayoutSetPrototypeLinkEnabled");
1449    
1450                            if (!publicLayoutSetPrototypeLinkEnabled) {
1451                                    publicLayoutSetPrototypeLinkEnabled = ParamUtil.getBoolean(
1452                                            serviceContext, "layoutSetPrototypeLinkEnabled", true);
1453                            }
1454    
1455                            parameterMap.put(
1456                                    PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED,
1457                                    new String[] {
1458                                            String.valueOf(publicLayoutSetPrototypeLinkEnabled)
1459                                    });
1460                    }
1461            }
1462    
1463            protected static void updateLayoutSetPrototypeLink(
1464                            long groupId, boolean privateLayout, long layoutSetPrototypeId,
1465                            boolean layoutSetPrototypeLinkEnabled)
1466                    throws Exception {
1467    
1468                    String layoutSetPrototypeUuid = null;
1469    
1470                    if (layoutSetPrototypeId > 0) {
1471                            LayoutSetPrototype layoutSetPrototype =
1472                                    LayoutSetPrototypeLocalServiceUtil.fetchLayoutSetPrototype(
1473                                            layoutSetPrototypeId);
1474    
1475                            if (layoutSetPrototype != null) {
1476                                    layoutSetPrototypeUuid = layoutSetPrototype.getUuid();
1477    
1478                                    // Merge without enabling the link
1479    
1480                                    if (!layoutSetPrototypeLinkEnabled &&
1481                                            (layoutSetPrototypeId > 0)) {
1482    
1483                                            Map<String, String[]> parameterMap =
1484                                                    getLayoutSetPrototypesParameters(true);
1485    
1486                                            importLayoutSetPrototype(
1487                                                    layoutSetPrototype, groupId, privateLayout,
1488                                                    parameterMap, true);
1489                                    }
1490                            }
1491                    }
1492    
1493                    LayoutSetServiceUtil.updateLayoutSetPrototypeLinkEnabled(
1494                            groupId, privateLayout, layoutSetPrototypeLinkEnabled,
1495                            layoutSetPrototypeUuid);
1496    
1497                    LayoutLocalServiceUtil.updatePriorities(groupId, privateLayout);
1498            }
1499    
1500            private static final String _TEMP_DIR =
1501                    SystemProperties.get(SystemProperties.TMP_DIR) +
1502                            "/liferay/layout_set_prototype/";
1503    
1504            private static Log _log = LogFactoryUtil.getLog(SitesUtil.class);
1505    
1506    }