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