001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.lar;
016    
017    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.lar.ExportImportDateUtil;
021    import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
022    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
023    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
024    import com.liferay.portal.kernel.lar.ManifestSummary;
025    import com.liferay.portal.kernel.lar.PortletDataContext;
026    import com.liferay.portal.kernel.lar.PortletDataContextFactoryUtil;
027    import com.liferay.portal.kernel.lar.PortletDataHandler;
028    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
029    import com.liferay.portal.kernel.lar.PortletDataHandlerStatusMessageSenderUtil;
030    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
031    import com.liferay.portal.kernel.lar.StagedModelType;
032    import com.liferay.portal.kernel.lar.lifecycle.ExportImportLifecycleConstants;
033    import com.liferay.portal.kernel.lar.lifecycle.ExportImportLifecycleManager;
034    import com.liferay.portal.kernel.lar.xstream.XStreamAliasRegistryUtil;
035    import com.liferay.portal.kernel.log.Log;
036    import com.liferay.portal.kernel.log.LogFactoryUtil;
037    import com.liferay.portal.kernel.settings.Settings;
038    import com.liferay.portal.kernel.settings.SettingsFactoryUtil;
039    import com.liferay.portal.kernel.staging.LayoutStagingUtil;
040    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
041    import com.liferay.portal.kernel.util.ArrayUtil;
042    import com.liferay.portal.kernel.util.Constants;
043    import com.liferay.portal.kernel.util.DateRange;
044    import com.liferay.portal.kernel.util.FileUtil;
045    import com.liferay.portal.kernel.util.LocaleUtil;
046    import com.liferay.portal.kernel.util.MapUtil;
047    import com.liferay.portal.kernel.util.ReleaseInfo;
048    import com.liferay.portal.kernel.util.StringPool;
049    import com.liferay.portal.kernel.util.StringUtil;
050    import com.liferay.portal.kernel.util.Time;
051    import com.liferay.portal.kernel.util.Validator;
052    import com.liferay.portal.kernel.xml.Document;
053    import com.liferay.portal.kernel.xml.Element;
054    import com.liferay.portal.kernel.xml.SAXReaderUtil;
055    import com.liferay.portal.kernel.zip.ZipWriter;
056    import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
057    import com.liferay.portal.model.Group;
058    import com.liferay.portal.model.Image;
059    import com.liferay.portal.model.Layout;
060    import com.liferay.portal.model.LayoutConstants;
061    import com.liferay.portal.model.LayoutPrototype;
062    import com.liferay.portal.model.LayoutRevision;
063    import com.liferay.portal.model.LayoutSet;
064    import com.liferay.portal.model.LayoutSetBranch;
065    import com.liferay.portal.model.LayoutSetPrototype;
066    import com.liferay.portal.model.LayoutStagingHandler;
067    import com.liferay.portal.model.LayoutTypePortlet;
068    import com.liferay.portal.model.Portlet;
069    import com.liferay.portal.model.impl.LayoutImpl;
070    import com.liferay.portal.service.GroupLocalServiceUtil;
071    import com.liferay.portal.service.ImageLocalServiceUtil;
072    import com.liferay.portal.service.LayoutLocalServiceUtil;
073    import com.liferay.portal.service.LayoutPrototypeLocalServiceUtil;
074    import com.liferay.portal.service.LayoutRevisionLocalServiceUtil;
075    import com.liferay.portal.service.LayoutSetBranchLocalServiceUtil;
076    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
077    import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
078    import com.liferay.portal.service.PortletLocalServiceUtil;
079    import com.liferay.portal.service.ServiceContext;
080    import com.liferay.portal.service.ServiceContextThreadLocal;
081    import com.liferay.portal.service.UserLocalServiceUtil;
082    import com.liferay.portal.service.permission.PortletPermissionUtil;
083    
084    import java.io.File;
085    
086    import java.util.Collections;
087    import java.util.Date;
088    import java.util.Iterator;
089    import java.util.LinkedHashMap;
090    import java.util.List;
091    import java.util.Map;
092    import java.util.concurrent.Callable;
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 List<Portlet> getDataSiteLevelPortlets(long companyId)
111                    throws Exception {
112    
113                    return getDataSiteLevelPortlets(companyId, false);
114            }
115    
116            public static List<Portlet> getDataSiteLevelPortlets(
117                            long companyId, boolean excludeDataAlwaysStaged)
118                    throws Exception {
119    
120                    List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
121    
122                    Iterator<Portlet> itr = portlets.iterator();
123    
124                    while (itr.hasNext()) {
125                            Portlet portlet = itr.next();
126    
127                            if (!portlet.isActive()) {
128                                    itr.remove();
129    
130                                    continue;
131                            }
132    
133                            PortletDataHandler portletDataHandler =
134                                    portlet.getPortletDataHandlerInstance();
135    
136                            if ((portletDataHandler == null) ||
137                                    !portletDataHandler.isDataSiteLevel() ||
138                                    (excludeDataAlwaysStaged &&
139                                     portletDataHandler.isDataAlwaysStaged())) {
140    
141                                    itr.remove();
142                            }
143                    }
144    
145                    return portlets;
146            }
147    
148            public static LayoutExporter getInstance() {
149                    return _instance;
150            }
151    
152            /**
153             * @deprecated As of 7.0.0, with no direct replacement
154             */
155            @Deprecated
156            public static List<Portlet> getPortletDataHandlerPortlets(
157                            long groupId, List<Layout> layouts)
158                    throws Exception {
159    
160                    return Collections.emptyList();
161            }
162    
163            /**
164             * @deprecated As of 7.0.0, with no direct replacement
165             */
166            @Deprecated
167            public byte[] exportLayouts(
168                            long groupId, boolean privateLayout, long[] layoutIds,
169                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
170                    throws Exception {
171    
172                    File file = exportLayoutsAsFile(
173                            groupId, privateLayout, layoutIds, parameterMap, startDate,
174                            endDate);
175    
176                    try {
177                            return FileUtil.getBytes(file);
178                    }
179                    finally {
180                            file.delete();
181                    }
182            }
183    
184            public File exportLayoutsAsFile(
185                            long groupId, boolean privateLayout, long[] layoutIds,
186                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
187                    throws Exception {
188    
189                    PortletDataContext portletDataContext = null;
190    
191                    try {
192                            ExportImportThreadLocal.setLayoutExportInProcess(true);
193    
194                            portletDataContext = getPortletDataContext(
195                                    groupId, privateLayout, parameterMap, startDate, endDate);
196    
197                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
198                                    ExportImportLifecycleConstants.EVENT_LAYOUT_EXPORT_STARTED,
199                                    PortletDataContextFactoryUtil.clonePortletDataContext(
200                                            portletDataContext));
201    
202                            File file = doExportLayoutsAsFile(portletDataContext, layoutIds);
203    
204                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
205                                    ExportImportLifecycleConstants.EVENT_LAYOUT_EXPORT_SUCCEEDED,
206                                    PortletDataContextFactoryUtil.clonePortletDataContext(
207                                            portletDataContext));
208    
209                            return file;
210                    }
211                    catch (Throwable t) {
212                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
213                                    ExportImportLifecycleConstants.EVENT_LAYOUT_EXPORT_FAILED,
214                                    PortletDataContextFactoryUtil.clonePortletDataContext(
215                                            portletDataContext),
216                                    t);
217    
218                            throw t;
219                    }
220                    finally {
221                            ExportImportThreadLocal.setLayoutExportInProcess(false);
222                    }
223            }
224    
225            protected File doExportLayoutsAsFile(
226                            PortletDataContext portletDataContext, long[] layoutIds)
227                    throws Exception {
228    
229                    Map<String, String[]> parameterMap =
230                            portletDataContext.getParameterMap();
231    
232                    boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
233                            parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
234                    boolean exportPermissions = MapUtil.getBoolean(
235                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
236                    boolean exportLogo = MapUtil.getBoolean(
237                            parameterMap, PortletDataHandlerKeys.LOGO);
238                    boolean exportLayoutSetSettings = MapUtil.getBoolean(
239                            parameterMap, PortletDataHandlerKeys.LAYOUT_SET_SETTINGS);
240    
241                    if (_log.isDebugEnabled()) {
242                            _log.debug("Export permissions " + exportPermissions);
243                    }
244    
245                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
246                            portletDataContext.getGroupId(),
247                            portletDataContext.isPrivateLayout());
248    
249                    long companyId = layoutSet.getCompanyId();
250                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
251    
252                    ServiceContext serviceContext =
253                            ServiceContextThreadLocal.popServiceContext();
254    
255                    if (serviceContext == null) {
256                            serviceContext = new ServiceContext();
257                    }
258    
259                    serviceContext.setCompanyId(companyId);
260                    serviceContext.setSignedIn(false);
261                    serviceContext.setUserId(defaultUserId);
262    
263                    serviceContext.setAttribute("exporting", Boolean.TRUE);
264    
265                    long layoutSetBranchId = MapUtil.getLong(
266                            parameterMap, "layoutSetBranchId");
267    
268                    serviceContext.setAttribute("layoutSetBranchId", layoutSetBranchId);
269    
270                    ServiceContextThreadLocal.pushServiceContext(serviceContext);
271    
272                    if (exportIgnoreLastPublishDate) {
273                            portletDataContext.setEndDate(null);
274                            portletDataContext.setStartDate(null);
275                    }
276    
277                    StopWatch stopWatch = new StopWatch();
278    
279                    stopWatch.start();
280    
281                    portletDataContext.setPortetDataContextListener(
282                            new PortletDataContextListenerImpl(portletDataContext));
283    
284                    Document document = SAXReaderUtil.createDocument();
285    
286                    Element rootElement = document.addElement("root");
287    
288                    portletDataContext.setExportDataRootElement(rootElement);
289    
290                    Element headerElement = rootElement.addElement("header");
291    
292                    headerElement.addAttribute(
293                            "available-locales",
294                            StringUtil.merge(
295                                    LanguageUtil.getAvailableLocales(
296                                            portletDataContext.getScopeGroupId())));
297                    headerElement.addAttribute(
298                            "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
299                    headerElement.addAttribute("export-date", Time.getRFC822());
300    
301                    if (portletDataContext.hasDateRange()) {
302                            headerElement.addAttribute(
303                                    "start-date",
304                                    String.valueOf(portletDataContext.getStartDate()));
305                            headerElement.addAttribute(
306                                    "end-date", String.valueOf(portletDataContext.getEndDate()));
307                    }
308    
309                    headerElement.addAttribute(
310                            "company-id", String.valueOf(portletDataContext.getCompanyId()));
311                    headerElement.addAttribute(
312                            "company-group-id",
313                            String.valueOf(portletDataContext.getCompanyGroupId()));
314                    headerElement.addAttribute(
315                            "group-id", String.valueOf(portletDataContext.getGroupId()));
316                    headerElement.addAttribute(
317                            "user-personal-site-group-id",
318                            String.valueOf(portletDataContext.getUserPersonalSiteGroupId()));
319                    headerElement.addAttribute(
320                            "private-layout",
321                            String.valueOf(portletDataContext.isPrivateLayout()));
322    
323                    Group group = layoutSet.getGroup();
324    
325                    String type = "layout-set";
326    
327                    if (group.isLayoutPrototype()) {
328                            type = "layout-prototype";
329    
330                            LayoutPrototype layoutPrototype =
331                                    LayoutPrototypeLocalServiceUtil.getLayoutPrototype(
332                                            group.getClassPK());
333    
334                            headerElement.addAttribute("type-uuid", layoutPrototype.getUuid());
335                    }
336                    else if (group.isLayoutSetPrototype()) {
337                            type ="layout-set-prototype";
338    
339                            LayoutSetPrototype layoutSetPrototype =
340                                    LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototype(
341                                            group.getClassPK());
342    
343                            headerElement.addAttribute(
344                                    "type-uuid", layoutSetPrototype.getUuid());
345                    }
346    
347                    headerElement.addAttribute("type", type);
348    
349                    LayoutSetBranch layoutSetBranch =
350                            LayoutSetBranchLocalServiceUtil.fetchLayoutSetBranch(
351                                    layoutSetBranchId);
352    
353                    if (exportLogo) {
354                            Image image = null;
355    
356                            if (layoutSetBranch != null) {
357                                    image = ImageLocalServiceUtil.getImage(
358                                            layoutSetBranch.getLogoId());
359                            }
360                            else {
361                                    image = ImageLocalServiceUtil.getImage(layoutSet.getLogoId());
362                            }
363    
364                            if ((image != null) && (image.getTextObj() != null)) {
365                                    String logoPath = ExportImportPathUtil.getRootPath(
366                                            portletDataContext);
367    
368                                    logoPath += "/logo";
369    
370                                    headerElement.addAttribute("logo-path", logoPath);
371    
372                                    portletDataContext.addZipEntry(logoPath, image.getTextObj());
373                            }
374                    }
375    
376                    Element missingReferencesElement = rootElement.addElement(
377                            "missing-references");
378    
379                    portletDataContext.setMissingReferencesElement(
380                            missingReferencesElement);
381    
382                    if (layoutSetBranch != null) {
383                            _themeExporter.exportTheme(portletDataContext, layoutSetBranch);
384                    }
385                    else {
386                            _themeExporter.exportTheme(portletDataContext, layoutSet);
387                    }
388    
389                    if (exportLayoutSetSettings) {
390                            Element settingsElement = headerElement.addElement("settings");
391    
392                            if (layoutSetBranch != null) {
393                                    settingsElement.addCDATA(layoutSetBranch.getSettings());
394                            }
395                            else {
396                                    settingsElement.addCDATA(layoutSet.getSettings());
397                            }
398                    }
399    
400                    Map<String, Object[]> portletIds =
401                            new LinkedHashMap<String, Object[]>();
402    
403                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
404                            portletDataContext.getGroupId(),
405                            portletDataContext.isPrivateLayout());
406    
407                    if (group.isStagingGroup()) {
408                            group = group.getLiveGroup();
409                    }
410    
411                    // Collect data portlets
412    
413                    for (Portlet portlet : getDataSiteLevelPortlets(companyId)) {
414                            String portletId = portlet.getRootPortletId();
415    
416                            if (!group.isStagedPortlet(portletId)) {
417                                    continue;
418                            }
419    
420                            // Calculate the amount of exported data
421    
422                            if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
423                                    PortletDataHandler portletDataHandler =
424                                            portlet.getPortletDataHandlerInstance();
425    
426                                    portletDataHandler.prepareManifestSummary(portletDataContext);
427                            }
428    
429                            // Add portlet ID to exportable portlets list
430    
431                            portletIds.put(
432                                    PortletPermissionUtil.getPrimaryKey(0, portletId),
433                                    new Object[] {
434                                            portletId, LayoutConstants.DEFAULT_PLID,
435                                            portletDataContext.getGroupId(), StringPool.BLANK,
436                                            StringPool.BLANK
437                                    });
438    
439                            if (!portlet.isScopeable()) {
440                                    continue;
441                            }
442    
443                            // Scoped data
444    
445                            for (Layout layout : layouts) {
446                                    if (!ArrayUtil.contains(layoutIds, layout.getLayoutId()) ||
447                                            !layout.isTypePortlet() || !layout.hasScopeGroup()) {
448    
449                                            continue;
450                                    }
451    
452                                    Group scopeGroup = layout.getScopeGroup();
453    
454                                    portletIds.put(
455                                            PortletPermissionUtil.getPrimaryKey(
456                                                    layout.getPlid(), portlet.getPortletId()),
457                                            new Object[] {
458                                                    portlet.getPortletId(), layout.getPlid(),
459                                                    scopeGroup.getGroupId(), StringPool.BLANK,
460                                                    layout.getUuid()
461                                            });
462                            }
463                    }
464    
465                    portletDataContext.addDeletionSystemEventStagedModelTypes(
466                            new StagedModelType(Layout.class));
467    
468                    Element layoutsElement = portletDataContext.getExportDataGroupElement(
469                            Layout.class);
470    
471                    String layoutSetPrototypeUuid = layoutSet.getLayoutSetPrototypeUuid();
472    
473                    if (Validator.isNotNull(layoutSetPrototypeUuid)) {
474                            LayoutSetPrototype layoutSetPrototype =
475                                    LayoutSetPrototypeLocalServiceUtil.
476                                            getLayoutSetPrototypeByUuidAndCompanyId(
477                                                    layoutSetPrototypeUuid, companyId);
478    
479                            layoutsElement.addAttribute(
480                                    "layout-set-prototype-uuid", layoutSetPrototypeUuid);
481    
482                            layoutsElement.addAttribute(
483                                    "layout-set-prototype-name",
484                                    layoutSetPrototype.getName(LocaleUtil.getDefault()));
485                    }
486    
487                    for (Layout layout : layouts) {
488                            exportLayout(portletDataContext, layoutIds, portletIds, layout);
489                    }
490    
491                    if (BackgroundTaskThreadLocal.hasBackgroundTask()) {
492                            ManifestSummary manifestSummary =
493                                    portletDataContext.getManifestSummary();
494    
495                            PortletDataHandlerStatusMessageSenderUtil.sendStatusMessage(
496                                    "layout", ArrayUtil.toStringArray(portletIds.keySet()),
497                                    manifestSummary);
498    
499                            manifestSummary.resetCounters();
500                    }
501    
502                    Element portletsElement = rootElement.addElement("portlets");
503    
504                    Element servicesElement = rootElement.addElement("services");
505    
506                    long previousScopeGroupId = portletDataContext.getScopeGroupId();
507    
508                    for (Map.Entry<String, Object[]> portletIdsEntry :
509                                    portletIds.entrySet()) {
510    
511                            Object[] portletObjects = portletIdsEntry.getValue();
512    
513                            String portletId = null;
514                            long plid = LayoutConstants.DEFAULT_PLID;
515                            long scopeGroupId = 0;
516                            String scopeType = StringPool.BLANK;
517                            String scopeLayoutUuid = null;
518    
519                            if (portletObjects.length == 4) {
520                                    portletId = (String)portletIdsEntry.getValue()[0];
521                                    plid = (Long)portletIdsEntry.getValue()[1];
522                                    scopeGroupId = (Long)portletIdsEntry.getValue()[2];
523                                    scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
524                            }
525                            else {
526                                    portletId = (String)portletIdsEntry.getValue()[0];
527                                    plid = (Long)portletIdsEntry.getValue()[1];
528                                    scopeGroupId = (Long)portletIdsEntry.getValue()[2];
529                                    scopeType = (String)portletIdsEntry.getValue()[3];
530                                    scopeLayoutUuid = (String)portletIdsEntry.getValue()[4];
531                            }
532    
533                            Layout layout = LayoutLocalServiceUtil.fetchLayout(plid);
534    
535                            if (layout == null) {
536                                    layout = new LayoutImpl();
537    
538                                    layout.setCompanyId(companyId);
539                                    layout.setGroupId(portletDataContext.getGroupId());
540                            }
541    
542                            portletDataContext.setPlid(plid);
543                            portletDataContext.setOldPlid(plid);
544                            portletDataContext.setPortletId(portletId);
545                            portletDataContext.setScopeGroupId(scopeGroupId);
546                            portletDataContext.setScopeType(scopeType);
547                            portletDataContext.setScopeLayoutUuid(scopeLayoutUuid);
548    
549                            Map<String, Boolean> exportPortletControlsMap =
550                                    ExportImportHelperUtil.getExportPortletControlsMap(
551                                            companyId, portletId, parameterMap, type);
552    
553                            try {
554                                    ExportImportLifecycleManager.fireExportImportLifecycleEvent(
555                                            ExportImportLifecycleConstants.EVENT_PORTLET_EXPORT_STARTED,
556                                            PortletDataContextFactoryUtil.clonePortletDataContext(
557                                                    portletDataContext));
558    
559                                    _portletExporter.exportPortlet(
560                                            portletDataContext, layout, portletsElement,
561                                            exportPermissions,
562                                            exportPortletControlsMap.get(
563                                                    PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS),
564                                            exportPortletControlsMap.get(
565                                                    PortletDataHandlerKeys.PORTLET_DATA),
566                                            exportPortletControlsMap.get(
567                                                    PortletDataHandlerKeys.PORTLET_SETUP),
568                                            exportPortletControlsMap.get(
569                                                    PortletDataHandlerKeys.PORTLET_USER_PREFERENCES));
570                                    _portletExporter.exportService(
571                                            portletDataContext, servicesElement,
572                                            exportPortletControlsMap.get(
573                                                    PortletDataHandlerKeys.PORTLET_SETUP));
574    
575                                    ExportImportLifecycleManager.fireExportImportLifecycleEvent(
576                                            ExportImportLifecycleConstants.
577                                                    EVENT_PORTLET_EXPORT_SUCCEEDED,
578                                            PortletDataContextFactoryUtil.clonePortletDataContext(
579                                                    portletDataContext));
580                            }
581                            catch (Throwable t) {
582                                    ExportImportLifecycleManager.fireExportImportLifecycleEvent(
583                                            ExportImportLifecycleConstants.EVENT_PORTLET_EXPORT_FAILED,
584                                            PortletDataContextFactoryUtil.clonePortletDataContext(
585                                                    portletDataContext),
586                                            t);
587    
588                                    throw t;
589                            }
590                    }
591    
592                    portletDataContext.setScopeGroupId(previousScopeGroupId);
593    
594                    _portletExporter.exportAssetLinks(portletDataContext);
595                    _portletExporter.exportAssetTags(portletDataContext);
596                    _portletExporter.exportExpandoTables(portletDataContext);
597                    _portletExporter.exportLocks(portletDataContext);
598    
599                    _deletionSystemEventExporter.exportDeletionSystemEvents(
600                            portletDataContext);
601    
602                    if (exportPermissions) {
603                            _permissionExporter.exportPortletDataPermissions(
604                                    portletDataContext);
605                    }
606    
607                    ExportImportHelperUtil.writeManifestSummary(
608                            document, portletDataContext.getManifestSummary());
609    
610                    if (_log.isInfoEnabled()) {
611                            _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
612                    }
613    
614                    boolean updateLastPublishDate = MapUtil.getBoolean(
615                            portletDataContext.getParameterMap(),
616                            PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);
617    
618                    if (updateLastPublishDate) {
619                            TransactionCommitCallbackRegistryUtil.registerCallback(
620                                    new UpdateLayoutSetLastPublishDateCallable(
621                                            portletDataContext.getDateRange(),
622                                            portletDataContext.getGroupId(),
623                                            portletDataContext.isPrivateLayout()));
624                    }
625    
626                    portletDataContext.addZipEntry(
627                            "/manifest.xml", document.formattedString());
628    
629                    ZipWriter zipWriter = portletDataContext.getZipWriter();
630    
631                    return zipWriter.getFile();
632            }
633    
634            protected void exportLayout(
635                            PortletDataContext portletDataContext, long[] layoutIds,
636                            Map<String, Object[]> portletIds, Layout layout)
637                    throws Exception {
638    
639                    if (!ArrayUtil.contains(layoutIds, layout.getLayoutId())) {
640                            Element layoutElement = portletDataContext.getExportDataElement(
641                                    layout);
642    
643                            layoutElement.addAttribute(Constants.ACTION, Constants.SKIP);
644    
645                            return;
646                    }
647    
648                    boolean exportLAR = MapUtil.getBoolean(
649                            portletDataContext.getParameterMap(), "exportLAR");
650    
651                    if (!exportLAR && LayoutStagingUtil.isBranchingLayout(layout)) {
652                            long layoutSetBranchId = MapUtil.getLong(
653                                    portletDataContext.getParameterMap(), "layoutSetBranchId");
654    
655                            if (layoutSetBranchId <= 0) {
656                                    return;
657                            }
658    
659                            LayoutRevision layoutRevision =
660                                    LayoutRevisionLocalServiceUtil.fetchLayoutRevision(
661                                            layoutSetBranchId, true, layout.getPlid());
662    
663                            if (layoutRevision == null) {
664                                    return;
665                            }
666    
667                            LayoutStagingHandler layoutStagingHandler =
668                                    LayoutStagingUtil.getLayoutStagingHandler(layout);
669    
670                            layoutStagingHandler.setLayoutRevision(layoutRevision);
671                    }
672    
673                    StagedModelDataHandlerUtil.exportStagedModel(
674                            portletDataContext, layout);
675    
676                    if (!layout.isSupportsEmbeddedPortlets()) {
677    
678                            // Only portlet type layouts support page scoping
679    
680                            return;
681                    }
682    
683                    LayoutTypePortlet layoutTypePortlet =
684                            (LayoutTypePortlet)layout.getLayoutType();
685    
686                    // The getAllPortlets method returns all effective nonsystem portlets
687                    // for any layout type, including embedded portlets, or in the case of
688                    // panel type layout, selected portlets
689    
690                    for (Portlet portlet : layoutTypePortlet.getAllPortlets(false)) {
691                            String portletId = portlet.getPortletId();
692    
693                            Settings portletInstanceSettings =
694                                    SettingsFactoryUtil.getPortletInstanceSettings(
695                                            layout, portletId);
696    
697                            String scopeType = portletInstanceSettings.getValue(
698                                    "lfrScopeType", null);
699                            String scopeLayoutUuid = portletInstanceSettings.getValue(
700                                    "lfrScopeLayoutUuid", null);
701    
702                            long scopeGroupId = portletDataContext.getScopeGroupId();
703    
704                            if (Validator.isNotNull(scopeType)) {
705                                    Group scopeGroup = null;
706    
707                                    if (scopeType.equals("company")) {
708                                            scopeGroup = GroupLocalServiceUtil.getCompanyGroup(
709                                                    layout.getCompanyId());
710                                    }
711                                    else if (scopeType.equals("layout")) {
712                                            Layout scopeLayout = null;
713    
714                                            scopeLayout =
715                                                    LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
716                                                            scopeLayoutUuid, portletDataContext.getGroupId(),
717                                                            portletDataContext.isPrivateLayout());
718    
719                                            if (scopeLayout == null) {
720                                                    continue;
721                                            }
722    
723                                            scopeGroup = scopeLayout.getScopeGroup();
724                                    }
725                                    else {
726                                            throw new IllegalArgumentException(
727                                                    "Scope type " + scopeType + " is invalid");
728                                    }
729    
730                                    if (scopeGroup != null) {
731                                            scopeGroupId = scopeGroup.getGroupId();
732                                    }
733                            }
734    
735                            String key = PortletPermissionUtil.getPrimaryKey(
736                                    layout.getPlid(), portletId);
737    
738                            portletIds.put(
739                                    key,
740                                    new Object[] {
741                                            portletId, layout.getPlid(), scopeGroupId, scopeType,
742                                            scopeLayoutUuid
743                                    }
744                            );
745                    }
746            }
747    
748            protected PortletDataContext getPortletDataContext(
749                            long groupId, boolean privateLayout,
750                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
751                    throws PortalException {
752    
753                    Group group = GroupLocalServiceUtil.getGroup(groupId);
754    
755                    PortletDataContext portletDataContext =
756                            PortletDataContextFactoryUtil.createExportPortletDataContext(
757                                    group.getCompanyId(), groupId, parameterMap, startDate, endDate,
758                                    ZipWriterFactoryUtil.getZipWriter());
759    
760                    portletDataContext.setPrivateLayout(privateLayout);
761    
762                    return portletDataContext;
763            }
764    
765            private LayoutExporter() {
766                    XStreamAliasRegistryUtil.register(LayoutImpl.class, "Layout");
767            }
768    
769            private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
770    
771            private static LayoutExporter _instance = new LayoutExporter();
772    
773            private DeletionSystemEventExporter _deletionSystemEventExporter =
774                    DeletionSystemEventExporter.getInstance();
775            private PermissionExporter _permissionExporter =
776                    PermissionExporter.getInstance();
777            private PortletExporter _portletExporter = PortletExporter.getInstance();
778            private ThemeExporter _themeExporter = ThemeExporter.getInstance();
779    
780            private class UpdateLayoutSetLastPublishDateCallable
781                    implements Callable<Void> {
782    
783                    public UpdateLayoutSetLastPublishDateCallable(
784                            DateRange dateRange, long groupId, boolean privateLayout) {
785    
786                            _dateRange = dateRange;
787                            _groupId = groupId;
788                            _privateLayout = privateLayout;
789                    }
790    
791                    @Override
792                    public Void call() throws PortalException {
793                            Group group = GroupLocalServiceUtil.getGroup(_groupId);
794    
795                            if (group.isStagedRemotely()) {
796                                    return null;
797                            }
798    
799                            Date endDate = null;
800    
801                            if (_dateRange != null) {
802                                    endDate = _dateRange.getEndDate();
803                            }
804    
805                            if (ExportImportThreadLocal.isStagingInProcess() &&
806                                    group.hasStagingGroup()) {
807    
808                                    Group stagingGroup = group.getStagingGroup();
809    
810                                    ExportImportDateUtil.updateLastPublishDate(
811                                            stagingGroup.getGroupId(), _privateLayout, _dateRange,
812                                            endDate);
813                            }
814                            else {
815                                    ExportImportDateUtil.updateLastPublishDate(
816                                            _groupId, _privateLayout, _dateRange, endDate);
817                            }
818    
819                            return null;
820                    }
821    
822                    private final DateRange _dateRange;
823                    private final long _groupId;
824                    private final boolean _privateLayout;
825    
826            }
827    
828    }