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