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.lar.PortletDataContext;
20  import com.liferay.portal.kernel.lar.PortletDataHandler;
21  import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
22  import com.liferay.portal.kernel.log.Log;
23  import com.liferay.portal.kernel.log.LogFactoryUtil;
24  import com.liferay.portal.kernel.servlet.ServletContextPool;
25  import com.liferay.portal.kernel.util.FileUtil;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.MapUtil;
28  import com.liferay.portal.kernel.util.ReleaseInfo;
29  import com.liferay.portal.kernel.util.StringBundler;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.StringUtil;
32  import com.liferay.portal.kernel.util.Time;
33  import com.liferay.portal.kernel.util.UnicodeProperties;
34  import com.liferay.portal.kernel.xml.Document;
35  import com.liferay.portal.kernel.xml.Element;
36  import com.liferay.portal.kernel.xml.SAXReaderUtil;
37  import com.liferay.portal.kernel.zip.ZipWriter;
38  import com.liferay.portal.kernel.zip.ZipWriterFactoryUtil;
39  import com.liferay.portal.model.Group;
40  import com.liferay.portal.model.Image;
41  import com.liferay.portal.model.Layout;
42  import com.liferay.portal.model.LayoutSet;
43  import com.liferay.portal.model.LayoutTypePortlet;
44  import com.liferay.portal.model.Portlet;
45  import com.liferay.portal.model.PortletConstants;
46  import com.liferay.portal.model.Theme;
47  import com.liferay.portal.service.ImageLocalServiceUtil;
48  import com.liferay.portal.service.LayoutLocalServiceUtil;
49  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
50  import com.liferay.portal.service.PortletLocalServiceUtil;
51  import com.liferay.portal.service.UserLocalServiceUtil;
52  import com.liferay.portal.service.permission.PortletPermissionUtil;
53  import com.liferay.portal.service.persistence.LayoutUtil;
54  import com.liferay.portal.theme.ThemeLoader;
55  import com.liferay.portal.theme.ThemeLoaderFactory;
56  import com.liferay.portal.util.ContentUtil;
57  import com.liferay.portal.util.PortletKeys;
58  import com.liferay.portal.util.PropsValues;
59  import com.liferay.portlet.PortletPreferencesFactoryUtil;
60  import com.liferay.portlet.asset.model.AssetCategory;
61  import com.liferay.portlet.asset.model.AssetVocabulary;
62  import com.liferay.portlet.asset.service.AssetVocabularyLocalServiceUtil;
63  import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
64  
65  import java.io.File;
66  import java.io.IOException;
67  
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         context.setPortetDataContextListener(
200             new PortletDataContextListenerImpl(context));
201 
202         // Build compatibility
203 
204         Document doc = SAXReaderUtil.createDocument();
205 
206         Element root = doc.addElement("root");
207 
208         Element header = root.addElement("header");
209 
210         header.addAttribute(
211             "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
212         header.addAttribute("export-date", Time.getRFC822());
213 
214         if (context.hasDateRange()) {
215             header.addAttribute(
216                 "start-date", String.valueOf(context.getStartDate()));
217             header.addAttribute(
218                 "end-date", String.valueOf(context.getEndDate()));
219         }
220 
221         header.addAttribute("type", "layout-set");
222         header.addAttribute("group-id", String.valueOf(groupId));
223         header.addAttribute("private-layout", String.valueOf(privateLayout));
224         header.addAttribute("theme-id", layoutSet.getThemeId());
225         header.addAttribute("color-scheme-id", layoutSet.getColorSchemeId());
226 
227         // Layout Configuration Portlet
228 
229         Portlet layoutConfigurationPortlet =
230             PortletLocalServiceUtil.getPortletById(
231                 context.getCompanyId(), PortletKeys.LAYOUT_CONFIGURATION);
232 
233         // Layouts
234 
235         Map<String, Object[]> portletIds =
236             new LinkedHashMap<String, Object[]>();
237 
238         List<Layout> layouts = null;
239 
240         if ((layoutIds == null) || (layoutIds.length == 0)) {
241             layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
242         }
243         else {
244             layouts = LayoutLocalServiceUtil.getLayouts(
245                 groupId, privateLayout, layoutIds);
246         }
247 
248         Element layoutsEl = root.addElement("layouts");
249 
250         for (Layout layout : layouts) {
251             boolean deleteLayout = MapUtil.getBoolean(
252                 parameterMap, "delete_" + layout.getPlid());
253 
254             if (deleteLayout) {
255                 Element el = layoutsEl.addElement("layout");
256 
257                 el.addAttribute(
258                     "layout-id", String.valueOf(layout.getLayoutId()));
259                 el.addAttribute("delete", String.valueOf(true));
260 
261                 continue;
262             }
263 
264             fixTypeSettings(layout);
265 
266             context.setPlid(layout.getPlid());
267 
268             Document layoutDoc = SAXReaderUtil.createDocument();
269 
270             Element layoutEl = layoutDoc.addElement("layout");
271 
272             layoutEl.addAttribute("old-plid", String.valueOf(layout.getPlid()));
273             layoutEl.addAttribute(
274                 "layout-id", String.valueOf(layout.getLayoutId()));
275             layoutEl.addElement("parent-layout-id").addText(
276                 String.valueOf(layout.getParentLayoutId()));
277             layoutEl.addElement("name").addCDATA(layout.getName());
278             layoutEl.addElement("title").addCDATA(layout.getTitle());
279             layoutEl.addElement("description").addText(layout.getDescription());
280             layoutEl.addElement("type").addText(layout.getType());
281             layoutEl.addElement("type-settings").addCDATA(
282                 layout.getTypeSettings());
283             layoutEl.addElement("hidden").addText(
284                 String.valueOf(layout.getHidden()));
285             layoutEl.addElement("friendly-url").addText(
286                 layout.getFriendlyURL());
287             layoutEl.addElement("icon-image").addText(
288                 String.valueOf(layout.getIconImage()));
289 
290             if (layout.isIconImage()) {
291                 Image image = ImageLocalServiceUtil.getImage(
292                     layout.getIconImageId());
293 
294                 if (image != null) {
295                     String iconPath = getLayoutIconPath(context, layout, image);
296 
297                     layoutEl.addElement("icon-image-path").addText(
298                         iconPath);
299 
300                     context.addZipEntry(iconPath, image.getTextObj());
301                 }
302             }
303 
304             layoutEl.addElement("theme-id").addText(layout.getThemeId());
305             layoutEl.addElement("color-scheme-id").addText(
306                 layout.getColorSchemeId());
307             layoutEl.addElement("wap-theme-id").addText(layout.getWapThemeId());
308             layoutEl.addElement("wap-color-scheme-id").addText(
309                 layout.getWapColorSchemeId());
310             layoutEl.addElement("css").addCDATA(layout.getCss());
311             layoutEl.addElement("priority").addText(
312                 String.valueOf(layout.getPriority()));
313 
314             // Layout permissions
315 
316             if (exportPermissions) {
317                 _permissionExporter.exportLayoutPermissions(
318                     context, layoutCache, companyId, groupId, layout, layoutEl,
319                     exportUserPermissions);
320             }
321 
322             if (layout.isTypePortlet()) {
323                 LayoutTypePortlet layoutTypePortlet =
324                     (LayoutTypePortlet)layout.getLayoutType();
325 
326                 long scopeGroupId = groupId;
327 
328                 for (String portletId : layoutTypePortlet.getPortletIds()) {
329                     javax.portlet.PortletPreferences jxPreferences =
330                         PortletPreferencesFactoryUtil.getLayoutPortletSetup(
331                             layout, portletId);
332 
333                     long scopeLayoutId = GetterUtil.getLong(
334                         jxPreferences.getValue("lfr-scope-layout-id", null));
335 
336                     if (scopeLayoutId != 0) {
337                         Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
338                             groupId, layout.isPrivateLayout(), scopeLayoutId);
339 
340                         Group scopeGroup = scopeLayout.getScopeGroup();
341 
342                         if (scopeGroup != null) {
343                             scopeGroupId = scopeGroup.getGroupId();
344                         }
345                     }
346 
347                     String key = PortletPermissionUtil.getPrimaryKey(
348                         layout.getPlid(), portletId);
349 
350                     portletIds.put(
351                         key,
352                         new Object[] {
353                             portletId, layout.getPlid(), scopeGroupId,
354                             scopeLayoutId
355                         }
356                     );
357                 }
358             }
359 
360             List<Portlet> portlets = getAlwaysExportablePortlets(
361                 context.getCompanyId());
362 
363             for (Portlet portlet : portlets) {
364                 String portletId = portlet.getRootPortletId();
365 
366                 if (portlet.isScopeable() && layout.hasScopeGroup()) {
367                     String key = PortletPermissionUtil.getPrimaryKey(
368                         layout.getPlid(), portletId);
369 
370                     portletIds.put(
371                         key,
372                         new Object[] {
373                             portletId, layout.getPlid(),
374                             layout.getScopeGroup().getGroupId(),
375                             layout.getLayoutId()
376                         }
377                     );
378                 }
379                 else {
380                     String key = PortletPermissionUtil.getPrimaryKey(
381                         0, portletId);
382 
383                     if (portletIds.get(key) == null) {
384                         portletIds.put(
385                             key,
386                             new Object[] {
387                                 portletId, layout.getPlid(), groupId, 0L
388                             }
389                         );
390                     }
391                 }
392             }
393 
394             String layoutPath = context.getLayoutPath(layout.getLayoutId()) +
395                 "/layout.xml";
396 
397             Element el = layoutsEl.addElement("layout");
398 
399             el.addAttribute("layout-id", String.valueOf(layout.getLayoutId()));
400             el.addAttribute("path", layoutPath);
401 
402             _portletExporter.exportPortletData(
403                 context, layoutConfigurationPortlet, layout, null, layoutEl);
404 
405             try {
406                 context.addZipEntry(layoutPath, layoutDoc.formattedString());
407             }
408             catch (IOException ioe) {
409             }
410         }
411 
412         if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM < 5) {
413             Element rolesEl = root.addElement("roles");
414 
415             // Layout roles
416 
417             if (exportPermissions) {
418                 _permissionExporter.exportLayoutRoles(
419                     layoutCache, companyId, groupId, rolesEl);
420             }
421         }
422 
423         // Export portlets
424 
425         long previousScopeGroupId = context.getScopeGroupId();
426 
427         Element portletsEl = root.addElement("portlets");
428 
429         for (Map.Entry<String, Object[]> portletIdsEntry :
430                 portletIds.entrySet()) {
431 
432             String portletId = (String)portletIdsEntry.getValue()[0];
433             long plid = (Long)portletIdsEntry.getValue()[1];
434             long scopeGroupId = (Long)portletIdsEntry.getValue()[2];
435             long scopeLayoutId = (Long)portletIdsEntry.getValue()[3];
436 
437             Layout layout = LayoutUtil.findByPrimaryKey(plid);
438 
439             context.setPlid(layout.getPlid());
440             context.setOldPlid(layout.getPlid());
441             context.setScopeGroupId(scopeGroupId);
442             context.setScopeLayoutId(scopeLayoutId);
443 
444             boolean[] exportPortletControls = getExportPortletControls(
445                 context.getCompanyId(), portletId, context, parameterMap);
446 
447             _portletExporter.exportPortlet(
448                 context, layoutCache, portletId, layout, portletsEl,
449                 defaultUserId, exportPermissions, exportPortletArchivedSetups,
450                 exportPortletControls[0], exportPortletControls[1],
451                 exportPortletUserPreferences, exportUserPermissions);
452         }
453 
454         context.setScopeGroupId(previousScopeGroupId);
455 
456         // Categories
457 
458         if (exportCategories) {
459             exportCategories(context);
460         }
461 
462         // Comments
463 
464         _portletExporter.exportComments(context, root);
465 
466         // Locks
467 
468         _portletExporter.exportLocks(context, root);
469 
470         // Portlet data permissions
471 
472         if (exportPermissions) {
473             _permissionExporter.exportPortletDataPermissions(context);
474         }
475 
476         // Ratings
477 
478         _portletExporter.exportRatings(context, root);
479 
480         // Tags
481 
482         _portletExporter.exportTags(context, root);
483 
484         // Look and feel
485 
486         try {
487             if (exportTheme) {
488                 exportTheme(layoutSet, zipWriter);
489             }
490 
491             // Log
492 
493             if (_log.isInfoEnabled()) {
494                 if (stopWatch != null) {
495                     _log.info(
496                         "Exporting layouts takes " + stopWatch.getTime() +
497                             " ms");
498                 }
499                 else {
500                     _log.info("Exporting layouts is finished");
501                 }
502             }
503 
504             // Zip
505 
506             context.addZipEntry("/manifest.xml", doc.formattedString());
507         }
508         catch (IOException ioe) {
509             throw new SystemException(ioe);
510         }
511 
512         return zipWriter.getFile();
513     }
514 
515     protected void exportCategories(PortletDataContext context)
516         throws SystemException {
517 
518         try {
519             Document doc = SAXReaderUtil.createDocument();
520 
521             Element root = doc.addElement("categories-hierarchy");
522 
523             Element vocabulariesEl = root.addElement("vocabularies");
524 
525             List<AssetVocabulary> assetVocabularies =
526                 AssetVocabularyLocalServiceUtil.getGroupVocabularies(
527                     context.getGroupId());
528 
529             for (AssetVocabulary assetVocabulary : assetVocabularies) {
530                 _portletExporter.exportVocabulary(
531                     context, vocabulariesEl, assetVocabulary);
532             }
533 
534             Element categoriesEl = root.addElement("categories");
535 
536             List<AssetCategory> assetCategories =
537                 AssetCategoryUtil.findByGroupId(context.getGroupId());
538 
539             for (AssetCategory assetCategory : assetCategories) {
540                 _portletExporter.exportCategory(
541                     context, vocabulariesEl, categoriesEl, assetCategory);
542             }
543 
544             _portletExporter.exportCategories(context, root);
545 
546             context.addZipEntry(
547                 context.getRootPath() + "/categories-hierarchy.xml",
548                 doc.formattedString());
549         }
550         catch (Exception e) {
551             throw new SystemException(e);
552         }
553     }
554 
555     protected void exportTheme(LayoutSet layoutSet, ZipWriter zipWriter)
556         throws IOException, SystemException {
557 
558         Theme theme = layoutSet.getTheme();
559 
560         String lookAndFeelXML = ContentUtil.get(
561             "com/liferay/portal/dependencies/liferay-look-and-feel.xml.tmpl");
562 
563         lookAndFeelXML = StringUtil.replace(
564             lookAndFeelXML,
565             new String[] {
566                 "[$TEMPLATE_EXTENSION$]", "[$VIRTUAL_PATH$]"
567             },
568             new String[] {
569                 theme.getTemplateExtension(), theme.getVirtualPath()
570             }
571         );
572 
573         String servletContextName = theme.getServletContextName();
574 
575         ServletContext servletContext = ServletContextPool.get(
576             servletContextName);
577 
578         if (servletContext == null) {
579             if (_log.isWarnEnabled()) {
580                 _log.warn(
581                     "Servlet context not found for theme " +
582                         theme.getThemeId());
583             }
584 
585             return;
586         }
587 
588         File themeZip = new File(zipWriter.getPath() + "/theme.zip");
589 
590         ZipWriter themeZipWriter = ZipWriterFactoryUtil.getZipWriter(themeZip);
591 
592         themeZipWriter.addEntry("liferay-look-and-feel.xml", lookAndFeelXML);
593 
594         File cssPath = null;
595         File imagesPath = null;
596         File javaScriptPath = null;
597         File templatesPath = null;
598 
599         if (!theme.isLoadFromServletContext()) {
600             ThemeLoader themeLoader = ThemeLoaderFactory.getThemeLoader(
601                 servletContextName);
602 
603             if (themeLoader == null) {
604                 _log.error(
605                     servletContextName + " does not map to a theme loader");
606             }
607             else {
608                 String realPath =
609                     themeLoader.getFileStorage().getPath() + StringPool.SLASH +
610                         theme.getName();
611 
612                 cssPath = new File(realPath + "/css");
613                 imagesPath = new File(realPath + "/images");
614                 javaScriptPath = new File(realPath + "/javascript");
615                 templatesPath = new File(realPath + "/templates");
616             }
617         }
618         else {
619             cssPath = new File(servletContext.getRealPath(theme.getCssPath()));
620             imagesPath = new File(
621                 servletContext.getRealPath(theme.getImagesPath()));
622             javaScriptPath = new File(
623                 servletContext.getRealPath(theme.getJavaScriptPath()));
624             templatesPath = new File(
625                 servletContext.getRealPath(theme.getTemplatesPath()));
626         }
627 
628         exportThemeFiles("css", cssPath, themeZipWriter);
629         exportThemeFiles("images", imagesPath, themeZipWriter);
630         exportThemeFiles("javascript", javaScriptPath, themeZipWriter);
631         exportThemeFiles("templates", templatesPath, themeZipWriter);
632     }
633 
634     protected void exportThemeFiles(String path, File dir, ZipWriter zipWriter)
635         throws IOException {
636 
637         if ((dir == null) || (!dir.exists())) {
638             return;
639         }
640 
641         File[] files = dir.listFiles();
642 
643         for (File file : files) {
644             if (file.isDirectory()) {
645                 exportThemeFiles(
646                     path + StringPool.SLASH + file.getName(), file, zipWriter);
647             }
648             else {
649                 zipWriter.addEntry(
650                     path + StringPool.SLASH + file.getName(),
651                     FileUtil.getBytes(file));
652             }
653         }
654     }
655 
656     protected void fixTypeSettings(Layout layout)
657         throws PortalException, SystemException {
658 
659         if (!layout.isTypeURL()) {
660             return;
661         }
662 
663         UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
664 
665         String url = GetterUtil.getString(typeSettings.getProperty("url"));
666 
667         String friendlyURLPrivateGroupPath =
668             PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
669         String friendlyURLPrivateUserPath =
670             PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
671         String friendlyURLPublicPath =
672             PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
673 
674         if (!url.startsWith(friendlyURLPrivateGroupPath) &&
675             !url.startsWith(friendlyURLPrivateUserPath) &&
676             !url.startsWith(friendlyURLPublicPath)) {
677 
678             return;
679         }
680 
681         int x = url.indexOf(StringPool.SLASH, 1);
682 
683         if (x == -1) {
684             return;
685         }
686 
687         int y = url.indexOf(StringPool.SLASH, x + 1);
688 
689         if (y == -1) {
690             return;
691         }
692 
693         String friendlyURL = url.substring(x, y);
694         String groupFriendlyURL = layout.getGroup().getFriendlyURL();
695 
696         if (!friendlyURL.equals(groupFriendlyURL)) {
697             return;
698         }
699 
700         typeSettings.setProperty(
701             "url",
702             url.substring(0, x) + SAME_GROUP_FRIENDLY_URL + url.substring(y));
703     }
704 
705     protected boolean[] getExportPortletControls(
706             long companyId, String portletId, PortletDataContext context,
707             Map<String, String[]> parameterMap)
708         throws SystemException {
709 
710         boolean exportPortletData = MapUtil.getBoolean(
711             parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
712         boolean exportPortletDataAll = MapUtil.getBoolean(
713             parameterMap, PortletDataHandlerKeys.PORTLET_DATA_ALL);
714         boolean exportPortletSetup = MapUtil.getBoolean(
715             parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
716 
717         if (_log.isDebugEnabled()) {
718             _log.debug("Export portlet data " + exportPortletData);
719             _log.debug("Export all portlet data " + exportPortletDataAll);
720             _log.debug("Export portlet setup " + exportPortletSetup);
721         }
722 
723         boolean exportCurPortletData = exportPortletData;
724         boolean exportCurPortletSetup = exportPortletSetup;
725 
726         // If PORTLET_DATA_ALL is true, this means that staging has just been
727         // activated and all data and setup must be exported. There is no
728         // portlet export control to check in this case.
729 
730         if (exportPortletDataAll) {
731             exportCurPortletData = true;
732             exportCurPortletSetup = true;
733         }
734         else {
735             Portlet portlet = PortletLocalServiceUtil.getPortletById(
736                 companyId, portletId);
737 
738             if (portlet != null) {
739                 String portletDataHandlerClass =
740                     portlet.getPortletDataHandlerClass();
741 
742                 // Checking if the portlet has a data handler, if it doesn't,
743                 // the default values are the ones set in PORTLET_DATA and
744                 // PORTLET_SETUP. If it has a data handler, iterate over each
745                 // portlet export control.
746 
747                 if (portletDataHandlerClass != null) {
748                     String rootPortletId = PortletConstants.getRootPortletId(
749                         portletId);
750 
751                     // PORTLET_DATA and the PORTLET_DATA for this specific
752                     // data handler must be true
753 
754                     exportCurPortletData =
755                         exportPortletData &&
756                         MapUtil.getBoolean(
757                             parameterMap,
758                             PortletDataHandlerKeys.PORTLET_DATA +
759                                 StringPool.UNDERLINE + rootPortletId);
760 
761                     // PORTLET_DATA and the PORTLET_SETUP for this specific
762                     // data handler must be true
763 
764                     exportCurPortletSetup =
765                         exportPortletData &&
766                         MapUtil.getBoolean(
767                             parameterMap,
768                             PortletDataHandlerKeys.PORTLET_SETUP +
769                                 StringPool.UNDERLINE + rootPortletId);
770                 }
771             }
772         }
773 
774         return new boolean[] {exportCurPortletData, exportCurPortletSetup};
775     }
776 
777     protected String getLayoutIconPath(
778         PortletDataContext context, Layout layout, Image image) {
779 
780         StringBundler sb = new StringBundler(5);
781 
782         sb.append(context.getLayoutPath(layout.getLayoutId()));
783         sb.append("/icons/");
784         sb.append(image.getImageId());
785         sb.append(StringPool.PERIOD);
786         sb.append(image.getType());
787 
788         return sb.toString();
789     }
790 
791     private static Log _log = LogFactoryUtil.getLog(LayoutExporter.class);
792 
793     private PermissionExporter _permissionExporter = new PermissionExporter();
794     private PortletExporter _portletExporter = new PortletExporter();
795 
796 }