1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.lar;
21  
22  import com.liferay.portal.PortalException;
23  import com.liferay.portal.SystemException;
24  import com.liferay.portal.kernel.io.FileCacheOutputStream;
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.util.FileUtil;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.ListUtil;
30  import com.liferay.portal.kernel.util.MapUtil;
31  import com.liferay.portal.kernel.util.ReleaseInfo;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Time;
35  import com.liferay.portal.kernel.xml.Document;
36  import com.liferay.portal.kernel.xml.Element;
37  import com.liferay.portal.kernel.xml.SAXReaderUtil;
38  import com.liferay.portal.kernel.zip.ZipWriter;
39  import com.liferay.portal.model.Group;
40  import com.liferay.portal.model.GroupConstants;
41  import com.liferay.portal.model.Image;
42  import com.liferay.portal.model.Layout;
43  import com.liferay.portal.model.LayoutConstants;
44  import com.liferay.portal.model.LayoutSet;
45  import com.liferay.portal.model.LayoutTypePortlet;
46  import com.liferay.portal.model.Portlet;
47  import com.liferay.portal.model.PortletConstants;
48  import com.liferay.portal.model.Resource;
49  import com.liferay.portal.model.ResourceConstants;
50  import com.liferay.portal.model.Theme;
51  import com.liferay.portal.service.GroupLocalServiceUtil;
52  import com.liferay.portal.service.ImageLocalServiceUtil;
53  import com.liferay.portal.service.LayoutLocalServiceUtil;
54  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
55  import com.liferay.portal.service.PortletLocalServiceUtil;
56  import com.liferay.portal.service.UserLocalServiceUtil;
57  import com.liferay.portal.service.permission.PortletPermissionUtil;
58  import com.liferay.portal.service.persistence.LayoutUtil;
59  import com.liferay.portal.theme.ThemeLoader;
60  import com.liferay.portal.theme.ThemeLoaderFactory;
61  import com.liferay.portal.util.ContentUtil;
62  import com.liferay.portal.util.PortletKeys;
63  import com.liferay.portal.util.PropsValues;
64  import com.liferay.portal.velocity.VelocityContextPool;
65  import com.liferay.portlet.PortletPreferencesFactoryUtil;
66  import com.liferay.portlet.tags.model.TagsEntry;
67  import com.liferay.portlet.tags.model.TagsEntryConstants;
68  import com.liferay.portlet.tags.model.TagsVocabulary;
69  import com.liferay.portlet.tags.service.TagsEntryLocalServiceUtil;
70  import com.liferay.portlet.tags.service.TagsVocabularyLocalServiceUtil;
71  
72  import java.io.File;
73  import java.io.IOException;
74  import java.io.InputStream;
75  
76  import java.util.ArrayList;
77  import java.util.Date;
78  import java.util.HashSet;
79  import java.util.Iterator;
80  import java.util.LinkedHashMap;
81  import java.util.List;
82  import java.util.Map;
83  
84  import javax.servlet.ServletContext;
85  
86  import org.apache.commons.lang.time.StopWatch;
87  
88  /**
89   * <a href="LayoutExporter.java.html"><b><i>View Source</i></b></a>
90   *
91   * @author Brian Wing Shun Chan
92   * @author Joel Kozikowski
93   * @author Charles May
94   * @author Raymond Augé
95   * @author Jorge Ferrer
96   * @author Bruno Farache
97   * @author Karthik Sudarshan
98   *
99   */
100 public class LayoutExporter {
101 
102     public static List<Portlet> getAlwaysExportablePortlets(long companyId)
103         throws SystemException {
104 
105         List<Portlet> portlets = PortletLocalServiceUtil.getPortlets(companyId);
106 
107         Iterator<Portlet> itr = portlets.iterator();
108 
109         while (itr.hasNext()) {
110             Portlet portlet = itr.next();
111 
112             if (!portlet.isActive()) {
113                 itr.remove();
114 
115                 continue;
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 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
322                     exportLayoutPermissions_6(
323                         layoutCache, companyId, groupId, resourceName,
324                         resourcePrimKey, permissionsEl);
325                 }
326                 else {
327                     exportLayoutPermissions_4(
328                         layoutCache, companyId, groupId, guestGroup,
329                         resourceName, resourcePrimKey, permissionsEl,
330                         exportUserPermissions);
331                 }
332             }
333 
334             if (layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
335                 LayoutTypePortlet layoutTypePortlet =
336                     (LayoutTypePortlet)layout.getLayoutType();
337 
338                 long scopeGroupId = groupId;
339 
340                 for (String portletId : layoutTypePortlet.getPortletIds()) {
341                     javax.portlet.PortletPreferences jxPreferences =
342                         PortletPreferencesFactoryUtil.getLayoutPortletSetup(
343                             layout, portletId);
344 
345                     long scopeLayoutId = GetterUtil.getLong(
346                         jxPreferences.getValue("lfr-scope-layout-id", null));
347 
348                     if (scopeLayoutId != 0) {
349                         Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
350                             groupId, layout.isPrivateLayout(), scopeLayoutId);
351 
352                         Group scopeGroup = scopeLayout.getScopeGroup();
353 
354                         if (scopeGroup != null) {
355                             scopeGroupId = scopeGroup.getGroupId();
356                         }
357                     }
358 
359                     String key = PortletPermissionUtil.getPrimaryKey(
360                         layout.getPlid(), portletId);
361 
362                     portletIds.put(
363                         key,
364                         new Object[] {
365                             portletId, layout.getPlid(), scopeGroupId,
366                             scopeLayoutId
367                         }
368                     );
369                 }
370             }
371 
372             List<Portlet> portlets = getAlwaysExportablePortlets(
373                 context.getCompanyId());
374 
375             for (Portlet portlet : portlets) {
376                 String portletId = portlet.getRootPortletId();
377 
378                 if (portlet.isScopeable() && layout.hasScopeGroup()) {
379                     String key = PortletPermissionUtil.getPrimaryKey(
380                         layout.getPlid(), portletId);
381 
382                     portletIds.put(
383                         key,
384                         new Object[] {
385                             portletId, layout.getPlid(),
386                             layout.getScopeGroup().getGroupId(),
387                             layout.getLayoutId()
388                         }
389                     );
390                 }
391                 else {
392                     String key = PortletPermissionUtil.getPrimaryKey(
393                         0, portletId);
394 
395                     if (portletIds.get(key) == null) {
396                         portletIds.put(
397                             key,
398                             new Object[] {
399                                 portletId, layout.getPlid(), groupId, 0L
400                             }
401                         );
402                     }
403                 }
404             }
405 
406             String layoutPath = context.getLayoutPath(layout.getLayoutId()) +
407                 "/layout.xml";
408 
409             Element el = layoutsEl.addElement("layout");
410 
411             el.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
412             el.addAttribute("path", layoutPath);
413 
414             _portletExporter.exportPortletData(
415                 context, layoutConfigurationPortlet, layout, null, layoutEl);
416 
417             try {
418                 context.addZipEntry(layoutPath, layoutDoc.formattedString());
419             }
420             catch (IOException ioe) {
421             }
422         }
423 
424         if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
425             Element rolesEl = root.addElement("roles");
426 
427             // Layout roles
428 
429             if (exportPermissions) {
430                 exportLayoutRoles(layoutCache, companyId, groupId, rolesEl);
431             }
432         }
433 
434         // Export Portlets
435 
436         long previousScopeGroupId = context.getScopeGroupId();
437 
438         Element portletsEl = root.addElement("portlets");
439 
440         for (Map.Entry<String, Object[]> portletIdsEntry :
441                 portletIds.entrySet()) {
442 
443             String portletId = (String)portletIdsEntry.getValue()[0];
444             long plid = (Long)portletIdsEntry.getValue()[1];
445             long scopeGroupId = (Long)portletIdsEntry.getValue()[2];
446             long scopeLayoutId = (Long)portletIdsEntry.getValue()[3];
447 
448             Layout layout = LayoutUtil.findByPrimaryKey(plid);
449 
450             context.setPlid(layout.getPlid());
451             context.setOldPlid(layout.getPlid());
452             context.setScopeGroupId(scopeGroupId);
453             context.setScopeLayoutId(scopeLayoutId);
454 
455             boolean[] exportPortletControls = getExportPortletControls(
456                 context.getCompanyId(), portletId, context, parameterMap);
457 
458             _portletExporter.exportPortlet(
459                 context, layoutCache, portletId, layout, portletsEl,
460                 defaultUserId, exportPermissions, exportPortletArchivedSetups,
461                 exportPortletControls[0], exportPortletControls[1],
462                 exportPortletUserPreferences, exportUserPermissions);
463         }
464 
465         context.setScopeGroupId(previousScopeGroupId);
466 
467         // Categories
468 
469         if (exportCategories) {
470             exportCategories(context);
471         }
472 
473         _portletExporter.exportCategories(context, root);
474 
475         // Comments
476 
477         _portletExporter.exportComments(context, root);
478 
479         // Ratings
480 
481         _portletExporter.exportRatings(context, root);
482 
483         // Tags
484 
485         _portletExporter.exportTags(context, root);
486 
487         // Look and feel
488 
489         InputStream themeZip = null;
490 
491         try {
492             if (exportTheme) {
493                 themeZip = exportTheme(layoutSet).getFileInputStream();
494             }
495         }
496         catch (IOException ioe) {
497             throw new SystemException(ioe);
498         }
499 
500         // Log
501 
502         if (_log.isInfoEnabled()) {
503             _log.info("Exporting layouts takes " + stopWatch.getTime() + " ms");
504         }
505 
506         // Zip
507 
508         try {
509             context.addZipEntry("/manifest.xml", doc.formattedString());
510 
511             if (themeZip != null) {
512                 context.addZipEntry("/theme.zip", themeZip);
513             }
514 
515             return zipWriter.finishWithStream();
516         }
517         catch (IOException ioe) {
518             throw new SystemException(ioe);
519         }
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 FileCacheOutputStream exportTheme(LayoutSet layoutSet)
648         throws IOException, SystemException {
649 
650         Theme theme = layoutSet.getTheme();
651 
652         ZipWriter zipWriter = new ZipWriter();
653 
654         String lookAndFeelXML = ContentUtil.get(
655             "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
656 
657         lookAndFeelXML = StringUtil.replace(
658             lookAndFeelXML,
659             new String[] {
660                 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
661             },
662             new String[] {
663                 theme.getTemplateExtension(), theme.getVirtualPath()
664             }
665         );
666 
667         zipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
668 
669         String servletContextName = theme.getServletContextName();
670 
671         ServletContext servletContext = VelocityContextPool.get(
672             servletContextName);
673 
674         if (servletContext == null) {
675             if (_log.isWarnEnabled()) {
676                 _log.warn(
677                     "Servlet context not found for theme " +
678                         theme.getThemeId());
679             }
680 
681             return null;
682         }
683 
684         File cssPath = null;
685         File imagesPath = null;
686         File javaScriptPath = null;
687         File templatesPath = null;
688 
689         if (!theme.isLoadFromServletContext()) {
690             ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
691                 servletContextName);
692 
693             if (themeLoader == null) {
694                 _log.error(
695                     servletContextName + " does not map to a theme loader");
696             }
697             else {
698                 String realPath =
699                     themeLoader.getFileStorage().getPath() + "/" +
700                         theme.getName();
701 
702                 cssPath = new File(realPath + "/css");
703                 imagesPath = new File(realPath + "/images");
704                 javaScriptPath = new File(realPath + "/javascript");
705                 templatesPath = new File(realPath + "/templates");
706             }
707         }
708         else {
709             cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
710             imagesPath = new File(
711                 servletContext.getRealPath(theme.getImagesPath()));
712             javaScriptPath = new File(
713                 servletContext.getRealPath(theme.getJavaScriptPath()));
714             templatesPath = new File(
715                 servletContext.getRealPath(theme.getTemplatesPath()));
716         }
717 
718         exportThemeFiles("css", cssPath, zipWriter);
719         exportThemeFiles("images", imagesPath, zipWriter);
720         exportThemeFiles("javascript", javaScriptPath, zipWriter);
721         exportThemeFiles("templates", templatesPath, zipWriter);
722 
723         return zipWriter.finishWithStream();
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 (int i = 0; i < files.length; i++) {
736             File file = files[i];
737 
738             if (file.isDirectory()) {
739                 exportThemeFiles(path + "/" + file.getName(), file, zipWriter);
740             }
741             else {
742                 zipWriter.addEntry(
743                     path + "/" + file.getName(), 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 }