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.portal.lar;
016    
017    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
018    import com.liferay.portal.kernel.language.LanguageUtil;
019    import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
020    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
021    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
022    import com.liferay.portal.kernel.lar.ManifestSummary;
023    import com.liferay.portal.kernel.lar.PortletDataContext;
024    import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
025    import com.liferay.portal.kernel.lar.PortletDataHandler;
026    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
027    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
028    import com.liferay.portal.kernel.lar.PortletDataHandlerStatusMessageSenderUtil;
029    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
030    import com.liferay.portal.kernel.lar.StagedModelType;
031    import com.liferay.portal.kernel.log.Log;
032    import com.liferay.portal.kernel.log.LogFactoryUtil;
033    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
034    import com.liferay.portal.kernel.util.ArrayUtil;
035    import com.liferay.portal.kernel.util.Constants;
036    import com.liferay.portal.kernel.util.FileUtil;
037    import com.liferay.portal.kernel.util.GetterUtil;
038    import com.liferay.portal.kernel.util.LocaleUtil;
039    import com.liferay.portal.kernel.util.MapUtil;
040    import com.liferay.portal.kernel.util.ReleaseInfo;
041    import com.liferay.portal.kernel.util.StringPool;
042    import com.liferay.portal.kernel.util.StringUtil;
043    import com.liferay.portal.kernel.util.Time;
044    import com.liferay.portal.kernel.util.Validator;
045    import com.liferay.portal.kernel.xml.Document;
046    import com.liferay.portal.kernel.xml.Element;
047    import com.liferay.portal.kernel.xml.SAXReaderUtil;
048    import com.liferay.portal.kernel.zip.ZipWriter;
049    import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
050    import com.liferay.portal.model.Group;
051    import com.liferay.portal.model.Image;
052    import com.liferay.portal.model.Layout;
053    import com.liferay.portal.model.LayoutConstants;
054    import com.liferay.portal.model.LayoutPrototype;
055    import com.liferay.portal.model.LayoutRevision;
056    import com.liferay.portal.model.LayoutSet;
057    import com.liferay.portal.model.LayoutSetBranch;
058    import com.liferay.portal.model.LayoutSetPrototype;
059    import com.liferay.portal.model.LayoutStagingHandler;
060    import com.liferay.portal.model.LayoutTypePortlet;
061    import com.liferay.portal.model.Portlet;
062    import com.liferay.portal.model.impl.LayoutImpl;
063    import com.liferay.portal.service.GroupLocalServiceUtil;
064    import com.liferay.portal.service.ImageLocalServiceUtil;
065    import com.liferay.portal.service.LayoutLocalServiceUtil;
066    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
067    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
068    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
069    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
070    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
071    import com.liferay.portal.service.PortletLocalServiceUtil;
072    import com.liferay.portal.service.ServiceContext;
073    import com.liferay.portal.service.ServiceContextThreadLocal;
074    import com.liferay.portal.service.UserLocalServiceUtil;
075    import com.liferay.portal.service.permission.PortletPermissionUtil;
076    import com.liferay.portlet.PortletPreferencesFactoryUtil;
077    import com.liferay.portlet.asset.model.AssetCategory;
078    import com.liferay.portlet.asset.model.AssetVocabulary;
079    import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
080    import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
081    
082    import java.io.File;
083    
084    import java.util.ArrayList;
085    import java.util.Date;
086    import java.util.HashMap;
087    import java.util.HashSet;
088    import java.util.Iterator;
089    import java.util.LinkedHashMap;
090    import java.util.List;
091    import java.util.Map;
092    import java.util.Set;
093    
094    import org.apache.commons.lang.time.StopWatch;
095    
096    /**
097     * @author Brian Wing Shun Chan
098     * @author Joel Kozikowski
099     * @author Charles May
100     * @author Raymond Aug??
101     * @author Jorge Ferrer
102     * @author Bruno Farache
103     * @author Karthik Sudarshan
104     * @author Zsigmond Rab
105     * @author Douglas Wong
106     * @author Mate Thurzo
107     */
108    public class LayoutExporter {
109    
110            public static final String SAME_GROUP_FRIENDLY_URL =
111                    "/[$SAME_GROUP_FRIENDLY_URL$]";
112    
113            public static List<Portlet> getDataSiteLevelPortlets(long companyId)
114                    throws Exception {
115    
116                    List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
117    
118                    Iterator<Portlet> itr = portlets.iterator();
119    
120                    while (itr.hasNext()) {
121                            Portlet portlet = itr.next();
122    
123                            if (!portlet.isActive()) {
124                                    itr.remove();
125    
126                                    continue;
127                            }
128    
129                            PortletDataHandler portletDataHandler =
130                                    portlet.getPortletDataHandlerInstance();
131    
132                            if ((portletDataHandler == null) ||
133                                    !portletDataHandler.isDataSiteLevel()) {
134    
135                                    itr.remove();
136                            }
137                    }
138    
139                    return portlets;
140            }
141    
142            public static Map<String, Boolean> getExportPortletControlsMap(
143                            long companyId, String portletId,
144                            Map<String, String[]> parameterMap)
145                    throws Exception {
146    
147                    return getExportPortletControlsMap(
148                            companyId, portletId, parameterMap, "layout-set");
149            }
150    
151            public static Map<String, Boolean> getExportPortletControlsMap(
152                            long companyId, String portletId,
153                            Map<String, String[]> parameterMap, String type)
154                    throws Exception {
155    
156                    boolean exportPortletConfiguration = MapUtil.getBoolean(
157                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION);
158                    boolean exportPortletConfigurationAll = MapUtil.getBoolean(
159                            parameterMap, PortletDataHandlerKeys.PORTLET_CONFIGURATION_ALL);
160                    boolean exportPortletData = MapUtil.getBoolean(
161                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
162                    boolean exportPortletDataAll = MapUtil.getBoolean(
163                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
164    
165                    if (_log.isDebugEnabled()) {
166                            _log.debug("Export portlet data " + exportPortletData);
167                            _log.debug("Export all portlet data " + exportPortletDataAll);
168                            _log.debug(
169                                    "Export portlet configuration " + exportPortletConfiguration);
170                    }
171    
172                    boolean exportCurPortletData = exportPortletData;
173    
174                    String rootPortletId =
175                            ExportImportHelperUtil.getExportableRootPortletId(
176                                    companyId, portletId);
177    
178                    if (exportPortletDataAll) {
179                            exportCurPortletData = true;
180                    }
181                    else if (rootPortletId != null) {
182    
183                            // PORTLET_DATA and the PORTLET_DATA for this specific data handler
184                            // must be true
185    
186                            exportCurPortletData =
187                                    exportPortletData &&
188                                    MapUtil.getBoolean(
189                                            parameterMap,
190                                            PortletDataHandlerKeys.PORTLET_DATA +
191                                                    StringPool.UNDERLINE + rootPortletId);
192                    }
193    
194                    boolean exportCurPortletArchivedSetups = exportPortletConfiguration;
195                    boolean exportCurPortletConfiguration = exportPortletConfiguration;
196                    boolean exportCurPortletSetup = exportPortletConfiguration;
197                    boolean exportCurPortletUserPreferences = exportPortletConfiguration;
198    
199                    if (exportPortletConfigurationAll ||
200                            (exportPortletConfiguration && type.equals("layout-prototype"))) {
201    
202                            exportCurPortletConfiguration = true;
203    
204                            exportCurPortletArchivedSetups =
205                                    MapUtil.getBoolean(
206                                            parameterMap,
207                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS_ALL);
208                            exportCurPortletSetup =
209                                    MapUtil.getBoolean(
210                                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP_ALL);
211                            exportCurPortletUserPreferences =
212                                    MapUtil.getBoolean(
213                                            parameterMap,
214                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES_ALL);
215                    }
216                    else if (rootPortletId != null) {
217                            exportCurPortletConfiguration =
218                                    exportPortletConfiguration &&
219                                    MapUtil.getBoolean(
220                                            parameterMap,
221                                            PortletDataHandlerKeys.PORTLET_CONFIGURATION +
222                                                    StringPool.UNDERLINE + rootPortletId);
223    
224                            exportCurPortletArchivedSetups =
225                                    exportCurPortletConfiguration &&
226                                    MapUtil.getBoolean(
227                                            parameterMap,
228                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS +
229                                                    StringPool.UNDERLINE + rootPortletId);
230                            exportCurPortletSetup =
231                                    exportCurPortletConfiguration &&
232                                    MapUtil.getBoolean(
233                                            parameterMap,
234                                            PortletDataHandlerKeys.PORTLET_SETUP +
235                                                    StringPool.UNDERLINE + rootPortletId);
236                            exportCurPortletUserPreferences =
237                                    exportCurPortletConfiguration &&
238                                    MapUtil.getBoolean(
239                                            parameterMap,
240                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES +
241                                                    StringPool.UNDERLINE + rootPortletId);
242                    }
243    
244                    Map<String, Boolean> exportPortletControlsMap =
245                            new HashMap<String, Boolean>();
246    
247                    exportPortletControlsMap.put(
248                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS,
249                            exportCurPortletArchivedSetups);
250                    exportPortletControlsMap.put(
251                            PortletDataHandlerKeys.PORTLET_CONFIGURATION,
252                            exportCurPortletConfiguration);
253                    exportPortletControlsMap.put(
254                            PortletDataHandlerKeys.PORTLET_DATA, exportCurPortletData);
255                    exportPortletControlsMap.put(
256                            PortletDataHandlerKeys.PORTLET_SETUP, exportCurPortletSetup);
257                    exportPortletControlsMap.put(
258                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES,
259                            exportCurPortletUserPreferences);
260    
261                    return exportPortletControlsMap;
262            }
263    
264            public static List<Portlet> getPortletDataHandlerPortlets(
265                            List<Layout> layouts)
266                    throws Exception {
267    
268                    List<Portlet> portlets = new ArrayList<Portlet>();
269                    Set<String> rootPortletIds = new HashSet<String>();
270    
271                    for (Layout layout : layouts) {
272                            if (!layout.isTypePortlet()) {
273                                    continue;
274                            }
275    
276                            LayoutTypePortlet layoutTypePortlet =
277                                    (LayoutTypePortlet)layout.getLayoutType();
278    
279                            for (String portletId : layoutTypePortlet.getPortletIds()) {
280                                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
281                                            layout.getCompanyId(), portletId);
282    
283                                    if ((portlet == null) ||
284                                            rootPortletIds.contains(portlet.getRootPortletId())) {
285    
286                                            continue;
287                                    }
288    
289                                    PortletDataHandler portletDataHandler =
290                                            portlet.getPortletDataHandlerInstance();
291    
292                                    if (portletDataHandler == null) {
293                                            continue;
294                                    }
295    
296                                    PortletDataHandlerControl[] portletDataHandlerControls =
297                                            portletDataHandler.getExportConfigurationControls(
298                                                    layout.getCompanyId(), layout.getGroupId(), portlet,
299                                                    layout.getPlid(), layout.getPrivateLayout());
300    
301                                    if (ArrayUtil.isNotEmpty(portletDataHandlerControls)) {
302                                            rootPortletIds.add(portlet.getRootPortletId());
303    
304                                            portlets.add(portlet);
305                                    }
306                            }
307                    }
308    
309                    return portlets;
310            }
311    
312            public static List<Portlet> getPortletDataHandlerPortlets(
313                            long groupId, boolean privateLayout)
314                    throws Exception {
315    
316                    return getPortletDataHandlerPortlets(
317                            LayoutLocalServiceUtil.getLayouts(groupId, privateLayout));
318            }
319    
320            public byte[] exportLayouts(
321                            long groupId, boolean privateLayout, long[] layoutIds,
322                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
323                    throws Exception {
324    
325                    File file = exportLayoutsAsFile(
326                            groupId, privateLayout, layoutIds, parameterMap, startDate,
327                            endDate);
328    
329                    try {
330                            return FileUtil.getBytes(file);
331                    }
332                    finally {
333                            file.delete();
334                    }
335            }
336    
337            public File exportLayoutsAsFile(
338                            long groupId, boolean privateLayout, long[] layoutIds,
339                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
340                    throws Exception {
341    
342                    try {
343                            ExportImportThreadLocal.setLayoutExportInProcess(true);
344    
345                            return doExportLayoutsAsFile(
346                                    groupId, privateLayout, layoutIds, parameterMap, startDate,
347                                    endDate);
348                    }
349                    finally {
350                            ExportImportThreadLocal.setLayoutExportInProcess(false);
351                    }
352            }
353    
354            protected File doExportLayoutsAsFile(
355                            long groupId, boolean privateLayout, long[] layoutIds,
356                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
357                    throws Exception {
358    
359                    boolean exportCategories = MapUtil.getBoolean(
360                            parameterMap, PortletDataHandlerKeys.CATEGORIES);
361                    boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
362                            parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
363                    boolean exportPermissions = MapUtil.getBoolean(
364                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
365                    boolean exportPortletDataAll = MapUtil.getBoolean(
366                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
367                    boolean exportLogo = MapUtil.getBoolean(
368                            parameterMap, PortletDataHandlerKeys.LOGO);
369                    boolean exportLayoutSetSettings = MapUtil.getBoolean(
370                            parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
371    
372                    if (_log.isDebugEnabled()) {
373                            _log.debug("Export permissions " + exportPermissions);
374                    }
375    
376                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
377                            groupId, privateLayout);
378    
379                    long companyId = layoutSet.getCompanyId();
380                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
381    
382                    ServiceContext serviceContext =
383                            ServiceContextThreadLocal.getServiceContext();
384    
385                    if (serviceContext == null) {
386                            serviceContext = new ServiceContext();
387    
388                            serviceContext.setCompanyId(companyId);
389                            serviceContext.setSignedIn(false);
390                            serviceContext.setUserId(defaultUserId);
391    
392                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
393                    }
394    
395                    serviceContext.setAttribute("exporting", Boolean.TRUE);
396    
397                    long layoutSetBranchId = MapUtil.getLong(
398                            parameterMap, "layoutSetBranchId");
399    
400                    serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
401    
402                    if (exportIgnoreLastPublishDate) {
403                            endDate = null;
404                            startDate = null;
405                    }
406    
407                    StopWatch stopWatch = new StopWatch();
408    
409                    stopWatch.start();
410    
411                    LayoutCache layoutCache = new LayoutCache();
412    
413                    ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
414    
415                    PortletDataContext portletDataContext =
416                            PortletDataContextFactoryUtil.createExportPortletDataContext(
417                                    companyId, groupId, parameterMap, startDate, endDate,
418                                    zipWriter);
419    
420                    portletDataContext.setPortetDataContextListener(
421                            new PortletDataContextListenerImpl(portletDataContext));
422                    portletDataContext.setPrivateLayout(privateLayout);
423    
424                    Document document = SAXReaderUtil.createDocument();
425    
426                    Element rootElement = document.addElement("root");
427    
428                    portletDataContext.setExportDataRootElement(rootElement);
429    
430                    Element headerElement = rootElement.addElement("header");
431    
432                    headerElement.addAttribute(
433                            "available-locales",
434                            StringUtil.merge(
435                                    LanguageUtil.getAvailableLocales(
436                                            portletDataContext.getScopeGroupId())));
437                    headerElement.addAttribute(
438                            "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
439                    headerElement.addAttribute("export-date", Time.getRFC822());
440    
441                    if (portletDataContext.hasDateRange()) {
442                            headerElement.addAttribute(
443                                    "start-date",
444                                    String.valueOf(portletDataContext.getStartDate()));
445                            headerElement.addAttribute(
446                                    "end-date", String.valueOf(portletDataContext.getEndDate()));
447                    }
448    
449                    headerElement.addAttribute(
450                            "company-id", String.valueOf(portletDataContext.getCompanyId()));
451                    headerElement.addAttribute(
452                            "company-group-id",
453                            String.valueOf(portletDataContext.getCompanyGroupId()));
454                    headerElement.addAttribute("group-id", String.valueOf(groupId));
455                    headerElement.addAttribute(
456                            "user-personal-site-group-id",
457                            String.valueOf(portletDataContext.getUserPersonalSiteGroupId()));
458                    headerElement.addAttribute(
459                            "private-layout", String.valueOf(privateLayout));
460    
461                    Group group = layoutSet.getGroup();
462    
463                    String type = "layout-set";
464    
465                    if (group.isLayoutPrototype()) {
466                            type = "layout-prototype";
467    
468                            LayoutPrototype layoutPrototype =
469                                    LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
470                                            group.getClassPK());
471    
472                            headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
473                    }
474                    else if (group.isLayoutSetPrototype()) {
475                            type ="layout-set-prototype";
476    
477                            LayoutSetPrototype layoutSetPrototype =
478                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
479                                            group.getClassPK());
480    
481                            headerElement.addAttribute(
482                                    "type-uuid", layoutSetPrototype.getUuid());
483                    }
484    
485                    headerElement.addAttribute("type", type);
486    
487                    LayoutSetBranch layoutSetBranch =
488                            LayoutSetBranchLocalServiceUtil.fetchLayoutSetBranch(
489                                    layoutSetBranchId);
490    
491                    if (exportLogo) {
492                            Image image = null;
493    
494                            if (layoutSetBranch != null) {
495                                    image = ImageLocalServiceUtil.getImage(
496                                            layoutSetBranch.getLogoId());
497                            }
498                            else {
499                                    image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
500                            }
501    
502                            if ((image != null) && (image.getTextObj() != null)) {
503                                    String logoPath = ExportImportPathUtil.getRootPath(
504                                            portletDataContext);
505    
506                                    logoPath += "/logo";
507    
508                                    headerElement.addAttribute("logo-path", logoPath);
509    
510                                    portletDataContext.addZipEntry(logoPath, image.getTextObj());
511                            }
512                    }
513    
514                    Element missingReferencesElement = rootElement.addElement(
515                            "missing-references");
516    
517                    portletDataContext.setMissingReferencesElement(
518                            missingReferencesElement);
519    
520                    if (layoutSetBranch != null) {
521                            _themeExporter.exportTheme(portletDataContext, layoutSetBranch);
522                    }
523                    else {
524                            _themeExporter.exportTheme(portletDataContext, layoutSet);
525                    }
526    
527                    if (exportLayoutSetSettings) {
528                            Element settingsElement = headerElement.addElement("settings");
529    
530                            if (layoutSetBranch != null) {
531                                    settingsElement.addCDATA(layoutSetBranch.getSettings());
532                            }
533                            else {
534                                    settingsElement.addCDATA(layoutSet.getSettings());
535                            }
536                    }
537    
538                    Map<String, Object[]> portletIds =
539                            new LinkedHashMap<String, Object[]>();
540    
541                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
542                            groupId, privateLayout);
543    
544                    if (group.isStagingGroup()) {
545                            group = group.getLiveGroup();
546                    }
547    
548                    // Collect data portlets
549    
550                    for (Portlet portlet : getDataSiteLevelPortlets(companyId)) {
551                            String portletId = portlet.getRootPortletId();
552    
553                            if (!group.isStagedPortlet(portletId)) {
554                                    continue;
555                            }
556    
557                            // Calculate the amount of exported data
558    
559                            if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
560                                    PortletDataHandler portletDataHandler =
561                                            portlet.getPortletDataHandlerInstance();
562    
563                                    portletDataHandler.prepareManifestSummary(portletDataContext);
564                            }
565    
566                            // Add portlet ID to exportable portlets list
567    
568                            portletIds.put(
569                                    PortletPermissionUtil.getPrimaryKey(0, portletId),
570                                    new Object[] {
571                                            portletId, LayoutConstants.DEFAULT_PLID, groupId,
572                                            StringPool.BLANK, StringPool.BLANK
573                                    });
574    
575                            if (!portlet.isScopeable()) {
576                                    continue;
577                            }
578    
579                            // Scoped data
580    
581                            for (Layout layout : layouts) {
582                                    if ((!ArrayUtil.contains(layoutIds, layout.getLayoutId()) &&
583                                             ArrayUtil.isNotEmpty(layoutIds)) ||
584                                            !layout.isTypePortlet() || !layout.hasScopeGroup()) {
585    
586                                            continue;
587                                    }
588    
589                                    Group scopeGroup = layout.getScopeGroup();
590    
591                                    portletIds.put(
592                                            PortletPermissionUtil.getPrimaryKey(
593                                                    layout.getPlid(), portlet.getPortletId()),
594                                            new Object[] {
595                                                    portlet.getPortletId(), layout.getPlid(),
596                                                    scopeGroup.getGroupId(), StringPool.BLANK,
597                                                    layout.getUuid()
598                                            });
599                            }
600                    }
601    
602                    portletDataContext.addDeletionSystemEventStagedModelTypes(
603                            new StagedModelType(Layout.class));
604    
605                    Element layoutsElement = portletDataContext.getExportDataGroupElement(
606                            Layout.class);
607    
608                    String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
609    
610                    if (!group.isStaged() && Validator.isNotNull(layoutSetPrototypeUuid)) {
611                            LayoutSetPrototype layoutSetPrototype =
612                                    LayoutSetPrototypeLocalServiceUtil.
613                                            getLayoutSetPrototypeByUuidAndCompanyId(
614                                                    layoutSetPrototypeUuid, companyId);
615    
616                            layoutsElement.addAttribute(
617                                    "layout-set-prototype-uuid", layoutSetPrototypeUuid);
618    
619                            layoutsElement.addAttribute(
620                                    "layout-set-prototype-name",
621                                    layoutSetPrototype.getName(LocaleUtil.getDefault()));
622                    }
623    
624                    for (Layout layout : layouts) {
625                            exportLayout(portletDataContext, layoutIds, portletIds, layout);
626                    }
627    
628                    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
629                            ManifestSummary manifestSummary =
630                                    portletDataContext.getManifestSummary();
631    
632                            Set<String> portletIdsSet = portletIds.keySet();
633    
634                            PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
635                                    "layout", portletIdsSet.toArray(
636                                            new String[portletIdsSet.size()]),
637                                    manifestSummary);
638    
639                            manifestSummary.resetCounters();
640                    }
641    
642                    long previousScopeGroupId = portletDataContext.getScopeGroupId();
643    
644                    Element portletsElement = rootElement.addElement("portlets");
645    
646                    for (Map.Entry<String, Object[]> portletIdsEntry :
647                                    portletIds.entrySet()) {
648    
649                            Object[] portletObjects = portletIdsEntry.getValue();
650    
651                            String portletId = null;
652                            long plid = LayoutConstants.DEFAULT_PLID;
653                            long scopeGroupId = 0;
654                            String scopeType = StringPool.BLANK;
655                            String scopeLayoutUuid = null;
656    
657                            if (portletObjects.length == 4) {
658                                    portletId = (String)portletIdsEntry.getValue()[0];
659                                    plid = (Long)portletIdsEntry.getValue()[1];
660                                    scopeGroupId = (Long)portletIdsEntry.getValue()[2];
661                                    scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
662                            }
663                            else {
664                                    portletId = (String)portletIdsEntry.getValue()[0];
665                                    plid = (Long)portletIdsEntry.getValue()[1];
666                                    scopeGroupId = (Long)portletIdsEntry.getValue()[2];
667                                    scopeType = (String)portletIdsEntry.getValue()[3];
668                                    scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
669                            }
670    
671                            Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
672    
673                            if (layout == null) {
674                                    layout = new LayoutImpl();
675    
676                                    layout.setGroupId(groupId);
677                                    layout.setCompanyId(companyId);
678                            }
679    
680                            portletDataContext.setPlid(plid);
681                            portletDataContext.setOldPlid(plid);
682                            portletDataContext.setScopeGroupId(scopeGroupId);
683                            portletDataContext.setScopeType(scopeType);
684                            portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
685    
686                            Map<String, Boolean> exportPortletControlsMap =
687                                    getExportPortletControlsMap(
688                                            companyId, portletId, parameterMap, type);
689    
690                            _portletExporter.exportPortlet(
691                                    portletDataContext, layoutCache, portletId, layout,
692                                    portletsElement, exportPermissions,
693                                    exportPortletControlsMap.get(
694                                            PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS),
695                                    exportPortletControlsMap.get(
696                                            PortletDataHandlerKeys.PORTLET_DATA),
697                                    exportPortletControlsMap.get(
698                                            PortletDataHandlerKeys.PORTLET_SETUP),
699                                    exportPortletControlsMap.get(
700                                            PortletDataHandlerKeys.PORTLET_USER_PREFERENCES));
701                    }
702    
703                    portletDataContext.setScopeGroupId(previousScopeGroupId);
704    
705                    exportAssetCategories(
706                            portletDataContext, exportPortletDataAll, exportCategories,
707                            group.isCompany());
708    
709                    _portletExporter.exportAssetLinks(portletDataContext);
710                    _portletExporter.exportAssetTags(portletDataContext);
711                    _portletExporter.exportComments(portletDataContext);
712                    _portletExporter.exportExpandoTables(portletDataContext);
713                    _portletExporter.exportLocks(portletDataContext);
714    
715                    _deletionSystemEventExporter.exportDeletionSystemEvents(
716                            portletDataContext);
717    
718                    if (exportPermissions) {
719                            _permissionExporter.exportPortletDataPermissions(
720                                    portletDataContext);
721                    }
722    
723                    _portletExporter.exportRatingsEntries(portletDataContext, rootElement);
724    
725                    ExportImportHelperUtil.writeManifestSummary(
726                            document, portletDataContext.getManifestSummary());
727    
728                    if (_log.isInfoEnabled()) {
729                            _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
730                    }
731    
732                    portletDataContext.addZipEntry(
733                            "/manifest.xml", document.formattedString());
734    
735                    return zipWriter.getFile();
736            }
737    
738            protected void exportAssetCategories(
739                            PortletDataContext portletDataContext, boolean exportPortletDataAll,
740                            boolean exportCategories, boolean companyGroup)
741                    throws Exception {
742    
743                    Document document = SAXReaderUtil.createDocument();
744    
745                    Element rootElement = document.addElement("categories-hierarchy");
746    
747                    if (exportPortletDataAll || exportCategories || companyGroup) {
748                            if (_log.isDebugEnabled()) {
749                                    _log.debug("Export categories");
750                            }
751    
752                            Element assetVocabulariesElement = rootElement.addElement(
753                                    "vocabularies");
754    
755                            List<AssetVocabulary> assetVocabularies =
756                                    AssetVocabularyLocalServiceUtil.getGroupVocabularies(
757                                            portletDataContext.getGroupId());
758    
759                            for (AssetVocabulary assetVocabulary : assetVocabularies) {
760                                    _portletExporter.exportAssetVocabulary(
761                                            portletDataContext, assetVocabulariesElement,
762                                            assetVocabulary);
763                            }
764    
765                            Element categoriesElement = rootElement.addElement("categories");
766    
767                            List<AssetCategory> assetCategories =
768                                    AssetCategoryUtil.findByGroupId(
769                                            portletDataContext.getGroupId());
770    
771                            for (AssetCategory assetCategory : assetCategories) {
772                                    _portletExporter.exportAssetCategory(
773                                            portletDataContext, assetVocabulariesElement,
774                                            categoriesElement, assetCategory);
775                            }
776                    }
777    
778                    _portletExporter.exportAssetCategories(portletDataContext, rootElement);
779    
780                    portletDataContext.addZipEntry(
781                            ExportImportPathUtil.getRootPath(portletDataContext) +
782                                    "/categories-hierarchy.xml",
783                            document.formattedString());
784            }
785    
786            protected void exportLayout(
787                            PortletDataContext portletDataContext, long[] layoutIds,
788                            Map<String, Object[]> portletIds, Layout layout)
789                    throws Exception {
790    
791                    if (!ArrayUtil.contains(layoutIds, layout.getLayoutId()) &&
792                            ArrayUtil.isNotEmpty(layoutIds)) {
793    
794                            Element layoutElement = portletDataContext.getExportDataElement(
795                                    layout);
796    
797                            layoutElement.addAttribute("action", Constants.SKIP);
798    
799                            return;
800                    }
801    
802                    boolean exportLAR = MapUtil.getBoolean(
803                            portletDataContext.getParameterMap(), "exportLAR");
804    
805                    if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout)) {
806                            long layoutSetBranchId = MapUtil.getLong(
807                                    portletDataContext.getParameterMap(), "layoutSetBranchId");
808    
809                            if (layoutSetBranchId <= 0) {
810                                    return;
811                            }
812    
813                            LayoutRevision layoutRevision =
814                                    LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
815                                            layoutSetBranchId, true, layout.getPlid());
816    
817                            if (layoutRevision == null) {
818                                    return;
819                            }
820    
821                            LayoutStagingHandler layoutStagingHandler =
822                                    LayoutStagingUtil.getLayoutStagingHandler(layout);
823    
824                            layoutStagingHandler.setLayoutRevision(layoutRevision);
825                    }
826    
827                    StagedModelDataHandlerUtil.exportStagedModel(
828                            portletDataContext, layout);
829    
830                    if (!layout.isSupportsEmbeddedPortlets()) {
831    
832                            // Only portlet type layouts support page scoping
833    
834                            return;
835                    }
836    
837                    LayoutTypePortlet layoutTypePortlet =
838                            (LayoutTypePortlet)layout.getLayoutType();
839    
840                    // The getAllPortlets method returns all effective nonsystem portlets
841                    // for any layout type, including embedded portlets, or in the case of
842                    // panel type layout, selected portlets
843    
844                    for (Portlet portlet : layoutTypePortlet.getAllPortlets(false)) {
845                            String portletId = portlet.getPortletId();
846    
847                            javax.portlet.PortletPreferences jxPortletPreferences =
848                                    PortletPreferencesFactoryUtil.getLayoutPortletSetup(
849                                            layout, portletId);
850    
851                            String scopeType = GetterUtil.getString(
852                                    jxPortletPreferences.getValue("lfrScopeType", null));
853                            String scopeLayoutUuid = GetterUtil.getString(
854                                    jxPortletPreferences.getValue("lfrScopeLayoutUuid", null));
855    
856                            long scopeGroupId = portletDataContext.getScopeGroupId();
857    
858                            if (Validator.isNotNull(scopeType)) {
859                                    Group scopeGroup = null;
860    
861                                    if (scopeType.equals("company")) {
862                                            scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
863                                                    layout.getCompanyId());
864                                    }
865                                    else if (scopeType.equals("layout")) {
866                                            Layout scopeLayout = null;
867    
868                                            scopeLayout =
869                                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
870                                                            scopeLayoutUuid, portletDataContext.getGroupId(),
871                                                            portletDataContext.isPrivateLayout());
872    
873                                            if (scopeLayout == null) {
874                                                    continue;
875                                            }
876    
877                                            scopeGroup = scopeLayout.getScopeGroup();
878                                    }
879                                    else {
880                                            throw new IllegalArgumentException(
881                                                    "Scope type " + scopeType + " is invalid");
882                                    }
883    
884                                    if (scopeGroup != null) {
885                                            scopeGroupId = scopeGroup.getGroupId();
886                                    }
887                            }
888    
889                            String key = PortletPermissionUtil.getPrimaryKey(
890                                    layout.getPlid(), portletId);
891    
892                            portletIds.put(
893                                    key,
894                                    new Object[] {
895                                            portletId, layout.getPlid(), scopeGroupId, scopeType,
896                                            scopeLayoutUuid
897                                    }
898                            );
899                    }
900            }
901    
902            private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
903    
904            private DeletionSystemEventExporter _deletionSystemEventExporter =
905                    new DeletionSystemEventExporter();
906            private PermissionExporter _permissionExporter = new PermissionExporter();
907            private PortletExporter _portletExporter = new PortletExporter();
908            private ThemeExporter _themeExporter = new ThemeExporter();
909    
910    }