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