1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.lar;
16  
17  import com.liferay.portal.kernel.exception.PortalException;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.log.Log;
20  import com.liferay.portal.kernel.log.LogFactoryUtil;
21  import com.liferay.portal.kernel.util.FileUtil;
22  import com.liferay.portal.kernel.util.GetterUtil;
23  import com.liferay.portal.kernel.util.ListUtil;
24  import com.liferay.portal.kernel.util.MapUtil;
25  import com.liferay.portal.kernel.util.ReleaseInfo;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.util.Time;
30  import com.liferay.portal.kernel.util.UnicodeProperties;
31  import com.liferay.portal.kernel.xml.Document;
32  import com.liferay.portal.kernel.xml.Element;
33  import com.liferay.portal.kernel.xml.SAXReaderUtil;
34  import com.liferay.portal.kernel.zip.ZipWriter;
35  import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
36  import com.liferay.portal.model.Group;
37  import com.liferay.portal.model.GroupConstants;
38  import com.liferay.portal.model.Image;
39  import com.liferay.portal.model.Layout;
40  import com.liferay.portal.model.LayoutConstants;
41  import com.liferay.portal.model.LayoutSet;
42  import com.liferay.portal.model.LayoutTypePortlet;
43  import com.liferay.portal.model.Portlet;
44  import com.liferay.portal.model.PortletConstants;
45  import com.liferay.portal.model.Resource;
46  import com.liferay.portal.model.ResourceConstants;
47  import com.liferay.portal.model.Theme;
48  import com.liferay.portal.service.GroupLocalServiceUtil;
49  import com.liferay.portal.service.ImageLocalServiceUtil;
50  import com.liferay.portal.service.LayoutLocalServiceUtil;
51  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
52  import com.liferay.portal.service.PortletLocalServiceUtil;
53  import com.liferay.portal.service.UserLocalServiceUtil;
54  import com.liferay.portal.service.permission.PortletPermissionUtil;
55  import com.liferay.portal.service.persistence.LayoutUtil;
56  import com.liferay.portal.theme.ThemeLoader;
57  import com.liferay.portal.theme.ThemeLoaderFactory;
58  import com.liferay.portal.util.ContentUtil;
59  import com.liferay.portal.util.PortletKeys;
60  import com.liferay.portal.util.PropsValues;
61  import com.liferay.portal.velocity.VelocityContextPool;
62  import com.liferay.portlet.PortletPreferencesFactoryUtil;
63  import com.liferay.portlet.asset.model.AssetCategory;
64  import com.liferay.portlet.asset.model.AssetCategoryConstants;
65  import com.liferay.portlet.asset.model.AssetVocabulary;
66  import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
67  import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
68  
69  import java.io.File;
70  import java.io.IOException;
71  
72  import java.util.ArrayList;
73  import java.util.Date;
74  import java.util.HashSet;
75  import java.util.Iterator;
76  import java.util.LinkedHashMap;
77  import java.util.List;
78  import java.util.Map;
79  
80  import javax.servlet.ServletContext;
81  
82  import org.apache.commons.lang.time.StopWatch;
83  
84  /**
85   * <a href="LayoutExporter.java.html"><b><i>View Source</i></b></a>
86   *
87   * @author Brian Wing Shun Chan
88   * @author Joel Kozikowski
89   * @author Charles May
90   * @author Raymond Augé
91   * @author Jorge Ferrer
92   * @author Bruno Farache
93   * @author Karthik Sudarshan
94   */
95  public class LayoutExporter {
96  
97      public static final String SAME_GROUP_FRIENDLY_URL =
98          "/[$SAME_GROUP_FRIENDLY_URL$]";
99  
100     public static List<Portlet> getAlwaysExportablePortlets(long companyId)
101         throws SystemException {
102 
103         List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
104 
105         Iterator<Portlet> itr = portlets.iterator();
106 
107         while (itr.hasNext()) {
108             Portlet portlet = itr.next();
109 
110             if (!portlet.isActive()) {
111                 itr.remove();
112 
113                 continue;
114             }
115 
116             PortletDataHandler portletDataHandler =
117                 portlet.getPortletDataHandlerInstance();
118 
119             if ((portletDataHandler == null) ||
120                 (!portletDataHandler.isAlwaysExportable())) {
121 
122                 itr.remove();
123             }
124         }
125 
126         return portlets;
127     }
128 
129     public byte[] exportLayouts(
130             long groupId, boolean privateLayout, long[] layoutIds,
131             Map<String, String[]> parameterMap, Date startDate, Date endDate)
132         throws PortalException, SystemException {
133 
134         File file = exportLayoutsAsFile(
135             groupId, privateLayout, layoutIds, parameterMap, startDate,
136             endDate);
137 
138         try {
139             return FileUtil.getBytes(file);
140         }
141         catch (IOException ioe) {
142             throw new SystemException(ioe);
143         }
144         finally {
145             file.delete();
146         }
147     }
148 
149     public File exportLayoutsAsFile(
150             long groupId, boolean privateLayout, long[] layoutIds,
151             Map<String, String[]> parameterMap, Date startDate, Date endDate)
152         throws PortalException, SystemException {
153 
154         boolean exportCategories = MapUtil.getBoolean(
155             parameterMap, PortletDataHandlerKeys.CATEGORIES);
156         boolean exportPermissions = MapUtil.getBoolean(
157             parameterMap, PortletDataHandlerKeys.PERMISSIONS);
158         boolean exportUserPermissions = MapUtil.getBoolean(
159             parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
160         boolean exportPortletArchivedSetups = MapUtil.getBoolean(
161             parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
162         boolean exportPortletUserPreferences = MapUtil.getBoolean(
163             parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
164         boolean exportTheme = MapUtil.getBoolean(
165             parameterMap, PortletDataHandlerKeys.THEME);
166 
167         if (_log.isDebugEnabled()) {
168             _log.debug("Export categories " + exportCategories);
169             _log.debug("Export permissions " + exportPermissions);
170             _log.debug("Export user permissions " + exportUserPermissions);
171             _log.debug(
172                 "Export portlet archived setups " +
173                     exportPortletArchivedSetups);
174             _log.debug(
175                 "Export portlet user preferences " +
176                     exportPortletUserPreferences);
177             _log.debug("Export theme " + exportTheme);
178         }
179 
180         StopWatch stopWatch = null;
181 
182         if (_log.isInfoEnabled()) {
183             stopWatch = new StopWatch();
184 
185             stopWatch.start();
186         }
187 
188         LayoutCache layoutCache = new LayoutCache();
189 
190         LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
191             groupId, privateLayout);
192 
193         long companyId = layoutSet.getCompanyId();
194         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
195 
196         ZipWriter zipWriter = ZipWriterFactoryUtil.getZipWriter();
197 
198         PortletDataContext context = new PortletDataContextImpl(
199             companyId, groupId, parameterMap, new HashSet<String>(), startDate,
200             endDate, zipWriter);
201 
202         Group guestGroup = GroupLocalServiceUtil.getGroup(
203             companyId, GroupConstants.GUEST);
204 
205         // Build compatibility
206 
207         Document doc = SAXReaderUtil.createDocument();
208 
209         Element root = doc.addElement("root");
210 
211         Element header = root.addElement("header");
212 
213         header.addAttribute(
214             "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
215         header.addAttribute("export-date", Time.getRFC822());
216 
217         if (context.hasDateRange()) {
218             header.addAttribute(
219                 "start-date", String.valueOf(context.getStartDate()));
220             header.addAttribute(
221                 "end-date", String.valueOf(context.getEndDate()));
222         }
223 
224         header.addAttribute("type", "layout-set");
225         header.addAttribute("group-id", String.valueOf(groupId));
226         header.addAttribute("private-layout", String.valueOf(privateLayout));
227         header.addAttribute("theme-id", layoutSet.getThemeId());
228         header.addAttribute("color-scheme-id", layoutSet.getColorSchemeId());
229 
230         // Layout Configuration Portlet
231 
232         Portlet layoutConfigurationPortlet =
233             PortletLocalServiceUtil.getPortletById(
234                 context.getCompanyId(), PortletKeys.LAYOUT_CONFIGURATION);
235 
236         // Layouts
237 
238         Map<String, Object[]> portletIds =
239             new LinkedHashMap<String, Object[]>();
240 
241         List<Layout> layouts = null;
242 
243         if ((layoutIds == null) || (layoutIds.length == 0)) {
244             layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
245         }
246         else {
247             layouts = LayoutLocalServiceUtil.getLayouts(
248                 groupId, privateLayout, layoutIds);
249         }
250 
251         Element layoutsEl = root.addElement("layouts");
252 
253         for (Layout layout : layouts) {
254             boolean deleteLayout = MapUtil.getBoolean(
255                 parameterMap, "delete_" + layout.getPlid());
256 
257             if (deleteLayout) {
258                 Element el = layoutsEl.addElement("layout");
259 
260                 el.addAttribute(
261                     "layout-id", String.valueOf(layout.getLayoutId()));
262                 el.addAttribute("delete", String.valueOf(true));
263 
264                 continue;
265             }
266 
267             fixTypeSettings(layout);
268 
269             context.setPlid(layout.getPlid());
270 
271             Document layoutDoc = SAXReaderUtil.createDocument();
272 
273             Element layoutEl = layoutDoc.addElement("layout");
274 
275             layoutEl.addAttribute("old-plid", String.valueOf(layout.getPlid()));
276             layoutEl.addAttribute(
277                 "layout-id", String.valueOf(layout.getLayoutId()));
278             layoutEl.addElement("parent-layout-id").addText(
279                 String.valueOf(layout.getParentLayoutId()));
280             layoutEl.addElement("name").addCDATA(layout.getName());
281             layoutEl.addElement("title").addCDATA(layout.getTitle());
282             layoutEl.addElement("description").addText(layout.getDescription());
283             layoutEl.addElement("type").addText(layout.getType());
284             layoutEl.addElement("type-settings").addCDATA(
285                 layout.getTypeSettings());
286             layoutEl.addElement("hidden").addText(
287                 String.valueOf(layout.getHidden()));
288             layoutEl.addElement("friendly-url").addText(
289                 layout.getFriendlyURL());
290             layoutEl.addElement("icon-image").addText(
291                 String.valueOf(layout.getIconImage()));
292 
293             if (layout.isIconImage()) {
294                 Image image = ImageLocalServiceUtil.getImage(
295                     layout.getIconImageId());
296 
297                 if (image != null) {
298                     String iconPath = getLayoutIconPath(context, layout, image);
299 
300                     layoutEl.addElement("icon-image-path").addText(
301                         iconPath);
302 
303                     context.addZipEntry(iconPath, image.getTextObj());
304                 }
305             }
306 
307             layoutEl.addElement("theme-id").addText(layout.getThemeId());
308             layoutEl.addElement("color-scheme-id").addText(
309                 layout.getColorSchemeId());
310             layoutEl.addElement("wap-theme-id").addText(layout.getWapThemeId());
311             layoutEl.addElement("wap-color-scheme-id").addText(
312                 layout.getWapColorSchemeId());
313             layoutEl.addElement("css").addCDATA(layout.getCss());
314             layoutEl.addElement("priority").addText(
315                 String.valueOf(layout.getPriority()));
316 
317             // Layout permissions
318 
319             if (exportPermissions) {
320                 Element permissionsEl = layoutEl.addElement("permissions");
321 
322                 String resourceName = Layout.class.getName();
323                 String resourcePrimKey = String.valueOf(layout.getPlid());
324 
325                 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
326                     exportLayoutPermissions_5(
327                         layoutCache, companyId, groupId, resourceName,
328                         resourcePrimKey, permissionsEl);
329                 }
330                 else if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
331                     exportLayoutPermissions_6(
332                         layoutCache, companyId, groupId, resourceName,
333                         resourcePrimKey, permissionsEl);
334                 }
335                 else {
336                     exportLayoutPermissions_4(
337                         layoutCache, companyId, groupId, guestGroup,
338                         resourceName, resourcePrimKey, permissionsEl,
339                         exportUserPermissions);
340                 }
341             }
342 
343             if (layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
344                 LayoutTypePortlet layoutTypePortlet =
345                     (LayoutTypePortlet)layout.getLayoutType();
346 
347                 long scopeGroupId = groupId;
348 
349                 for (String portletId : layoutTypePortlet.getPortletIds()) {
350                     javax.portlet.PortletPreferences jxPreferences =
351                         PortletPreferencesFactoryUtil.getLayoutPortletSetup(
352                             layout, portletId);
353 
354                     long scopeLayoutId = GetterUtil.getLong(
355                         jxPreferences.getValue("lfr-scope-layout-id", null));
356 
357                     if (scopeLayoutId != 0) {
358                         Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
359                             groupId, layout.isPrivateLayout(), scopeLayoutId);
360 
361                         Group scopeGroup = scopeLayout.getScopeGroup();
362 
363                         if (scopeGroup != null) {
364                             scopeGroupId = scopeGroup.getGroupId();
365                         }
366                     }
367 
368                     String key = PortletPermissionUtil.getPrimaryKey(
369                         layout.getPlid(), portletId);
370 
371                     portletIds.put(
372                         key,
373                         new Object[] {
374                             portletId, layout.getPlid(), scopeGroupId,
375                             scopeLayoutId
376                         }
377                     );
378                 }
379             }
380 
381             List<Portlet> portlets = getAlwaysExportablePortlets(
382                 context.getCompanyId());
383 
384             for (Portlet portlet : portlets) {
385                 String portletId = portlet.getRootPortletId();
386 
387                 if (portlet.isScopeable() && layout.hasScopeGroup()) {
388                     String key = PortletPermissionUtil.getPrimaryKey(
389                         layout.getPlid(), portletId);
390 
391                     portletIds.put(
392                         key,
393                         new Object[] {
394                             portletId, layout.getPlid(),
395                             layout.getScopeGroup().getGroupId(),
396                             layout.getLayoutId()
397                         }
398                     );
399                 }
400                 else {
401                     String key = PortletPermissionUtil.getPrimaryKey(
402                         0, portletId);
403 
404                     if (portletIds.get(key) == null) {
405                         portletIds.put(
406                             key,
407                             new Object[] {
408                                 portletId, layout.getPlid(), groupId, 0L
409                             }
410                         );
411                     }
412                 }
413             }
414 
415             String layoutPath = context.getLayoutPath(layout.getLayoutId()) +
416                 "/layout.xml";
417 
418             Element el = layoutsEl.addElement("layout");
419 
420             el.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
421             el.addAttribute("path", layoutPath);
422 
423             _portletExporter.exportPortletData(
424                 context, layoutConfigurationPortlet, layout, null, layoutEl);
425 
426             try {
427                 context.addZipEntry(layoutPath, layoutDoc.formattedString());
428             }
429             catch (IOException ioe) {
430             }
431         }
432 
433         if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
434             Element rolesEl = root.addElement("roles");
435 
436             // Layout roles
437 
438             if (exportPermissions) {
439                 exportLayoutRoles(layoutCache, companyId, groupId, rolesEl);
440             }
441         }
442 
443         // Export Portlets
444 
445         long previousScopeGroupId = context.getScopeGroupId();
446 
447         Element portletsEl = root.addElement("portlets");
448 
449         for (Map.Entry<String, Object[]> portletIdsEntry :
450                 portletIds.entrySet()) {
451 
452             String portletId = (String)portletIdsEntry.getValue()[0];
453             long plid = (Long)portletIdsEntry.getValue()[1];
454             long scopeGroupId = (Long)portletIdsEntry.getValue()[2];
455             long scopeLayoutId = (Long)portletIdsEntry.getValue()[3];
456 
457             Layout layout = LayoutUtil.findByPrimaryKey(plid);
458 
459             context.setPlid(layout.getPlid());
460             context.setOldPlid(layout.getPlid());
461             context.setScopeGroupId(scopeGroupId);
462             context.setScopeLayoutId(scopeLayoutId);
463 
464             boolean[] exportPortletControls = getExportPortletControls(
465                 context.getCompanyId(), portletId, context, parameterMap);
466 
467             _portletExporter.exportPortlet(
468                 context, layoutCache, portletId, layout, portletsEl,
469                 defaultUserId, exportPermissions, exportPortletArchivedSetups,
470                 exportPortletControls[0], exportPortletControls[1],
471                 exportPortletUserPreferences, exportUserPermissions);
472         }
473 
474         context.setScopeGroupId(previousScopeGroupId);
475 
476         // Categories
477 
478         if (exportCategories) {
479             exportCategories(context);
480         }
481 
482         _portletExporter.exportCategories(context, root);
483 
484         // Comments
485 
486         _portletExporter.exportComments(context, root);
487 
488         // Ratings
489 
490         _portletExporter.exportRatings(context, root);
491 
492         // Tags
493 
494         _portletExporter.exportTags(context, root);
495 
496         // Look and feel
497 
498         try {
499             if (exportTheme) {
500                 exportTheme(layoutSet, zipWriter);
501             }
502 
503             // Log
504 
505             if (_log.isInfoEnabled()) {
506                 _log.info(
507                     "Exporting layouts takes " + stopWatch.getTime() + " ms");
508             }
509 
510             // Zip
511 
512             context.addZipEntry("/manifest.xml", doc.formattedString());
513         }
514         catch (IOException ioe) {
515             throw new SystemException(ioe);
516         }
517 
518         return zipWriter.getFile();
519     }
520 
521     protected void exportCategories(PortletDataContext context)
522         throws SystemException {
523 
524         try {
525             Document doc = SAXReaderUtil.createDocument();
526 
527             Element root = doc.addElement("categories-hierarchy");
528 
529             List<AssetVocabulary> assetVocabularies =
530                 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
531                     context.getGroupId());
532 
533             for (AssetVocabulary assetVocabulary : assetVocabularies) {
534                 Element vocabularyEl = root.addElement("vocabulary");
535 
536                 long vocabularyId = assetVocabulary.getVocabularyId();
537 
538                 vocabularyEl.addAttribute("uuid", assetVocabulary.getUuid());
539                 vocabularyEl.addAttribute("id", String.valueOf(vocabularyId));
540                 vocabularyEl.addAttribute("name", assetVocabulary.getName());
541                 vocabularyEl.addAttribute(
542                     "userUuid", assetVocabulary.getUserUuid());
543 
544                 List<AssetCategory> assetCategories =
545                     AssetCategoryLocalServiceUtil.getVocabularyCategories(
546                         assetVocabulary.getVocabularyId());
547 
548                 assetCategories = ListUtil.copy(assetCategories);
549 
550                 orderCategories(
551                     assetCategories, vocabularyEl,
552                     AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID);
553             }
554 
555             context.addZipEntry(
556                 context.getRootPath() + "/categories-hierarchy.xml",
557                 doc.formattedString());
558         }
559         catch (Exception e) {
560             throw new SystemException(e);
561         }
562     }
563 
564     protected void exportLayoutPermissions_4(
565             LayoutCache layoutCache, long companyId, long groupId,
566             Group guestGroup, String resourceName, String resourcePrimKey,
567             Element permissionsEl, boolean exportUserPermissions)
568         throws SystemException {
569 
570         _portletExporter.exportGroupPermissions(
571             companyId, groupId, resourceName, resourcePrimKey, permissionsEl,
572             "community-actions");
573 
574         if (groupId != guestGroup.getGroupId()) {
575             _portletExporter.exportGroupPermissions(
576                 companyId, guestGroup.getGroupId(), resourceName,
577                 resourcePrimKey, permissionsEl, "guest-actions");
578         }
579 
580         if (exportUserPermissions) {
581             _portletExporter.exportUserPermissions(
582                 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
583                 permissionsEl);
584         }
585 
586         _portletExporter.exportInheritedPermissions(
587             layoutCache, companyId, resourceName, resourcePrimKey,
588             permissionsEl, "organization");
589 
590         _portletExporter.exportInheritedPermissions(
591             layoutCache, companyId, resourceName, resourcePrimKey,
592             permissionsEl, "user-group");
593     }
594 
595     protected void exportLayoutPermissions_5(
596             LayoutCache layoutCache, long companyId, long groupId,
597             String resourceName, String resourcePrimKey, Element permissionsEl)
598         throws PortalException, SystemException {
599 
600         boolean portletActions = false;
601 
602         Resource resource = layoutCache.getResource(
603             companyId, groupId, resourceName,
604             ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
605             portletActions);
606 
607         _portletExporter.exportPermissions_5(
608             layoutCache, groupId, resourceName, resource.getResourceId(),
609             permissionsEl);
610     }
611 
612     protected void exportLayoutPermissions_6(
613             LayoutCache layoutCache, long companyId, long groupId,
614             String resourceName, String resourcePrimKey, Element permissionsEl)
615         throws PortalException, SystemException {
616 
617         boolean portletActions = false;
618 
619         _portletExporter.exportPermissions_6(
620             layoutCache, companyId, groupId, resourceName, resourcePrimKey,
621             permissionsEl, portletActions);
622     }
623 
624     protected void exportLayoutRoles(
625             LayoutCache layoutCache, long companyId, long groupId,
626             Element rolesEl)
627         throws SystemException {
628 
629         String resourceName = Layout.class.getName();
630 
631         _portletExporter.exportGroupRoles(
632             layoutCache, companyId, groupId, resourceName, "community",
633             rolesEl);
634 
635         _portletExporter.exportUserRoles(
636         layoutCache, companyId, groupId, resourceName, rolesEl);
637 
638         _portletExporter.exportInheritedRoles(
639             layoutCache, companyId, groupId, resourceName, "organization",
640             rolesEl);
641 
642         _portletExporter.exportInheritedRoles(
643             layoutCache, companyId, groupId, resourceName, "user-group",
644             rolesEl);
645     }
646 
647     protected void exportTheme(LayoutSet layoutSet, ZipWriter zipWriter)
648         throws IOException, SystemException {
649 
650         Theme theme = layoutSet.getTheme();
651 
652         String lookAndFeelXML = ContentUtil.get(
653             "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
654 
655         lookAndFeelXML = StringUtil.replace(
656             lookAndFeelXML,
657             new String[] {
658                 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
659             },
660             new String[] {
661                 theme.getTemplateExtension(), theme.getVirtualPath()
662             }
663         );
664 
665         String servletContextName = theme.getServletContextName();
666 
667         ServletContext servletContext = VelocityContextPool.get(
668             servletContextName);
669 
670         if (servletContext == null) {
671             if (_log.isWarnEnabled()) {
672                 _log.warn(
673                     "Servlet context not found for theme " +
674                         theme.getThemeId());
675             }
676 
677             return;
678         }
679 
680         File themeZip = new File(zipWriter.getPath() + "/theme.zip");
681 
682         ZipWriter themeZipWriter = ZipWriterFactoryUtil.getZipWriter(themeZip);
683 
684         themeZipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
685 
686         File cssPath = null;
687         File imagesPath = null;
688         File javaScriptPath = null;
689         File templatesPath = null;
690 
691         if (!theme.isLoadFromServletContext()) {
692             ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
693                 servletContextName);
694 
695             if (themeLoader == null) {
696                 _log.error(
697                     servletContextName + " does not map to a theme loader");
698             }
699             else {
700                 String realPath =
701                     themeLoader.getFileStorage().getPath() + StringPool.SLASH +
702                         theme.getName();
703 
704                 cssPath = new File(realPath + "/css");
705                 imagesPath = new File(realPath + "/images");
706                 javaScriptPath = new File(realPath + "/javascript");
707                 templatesPath = new File(realPath + "/templates");
708             }
709         }
710         else {
711             cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
712             imagesPath = new File(
713                 servletContext.getRealPath(theme.getImagesPath()));
714             javaScriptPath = new File(
715                 servletContext.getRealPath(theme.getJavaScriptPath()));
716             templatesPath = new File(
717                 servletContext.getRealPath(theme.getTemplatesPath()));
718         }
719 
720         exportThemeFiles("css", cssPath, themeZipWriter);
721         exportThemeFiles("images", imagesPath, themeZipWriter);
722         exportThemeFiles("javascript", javaScriptPath, themeZipWriter);
723         exportThemeFiles("templates", templatesPath, themeZipWriter);
724     }
725 
726     protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
727         throws IOException {
728 
729         if ((dir == null) || (!dir.exists())) {
730             return;
731         }
732 
733         File[] files = dir.listFiles();
734 
735         for (File file : files) {
736             if (file.isDirectory()) {
737                 exportThemeFiles(
738                     path + StringPool.SLASH + file.getName(), file, zipWriter);
739             }
740             else {
741                 zipWriter.addEntry(
742                     path + StringPool.SLASH + file.getName(),
743                     FileUtil.getBytes(file));
744             }
745         }
746     }
747 
748     protected void fixTypeSettings(Layout layout) {
749         if (!layout.getType().equals(LayoutConstants.TYPE_URL)) {
750             return;
751         }
752 
753         UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
754 
755         String url = GetterUtil.getString(typeSettings.getProperty("url"));
756 
757         String friendlyURLPrivateGroupPath =
758             PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
759         String friendlyURLPrivateUserPath =
760             PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
761         String friendlyURLPublicPath =
762             PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
763 
764         if (!url.startsWith(friendlyURLPrivateGroupPath) &&
765             !url.startsWith(friendlyURLPrivateUserPath) &&
766             !url.startsWith(friendlyURLPublicPath)) {
767 
768             return;
769         }
770 
771         int x = url.indexOf(StringPool.SLASH, 1);
772 
773         if (x == -1) {
774             return;
775         }
776 
777         int y = url.indexOf(StringPool.SLASH, x + 1);
778 
779         if (y == -1) {
780             return;
781         }
782 
783         String friendlyURL = url.substring(x, y);
784         String groupFriendlyURL = layout.getGroup().getFriendlyURL();
785 
786         if (!friendlyURL.equals(groupFriendlyURL)) {
787             return;
788         }
789 
790         typeSettings.setProperty(
791             "url",
792             url.substring(0, x) + SAME_GROUP_FRIENDLY_URL + url.substring(y));
793     }
794 
795     protected boolean[] getExportPortletControls(
796             long companyId, String portletId, PortletDataContext context,
797             Map<String, String[]> parameterMap)
798         throws SystemException {
799 
800         boolean exportPortletData = MapUtil.getBoolean(
801             parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
802         boolean exportPortletDataAll = MapUtil.getBoolean(
803             parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
804         boolean exportPortletSetup = MapUtil.getBoolean(
805             parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
806 
807         if (_log.isDebugEnabled()) {
808             _log.debug("Export portlet data " + exportPortletData);
809             _log.debug("Export all portlet data " + exportPortletDataAll);
810             _log.debug("Export portlet setup " + exportPortletSetup);
811         }
812 
813         boolean exportCurPortletData = exportPortletData;
814         boolean exportCurPortletSetup = exportPortletSetup;
815 
816         // If PORTLET_DATA_ALL is true, this means that staging has just been
817         // activated and all data and setup must be exported. There is no
818         // portlet export control to check in this case.
819 
820         if (exportPortletDataAll) {
821             exportCurPortletData = true;
822             exportCurPortletSetup = true;
823         }
824         else {
825             Portlet portlet = PortletLocalServiceUtil.getPortletById(
826                 companyId, portletId);
827 
828             if (portlet != null) {
829                 String portletDataHandlerClass =
830                     portlet.getPortletDataHandlerClass();
831 
832                 // Checking if the portlet has a data handler, if it doesn't,
833                 // the default values are the ones set in PORTLET_DATA and
834                 // PORTLET_SETUP. If it has a data handler, iterate over each
835                 // portlet export control.
836 
837                 if (portletDataHandlerClass != null) {
838                     String rootPortletId = PortletConstants.getRootPortletId(
839                         portletId);
840 
841                     // PORTLET_DATA and the PORTLET_DATA for this specific
842                     // data handler must be true
843 
844                     exportCurPortletData =
845                         exportPortletData &&
846                         MapUtil.getBoolean(
847                             parameterMap,
848                             PortletDataHandlerKeys.PORTLET_DATA +
849                                 StringPool.UNDERLINE + rootPortletId);
850 
851                     // PORTLET_DATA and the PORTLET_SETUP for this specific
852                     // data handler must be true
853 
854                     exportCurPortletSetup =
855                         exportPortletData &&
856                         MapUtil.getBoolean(
857                             parameterMap,
858                             PortletDataHandlerKeys.PORTLET_SETUP +
859                                 StringPool.UNDERLINE + rootPortletId);
860                 }
861             }
862         }
863 
864         return new boolean[] {exportCurPortletData, exportCurPortletSetup};
865     }
866 
867     protected String getLayoutIconPath(
868         PortletDataContext context, Layout layout, Image image) {
869 
870         StringBundler sb = new StringBundler(5);
871 
872         sb.append(context.getLayoutPath(layout.getLayoutId()));
873         sb.append("/icons/");
874         sb.append(image.getImageId());
875         sb.append(StringPool.PERIOD);
876         sb.append(image.getType());
877 
878         return sb.toString();
879     }
880 
881     protected void orderCategories(
882             List<AssetCategory> assetCategories, Element parentEl,
883             long parentCategoryId)
884         throws PortalException, SystemException {
885 
886         List<AssetCategory> parentCategories = new ArrayList<AssetCategory>();
887 
888         Iterator<AssetCategory> itr = assetCategories.iterator();
889 
890         while (itr.hasNext()) {
891             AssetCategory assetCategory = itr.next();
892 
893             if (assetCategory.getParentCategoryId() == parentCategoryId) {
894                 Element categoryEl = parentEl.addElement("category");
895 
896                 categoryEl.addAttribute("uuid", assetCategory.getUuid());
897                 categoryEl.addAttribute("name", assetCategory.getName());
898                 categoryEl.addAttribute(
899                     "userUuid", assetCategory.getUserUuid());
900 
901                 if (parentCategoryId > 0) {
902                     AssetCategory parentCategory =
903                         AssetCategoryLocalServiceUtil.getCategory(
904                             parentCategoryId);
905 
906                     categoryEl.addAttribute(
907                         "parentCategoryUuid", parentCategory.getUuid());
908                 }
909 
910                 parentCategories.add(assetCategory);
911 
912                 itr.remove();
913             }
914         }
915 
916         for (AssetCategory parentCategory : parentCategories) {
917             orderCategories(
918                 assetCategories, parentEl, parentCategory.getCategoryId());
919         }
920     }
921 
922     private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
923 
924     private PortletExporter _portletExporter = new PortletExporter();
925 
926 }