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