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