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