1
22
23 package com.liferay.portal.lar;
24
25 import com.liferay.portal.LARFileException;
26 import com.liferay.portal.LARTypeException;
27 import com.liferay.portal.LayoutImportException;
28 import com.liferay.portal.PortalException;
29 import com.liferay.portal.PortletIdException;
30 import com.liferay.portal.SystemException;
31 import com.liferay.portal.kernel.log.Log;
32 import com.liferay.portal.kernel.log.LogFactoryUtil;
33 import com.liferay.portal.kernel.util.GetterUtil;
34 import com.liferay.portal.kernel.util.MapUtil;
35 import com.liferay.portal.kernel.util.ObjectValuePair;
36 import com.liferay.portal.kernel.util.ReleaseInfo;
37 import com.liferay.portal.kernel.util.StringUtil;
38 import com.liferay.portal.kernel.xml.Document;
39 import com.liferay.portal.kernel.xml.DocumentException;
40 import com.liferay.portal.kernel.xml.Element;
41 import com.liferay.portal.kernel.xml.SAXReaderUtil;
42 import com.liferay.portal.kernel.zip.ZipReader;
43 import com.liferay.portal.model.Group;
44 import com.liferay.portal.model.Layout;
45 import com.liferay.portal.model.Portlet;
46 import com.liferay.portal.model.PortletConstants;
47 import com.liferay.portal.model.PortletItem;
48 import com.liferay.portal.model.PortletPreferences;
49 import com.liferay.portal.model.User;
50 import com.liferay.portal.service.GroupLocalServiceUtil;
51 import com.liferay.portal.service.LayoutLocalServiceUtil;
52 import com.liferay.portal.service.PortletItemLocalServiceUtil;
53 import com.liferay.portal.service.PortletLocalServiceUtil;
54 import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
55 import com.liferay.portal.service.UserLocalServiceUtil;
56 import com.liferay.portal.service.persistence.PortletPreferencesUtil;
57 import com.liferay.portal.service.persistence.UserUtil;
58 import com.liferay.portal.util.PortletKeys;
59 import com.liferay.portlet.PortletPreferencesFactoryUtil;
60 import com.liferay.portlet.PortletPreferencesImpl;
61 import com.liferay.portlet.PortletPreferencesSerializer;
62 import com.liferay.portlet.messageboards.model.MBMessage;
63 import com.liferay.portlet.ratings.model.RatingsEntry;
64 import com.liferay.portlet.social.util.SocialActivityThreadLocal;
65
66 import java.io.InputStream;
67
68 import java.util.ArrayList;
69 import java.util.HashSet;
70 import java.util.List;
71 import java.util.Map;
72
73 import org.apache.commons.lang.time.StopWatch;
74
75
85 public class PortletImporter {
86
87 public void importPortletInfo(
88 long userId, long plid, long groupId, String portletId,
89 Map<String, String[]> parameterMap, InputStream is)
90 throws PortalException, SystemException {
91
92 boolean deletePortletData = MapUtil.getBoolean(
93 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
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 = new ZipReader(is);
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
199 if (_log.isDebugEnabled()) {
200 _log.debug("Deleting portlet data");
201 }
202
203 if (deletePortletData) {
204 deletePortletData(context, portletId, plid);
205 }
206
207 Element portletRefEl = root.element("portlet");
208 Element portletEl = null;
209
210 try {
211 Document portletDoc = SAXReaderUtil.read(
212 context.getZipEntryAsString(
213 portletRefEl.attributeValue("path")));
214
215 portletEl = portletDoc.getRootElement();
216 }
217 catch (DocumentException de) {
218 throw new SystemException(de);
219 }
220
221
223 importPortletPreferences(
224 context, layout.getCompanyId(), groupId, layout, portletId,
225 portletEl, importPortletSetup, importPortletArchivedSetups,
226 importUserPreferences, true);
227
228
230 if (_log.isDebugEnabled()) {
231 _log.debug("Importing portlet data");
232 }
233
234 if (importPortletData) {
235 Element portletDataRefEl = portletEl.element("portlet-data");
236
237 if (portletDataRefEl != null) {
238 importPortletData(context, portletId, plid, portletDataRefEl);
239 }
240 else {
241 if (_log.isWarnEnabled()) {
242 _log.warn(
243 "Could not import portlet data because it cannot be " +
244 "found in the input");
245 }
246 }
247 }
248
249 if (_log.isInfoEnabled()) {
250 _log.info(
251 "Importing portlet data takes " + stopWatch.getTime() + " ms");
252 }
253 }
254
255 protected void deletePortletData(
256 PortletDataContext context, String portletId, long plid)
257 throws SystemException {
258
259 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
260 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
261
262 PortletPreferences portletPreferences =
263 PortletPreferencesUtil.fetchByO_O_P_P(
264 ownerId, ownerType, plid, portletId);
265
266 if (portletPreferences == null) {
267 portletPreferences =
268 new com.liferay.portal.model.impl.PortletPreferencesImpl();
269 }
270
271 String xml = deletePortletData(
272 context, portletId, portletPreferences);
273
274 if (xml != null) {
275 PortletPreferencesLocalServiceUtil.updatePreferences(
276 ownerId, ownerType, plid, portletId, xml);
277 }
278 }
279
280 protected String deletePortletData(
281 PortletDataContext context, String portletId,
282 PortletPreferences portletPreferences)
283 throws SystemException {
284
285 Portlet portlet = PortletLocalServiceUtil.getPortletById(
286 context.getCompanyId(), portletId);
287
288 if (portlet == null) {
289 if (_log.isDebugEnabled()) {
290 _log.debug(
291 "Do not delete portlet data for " + portletId +
292 " because the portlet does not exist");
293 }
294
295 return null;
296 }
297
298 PortletDataHandler portletDataHandler =
299 portlet.getPortletDataHandlerInstance();
300
301 if (portletDataHandler == null) {
302 if (_log.isDebugEnabled()) {
303 _log.debug(
304 "Do not delete portlet data for " + portletId +
305 " because the portlet does not have a " +
306 "PortletDataHandler");
307 }
308
309 return null;
310 }
311
312 if (_log.isDebugEnabled()) {
313 _log.debug("Deleting data for " + portletId);
314 }
315
316 PortletPreferencesImpl preferencesImpl =
317 (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
318 portletPreferences.getPreferences());
319
320 try {
321 preferencesImpl =
322 (PortletPreferencesImpl)portletDataHandler.deleteData(
323 context, portletId, preferencesImpl);
324 }
325 catch (Exception e) {
326 throw new SystemException(e);
327 }
328 finally {
329 context.setGroupId(context.getScopeGroupId());
330 }
331
332 if (preferencesImpl == null) {
333 return null;
334 }
335
336 return PortletPreferencesSerializer.toXML(preferencesImpl);
337 }
338
339 protected UserIdStrategy getUserIdStrategy(
340 User user, String userIdStrategy) {
341
342 if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
343 return new AlwaysCurrentUserIdStrategy(user);
344 }
345
346 return new CurrentUserIdStrategy(user);
347 }
348
349 protected void importPortletData(
350 PortletDataContext context, String portletId, long plid,
351 Element portletDataRefEl)
352 throws SystemException {
353
354 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
355 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
356
357 PortletPreferences portletPreferences =
358 PortletPreferencesUtil.fetchByO_O_P_P(
359 ownerId, ownerType, plid, portletId);
360
361 if (portletPreferences == null) {
362 portletPreferences =
363 new com.liferay.portal.model.impl.PortletPreferencesImpl();
364 }
365
366 String xml = importPortletData(
367 context, portletId, portletPreferences, portletDataRefEl);
368
369 if (xml != null) {
370 PortletPreferencesLocalServiceUtil.updatePreferences(
371 ownerId, ownerType, plid, portletId, xml);
372 }
373 }
374
375 protected String importPortletData(
376 PortletDataContext context, String portletId,
377 PortletPreferences portletPreferences, Element portletDataRefEl)
378 throws SystemException {
379
380 Portlet portlet = PortletLocalServiceUtil.getPortletById(
381 context.getCompanyId(), portletId);
382
383 if (portlet == null) {
384 if (_log.isDebugEnabled()) {
385 _log.debug(
386 "Do not import portlet data for " + portletId +
387 " because the portlet does not exist");
388 }
389
390 return null;
391 }
392
393 PortletDataHandler portletDataHandler =
394 portlet.getPortletDataHandlerInstance();
395
396 if (portletDataHandler == null) {
397 if (_log.isDebugEnabled()) {
398 _log.debug(
399 "Do not import portlet data for " + portletId +
400 " because the portlet does not have a " +
401 "PortletDataHandler");
402 }
403
404 return null;
405 }
406
407 if (_log.isDebugEnabled()) {
408 _log.debug("Importing data for " + portletId);
409 }
410
411
413 long groupId = context.getGroupId();
414
415 long scopeLayoutId = context.getScopeLayoutId();
416
417 if (scopeLayoutId == 0) {
418 scopeLayoutId = GetterUtil.getLong(
419 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
420 }
421
422 if (scopeLayoutId > 0) {
423 try {
424 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
425 context.getGroupId(), context.isPrivateLayout(),
426 scopeLayoutId);
427
428 Group scopeGroup = null;
429
430 if (scopeLayout.hasScopeGroup()) {
431 scopeGroup = scopeLayout.getScopeGroup();
432 }
433 else {
434 String name = String.valueOf(scopeLayout.getPlid());
435
436 scopeGroup = GroupLocalServiceUtil.addGroup(
437 context.getUserId(null), Layout.class.getName(),
438 scopeLayout.getPlid(), name, null, 0, null, true, null);
439 }
440
441 context.setGroupId(scopeGroup.getGroupId());
442 }
443 catch (PortalException pe) {
444 }
445 }
446
447 PortletPreferencesImpl preferencesImpl = null;
448
449 if (portletPreferences != null) {
450 preferencesImpl = (PortletPreferencesImpl)
451 PortletPreferencesSerializer.fromDefaultXML(
452 portletPreferences.getPreferences());
453 }
454
455 String portletData = context.getZipEntryAsString(
456 portletDataRefEl.attributeValue("path"));
457
458 try {
459 SocialActivityThreadLocal.setEnabled(false);
460
461 preferencesImpl =
462 (PortletPreferencesImpl)portletDataHandler.importData(
463 context, portletId, preferencesImpl, portletData);
464 }
465 catch (Exception e) {
466 throw new SystemException(e);
467 }
468 finally {
469 context.setGroupId(groupId);
470
471 SocialActivityThreadLocal.setEnabled(true);
472 }
473
474 if (preferencesImpl == null) {
475 return null;
476 }
477
478 return PortletPreferencesSerializer.toXML(preferencesImpl);
479 }
480
481 protected void importPortletPreferences(
482 PortletDataContext context, long companyId, long groupId,
483 Layout layout, String portletId, Element parentEl,
484 boolean importPortletSetup, boolean importPortletArchivedSetups,
485 boolean importUserPreferences, boolean preserveScopeLayoutId)
486 throws PortalException, SystemException {
487
488 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
489 long plid = 0;
490 long scopeLayoutId = 0;
491
492 if (layout != null) {
493 plid = layout.getPlid();
494
495 if (preserveScopeLayoutId && (portletId != null)) {
496 javax.portlet.PortletPreferences jxPreferences =
497 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
498 layout, portletId);
499
500 scopeLayoutId = GetterUtil.getLong(
501 jxPreferences.getValue("lfr-scope-layout-id", null));
502
503 context.setScopeLayoutId(scopeLayoutId);
504 }
505 }
506
507 List<Element> preferencesEls = parentEl.elements("portlet-preferences");
508
509 for (Element preferencesEl : preferencesEls) {
510 String path = preferencesEl.attributeValue("path");
511
512 if (context.isPathNotProcessed(path)) {
513 Element el = null;
514 String xml = null;
515
516 try {
517 xml = context.getZipEntryAsString(path);
518
519 Document preferencesDoc = SAXReaderUtil.read(xml);
520
521 el = preferencesDoc.getRootElement();
522 }
523 catch (DocumentException de) {
524 throw new SystemException(de);
525 }
526
527 long ownerId = GetterUtil.getLong(
528 el.attributeValue("owner-id"));
529 int ownerType = GetterUtil.getInteger(
530 el.attributeValue("owner-type"));
531
532 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
533 continue;
534 }
535
536 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
537 (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
538 !importPortletSetup) {
539
540 continue;
541 }
542
543 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
544 !importPortletArchivedSetups) {
545
546 continue;
547 }
548
549 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
550 (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
551 !importUserPreferences) {
552
553 continue;
554 }
555
556 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
557 plid = PortletKeys.PREFS_PLID_SHARED;
558 ownerId = context.getGroupId();
559 }
560
561 boolean defaultUser = GetterUtil.getBoolean(
562 el.attributeValue("default-user"));
563
564 if (portletId == null) {
565 portletId = el.attributeValue("portlet-id");
566 }
567
568 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
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<ObjectValuePair<String, byte[]>> entries =
636 context.getZipFolderEntries(path);
637
638 List<MBMessage> messages = new ArrayList<MBMessage>();
639
640 for (ObjectValuePair<String, byte[]> entry : entries) {
641 if (entry.getValue().length > 0) {
642 MBMessage message = (MBMessage)context.fromXML(
643 entry.getValue());
644
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<ObjectValuePair<String, byte[]>> entries =
681 context.getZipFolderEntries(path);
682
683 List<RatingsEntry> ratingsEntries =
684 new ArrayList<RatingsEntry>();
685
686 for (ObjectValuePair<String, byte[]> entry : entries) {
687 if (entry.getValue().length > 0) {
688 RatingsEntry rating = (RatingsEntry)context.fromXML(
689 entry.getValue());
690
691 ratingsEntries.add(rating);
692 }
693 }
694
695 context.addRatingsEntries(
696 className, new Long(classPK), ratingsEntries);
697 }
698 }
699 catch (Exception e) {
700 throw new SystemException(e);
701 }
702 }
703
704 protected void readCategories(PortletDataContext context, Element parentEl)
705 throws SystemException {
706
707 try {
708 String xml = context.getZipEntryAsString(
709 context.getSourceRootPath() + "/categories.xml");
710
711 if (xml == null) {
712 return;
713 }
714
715 Document doc = SAXReaderUtil.read(xml);
716
717 Element root = doc.getRootElement();
718
719 List<Element> assets = root.elements("asset");
720
721 for (Element asset : assets) {
722 String className = GetterUtil.getString(
723 asset.attributeValue("class-name"));
724 long classPK = GetterUtil.getLong(
725 asset.attributeValue("class-pk"));
726 String entries = GetterUtil.getString(
727 asset.attributeValue("entries"));
728
729 context.addTagsCategories(
730 className, new Long(classPK), StringUtil.split(entries));
731 }
732 }
733 catch (Exception e) {
734 throw new SystemException(e);
735 }
736 }
737
738 protected void readTags(PortletDataContext context, Element parentEl)
739 throws SystemException {
740
741 try {
742 String xml = context.getZipEntryAsString(
743 context.getSourceRootPath() + "/tags.xml");
744
745 if (xml == null) {
746 return;
747 }
748
749 Document doc = SAXReaderUtil.read(xml);
750
751 Element root = doc.getRootElement();
752
753 List<Element> assets = root.elements("asset");
754
755 for (Element asset : assets) {
756 String className = GetterUtil.getString(
757 asset.attributeValue("class-name"));
758 long classPK = GetterUtil.getLong(
759 asset.attributeValue("class-pk"));
760 String entries = GetterUtil.getString(
761 asset.attributeValue("entries"));
762
763 context.addTagsEntries(
764 className, new Long(classPK), StringUtil.split(entries));
765 }
766 }
767 catch (Exception e) {
768 throw new SystemException(e);
769 }
770 }
771
772 private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
773
774 }