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