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