001    /**
002     * Copyright (c) 2000-2010 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.NoSuchLayoutException;
018    import com.liferay.portal.kernel.lar.PortletDataContext;
019    import com.liferay.portal.kernel.lar.PortletDataHandler;
020    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.servlet.ServletContextPool;
024    import com.liferay.portal.kernel.util.FileUtil;
025    import com.liferay.portal.kernel.util.GetterUtil;
026    import com.liferay.portal.kernel.util.MapUtil;
027    import com.liferay.portal.kernel.util.ReleaseInfo;
028    import com.liferay.portal.kernel.util.StringBundler;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.Time;
032    import com.liferay.portal.kernel.util.UnicodeProperties;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.xml.Document;
035    import com.liferay.portal.kernel.xml.Element;
036    import com.liferay.portal.kernel.xml.SAXReaderUtil;
037    import com.liferay.portal.kernel.zip.ZipWriter;
038    import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
039    import com.liferay.portal.model.Group;
040    import com.liferay.portal.model.Image;
041    import com.liferay.portal.model.Layout;
042    import com.liferay.portal.model.LayoutSet;
043    import com.liferay.portal.model.LayoutTypePortlet;
044    import com.liferay.portal.model.Portlet;
045    import com.liferay.portal.model.PortletConstants;
046    import com.liferay.portal.model.Theme;
047    import com.liferay.portal.service.ImageLocalServiceUtil;
048    import com.liferay.portal.service.LayoutLocalServiceUtil;
049    import com.liferay.portal.service.LayoutSetLocalServiceUtil;
050    import com.liferay.portal.service.PortletLocalServiceUtil;
051    import com.liferay.portal.service.UserLocalServiceUtil;
052    import com.liferay.portal.service.permission.PortletPermissionUtil;
053    import com.liferay.portal.service.persistence.LayoutUtil;
054    import com.liferay.portal.theme.ThemeLoader;
055    import com.liferay.portal.theme.ThemeLoaderFactory;
056    import com.liferay.portal.util.ContentUtil;
057    import com.liferay.portal.util.PortletKeys;
058    import com.liferay.portal.util.PropsValues;
059    import com.liferay.portlet.PortletPreferencesFactoryUtil;
060    import com.liferay.portlet.asset.model.AssetCategory;
061    import com.liferay.portlet.asset.model.AssetVocabulary;
062    import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
063    import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
064    
065    import java.io.File;
066    
067    import java.util.Date;
068    import java.util.HashSet;
069    import java.util.Iterator;
070    import java.util.LinkedHashMap;
071    import java.util.List;
072    import java.util.Map;
073    
074    import javax.servlet.ServletContext;
075    
076    import org.apache.commons.lang.time.StopWatch;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Joel Kozikowski
081     * @author Charles May
082     * @author Raymond Augé
083     * @author Jorge Ferrer
084     * @author Bruno Farache
085     * @author Karthik Sudarshan
086     * @author Zsigmond Rab
087     * @author Douglas Wong
088     */
089    public class LayoutExporter {
090    
091            public static final String SAME_GROUP_FRIENDLY_URL =
092                    "/[$SAME_GROUP_FRIENDLY_URL$]";
093    
094            public static List<Portlet> getAlwaysExportablePortlets(long companyId)
095                    throws Exception {
096    
097                    List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
098    
099                    Iterator<Portlet> itr = portlets.iterator();
100    
101                    while (itr.hasNext()) {
102                            Portlet portlet = itr.next();
103    
104                            if (!portlet.isActive()) {
105                                    itr.remove();
106    
107                                    continue;
108                            }
109    
110                            PortletDataHandler portletDataHandler =
111                                    portlet.getPortletDataHandlerInstance();
112    
113                            if ((portletDataHandler == null) ||
114                                    (!portletDataHandler.isAlwaysExportable())) {
115    
116                                    itr.remove();
117                            }
118                    }
119    
120                    return portlets;
121            }
122    
123            public static void updateLastPublishDate(
124                            LayoutSet layoutSet, long lastPublishDate)
125                    throws Exception {
126    
127                    UnicodeProperties settingsProperties =
128                            layoutSet.getSettingsProperties();
129    
130                    if (lastPublishDate <= 0) {
131                            settingsProperties.remove("last-publish-date");
132                    }
133                    else {
134                            settingsProperties.setProperty(
135                                    "last-publish-date", String.valueOf(lastPublishDate));
136                    }
137    
138                    LayoutSetLocalServiceUtil.updateSettings(
139                            layoutSet.getGroupId(), layoutSet.isPrivateLayout(),
140                            settingsProperties.toString());
141            }
142    
143            public byte[] exportLayouts(
144                            long groupId, boolean privateLayout, long[] layoutIds,
145                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
146                    throws Exception {
147    
148                    File file = exportLayoutsAsFile(
149                            groupId, privateLayout, layoutIds, parameterMap, startDate,
150                            endDate);
151    
152                    try {
153                            return FileUtil.getBytes(file);
154                    }
155                    finally {
156                            file.delete();
157                    }
158            }
159    
160            public File exportLayoutsAsFile(
161                            long groupId, boolean privateLayout, long[] layoutIds,
162                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
163                    throws Exception {
164    
165                    boolean exportCategories = MapUtil.getBoolean(
166                            parameterMap, PortletDataHandlerKeys.CATEGORIES);
167                    boolean exportIgnoreLastPublishDate = MapUtil.getBoolean(
168                            parameterMap, PortletDataHandlerKeys.IGNORE_LAST_PUBLISH_DATE);
169                    boolean exportPermissions = MapUtil.getBoolean(
170                            parameterMap, PortletDataHandlerKeys.PERMISSIONS);
171                    boolean exportUserPermissions = MapUtil.getBoolean(
172                            parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
173                    boolean exportPortletArchivedSetups = MapUtil.getBoolean(
174                            parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
175                    boolean exportPortletUserPreferences = MapUtil.getBoolean(
176                            parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
177                    boolean exportTheme = MapUtil.getBoolean(
178                            parameterMap, PortletDataHandlerKeys.THEME);
179    
180                    if (_log.isDebugEnabled()) {
181                            _log.debug("Export categories " + exportCategories);
182                            _log.debug("Export permissions " + exportPermissions);
183                            _log.debug("Export user permissions " + exportUserPermissions);
184                            _log.debug(
185                                    "Export portlet archived setups " +
186                                            exportPortletArchivedSetups);
187                            _log.debug(
188                                    "Export portlet user preferences " +
189                                            exportPortletUserPreferences);
190                            _log.debug("Export theme " + exportTheme);
191                    }
192    
193                    long lastPublishDate = System.currentTimeMillis();
194    
195                    if (endDate != null) {
196                            lastPublishDate = endDate.getTime();
197                    }
198    
199                    if (exportIgnoreLastPublishDate) {
200                            endDate = null;
201                            startDate = null;
202                    }
203    
204                    StopWatch stopWatch = null;
205    
206                    if (_log.isInfoEnabled()) {
207                            stopWatch = new StopWatch();
208    
209                            stopWatch.start();
210                    }
211    
212                    LayoutCache layoutCache = new LayoutCache();
213    
214                    LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
215                            groupId, privateLayout);
216    
217                    long companyId = layoutSet.getCompanyId();
218                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
219    
220                    ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
221    
222                    PortletDataContext context = new PortletDataContextImpl(
223                            companyId, groupId, parameterMap, new HashSet<String>(), startDate,
224                            endDate, zipWriter);
225    
226                    context.setPortetDataContextListener(
227                            new PortletDataContextListenerImpl(context));
228    
229                    // Build compatibility
230    
231                    Document document = SAXReaderUtil.createDocument();
232    
233                    Element rootElement = document.addElement("root");
234    
235                    Element headerElement = rootElement.addElement("header");
236    
237                    headerElement.addAttribute(
238                            "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
239                    headerElement.addAttribute("export-date", Time.getRFC822());
240    
241                    if (context.hasDateRange()) {
242                            headerElement.addAttribute(
243                                    "start-date", String.valueOf(context.getStartDate()));
244                            headerElement.addAttribute(
245                                    "end-date", String.valueOf(context.getEndDate()));
246                    }
247    
248                    headerElement.addAttribute("type", "layout-set");
249                    headerElement.addAttribute("group-id", String.valueOf(groupId));
250                    headerElement.addAttribute(
251                            "private-layout", String.valueOf(privateLayout));
252                    headerElement.addAttribute("theme-id", layoutSet.getThemeId());
253                    headerElement.addAttribute(
254                            "color-scheme-id", layoutSet.getColorSchemeId());
255    
256                    // Layout configuration portlet
257    
258                    Portlet layoutConfigurationPortlet =
259                            PortletLocalServiceUtil.getPortletById(
260                                    context.getCompanyId(), PortletKeys.LAYOUT_CONFIGURATION);
261    
262                    // Layouts
263    
264                    Map<String, Object[]> portletIds =
265                            new LinkedHashMap<String, Object[]>();
266    
267                    List<Layout> layouts = null;
268    
269                    if ((layoutIds == null) || (layoutIds.length == 0)) {
270                            layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
271                    }
272                    else {
273                            layouts = LayoutLocalServiceUtil.getLayouts(
274                                    groupId, privateLayout, layoutIds);
275                    }
276    
277                    Layout firstLayout = layouts.get(0);
278    
279                    List<Portlet> portlets = getAlwaysExportablePortlets(companyId);
280    
281                    for (Portlet portlet : portlets) {
282                            String portletId = portlet.getRootPortletId();
283    
284                            if (portlet.isScopeable() && firstLayout.hasScopeGroup()) {
285                                    String key = PortletPermissionUtil.getPrimaryKey(
286                                            firstLayout.getPlid(), portletId);
287    
288                                    portletIds.put(
289                                            key,
290                                            new Object[] {
291                                                    portletId, firstLayout.getPlid(),
292                                                    firstLayout.getScopeGroup().getGroupId(),
293                                                    firstLayout.getUuid()
294                                            }
295                                    );
296                            }
297                            else {
298                                    String key = PortletPermissionUtil.getPrimaryKey(
299                                            0, portletId);
300    
301                                    if (portletIds.get(key) == null) {
302                                            portletIds.put(
303                                                    key,
304                                                    new Object[] {
305                                                            portletId, firstLayout.getPlid(), groupId,
306                                                            StringPool.BLANK
307                                                    }
308                                            );
309                                    }
310                            }
311                    }
312    
313                    Element layoutsElement = rootElement.addElement("layouts");
314    
315                    for (Layout layout : layouts) {
316                            exportLayout(
317                                    context, layoutConfigurationPortlet, layoutCache, portletIds,
318                                    exportPermissions, exportUserPermissions, layout,
319                                    layoutsElement);
320                    }
321    
322                    if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
323                            Element rolesElement = rootElement.addElement("roles");
324    
325                            // Layout roles
326    
327                            if (exportPermissions) {
328                                    _permissionExporter.exportLayoutRoles(
329                                            layoutCache, companyId, groupId, rolesElement);
330                            }
331                    }
332    
333                    // Export portlets
334    
335                    long previousScopeGroupId = context.getScopeGroupId();
336    
337                    Element portletsElement = rootElement.addElement("portlets");
338    
339                    for (Map.Entry<String, Object[]> portletIdsEntry :
340                                    portletIds.entrySet()) {
341    
342                            String portletId = (String)portletIdsEntry.getValue()[0];
343                            long plid = (Long)portletIdsEntry.getValue()[1];
344                            long scopeGroupId = (Long)portletIdsEntry.getValue()[2];
345                            String scopeLayoutUuid = (String)portletIdsEntry.getValue()[3];
346    
347                            Layout layout = LayoutUtil.findByPrimaryKey(plid);
348    
349                            context.setPlid(layout.getPlid());
350                            context.setOldPlid(layout.getPlid());
351                            context.setScopeGroupId(scopeGroupId);
352                            context.setScopeLayoutUuid(scopeLayoutUuid);
353    
354                            boolean[] exportPortletControls = getExportPortletControls(
355                                    companyId, portletId, context, parameterMap);
356    
357                            _portletExporter.exportPortlet(
358                                    context, layoutCache, portletId, layout, portletsElement,
359                                    defaultUserId, exportPermissions, exportPortletArchivedSetups,
360                                    exportPortletControls[0], exportPortletControls[1],
361                                    exportPortletUserPreferences, exportUserPermissions);
362                    }
363    
364                    context.setScopeGroupId(previousScopeGroupId);
365    
366                    // Categories
367    
368                    if (exportCategories) {
369                            exportCategories(context);
370                    }
371    
372                    // Comments
373    
374                    _portletExporter.exportComments(context, rootElement);
375    
376                    // Locks
377    
378                    _portletExporter.exportLocks(context, rootElement);
379    
380                    // Portlet data permissions
381    
382                    if (exportPermissions) {
383                            _permissionExporter.exportPortletDataPermissions(context);
384                    }
385    
386                    // Ratings
387    
388                    _portletExporter.exportRatings(context, rootElement);
389    
390                    // Tags
391    
392                    _portletExporter.exportTags(context, rootElement);
393    
394                    // Look and feel
395    
396                    if (exportTheme) {
397                            exportTheme(layoutSet, zipWriter);
398                    }
399    
400                    // Log
401    
402                    if (_log.isInfoEnabled()) {
403                            if (stopWatch != null) {
404                                    _log.info(
405                                            "Exporting layouts takes " + stopWatch.getTime() + " ms");
406                            }
407                            else {
408                                    _log.info("Exporting layouts is finished");
409                            }
410                    }
411    
412                    // Zip
413    
414                    context.addZipEntry("/manifest.xml", document.formattedString());
415    
416                    try {
417                            return zipWriter.getFile();
418                    }
419                    finally {
420                            updateLastPublishDate(layoutSet, lastPublishDate);
421                    }
422            }
423    
424            protected void exportCategories(PortletDataContext context)
425                    throws Exception {
426    
427                    Document document = SAXReaderUtil.createDocument();
428    
429                    Element rootElement = document.addElement("categories-hierarchy");
430    
431                    Element vocabulariesElement = rootElement.addElement("vocabularies");
432    
433                    List<AssetVocabulary> assetVocabularies =
434                            AssetVocabularyLocalServiceUtil.getGroupVocabularies(
435                                    context.getGroupId());
436    
437                    for (AssetVocabulary assetVocabulary : assetVocabularies) {
438                            _portletExporter.exportVocabulary(
439                                    context, vocabulariesElement, assetVocabulary);
440                    }
441    
442                    Element categoriesElement = rootElement.addElement("categories");
443    
444                    List<AssetCategory> assetCategories =
445                            AssetCategoryUtil.findByGroupId(context.getGroupId());
446    
447                    for (AssetCategory assetCategory : assetCategories) {
448                            _portletExporter.exportCategory(
449                                    context, vocabulariesElement, categoriesElement, assetCategory);
450                    }
451    
452                    _portletExporter.exportCategories(context, rootElement);
453    
454                    context.addZipEntry(
455                            context.getRootPath() + "/categories-hierarchy.xml",
456                            document.formattedString());
457            }
458    
459            protected void exportLayout(
460                            PortletDataContext context, Portlet layoutConfigurationPortlet,
461                            LayoutCache layoutCache, Map<String, Object[]> portletIds,
462                            boolean exportPermissions, boolean exportUserPermissions,
463                            Layout layout, Element layoutsElement)
464                    throws Exception {
465    
466                    String path = context.getLayoutPath(
467                            layout.getLayoutId()) + "/layout.xml";
468    
469                    if (!context.isPathNotProcessed(path)) {
470                            return;
471                    }
472    
473                    Element layoutElement = layoutsElement.addElement("layout");
474    
475                    layoutElement.addAttribute(
476                            "layout-uuid", layout.getUuid());
477                    layoutElement.addAttribute(
478                            "layout-id", String.valueOf(layout.getLayoutId()));
479    
480                    boolean deleteLayout = MapUtil.getBoolean(
481                            context.getParameterMap(), "delete_" + layout.getPlid());
482    
483                    if (deleteLayout) {
484                            layoutElement.addAttribute("delete", String.valueOf(true));
485    
486                            return;
487                    }
488    
489                    context.setPlid(layout.getPlid());
490    
491                    if (layout.isIconImage()) {
492                            Image image = ImageLocalServiceUtil.getImage(
493                                    layout.getIconImageId());
494    
495                            if (image != null) {
496                                    String iconPath = getLayoutIconPath(context, layout, image);
497    
498                                    layoutElement.addElement("icon-image-path").addText(iconPath);
499    
500                                    context.addZipEntry(iconPath, image.getTextObj());
501                            }
502                    }
503    
504                    _portletExporter.exportPortletData(
505                            context, layoutConfigurationPortlet, layout, null, layoutElement);
506    
507                    // Layout permissions
508    
509                    if (exportPermissions) {
510                            _permissionExporter.exportLayoutPermissions(
511                                    context, layoutCache, context.getCompanyId(),
512                                    context.getScopeGroupId(), layout, layoutElement,
513                                    exportUserPermissions);
514                    }
515    
516                    if (layout.isTypePortlet()) {
517                            LayoutTypePortlet layoutTypePortlet =
518                                    (LayoutTypePortlet)layout.getLayoutType();
519    
520                            for (String portletId : layoutTypePortlet.getPortletIds()) {
521                                    javax.portlet.PortletPreferences jxPreferences =
522                                            PortletPreferencesFactoryUtil.getLayoutPortletSetup(
523                                                    layout, portletId);
524    
525                                    String scopeLayoutUuid = GetterUtil.getString(
526                                            jxPreferences.getValue("lfr-scope-layout-uuid", null));
527    
528                                    long scopeGroupId = context.getScopeGroupId();
529    
530                                    if (Validator.isNotNull(scopeLayoutUuid)) {
531                                            Layout scopeLayout =
532                                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
533                                                            scopeLayoutUuid, scopeGroupId);
534    
535                                            Group scopeGroup = scopeLayout.getScopeGroup();
536    
537                                            if (scopeGroup != null) {
538                                                    scopeGroupId = scopeGroup.getGroupId();
539                                            }
540                                    }
541    
542                                    String key = PortletPermissionUtil.getPrimaryKey(
543                                            layout.getPlid(), portletId);
544    
545                                    portletIds.put(
546                                            key,
547                                            new Object[] {
548                                                    portletId, layout.getPlid(), scopeGroupId,
549                                                    scopeLayoutUuid
550                                            }
551                                    );
552                            }
553                    }
554                    else if (layout.isTypeLinkToLayout()) {
555                            UnicodeProperties typeSettingsProperties =
556                                    layout.getTypeSettingsProperties();
557    
558                            long linkToLayoutId = GetterUtil.getLong(
559                                    typeSettingsProperties.getProperty(
560                                            "linkToLayoutId", StringPool.BLANK));
561    
562                            if (linkToLayoutId > 0) {
563                                    try {
564                                            Layout linkedToLayout = LayoutUtil.findByG_P_L(
565                                                    context.getScopeGroupId(), layout.isPrivateLayout(),
566                                                    linkToLayoutId);
567    
568                                            exportLayout(
569                                                    context, layoutConfigurationPortlet, layoutCache,
570                                                    portletIds,     exportPermissions, exportUserPermissions,
571                                                    linkedToLayout, layoutsElement);
572                                    }
573                                    catch (NoSuchLayoutException nsle) {
574                                    }
575                            }
576                    }
577    
578                    fixTypeSettings(layout);
579    
580                    layoutElement.addAttribute("path", path);
581    
582                    context.addZipEntry(path, layout);
583            }
584    
585            protected void exportTheme(LayoutSet layoutSet, ZipWriter zipWriter)
586                    throws Exception {
587    
588                    Theme theme = layoutSet.getTheme();
589    
590                    String lookAndFeelXML = ContentUtil.get(
591                            "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
592    
593                    lookAndFeelXML = StringUtil.replace(
594                            lookAndFeelXML,
595                            new String[] {
596                                    "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
597                            },
598                            new String[] {
599                                    theme.getTemplateExtension(), theme.getVirtualPath()
600                            }
601                    );
602    
603                    String servletContextName = theme.getServletContextName();
604    
605                    ServletContext servletContext = ServletContextPool.get(
606                            servletContextName);
607    
608                    if (servletContext == null) {
609                            if (_log.isWarnEnabled()) {
610                                    _log.warn(
611                                            "Servlet context not found for theme " +
612                                                    theme.getThemeId());
613                            }
614    
615                            return;
616                    }
617    
618                    File themeZip = new File(zipWriter.getPath() + "/theme.zip");
619    
620                    ZipWriter themeZipWriter = ZipWriterFactoryUtil.getZipWriter(themeZip);
621    
622                    themeZipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
623    
624                    File cssPath = null;
625                    File imagesPath = null;
626                    File javaScriptPath = null;
627                    File templatesPath = null;
628    
629                    if (!theme.isLoadFromServletContext()) {
630                            ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
631                                    servletContextName);
632    
633                            if (themeLoader == null) {
634                                    _log.error(
635                                            servletContextName + " does not map to a theme loader");
636                            }
637                            else {
638                                    String realPath =
639                                            themeLoader.getFileStorage().getPath() + StringPool.SLASH +
640                                                    theme.getName();
641    
642                                    cssPath = new File(realPath + "/css");
643                                    imagesPath = new File(realPath + "/images");
644                                    javaScriptPath = new File(realPath + "/javascript");
645                                    templatesPath = new File(realPath + "/templates");
646                            }
647                    }
648                    else {
649                            cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
650                            imagesPath = new File(
651                                    servletContext.getRealPath(theme.getImagesPath()));
652                            javaScriptPath = new File(
653                                    servletContext.getRealPath(theme.getJavaScriptPath()));
654                            templatesPath = new File(
655                                    servletContext.getRealPath(theme.getTemplatesPath()));
656                    }
657    
658                    exportThemeFiles("css", cssPath, themeZipWriter);
659                    exportThemeFiles("images", imagesPath, themeZipWriter);
660                    exportThemeFiles("javascript", javaScriptPath, themeZipWriter);
661                    exportThemeFiles("templates", templatesPath, themeZipWriter);
662            }
663    
664            protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
665                    throws Exception {
666    
667                    if ((dir == null) || (!dir.exists())) {
668                            return;
669                    }
670    
671                    File[] files = dir.listFiles();
672    
673                    for (File file : files) {
674                            if (file.isDirectory()) {
675                                    exportThemeFiles(
676                                            path + StringPool.SLASH + file.getName(), file, zipWriter);
677                            }
678                            else {
679                                    zipWriter.addEntry(
680                                            path + StringPool.SLASH + file.getName(),
681                                            FileUtil.getBytes(file));
682                            }
683                    }
684            }
685    
686            protected void fixTypeSettings(Layout layout)
687                    throws Exception {
688    
689                    if (!layout.isTypeURL()) {
690                            return;
691                    }
692    
693                    UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
694    
695                    String url = GetterUtil.getString(typeSettings.getProperty("url"));
696    
697                    String friendlyURLPrivateGroupPath =
698                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
699                    String friendlyURLPrivateUserPath =
700                            PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
701                    String friendlyURLPublicPath =
702                            PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
703    
704                    if (!url.startsWith(friendlyURLPrivateGroupPath) &&
705                            !url.startsWith(friendlyURLPrivateUserPath) &&
706                            !url.startsWith(friendlyURLPublicPath)) {
707    
708                            return;
709                    }
710    
711                    int x = url.indexOf(StringPool.SLASH, 1);
712    
713                    if (x == -1) {
714                            return;
715                    }
716    
717                    int y = url.indexOf(StringPool.SLASH, x + 1);
718    
719                    if (y == -1) {
720                            return;
721                    }
722    
723                    String friendlyURL = url.substring(x, y);
724                    String groupFriendlyURL = layout.getGroup().getFriendlyURL();
725    
726                    if (!friendlyURL.equals(groupFriendlyURL)) {
727                            return;
728                    }
729    
730                    typeSettings.setProperty(
731                            "url",
732                            url.substring(0, x) + SAME_GROUP_FRIENDLY_URL + url.substring(y));
733            }
734    
735            protected boolean[] getExportPortletControls(
736                            long companyId, String portletId, PortletDataContext context,
737                            Map<String, String[]> parameterMap)
738                    throws Exception {
739    
740                    boolean exportPortletData = MapUtil.getBoolean(
741                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
742                    boolean exportPortletDataAll = MapUtil.getBoolean(
743                            parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
744                    boolean exportPortletSetup = MapUtil.getBoolean(
745                            parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
746    
747                    if (_log.isDebugEnabled()) {
748                            _log.debug("Export portlet data " + exportPortletData);
749                            _log.debug("Export all portlet data " + exportPortletDataAll);
750                            _log.debug("Export portlet setup " + exportPortletSetup);
751                    }
752    
753                    boolean exportCurPortletData = exportPortletData;
754                    boolean exportCurPortletSetup = exportPortletSetup;
755    
756                    // If PORTLET_DATA_ALL is true, this means that staging has just been
757                    // activated and all data and setup must be exported. There is no
758                    // portlet export control to check in this case.
759    
760                    if (exportPortletDataAll) {
761                            exportCurPortletData = true;
762                            exportCurPortletSetup = true;
763                    }
764                    else {
765                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
766                                    companyId, portletId);
767    
768                            if (portlet != null) {
769                                    String portletDataHandlerClass =
770                                            portlet.getPortletDataHandlerClass();
771    
772                                    // Checking if the portlet has a data handler, if it doesn't,
773                                    // the default values are the ones set in PORTLET_DATA and
774                                    // PORTLET_SETUP. If it has a data handler, iterate over each
775                                    // portlet export control.
776    
777                                    if (portletDataHandlerClass != null) {
778                                            String rootPortletId = PortletConstants.getRootPortletId(
779                                                    portletId);
780    
781                                            // PORTLET_DATA and the PORTLET_DATA for this specific
782                                            // data handler must be true
783    
784                                            exportCurPortletData =
785                                                    exportPortletData &&
786                                                    MapUtil.getBoolean(
787                                                            parameterMap,
788                                                            PortletDataHandlerKeys.PORTLET_DATA +
789                                                                    StringPool.UNDERLINE + rootPortletId);
790    
791                                            // PORTLET_DATA and the PORTLET_SETUP for this specific
792                                            // data handler must be true
793    
794                                            exportCurPortletSetup =
795                                                    exportPortletData &&
796                                                    MapUtil.getBoolean(
797                                                            parameterMap,
798                                                            PortletDataHandlerKeys.PORTLET_SETUP +
799                                                                    StringPool.UNDERLINE + rootPortletId);
800                                    }
801                            }
802                    }
803    
804                    return new boolean[] {exportCurPortletData, exportCurPortletSetup};
805            }
806    
807            protected String getLayoutIconPath(
808                    PortletDataContext context, Layout layout, Image image) {
809    
810                    StringBundler sb = new StringBundler(5);
811    
812                    sb.append(context.getLayoutPath(layout.getLayoutId()));
813                    sb.append("/icons/");
814                    sb.append(image.getImageId());
815                    sb.append(StringPool.PERIOD);
816                    sb.append(image.getType());
817    
818                    return sb.toString();
819            }
820    
821            private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
822    
823            private PermissionExporter _permissionExporter = new PermissionExporter();
824            private PortletExporter _portletExporter = new PortletExporter();
825    
826    }