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