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