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