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