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