1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.lar;
24  
25  import com.liferay.portal.LayoutImportException;
26  import com.liferay.portal.NoSuchPortletPreferencesException;
27  import com.liferay.portal.PortalException;
28  import com.liferay.portal.SystemException;
29  import com.liferay.portal.kernel.io.FileCacheOutputStream;
30  import com.liferay.portal.kernel.log.Log;
31  import com.liferay.portal.kernel.log.LogFactoryUtil;
32  import com.liferay.portal.kernel.util.CharPool;
33  import com.liferay.portal.kernel.util.GetterUtil;
34  import com.liferay.portal.kernel.util.PortletClassInvoker;
35  import com.liferay.portal.kernel.util.ReleaseInfo;
36  import com.liferay.portal.kernel.util.StringPool;
37  import com.liferay.portal.kernel.util.StringUtil;
38  import com.liferay.portal.kernel.util.Time;
39  import com.liferay.portal.kernel.util.Validator;
40  import com.liferay.portal.kernel.xml.Document;
41  import com.liferay.portal.kernel.xml.Element;
42  import com.liferay.portal.kernel.xml.SAXReaderUtil;
43  import com.liferay.portal.kernel.zip.ZipWriter;
44  import com.liferay.portal.model.Group;
45  import com.liferay.portal.model.GroupConstants;
46  import com.liferay.portal.model.Layout;
47  import com.liferay.portal.model.LayoutConstants;
48  import com.liferay.portal.model.LayoutTypePortlet;
49  import com.liferay.portal.model.Permission;
50  import com.liferay.portal.model.Portlet;
51  import com.liferay.portal.model.PortletConstants;
52  import com.liferay.portal.model.PortletItem;
53  import com.liferay.portal.model.PortletPreferences;
54  import com.liferay.portal.model.Resource;
55  import com.liferay.portal.model.ResourceConstants;
56  import com.liferay.portal.model.Role;
57  import com.liferay.portal.model.RoleConstants;
58  import com.liferay.portal.model.User;
59  import com.liferay.portal.security.permission.ResourceActionsUtil;
60  import com.liferay.portal.service.GroupLocalServiceUtil;
61  import com.liferay.portal.service.LayoutLocalServiceUtil;
62  import com.liferay.portal.service.PermissionLocalServiceUtil;
63  import com.liferay.portal.service.PortletItemLocalServiceUtil;
64  import com.liferay.portal.service.PortletLocalServiceUtil;
65  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
66  import com.liferay.portal.service.RoleLocalServiceUtil;
67  import com.liferay.portal.service.UserLocalServiceUtil;
68  import com.liferay.portal.service.permission.PortletPermissionUtil;
69  import com.liferay.portal.util.PortalUtil;
70  import com.liferay.portal.util.PortletKeys;
71  import com.liferay.portal.util.PropsValues;
72  import com.liferay.portlet.PortletPreferencesFactoryUtil;
73  import com.liferay.portlet.messageboards.model.MBMessage;
74  import com.liferay.portlet.ratings.model.RatingsEntry;
75  import com.liferay.util.MapUtil;
76  
77  import java.io.IOException;
78  
79  import java.util.Date;
80  import java.util.HashSet;
81  import java.util.Iterator;
82  import java.util.List;
83  import java.util.Map;
84  import java.util.Set;
85  
86  import org.apache.commons.lang.time.StopWatch;
87  
88  /**
89   * <a href="PortletExporter.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   *
98   */
99  public class PortletExporter {
100 
101     public byte[] exportPortletInfo(
102             long plid, long groupId, String portletId,
103             Map<String, String[]> parameterMap, Date startDate, Date endDate)
104         throws PortalException, SystemException {
105 
106         FileCacheOutputStream fcos = exportPortletInfoAsStream(
107             plid, groupId, portletId, parameterMap, startDate, endDate);
108 
109         try {
110             return fcos.getBytes();
111         }
112         catch (IOException ioe) {
113             throw new SystemException(ioe);
114         }
115     }
116 
117     public FileCacheOutputStream exportPortletInfoAsStream(
118             long plid, long groupId, String portletId,
119             Map<String, String[]> parameterMap, Date startDate, Date endDate)
120         throws PortalException, SystemException {
121 
122         boolean exportPermissions = MapUtil.getBoolean(
123             parameterMap, PortletDataHandlerKeys.PERMISSIONS);
124         boolean exportPortletArchivedSetups = MapUtil.getBoolean(
125             parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
126         boolean exportPortletData = MapUtil.getBoolean(
127             parameterMap, PortletDataHandlerKeys.PORTLET_DATA + "_" +
128             PortletConstants.getRootPortletId(portletId));
129         boolean exportPortletSetup = MapUtil.getBoolean(
130             parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
131         boolean exportPortletUserPreferences = MapUtil.getBoolean(
132             parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
133         boolean exportUserPermissions = MapUtil.getBoolean(
134             parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
135 
136         if (_log.isDebugEnabled()) {
137             _log.debug("Export permissions " + exportPermissions);
138             _log.debug(
139                 "Export portlet archived setups " +
140                     exportPortletArchivedSetups);
141             _log.debug("Export portlet data " + exportPortletData);
142             _log.debug("Export portlet setup " + exportPortletSetup);
143             _log.debug(
144                 "Export portlet user preferences " +
145                     exportPortletUserPreferences);
146             _log.debug("Export user permissions " + exportUserPermissions);
147         }
148 
149         StopWatch stopWatch = null;
150 
151         if (_log.isInfoEnabled()) {
152             stopWatch = new StopWatch();
153 
154             stopWatch.start();
155         }
156 
157         LayoutCache layoutCache = new LayoutCache();
158 
159         Layout layout = LayoutLocalServiceUtil.getLayout(plid);
160 
161         String type = layout.getType();
162 
163         if (type.equals(LayoutConstants.TYPE_PORTLET)) {
164             LayoutTypePortlet layoutTypePortlet =
165                 (LayoutTypePortlet)layout.getLayoutType();
166 
167             if (!layoutTypePortlet.hasPortletId(portletId)) {
168                 throw new LayoutImportException(
169                     "The specified layout does not have portlet " + portletId);
170             }
171         }
172         else if (!type.equals(LayoutConstants.TYPE_CONTROL_PANEL) &&
173                  !type.equals(LayoutConstants.TYPE_PANEL)) {
174 
175             throw new LayoutImportException(
176                 "Layout type " + type + " is not valid");
177         }
178 
179         long companyId = layout.getCompanyId();
180         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
181 
182         ZipWriter zipWriter = null;
183 
184         try {
185             zipWriter = new ZipWriter();
186         }
187         catch (IOException ioe) {
188             throw new SystemException(ioe);
189         }
190 
191         long scopeGroupId = groupId;
192 
193         javax.portlet.PortletPreferences jxPreferences =
194             PortletPreferencesFactoryUtil.getLayoutPortletSetup(
195                 layout, portletId);
196 
197         long scopeLayoutId = GetterUtil.getLong(
198             jxPreferences.getValue("lfr-scope-layout-id", null));
199 
200         if (scopeLayoutId != 0) {
201             Group scopeGroup = layout.getScopeGroup();
202 
203             if (scopeGroup != null) {
204                 scopeGroupId = scopeGroup.getGroupId();
205             }
206         }
207 
208         PortletDataContext context = new PortletDataContextImpl(
209             companyId, scopeGroupId, parameterMap, new HashSet<String>(),
210             startDate, endDate, zipWriter);
211 
212         context.setPlid(plid);
213         context.setOldPlid(plid);
214         context.setScopeLayoutId(scopeLayoutId);
215 
216         // Build compatibility
217 
218         Document doc = SAXReaderUtil.createDocument();
219 
220         Element root = doc.addElement("root");
221 
222         Element header = root.addElement("header");
223 
224         header.addAttribute(
225             "build-number", String.valueOf(ReleaseInfo.getBuildNumber()));
226         header.addAttribute("export-date", Time.getRFC822());
227 
228         if (context.hasDateRange()) {
229             header.addAttribute(
230                 "start-date", String.valueOf(context.getStartDate()));
231             header.addAttribute(
232                 "end-date", String.valueOf(context.getEndDate()));
233         }
234 
235         header.addAttribute("type", "portlet");
236         header.addAttribute("group-id", String.valueOf(scopeGroupId));
237         header.addAttribute(
238             "private-layout", String.valueOf(layout.isPrivateLayout()));
239         header.addAttribute(
240             "root-portlet-id", PortletConstants.getRootPortletId(portletId));
241 
242         // Portlet
243 
244         exportPortlet(
245             context, layoutCache, portletId, layout, root, defaultUserId,
246             exportPermissions, exportPortletArchivedSetups, exportPortletData,
247             exportPortletSetup, exportPortletUserPreferences,
248             exportUserPermissions);
249 
250         // Categories
251 
252         exportCategories(context, root);
253 
254         // Comments
255 
256         exportComments(context, root);
257 
258         // Ratings
259 
260         exportRatings(context, root);
261 
262         // Tags
263 
264         exportTags(context, root);
265 
266         // Log
267 
268         if (_log.isInfoEnabled()) {
269             _log.info("Exporting portlet took " + stopWatch.getTime() + " ms");
270         }
271 
272         // Zip
273 
274         try {
275             context.addZipEntry("/manifest.xml", doc.formattedString());
276 
277             return zipWriter.finishWithStream();
278         }
279         catch (IOException ioe) {
280             throw new SystemException(ioe);
281         }
282     }
283 
284     protected void exportCategories(
285             PortletDataContext context, Element parentEl)
286         throws SystemException {
287 
288         try {
289             Document doc = SAXReaderUtil.createDocument();
290 
291             Element root = doc.addElement("categories");
292 
293             Set<Map.Entry<String, String[]>> categoriesEntries =
294                 context.getTagsCategories().entrySet();
295 
296             for (Map.Entry<String, String[]> entry : categoriesEntries) {
297                 String[] categoryEntry = entry.getKey().split(StringPool.POUND);
298 
299                 Element asset = root.addElement("asset");
300 
301                 asset.addAttribute("class-name", categoryEntry[0]);
302                 asset.addAttribute("class-pk", categoryEntry[1]);
303                 asset.addAttribute(
304                     "entries", StringUtil.merge(entry.getValue()));
305             }
306 
307             context.addZipEntry(
308                 context.getRootPath() + "/categories.xml",
309                 doc.formattedString());
310         }
311         catch (Exception e) {
312             throw new SystemException(e);
313         }
314     }
315 
316     protected void exportComments(PortletDataContext context, Element parentEl)
317         throws SystemException {
318 
319         try {
320             Document doc = SAXReaderUtil.createDocument();
321 
322             Element root = doc.addElement("comments");
323 
324             Map<String, List<MBMessage>> commentsMap = context.getComments();
325 
326             for (Map.Entry<String, List<MBMessage>> entry :
327                     commentsMap.entrySet()) {
328 
329                 String[] comment = entry.getKey().split(StringPool.POUND);
330 
331                 String path = getCommentsPath(context, comment[0], comment[1]);
332 
333                 Element asset = root.addElement("asset");
334 
335                 asset.addAttribute("path", path);
336                 asset.addAttribute("class-name", comment[0]);
337                 asset.addAttribute("class-pk", comment[1]);
338 
339                 List<MBMessage> messages = entry.getValue();
340 
341                 for (MBMessage message : messages) {
342                     path = getCommentsPath(
343                         context, comment[0], comment[1], message);
344 
345                     if (context.isPathNotProcessed(path)) {
346                         context.addZipEntry(path, message);
347                     }
348                 }
349             }
350 
351             context.addZipEntry(
352                 context.getRootPath() + "/comments.xml", doc.formattedString());
353         }
354         catch (IOException ioe) {
355             throw new SystemException(ioe);
356         }
357     }
358 
359     protected Element exportGroupPermissions(
360             long companyId, long groupId, String resourceName,
361             String resourcePrimKey, Element parentEl, String elName)
362         throws SystemException {
363 
364         Element el = parentEl.addElement(elName);
365 
366         List<Permission> permissions =
367             PermissionLocalServiceUtil.getGroupPermissions(
368                 groupId, companyId, resourceName,
369                 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey);
370 
371         List<String> actions = ResourceActionsUtil.getActions(permissions);
372 
373         for (int i = 0; i < actions.size(); i++) {
374             String action = actions.get(i);
375 
376             Element actionKeyEl = el.addElement("action-key");
377 
378             actionKeyEl.addText(action);
379         }
380 
381         return el;
382     }
383 
384     protected void exportGroupRoles(
385             LayoutCache layoutCache, long companyId, long groupId,
386             String resourceName, String entityName, Element parentEl)
387         throws SystemException {
388 
389         List<Role> roles = layoutCache.getGroupRoles_4(groupId);
390 
391         Element groupEl = exportRoles(
392             companyId, resourceName, ResourceConstants.SCOPE_GROUP,
393             String.valueOf(groupId), parentEl, entityName + "-roles", roles);
394 
395         if (groupEl.elements().isEmpty()) {
396             parentEl.remove(groupEl);
397         }
398     }
399 
400     protected void exportInheritedPermissions(
401             LayoutCache layoutCache, long companyId, String resourceName,
402             String resourcePrimKey, Element parentEl, String entityName)
403         throws SystemException {
404 
405         Element entityPermissionsEl = SAXReaderUtil.createElement(
406             entityName + "-permissions");
407 
408         Map<String, Long> entityMap = layoutCache.getEntityMap(
409             companyId, entityName);
410 
411         Iterator<Map.Entry<String, Long>> itr = entityMap.entrySet().iterator();
412 
413         while (itr.hasNext()) {
414             Map.Entry<String, Long> entry = itr.next();
415 
416             String name = entry.getKey().toString();
417 
418             long entityGroupId = entry.getValue();
419 
420             Element entityEl = exportGroupPermissions(
421                 companyId, entityGroupId, resourceName, resourcePrimKey,
422                 entityPermissionsEl, entityName + "-actions");
423 
424             if (entityEl.elements().isEmpty()) {
425                 entityPermissionsEl.remove(entityEl);
426             }
427             else {
428                 entityEl.addAttribute("name", name);
429             }
430         }
431 
432         if (!entityPermissionsEl.elements().isEmpty()) {
433             parentEl.add(entityPermissionsEl);
434         }
435     }
436 
437     protected void exportInheritedRoles(
438             LayoutCache layoutCache, long companyId, long groupId,
439             String resourceName, String entityName, Element parentEl)
440         throws SystemException {
441 
442         Element entityRolesEl = SAXReaderUtil.createElement(
443             entityName + "-roles");
444 
445         Map<String, Long> entityMap = layoutCache.getEntityMap(
446             companyId, entityName);
447 
448         Iterator<Map.Entry<String, Long>> itr = entityMap.entrySet().iterator();
449 
450         while (itr.hasNext()) {
451             Map.Entry<String, Long> entry = itr.next();
452 
453             String name = entry.getKey().toString();
454 
455             long entityGroupId = entry.getValue();
456 
457             List<Role> entityRoles = layoutCache.getGroupRoles_4(entityGroupId);
458 
459             Element entityEl = exportRoles(
460                 companyId, resourceName, ResourceConstants.SCOPE_GROUP,
461                 String.valueOf(groupId), entityRolesEl, entityName,
462                 entityRoles);
463 
464             if (entityEl.elements().isEmpty()) {
465                 entityRolesEl.remove(entityEl);
466             }
467             else {
468                 entityEl.addAttribute("name", name);
469             }
470         }
471 
472         if (!entityRolesEl.elements().isEmpty()) {
473             parentEl.add(entityRolesEl);
474         }
475     }
476 
477     protected void exportPermissions_5(
478             LayoutCache layoutCache, long groupId, String resourceName,
479             long resourceId, Element permissionsEl)
480         throws PortalException, SystemException {
481 
482         List<Role> roles = layoutCache.getGroupRoles_5(groupId, resourceName);
483 
484         for (Role role : roles) {
485             if (role.getName().equals(RoleConstants.ADMINISTRATOR)) {
486                 continue;
487             }
488 
489             Element roleEl = permissionsEl.addElement("role");
490 
491             roleEl.addAttribute("name", role.getName());
492             roleEl.addAttribute("description", role.getDescription());
493             roleEl.addAttribute("type", String.valueOf(role.getType()));
494 
495             List<Permission> permissions =
496                 PermissionLocalServiceUtil.getRolePermissions(
497                     role.getRoleId(), resourceId);
498 
499             List<String> actions = ResourceActionsUtil.getActions(permissions);
500 
501             for (String action : actions) {
502                 Element actionKeyEl = roleEl.addElement("action-key");
503 
504                 actionKeyEl.addText(action);
505             }
506         }
507     }
508 
509     protected void exportPortlet(
510             PortletDataContext context, LayoutCache layoutCache,
511             String portletId, Layout layout, Element parentEl,
512             long defaultUserId, boolean exportPermissions,
513             boolean exportPortletArchivedSetups, boolean exportPortletData,
514             boolean exportPortletSetup, boolean exportPortletUserPreferences,
515             boolean exportUserPermissions)
516         throws PortalException, SystemException {
517 
518         long companyId = context.getCompanyId();
519         long groupId = context.getGroupId();
520 
521         Portlet portlet = PortletLocalServiceUtil.getPortletById(
522             context.getCompanyId(), portletId);
523 
524         if (portlet == null) {
525             if (_log.isDebugEnabled()) {
526                 _log.debug(
527                     "Do not export portlet " + portletId +
528                         " because the portlet does not exist");
529             }
530 
531             return;
532         }
533 
534         if ((!portlet.isInstanceable()) &&
535             (!portlet.isPreferencesUniquePerLayout()) &&
536             (context.hasNotUniquePerLayout(portletId))) {
537 
538             return;
539         }
540 
541         Document doc = SAXReaderUtil.createDocument();
542 
543         Element portletEl = doc.addElement("portlet");
544 
545         portletEl.addAttribute("portlet-id", portletId);
546         portletEl.addAttribute(
547             "root-portlet-id", PortletConstants.getRootPortletId(portletId));
548         portletEl.addAttribute("old-plid", String.valueOf(layout.getPlid()));
549         portletEl.addAttribute(
550             "scope-layout-id", String.valueOf(context.getScopeLayoutId()));
551 
552         // Data
553 
554         javax.portlet.PortletPreferences jxPreferences =
555             PortletPreferencesFactoryUtil.getPortletSetup(
556                 layout, portletId, StringPool.BLANK);
557 
558         if (exportPortletData) {
559             if (!portlet.isPreferencesUniquePerLayout()) {
560                 String dataKey =
561                     portletId + StringPool.AT + context.getScopeLayoutId();
562 
563                 if (!context.hasNotUniquePerLayout(dataKey)) {
564                     context.putNotUniquePerLayout(dataKey);
565 
566                     exportPortletData(
567                         context, portlet, layout, jxPreferences, portletEl);
568                 }
569             }
570             else {
571                 exportPortletData(
572                     context, portlet, layout, jxPreferences, portletEl);
573             }
574         }
575 
576         // Portlet preferences
577 
578         if (exportPortletSetup) {
579             exportPortletPreferences(
580                 context, PortletKeys.PREFS_OWNER_ID_DEFAULT,
581                 PortletKeys.PREFS_OWNER_TYPE_LAYOUT, false, layout, portletId,
582                 portletEl);
583 
584             exportPortletPreferences(
585                 context, groupId, PortletKeys.PREFS_OWNER_TYPE_GROUP, false,
586                 layout, portletId, portletEl);
587 
588             exportPortletPreferences(
589                 context, companyId, PortletKeys.PREFS_OWNER_TYPE_COMPANY, false,
590                 layout, portletId, portletEl);
591         }
592 
593         // Portlet preferences
594 
595         if (exportPortletUserPreferences) {
596             exportPortletPreferences(
597                 context, defaultUserId, PortletKeys.PREFS_OWNER_TYPE_USER,
598                 true, layout, portletId, portletEl);
599 
600             try {
601                 PortletPreferences groupPortletPreferences =
602                     PortletPreferencesLocalServiceUtil.getPortletPreferences(
603                         groupId, PortletKeys.PREFS_OWNER_TYPE_GROUP,
604                         PortletKeys.PREFS_PLID_SHARED, portletId);
605 
606                 exportPortletPreference(
607                     context, groupId, PortletKeys.PREFS_OWNER_TYPE_GROUP, false,
608                     groupPortletPreferences, portletId,
609                     PortletKeys.PREFS_PLID_SHARED, portletEl);
610             }
611             catch (NoSuchPortletPreferencesException nsppe) {
612             }
613         }
614 
615         // Archived setups
616 
617         if (exportPortletArchivedSetups) {
618             String rootPortletId = PortletConstants.getRootPortletId(portletId);
619 
620             List<PortletItem> portletItems =
621                 PortletItemLocalServiceUtil.getPortletItems(
622                     groupId, rootPortletId, PortletPreferences.class.getName());
623 
624             for (PortletItem portletItem: portletItems) {
625                 long ownerId = portletItem.getPortletItemId();
626                 int ownerType = PortletKeys.PREFS_OWNER_TYPE_ARCHIVED;
627 
628                 exportPortletPreferences(
629                     context, ownerId, ownerType, false, null,
630                     portletItem.getPortletId(), portletEl);
631             }
632         }
633 
634         Group guestGroup = GroupLocalServiceUtil.getGroup(
635             companyId, GroupConstants.GUEST);
636 
637         // Permissions
638 
639         if (exportPermissions) {
640             Element permissionsEl = portletEl.addElement("permissions");
641 
642             String resourceName = PortletConstants.getRootPortletId(portletId);
643             String resourcePrimKey = PortletPermissionUtil.getPrimaryKey(
644                 layout.getPlid(), portletId);
645 
646             if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
647                 exportPortletPermissions_5(
648                     layoutCache, companyId, groupId, resourceName,
649                     resourcePrimKey, permissionsEl);
650             }
651             else {
652                 exportPortletPermissions_4(
653                     layoutCache, companyId, groupId, guestGroup, resourceName,
654                     resourcePrimKey, permissionsEl, exportUserPermissions);
655 
656                 Element rolesEl = portletEl.addElement("roles");
657 
658                 exportPortletRoles(
659                     layoutCache, companyId, groupId, portletId, rolesEl);
660             }
661         }
662 
663         // Zip
664 
665         StringBuilder sb = new StringBuilder();
666 
667         sb.append(context.getPortletPath(portletId));
668 
669         if (portlet.isPreferencesUniquePerLayout()) {
670             sb.append(StringPool.SLASH);
671             sb.append(layout.getPlid());
672         }
673 
674         sb.append("/portlet.xml");
675 
676         Element el = parentEl.addElement("portlet");
677 
678         el.addAttribute("portlet-id", portletId);
679         el.addAttribute(
680             "layout-id", String.valueOf(layout.getLayoutId()));
681         el.addAttribute("path", sb.toString());
682 
683         try {
684             context.addZipEntry(sb.toString(), doc.formattedString());
685         }
686         catch (IOException ioe) {
687             if (_log.isWarnEnabled()) {
688                 _log.warn(ioe.getMessage());
689             }
690         }
691     }
692 
693     protected void exportPortletData(
694             PortletDataContext context, Portlet portlet, Layout layout,
695             javax.portlet.PortletPreferences portletPreferences,
696             Element parentEl)
697         throws SystemException {
698 
699         String portletDataHandlerClass =
700             portlet.getPortletDataHandlerClass();
701 
702         if (Validator.isNull(portletDataHandlerClass)) {
703             return;
704         }
705 
706         String portletId = portlet.getPortletId();
707 
708         if (_log.isDebugEnabled()) {
709             _log.debug("Exporting data for " + portletId);
710         }
711 
712         String data = null;
713 
714         long groupId = context.getGroupId();
715 
716         context.setGroupId(context.getScopeGroupId());
717 
718         try {
719             data = (String)PortletClassInvoker.invoke(
720                 portletId, portletDataHandlerClass, "exportData", context,
721                 portletId, portletPreferences);
722         }
723         catch (Exception e) {
724             throw new SystemException(e);
725         }
726         finally {
727             context.setGroupId(groupId);
728         }
729 
730         if (Validator.isNull(data)) {
731             if (_log.isDebugEnabled()) {
732                 _log.debug(
733                     "Not exporting data for " + portletId +
734                         " because null data was returned");
735             }
736 
737             return;
738         }
739 
740         StringBuilder sb = new StringBuilder();
741 
742         sb.append(context.getPortletPath(portletId));
743 
744         if (portlet.isPreferencesUniquePerLayout()) {
745             sb.append(StringPool.SLASH);
746             sb.append(layout.getPlid());
747         }
748 
749         sb.append("/portlet-data.xml");
750 
751         Element portletDataEl = parentEl.addElement("portlet-data");
752 
753         portletDataEl.addAttribute("path", sb.toString());
754 
755         context.addZipEntry(sb.toString(), data);
756     }
757 
758     protected void exportPortletPermissions_4(
759             LayoutCache layoutCache, long companyId, long groupId,
760             Group guestGroup, String resourceName, String resourcePrimKey,
761             Element permissionsEl, boolean exportUserPermissions)
762         throws SystemException {
763 
764         exportGroupPermissions(
765             companyId, groupId, resourceName, resourcePrimKey, permissionsEl,
766             "community-actions");
767 
768         if (groupId != guestGroup.getGroupId()) {
769             exportGroupPermissions(
770                 companyId, guestGroup.getGroupId(), resourceName,
771                 resourcePrimKey, permissionsEl, "guest-actions");
772         }
773 
774         if (exportUserPermissions) {
775             exportUserPermissions(
776                 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
777                 permissionsEl);
778         }
779 
780         exportInheritedPermissions(
781             layoutCache, companyId, resourceName, resourcePrimKey,
782             permissionsEl, "organization");
783 
784         exportInheritedPermissions(
785             layoutCache, companyId, resourceName, resourcePrimKey,
786             permissionsEl, "user-group");
787     }
788 
789     protected void exportPortletPermissions_5(
790             LayoutCache layoutCache, long companyId, long groupId,
791             String resourceName, String resourcePrimKey, Element permissionsEl)
792         throws PortalException, SystemException {
793 
794         boolean portletActions = true;
795 
796         Resource resource = layoutCache.getResource(
797             companyId, groupId, resourceName,
798             ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
799             portletActions);
800 
801         exportPermissions_5(
802             layoutCache, groupId, resourceName, resource.getResourceId(),
803             permissionsEl);
804     }
805 
806     protected void exportPortletPreference(
807             PortletDataContext context, long ownerId, int ownerType,
808             boolean defaultUser, PortletPreferences portletPreferences,
809             String portletId, long plid, Element parentEl)
810         throws SystemException {
811 
812         try {
813             Document preferencesDoc = SAXReaderUtil.read(
814                 portletPreferences.getPreferences());
815 
816             Element root = preferencesDoc.getRootElement();
817 
818             root.addAttribute("owner-id", String.valueOf(ownerId));
819             root.addAttribute("owner-type", String.valueOf(ownerType));
820             root.addAttribute("default-user", String.valueOf(defaultUser));
821             root.addAttribute("plid", String.valueOf(plid));
822             root.addAttribute("portlet-id", portletId);
823 
824             if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
825                 PortletItem portletItem =
826                     PortletItemLocalServiceUtil.getPortletItem(ownerId);
827 
828                 User user = UserLocalServiceUtil.getUserById(
829                     portletItem.getUserId());
830 
831                 root.addAttribute("archive-user-uuid", user.getUuid());
832                 root.addAttribute("archive-name", portletItem.getName());
833             }
834 
835             String path = getPortletPreferencesPath(
836                 context, portletId, ownerId, ownerType, plid);
837 
838             parentEl.addElement(
839                 "portlet-preferences").addAttribute("path", path);
840 
841             if (context.isPathNotProcessed(path)) {
842                 context.addZipEntry(path, preferencesDoc.formattedString());
843             }
844         }
845         catch (Exception e) {
846             throw new SystemException(e);
847         }
848     }
849 
850     protected void exportPortletPreferences(
851             PortletDataContext context, long ownerId, int ownerType,
852             boolean defaultUser, Layout layout, String portletId,
853             Element parentEl)
854         throws PortalException, SystemException {
855 
856         PortletPreferences portletPreferences = null;
857 
858         long plid = PortletKeys.PREFS_OWNER_ID_DEFAULT;
859 
860         if (layout != null) {
861             plid = layout.getPlid();
862         }
863 
864         if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) ||
865             (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
866             (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED)) {
867 
868             plid = PortletKeys.PREFS_OWNER_ID_DEFAULT;
869         }
870 
871         try {
872             portletPreferences =
873                 PortletPreferencesLocalServiceUtil.getPortletPreferences(
874                     ownerId, ownerType, plid, portletId);
875 
876             LayoutTypePortlet layoutTypePortlet = null;
877 
878             if (layout != null) {
879                 layoutTypePortlet = (LayoutTypePortlet)layout.getLayoutType();
880             }
881 
882             if ((layoutTypePortlet == null) ||
883                 (layoutTypePortlet.hasPortletId(portletId))) {
884 
885                 exportPortletPreference(
886                     context, ownerId, ownerType, defaultUser,
887                     portletPreferences, portletId, plid, parentEl);
888             }
889         }
890         catch (NoSuchPortletPreferencesException nsppe) {
891         }
892     }
893 
894     protected void exportPortletRoles(
895             LayoutCache layoutCache, long companyId, long groupId,
896             String portletId, Element rolesEl)
897         throws SystemException {
898 
899         String resourceName = PortletConstants.getRootPortletId(
900             portletId);
901 
902         Element portletEl = rolesEl.addElement("portlet");
903 
904         portletEl.addAttribute("portlet-id", portletId);
905 
906         exportGroupRoles(
907             layoutCache, companyId, groupId, resourceName, "community",
908             portletEl);
909 
910         exportUserRoles(
911             layoutCache, companyId, groupId, resourceName, portletEl);
912 
913         exportInheritedRoles(
914             layoutCache, companyId, groupId, resourceName, "organization",
915             portletEl);
916 
917         exportInheritedRoles(
918             layoutCache, companyId, groupId, resourceName, "user-group",
919             portletEl);
920 
921         if (portletEl.elements().isEmpty()) {
922             rolesEl.remove(portletEl);
923         }
924     }
925 
926     protected void exportRatings(PortletDataContext context, Element parentEl)
927         throws SystemException {
928 
929         try {
930             Document doc = SAXReaderUtil.createDocument();
931 
932             Element root = doc.addElement("ratings");
933 
934             Map<String, List<RatingsEntry>> ratingsEntriesMap =
935                 context.getRatingsEntries();
936 
937             for (Map.Entry<String, List<RatingsEntry>> entry :
938                     ratingsEntriesMap.entrySet()) {
939 
940                 String[] ratingsEntry = entry.getKey().split(StringPool.POUND);
941 
942                 String ratingPath = getRatingsPath(
943                     context, ratingsEntry[0], ratingsEntry[1]);
944 
945                 Element asset = root.addElement("asset");
946 
947                 asset.addAttribute("path", ratingPath);
948                 asset.addAttribute("class-name", ratingsEntry[0]);
949                 asset.addAttribute("class-pk", ratingsEntry[1]);
950 
951                 List<RatingsEntry> ratingsEntries = entry.getValue();
952 
953                 for (RatingsEntry rating : ratingsEntries) {
954                     ratingPath = getRatingsPath(
955                         context, ratingsEntry[0], ratingsEntry[1], rating);
956 
957                     context.addZipEntry(ratingPath, rating);
958                 }
959             }
960 
961             context.addZipEntry(
962                 context.getRootPath() + "/ratings.xml", doc.formattedString());
963         }
964         catch (Exception e) {
965             throw new SystemException(e);
966         }
967     }
968 
969     protected Element exportRoles(
970             long companyId, String resourceName, int scope,
971             String resourcePrimKey, Element parentEl, String elName,
972             List<Role> roles)
973         throws SystemException {
974 
975         Element el = parentEl.addElement(elName);
976 
977         Map<String, List<String>> resourceRoles =
978             RoleLocalServiceUtil.getResourceRoles(
979                 companyId, resourceName, scope, resourcePrimKey);
980 
981         Iterator<Map.Entry<String, List<String>>> itr =
982             resourceRoles.entrySet().iterator();
983 
984         while (itr.hasNext()) {
985             Map.Entry<String, List<String>> entry = itr.next();
986 
987             String roleName = entry.getKey().toString();
988 
989             if (hasRole(roles, roleName)) {
990                 Element roleEl = el.addElement("role");
991 
992                 roleEl.addAttribute("name", roleName);
993 
994                 List<String> actions = entry.getValue();
995 
996                 for (int i = 0; i < actions.size(); i++) {
997                     String action = actions.get(i);
998 
999                     Element actionKeyEl = roleEl.addElement("action-key");
1000
1001                    actionKeyEl.addText(action);
1002                    actionKeyEl.addAttribute("scope", String.valueOf(scope));
1003                }
1004            }
1005        }
1006
1007        return el;
1008    }
1009
1010    protected void exportTags(PortletDataContext context, Element parentEl)
1011        throws SystemException {
1012
1013        try {
1014            Document doc = SAXReaderUtil.createDocument();
1015
1016            Element root = doc.addElement("tags");
1017
1018            Map<String, String[]> tagsEntries = context.getTagsEntries();
1019
1020            for (Map.Entry<String, String[]> entry : tagsEntries.entrySet()) {
1021                String[] tagsEntry = entry.getKey().split(StringPool.POUND);
1022
1023                Element asset = root.addElement("asset");
1024
1025                asset.addAttribute("class-name", tagsEntry[0]);
1026                asset.addAttribute("class-pk", tagsEntry[1]);
1027                asset.addAttribute(
1028                    "entries", StringUtil.merge(entry.getValue()));
1029            }
1030
1031            context.addZipEntry(
1032                context.getRootPath() + "/tags.xml", doc.formattedString());
1033        }
1034        catch (Exception e) {
1035            throw new SystemException(e);
1036        }
1037    }
1038
1039    protected void exportUserPermissions(
1040            LayoutCache layoutCache, long companyId, long groupId,
1041            String resourceName, String resourcePrimKey, Element parentEl)
1042        throws SystemException {
1043
1044        StopWatch stopWatch = null;
1045
1046        if (_log.isDebugEnabled()) {
1047            stopWatch = new StopWatch();
1048
1049            stopWatch.start();
1050        }
1051
1052        Element userPermissionsEl = SAXReaderUtil.createElement(
1053            "user-permissions");
1054
1055        List<User> users = layoutCache.getGroupUsers(groupId);
1056
1057        for (User user : users) {
1058            String uuid = user.getUuid();
1059
1060            Element userActionsEl = SAXReaderUtil.createElement("user-actions");
1061
1062            List<Permission> permissions =
1063                PermissionLocalServiceUtil.getUserPermissions(
1064                    user.getUserId(), companyId, resourceName,
1065                    ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey);
1066
1067            List<String> actions = ResourceActionsUtil.getActions(permissions);
1068
1069            for (String action : actions) {
1070                Element actionKeyEl = userActionsEl.addElement("action-key");
1071
1072                actionKeyEl.addText(action);
1073            }
1074
1075            if (!userActionsEl.elements().isEmpty()) {
1076                userActionsEl.addAttribute("uuid", uuid);
1077                userPermissionsEl.add(userActionsEl);
1078            }
1079        }
1080
1081        if (!userPermissionsEl.elements().isEmpty()) {
1082            parentEl.add(userPermissionsEl);
1083        }
1084
1085        if (_log.isDebugEnabled()) {
1086            _log.debug(
1087                "Export user permissions for {" + resourceName + ", " +
1088                    resourcePrimKey + "} with " + users.size() +
1089                        " users takes " + stopWatch.getTime() + " ms");
1090        }
1091    }
1092
1093    protected void exportUserRoles(
1094            LayoutCache layoutCache, long companyId, long groupId,
1095            String resourceName, Element parentEl)
1096        throws SystemException {
1097
1098        Element userRolesEl = SAXReaderUtil.createElement("user-roles");
1099
1100        List<User> users = layoutCache.getGroupUsers(groupId);
1101
1102        for (User user : users) {
1103            long userId = user.getUserId();
1104            String uuid = user.getUuid();
1105
1106            List<Role> userRoles = layoutCache.getUserRoles(userId);
1107
1108            Element userEl = exportRoles(
1109                companyId, resourceName, ResourceConstants.SCOPE_GROUP,
1110                String.valueOf(groupId), userRolesEl, "user", userRoles);
1111
1112            if (userEl.elements().isEmpty()) {
1113                userRolesEl.remove(userEl);
1114            }
1115            else {
1116                userEl.addAttribute("uuid", uuid);
1117            }
1118        }
1119
1120        if (!userRolesEl.elements().isEmpty()) {
1121            parentEl.add(userRolesEl);
1122        }
1123    }
1124
1125    protected String getCommentsPath(
1126        PortletDataContext context, String className, String classPK) {
1127
1128        StringBuilder sb = new StringBuilder();
1129
1130        sb.append(context.getRootPath());
1131        sb.append("/comments/");
1132        sb.append(PortalUtil.getClassNameId(className));
1133        sb.append(CharPool.FORWARD_SLASH);
1134        sb.append(classPK);
1135        sb.append(CharPool.FORWARD_SLASH);
1136
1137        return sb.toString();
1138    }
1139
1140    protected String getCommentsPath(
1141        PortletDataContext context, String className, String classPK,
1142        MBMessage message) {
1143
1144        StringBuilder sb = new StringBuilder();
1145
1146        sb.append(context.getRootPath());
1147        sb.append("/comments/");
1148        sb.append(PortalUtil.getClassNameId(className));
1149        sb.append(CharPool.FORWARD_SLASH);
1150        sb.append(classPK);
1151        sb.append(CharPool.FORWARD_SLASH);
1152        sb.append(message.getMessageId());
1153        sb.append(".xml");
1154
1155        return sb.toString();
1156    }
1157
1158    protected String getPortletDataPath(
1159        PortletDataContext context, String portletId) {
1160
1161        return context.getPortletPath(portletId) + "/portlet-data.xml";
1162    }
1163
1164    protected String getPortletPreferencesPath(
1165        PortletDataContext context, String portletId, long ownerId,
1166        int ownerType, long plid) {
1167
1168        StringBuilder sb = new StringBuilder();
1169
1170        sb.append(context.getPortletPath(portletId));
1171        sb.append("/preferences/");
1172
1173        if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
1174            sb.append("company/");
1175        }
1176        else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
1177            sb.append("group/");
1178        }
1179        else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT) {
1180            sb.append("layout/");
1181        }
1182        else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) {
1183            sb.append("user/");
1184        }
1185        else if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
1186            sb.append("archived/");
1187        }
1188
1189        sb.append(ownerId);
1190        sb.append(CharPool.FORWARD_SLASH);
1191        sb.append(plid);
1192        sb.append(CharPool.FORWARD_SLASH);
1193        sb.append("portlet-preferences.xml");
1194
1195        return sb.toString();
1196    }
1197
1198    protected String getRatingsPath(
1199        PortletDataContext context, String className, String classPK) {
1200
1201        StringBuilder sb = new StringBuilder();
1202
1203        sb.append(context.getRootPath());
1204        sb.append("/ratings/");
1205        sb.append(PortalUtil.getClassNameId(className));
1206        sb.append(CharPool.FORWARD_SLASH);
1207        sb.append(classPK);
1208        sb.append(CharPool.FORWARD_SLASH);
1209
1210        return sb.toString();
1211    }
1212
1213    protected String getRatingsPath(
1214        PortletDataContext context, String className, String classPK,
1215        RatingsEntry rating) {
1216
1217        StringBuilder sb = new StringBuilder();
1218
1219        sb.append(context.getRootPath());
1220        sb.append("/ratings/");
1221        sb.append(PortalUtil.getClassNameId(className));
1222        sb.append(CharPool.FORWARD_SLASH);
1223        sb.append(classPK);
1224        sb.append(CharPool.FORWARD_SLASH);
1225        sb.append(rating.getEntryId());
1226        sb.append(".xml");
1227
1228        return sb.toString();
1229    }
1230
1231    protected boolean hasRole(List<Role> roles, String roleName) {
1232        if ((roles == null) || (roles.size() == 0)) {
1233            return false;
1234        }
1235
1236        for (Role role : roles) {
1237            if (role.getName().equals(roleName)) {
1238                return true;
1239            }
1240        }
1241
1242        return false;
1243    }
1244
1245    private static Log _log = LogFactoryUtil.getLog(PortletExporter.class);
1246
1247}