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