1
14
15 package com.liferay.portal.lar;
16
17 import com.liferay.portal.LARFileException;
18 import com.liferay.portal.LARTypeException;
19 import com.liferay.portal.LayoutImportException;
20 import com.liferay.portal.PortletIdException;
21 import com.liferay.portal.kernel.exception.PortalException;
22 import com.liferay.portal.kernel.exception.SystemException;
23 import com.liferay.portal.kernel.log.Log;
24 import com.liferay.portal.kernel.log.LogFactoryUtil;
25 import com.liferay.portal.kernel.util.ArrayUtil;
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.StringUtil;
30 import com.liferay.portal.kernel.xml.Document;
31 import com.liferay.portal.kernel.xml.DocumentException;
32 import com.liferay.portal.kernel.xml.Element;
33 import com.liferay.portal.kernel.xml.SAXReaderUtil;
34 import com.liferay.portal.kernel.zip.ZipReader;
35 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
36 import com.liferay.portal.model.Group;
37 import com.liferay.portal.model.Layout;
38 import com.liferay.portal.model.Portlet;
39 import com.liferay.portal.model.PortletConstants;
40 import com.liferay.portal.model.PortletItem;
41 import com.liferay.portal.model.PortletPreferences;
42 import com.liferay.portal.model.User;
43 import com.liferay.portal.service.GroupLocalServiceUtil;
44 import com.liferay.portal.service.LayoutLocalServiceUtil;
45 import com.liferay.portal.service.PortletItemLocalServiceUtil;
46 import com.liferay.portal.service.PortletLocalServiceUtil;
47 import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
48 import com.liferay.portal.service.UserLocalServiceUtil;
49 import com.liferay.portal.service.persistence.PortletPreferencesUtil;
50 import com.liferay.portal.service.persistence.UserUtil;
51 import com.liferay.portal.util.PortletKeys;
52 import com.liferay.portlet.PortletPreferencesFactoryUtil;
53 import com.liferay.portlet.PortletPreferencesImpl;
54 import com.liferay.portlet.PortletPreferencesSerializer;
55 import com.liferay.portlet.asset.NoSuchCategoryException;
56 import com.liferay.portlet.asset.model.AssetCategory;
57 import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
58 import com.liferay.portlet.messageboards.model.MBMessage;
59 import com.liferay.portlet.ratings.model.RatingsEntry;
60 import com.liferay.portlet.social.util.SocialActivityThreadLocal;
61
62 import java.io.File;
63
64 import java.util.ArrayList;
65 import java.util.HashSet;
66 import java.util.List;
67 import java.util.Map;
68
69 import org.apache.commons.lang.time.StopWatch;
70
71
81 public class PortletImporter {
82
83 public void importPortletInfo(
84 long userId, long plid, long groupId, String portletId,
85 Map<String, String[]> parameterMap, File file)
86 throws PortalException, SystemException {
87
88 boolean deletePortletData = MapUtil.getBoolean(
89 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
90 boolean importPortletData = MapUtil.getBoolean(
91 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
92 boolean importPortletArchivedSetups = MapUtil.getBoolean(
93 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
94 boolean importPortletSetup = MapUtil.getBoolean(
95 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
96 boolean importUserPreferences = MapUtil.getBoolean(
97 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
98 String userIdStrategy = MapUtil.getString(
99 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
100
101 StopWatch stopWatch = null;
102
103 if (_log.isInfoEnabled()) {
104 stopWatch = new StopWatch();
105
106 stopWatch.start();
107 }
108
109 Layout layout = LayoutLocalServiceUtil.getLayout(plid);
110
111 long companyId = layout.getCompanyId();
112
113 User user = UserUtil.findByPrimaryKey(userId);
114
115 UserIdStrategy strategy = getUserIdStrategy(user, userIdStrategy);
116
117 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
118
119 PortletDataContext context = new PortletDataContextImpl(
120 companyId, groupId, parameterMap, new HashSet<String>(),
121 strategy, zipReader);
122
123 context.setPlid(plid);
124 context.setPrivateLayout(layout.isPrivateLayout());
125
126
128 Element root = null;
129
130
132 String xml = context.getZipEntryAsString("/manifest.xml");
133
134 try {
135 Document doc = SAXReaderUtil.read(xml);
136
137 root = doc.getRootElement();
138 }
139 catch (Exception e) {
140 throw new LARFileException(
141 "Cannot locate a manifest in this LAR file.");
142 }
143
144
146 Element header = root.element("header");
147
148 int buildNumber = ReleaseInfo.getBuildNumber();
149
150 int importBuildNumber = GetterUtil.getInteger(
151 header.attributeValue("build-number"));
152
153 if (buildNumber != importBuildNumber) {
154 throw new LayoutImportException(
155 "LAR build number " + importBuildNumber + " does not match " +
156 "portal build number " + buildNumber);
157 }
158
159
161 String type = header.attributeValue("type");
162
163 if (!type.equals("portlet")) {
164 throw new LARTypeException(
165 "Invalid type of LAR file (" + type + ")");
166 }
167
168
170 String rootPortletId = header.attributeValue("root-portlet-id");
171
172 if (!PortletConstants.getRootPortletId(portletId).equals(
173 rootPortletId)) {
174
175 throw new PortletIdException("Invalid portlet id " + rootPortletId);
176 }
177
178
180 long sourceGroupId = GetterUtil.getLong(
181 header.attributeValue("group-id"));
182
183 context.setSourceGroupId(sourceGroupId);
184
185
188 readCategories(context, root);
189 readComments(context, root);
190 readRatings(context, root);
191 readTags(context, root);
192
193
195 if (_log.isDebugEnabled()) {
196 _log.debug("Deleting portlet data");
197 }
198
199 if (deletePortletData) {
200 deletePortletData(context, portletId, plid);
201 }
202
203 Element portletRefEl = root.element("portlet");
204 Element portletEl = null;
205
206 try {
207 Document portletDoc = SAXReaderUtil.read(
208 context.getZipEntryAsString(
209 portletRefEl.attributeValue("path")));
210
211 portletEl = portletDoc.getRootElement();
212 }
213 catch (DocumentException de) {
214 throw new SystemException(de);
215 }
216
217
219 importPortletPreferences(
220 context, layout.getCompanyId(), groupId, layout, portletId,
221 portletEl, importPortletSetup, importPortletArchivedSetups,
222 importUserPreferences, true);
223
224
226 if (_log.isDebugEnabled()) {
227 _log.debug("Importing portlet data");
228 }
229
230 if (importPortletData) {
231 Element portletDataRefEl = portletEl.element("portlet-data");
232
233 if (portletDataRefEl != null) {
234 importPortletData(context, portletId, plid, portletDataRefEl);
235 }
236 else {
237 if (_log.isWarnEnabled()) {
238 _log.warn(
239 "Could not import portlet data because it cannot be " +
240 "found in the input");
241 }
242 }
243 }
244
245 if (_log.isInfoEnabled()) {
246 _log.info(
247 "Importing portlet data takes " + stopWatch.getTime() + " ms");
248 }
249
250 zipReader.close();
251 }
252
253 protected void deletePortletData(
254 PortletDataContext context, String portletId, long plid)
255 throws SystemException {
256
257 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
258 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
259
260 PortletPreferences portletPreferences =
261 PortletPreferencesUtil.fetchByO_O_P_P(
262 ownerId, ownerType, plid, portletId);
263
264 if (portletPreferences == null) {
265 portletPreferences =
266 new com.liferay.portal.model.impl.PortletPreferencesImpl();
267 }
268
269 String xml = deletePortletData(
270 context, portletId, portletPreferences);
271
272 if (xml != null) {
273 PortletPreferencesLocalServiceUtil.updatePreferences(
274 ownerId, ownerType, plid, portletId, xml);
275 }
276 }
277
278 protected String deletePortletData(
279 PortletDataContext context, String portletId,
280 PortletPreferences portletPreferences)
281 throws SystemException {
282
283 Portlet portlet = PortletLocalServiceUtil.getPortletById(
284 context.getCompanyId(), portletId);
285
286 if (portlet == null) {
287 if (_log.isDebugEnabled()) {
288 _log.debug(
289 "Do not delete portlet data for " + portletId +
290 " because the portlet does not exist");
291 }
292
293 return null;
294 }
295
296 PortletDataHandler portletDataHandler =
297 portlet.getPortletDataHandlerInstance();
298
299 if (portletDataHandler == null) {
300 if (_log.isDebugEnabled()) {
301 _log.debug(
302 "Do not delete portlet data for " + portletId +
303 " because the portlet does not have a " +
304 "PortletDataHandler");
305 }
306
307 return null;
308 }
309
310 if (_log.isDebugEnabled()) {
311 _log.debug("Deleting data for " + portletId);
312 }
313
314 PortletPreferencesImpl preferencesImpl =
315 (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
316 portletPreferences.getPreferences());
317
318 try {
319 preferencesImpl =
320 (PortletPreferencesImpl)portletDataHandler.deleteData(
321 context, portletId, preferencesImpl);
322 }
323 catch (Exception e) {
324 throw new SystemException(e);
325 }
326 finally {
327 context.setGroupId(context.getScopeGroupId());
328 }
329
330 if (preferencesImpl == null) {
331 return null;
332 }
333
334 return PortletPreferencesSerializer.toXML(preferencesImpl);
335 }
336
337 protected UserIdStrategy getUserIdStrategy(
338 User user, String userIdStrategy) {
339
340 if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
341 return new AlwaysCurrentUserIdStrategy(user);
342 }
343
344 return new CurrentUserIdStrategy(user);
345 }
346
347 protected void importPortletData(
348 PortletDataContext context, String portletId, long plid,
349 Element portletDataRefEl)
350 throws SystemException {
351
352 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
353 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
354
355 PortletPreferences portletPreferences =
356 PortletPreferencesUtil.fetchByO_O_P_P(
357 ownerId, ownerType, plid, portletId);
358
359 if (portletPreferences == null) {
360 portletPreferences =
361 new com.liferay.portal.model.impl.PortletPreferencesImpl();
362 }
363
364 String xml = importPortletData(
365 context, portletId, portletPreferences, portletDataRefEl);
366
367 if (xml != null) {
368 PortletPreferencesLocalServiceUtil.updatePreferences(
369 ownerId, ownerType, plid, portletId, xml);
370 }
371 }
372
373 protected String importPortletData(
374 PortletDataContext context, String portletId,
375 PortletPreferences portletPreferences, Element portletDataRefEl)
376 throws SystemException {
377
378 Portlet portlet = PortletLocalServiceUtil.getPortletById(
379 context.getCompanyId(), portletId);
380
381 if (portlet == null) {
382 if (_log.isDebugEnabled()) {
383 _log.debug(
384 "Do not import portlet data for " + portletId +
385 " because the portlet does not exist");
386 }
387
388 return null;
389 }
390
391 PortletDataHandler portletDataHandler =
392 portlet.getPortletDataHandlerInstance();
393
394 if (portletDataHandler == null) {
395 if (_log.isDebugEnabled()) {
396 _log.debug(
397 "Do not import portlet data for " + portletId +
398 " because the portlet does not have a " +
399 "PortletDataHandler");
400 }
401
402 return null;
403 }
404
405 if (_log.isDebugEnabled()) {
406 _log.debug("Importing data for " + portletId);
407 }
408
409
411 long groupId = context.getGroupId();
412
413 long scopeLayoutId = context.getScopeLayoutId();
414
415 if (scopeLayoutId == 0) {
416 scopeLayoutId = GetterUtil.getLong(
417 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
418 }
419
420 if (scopeLayoutId > 0) {
421 try {
422 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
423 context.getGroupId(), context.isPrivateLayout(),
424 scopeLayoutId);
425
426 Group scopeGroup = null;
427
428 if (scopeLayout.hasScopeGroup()) {
429 scopeGroup = scopeLayout.getScopeGroup();
430 }
431 else {
432 String name = String.valueOf(scopeLayout.getPlid());
433
434 scopeGroup = GroupLocalServiceUtil.addGroup(
435 context.getUserId(null), Layout.class.getName(),
436 scopeLayout.getPlid(), name, null, 0, null, true, null);
437 }
438
439 context.setGroupId(scopeGroup.getGroupId());
440 }
441 catch (PortalException pe) {
442 }
443 }
444
445 PortletPreferencesImpl preferencesImpl = null;
446
447 if (portletPreferences != null) {
448 preferencesImpl = (PortletPreferencesImpl)
449 PortletPreferencesSerializer.fromDefaultXML(
450 portletPreferences.getPreferences());
451 }
452
453 String portletData = context.getZipEntryAsString(
454 portletDataRefEl.attributeValue("path"));
455
456 try {
457 SocialActivityThreadLocal.setEnabled(false);
458
459 preferencesImpl =
460 (PortletPreferencesImpl)portletDataHandler.importData(
461 context, portletId, preferencesImpl, portletData);
462 }
463 catch (Exception e) {
464 throw new SystemException(e);
465 }
466 finally {
467 context.setGroupId(groupId);
468
469 SocialActivityThreadLocal.setEnabled(true);
470 }
471
472 if (preferencesImpl == null) {
473 return null;
474 }
475
476 return PortletPreferencesSerializer.toXML(preferencesImpl);
477 }
478
479 protected void importPortletPreferences(
480 PortletDataContext context, long companyId, long groupId,
481 Layout layout, String portletId, Element parentEl,
482 boolean importPortletSetup, boolean importPortletArchivedSetups,
483 boolean importUserPreferences, boolean preserveScopeLayoutId)
484 throws PortalException, SystemException {
485
486 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
487 long plid = 0;
488 long scopeLayoutId = 0;
489
490 if (layout != null) {
491 plid = layout.getPlid();
492
493 if (preserveScopeLayoutId && (portletId != null)) {
494 javax.portlet.PortletPreferences jxPreferences =
495 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
496 layout, portletId);
497
498 scopeLayoutId = GetterUtil.getLong(
499 jxPreferences.getValue("lfr-scope-layout-id", null));
500
501 context.setScopeLayoutId(scopeLayoutId);
502 }
503 }
504
505 List<Element> preferencesEls = parentEl.elements("portlet-preferences");
506
507 for (Element preferencesEl : preferencesEls) {
508 String path = preferencesEl.attributeValue("path");
509
510 if (context.isPathNotProcessed(path)) {
511 Element el = null;
512 String xml = null;
513
514 try {
515 xml = context.getZipEntryAsString(path);
516
517 Document preferencesDoc = SAXReaderUtil.read(xml);
518
519 el = preferencesDoc.getRootElement();
520 }
521 catch (DocumentException de) {
522 throw new SystemException(de);
523 }
524
525 long ownerId = GetterUtil.getLong(
526 el.attributeValue("owner-id"));
527 int ownerType = GetterUtil.getInteger(
528 el.attributeValue("owner-type"));
529
530 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
531 continue;
532 }
533
534 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
535 (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
536 !importPortletSetup) {
537
538 continue;
539 }
540
541 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
542 !importPortletArchivedSetups) {
543
544 continue;
545 }
546
547 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
548 (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
549 !importUserPreferences) {
550
551 continue;
552 }
553
554 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
555 plid = PortletKeys.PREFS_PLID_SHARED;
556 ownerId = context.getGroupId();
557 }
558
559 boolean defaultUser = GetterUtil.getBoolean(
560 el.attributeValue("default-user"));
561
562 if (portletId == null) {
563 portletId = el.attributeValue("portlet-id");
564 }
565
566 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
567 portletId = PortletConstants.getRootPortletId(portletId);
568
569 String userUuid = el.attributeValue("archive-user-uuid");
570 String name = el.attributeValue("archive-name");
571
572 long userId = context.getUserId(userUuid);
573
574 PortletItem portletItem =
575 PortletItemLocalServiceUtil.updatePortletItem(
576 userId, groupId, name, portletId,
577 PortletPreferences.class.getName());
578
579 plid = 0;
580 ownerId = portletItem.getPortletItemId();
581 }
582
583 if (defaultUser) {
584 ownerId = defaultUserId;
585 }
586
587 PortletPreferencesLocalServiceUtil.updatePreferences(
588 ownerId, ownerType, plid, portletId, xml);
589 }
590 }
591
592 if (preserveScopeLayoutId && (layout != null)) {
593 javax.portlet.PortletPreferences jxPreferences =
594 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
595 layout, portletId);
596
597 try {
598 jxPreferences.setValue(
599 "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
600
601 jxPreferences.store();
602 }
603 catch (Exception e) {
604 throw new PortalException(e);
605 }
606 finally {
607 context.setScopeLayoutId(scopeLayoutId);
608 }
609 }
610 }
611
612 protected void readComments(PortletDataContext context, Element parentEl)
613 throws SystemException {
614
615 try {
616 String xml = context.getZipEntryAsString(
617 context.getSourceRootPath() + "/comments.xml");
618
619 if (xml == null) {
620 return;
621 }
622
623 Document doc = SAXReaderUtil.read(xml);
624
625 Element root = doc.getRootElement();
626
627 List<Element> assets = root.elements("asset");
628
629 for (Element asset : assets) {
630 String path = asset.attributeValue("path");
631 String className = asset.attributeValue("class-name");
632 long classPK = GetterUtil.getLong(
633 asset.attributeValue("class-pk"));
634
635 List<String> zipFolderEntries = context.getZipFolderEntries(
636 path);
637
638 List<MBMessage> messages = new ArrayList<MBMessage>();
639
640 for (String zipFolderEntry : zipFolderEntries) {
641 MBMessage message = (MBMessage)context.getZipEntryAsObject(
642 zipFolderEntry);
643
644 if (message != null) {
645 messages.add(message);
646 }
647 }
648
649 context.addComments(className, classPK, messages);
650 }
651 }
652 catch (Exception e) {
653 throw new SystemException(e);
654 }
655 }
656
657 protected void readRatings(PortletDataContext context, Element parentEl)
658 throws SystemException {
659
660 try {
661 String xml = context.getZipEntryAsString(
662 context.getSourceRootPath() + "/ratings.xml");
663
664 if (xml == null) {
665 return;
666 }
667
668 Document doc = SAXReaderUtil.read(xml);
669
670 Element root = doc.getRootElement();
671
672 List<Element> assets = root.elements("asset");
673
674 for (Element asset : assets) {
675 String path = asset.attributeValue("path");
676 String className = asset.attributeValue("class-name");
677 long classPK = GetterUtil.getLong(
678 asset.attributeValue("class-pk"));
679
680 List<String> zipFolderEntries = context.getZipFolderEntries(
681 path);
682
683 List<RatingsEntry> ratingsEntries =
684 new ArrayList<RatingsEntry>();
685
686 for (String zipFolderEntry : zipFolderEntries) {
687 RatingsEntry ratingsEntry =
688 (RatingsEntry)context.getZipEntryAsObject(
689 zipFolderEntry);
690
691 if (ratingsEntry != null) {
692 ratingsEntries.add(ratingsEntry);
693 }
694 }
695
696 context.addRatingsEntries(
697 className, new Long(classPK), ratingsEntries);
698 }
699 }
700 catch (Exception e) {
701 throw new SystemException(e);
702 }
703 }
704
705 protected void readCategories(PortletDataContext context, Element parentEl)
706 throws SystemException {
707
708 try {
709 String xml = context.getZipEntryAsString(
710 context.getSourceRootPath() + "/categories.xml");
711
712 if (xml == null) {
713 return;
714 }
715
716 Document doc = SAXReaderUtil.read(xml);
717
718 Element root = doc.getRootElement();
719
720 List<Element> assets = root.elements("asset");
721
722 for (Element asset : assets) {
723 String className = GetterUtil.getString(
724 asset.attributeValue("class-name"));
725 long classPK = GetterUtil.getLong(
726 asset.attributeValue("class-pk"));
727 String[] assetCategoryUuids = StringUtil.split(
728 GetterUtil.getString(
729 asset.attributeValue("category-uuids")));
730
731 long[] assetCategoryIds = new long[0];
732
733 for (String assetCategoryUuid : assetCategoryUuids) {
734 try {
735 AssetCategory assetCategory =
736 AssetCategoryUtil.findByUUID_G(
737 assetCategoryUuid, context.getScopeGroupId());
738
739 assetCategoryIds = ArrayUtil.append(
740 assetCategoryIds, assetCategory.getCategoryId());
741 }
742 catch (NoSuchCategoryException nsce) {
743 }
744 }
745
746 context.addAssetCategories(
747 className, new Long(classPK), assetCategoryIds);
748 }
749 }
750 catch (Exception e) {
751 throw new SystemException(e);
752 }
753 }
754
755 protected void readTags(PortletDataContext context, Element parentEl)
756 throws SystemException {
757
758 try {
759 String xml = context.getZipEntryAsString(
760 context.getSourceRootPath() + "/tags.xml");
761
762 if (xml == null) {
763 return;
764 }
765
766 Document doc = SAXReaderUtil.read(xml);
767
768 Element root = doc.getRootElement();
769
770 List<Element> assets = root.elements("asset");
771
772 for (Element asset : assets) {
773 String className = GetterUtil.getString(
774 asset.attributeValue("class-name"));
775 long classPK = GetterUtil.getLong(
776 asset.attributeValue("class-pk"));
777 String assetTagNames = GetterUtil.getString(
778 asset.attributeValue("tags"));
779
780 context.addAssetTags(
781 className, new Long(classPK),
782 StringUtil.split(assetTagNames));
783 }
784 }
785 catch (Exception e) {
786 throw new SystemException(e);
787 }
788 }
789
790 private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
791
792 }