1
19
20 package com.liferay.portal.lar;
21
22 import com.liferay.portal.LARFileException;
23 import com.liferay.portal.LARTypeException;
24 import com.liferay.portal.LayoutImportException;
25 import com.liferay.portal.PortalException;
26 import com.liferay.portal.PortletIdException;
27 import com.liferay.portal.SystemException;
28 import com.liferay.portal.kernel.log.Log;
29 import com.liferay.portal.kernel.log.LogFactoryUtil;
30 import com.liferay.portal.kernel.util.GetterUtil;
31 import com.liferay.portal.kernel.util.MapUtil;
32 import com.liferay.portal.kernel.util.ObjectValuePair;
33 import com.liferay.portal.kernel.util.ReleaseInfo;
34 import com.liferay.portal.kernel.util.StringUtil;
35 import com.liferay.portal.kernel.xml.Document;
36 import com.liferay.portal.kernel.xml.DocumentException;
37 import com.liferay.portal.kernel.xml.Element;
38 import com.liferay.portal.kernel.xml.SAXReaderUtil;
39 import com.liferay.portal.kernel.zip.ZipReader;
40 import com.liferay.portal.model.Group;
41 import com.liferay.portal.model.Layout;
42 import com.liferay.portal.model.Portlet;
43 import com.liferay.portal.model.PortletConstants;
44 import com.liferay.portal.model.PortletItem;
45 import com.liferay.portal.model.PortletPreferences;
46 import com.liferay.portal.model.User;
47 import com.liferay.portal.service.GroupLocalServiceUtil;
48 import com.liferay.portal.service.LayoutLocalServiceUtil;
49 import com.liferay.portal.service.PortletItemLocalServiceUtil;
50 import com.liferay.portal.service.PortletLocalServiceUtil;
51 import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
52 import com.liferay.portal.service.UserLocalServiceUtil;
53 import com.liferay.portal.service.persistence.PortletPreferencesUtil;
54 import com.liferay.portal.service.persistence.UserUtil;
55 import com.liferay.portal.util.PortletKeys;
56 import com.liferay.portlet.PortletPreferencesFactoryUtil;
57 import com.liferay.portlet.PortletPreferencesImpl;
58 import com.liferay.portlet.PortletPreferencesSerializer;
59 import com.liferay.portlet.messageboards.model.MBMessage;
60 import com.liferay.portlet.ratings.model.RatingsEntry;
61 import com.liferay.portlet.social.util.SocialActivityThreadLocal;
62
63 import java.io.InputStream;
64
65 import java.util.ArrayList;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Map;
69
70 import org.apache.commons.lang.time.StopWatch;
71
72
83 public class PortletImporter {
84
85 public void importPortletInfo(
86 long userId, long plid, long groupId, String portletId,
87 Map<String, String[]> parameterMap, InputStream is)
88 throws PortalException, SystemException {
89
90 boolean deletePortletData = MapUtil.getBoolean(
91 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
92 boolean importPortletData = MapUtil.getBoolean(
93 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
94 boolean importPortletArchivedSetups = MapUtil.getBoolean(
95 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
96 boolean importPortletSetup = MapUtil.getBoolean(
97 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
98 boolean importUserPreferences = MapUtil.getBoolean(
99 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
100 String userIdStrategy = MapUtil.getString(
101 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
102
103 StopWatch stopWatch = null;
104
105 if (_log.isInfoEnabled()) {
106 stopWatch = new StopWatch();
107
108 stopWatch.start();
109 }
110
111 Layout layout = LayoutLocalServiceUtil.getLayout(plid);
112
113 long companyId = layout.getCompanyId();
114
115 User user = UserUtil.findByPrimaryKey(userId);
116
117 UserIdStrategy strategy = getUserIdStrategy(user, userIdStrategy);
118
119 ZipReader zipReader = new ZipReader(is);
120
121 PortletDataContext context = new PortletDataContextImpl(
122 companyId, groupId, parameterMap, new HashSet<String>(),
123 strategy, zipReader);
124
125 context.setPlid(plid);
126 context.setPrivateLayout(layout.isPrivateLayout());
127
128
130 Element root = null;
131
132
134 String xml = context.getZipEntryAsString("/manifest.xml");
135
136 try {
137 Document doc = SAXReaderUtil.read(xml);
138
139 root = doc.getRootElement();
140 }
141 catch (Exception e) {
142 throw new LARFileException(
143 "Cannot locate a manifest in this LAR file.");
144 }
145
146
148 Element header = root.element("header");
149
150 int buildNumber = ReleaseInfo.getBuildNumber();
151
152 int importBuildNumber = GetterUtil.getInteger(
153 header.attributeValue("build-number"));
154
155 if (buildNumber != importBuildNumber) {
156 throw new LayoutImportException(
157 "LAR build number " + importBuildNumber + " does not match " +
158 "portal build number " + buildNumber);
159 }
160
161
163 String type = header.attributeValue("type");
164
165 if (!type.equals("portlet")) {
166 throw new LARTypeException(
167 "Invalid type of LAR file (" + type + ")");
168 }
169
170
172 String rootPortletId = header.attributeValue("root-portlet-id");
173
174 if (!PortletConstants.getRootPortletId(portletId).equals(
175 rootPortletId)) {
176
177 throw new PortletIdException("Invalid portlet id " + rootPortletId);
178 }
179
180
182 long sourceGroupId = GetterUtil.getLong(
183 header.attributeValue("group-id"));
184
185 context.setSourceGroupId(sourceGroupId);
186
187
190 readCategories(context, root);
191 readComments(context, root);
192 readRatings(context, root);
193 readTags(context, root);
194
195
197 if (_log.isDebugEnabled()) {
198 _log.debug("Deleting portlet data");
199 }
200
201 if (deletePortletData) {
202 deletePortletData(context, portletId, plid);
203 }
204
205 Element portletRefEl = root.element("portlet");
206 Element portletEl = null;
207
208 try {
209 Document portletDoc = SAXReaderUtil.read(
210 context.getZipEntryAsString(
211 portletRefEl.attributeValue("path")));
212
213 portletEl = portletDoc.getRootElement();
214 }
215 catch (DocumentException de) {
216 throw new SystemException(de);
217 }
218
219
221 importPortletPreferences(
222 context, layout.getCompanyId(), groupId, layout, portletId,
223 portletEl, importPortletSetup, importPortletArchivedSetups,
224 importUserPreferences, true);
225
226
228 if (_log.isDebugEnabled()) {
229 _log.debug("Importing portlet data");
230 }
231
232 if (importPortletData) {
233 Element portletDataRefEl = portletEl.element("portlet-data");
234
235 if (portletDataRefEl != null) {
236 importPortletData(context, portletId, plid, portletDataRefEl);
237 }
238 else {
239 if (_log.isWarnEnabled()) {
240 _log.warn(
241 "Could not import portlet data because it cannot be " +
242 "found in the input");
243 }
244 }
245 }
246
247 if (_log.isInfoEnabled()) {
248 _log.info(
249 "Importing portlet data takes " + stopWatch.getTime() + " ms");
250 }
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 String userUuid = el.attributeValue("archive-user-uuid");
568 String name = el.attributeValue("archive-name");
569
570 long userId = context.getUserId(userUuid);
571
572 PortletItem portletItem =
573 PortletItemLocalServiceUtil.updatePortletItem(
574 userId, groupId, name, portletId,
575 PortletPreferences.class.getName());
576
577 plid = 0;
578 ownerId = portletItem.getPortletItemId();
579 }
580
581 if (defaultUser) {
582 ownerId = defaultUserId;
583 }
584
585 PortletPreferencesLocalServiceUtil.updatePreferences(
586 ownerId, ownerType, plid, portletId, xml);
587 }
588 }
589
590 if (preserveScopeLayoutId && (layout != null)) {
591 javax.portlet.PortletPreferences jxPreferences =
592 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
593 layout, portletId);
594
595 try {
596 jxPreferences.setValue(
597 "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
598
599 jxPreferences.store();
600 }
601 catch (Exception e) {
602 throw new PortalException(e);
603 }
604 finally {
605 context.setScopeLayoutId(scopeLayoutId);
606 }
607 }
608 }
609
610 protected void readComments(PortletDataContext context, Element parentEl)
611 throws SystemException {
612
613 try {
614 String xml = context.getZipEntryAsString(
615 context.getSourceRootPath() + "/comments.xml");
616
617 if (xml == null) {
618 return;
619 }
620
621 Document doc = SAXReaderUtil.read(xml);
622
623 Element root = doc.getRootElement();
624
625 List<Element> assets = root.elements("asset");
626
627 for (Element asset : assets) {
628 String path = asset.attributeValue("path");
629 String className = asset.attributeValue("class-name");
630 long classPK = GetterUtil.getLong(
631 asset.attributeValue("class-pk"));
632
633 List<ObjectValuePair<String, byte[]>> entries =
634 context.getZipFolderEntries(path);
635
636 List<MBMessage> messages = new ArrayList<MBMessage>();
637
638 for (ObjectValuePair<String, byte[]> entry : entries) {
639 if (entry.getValue().length > 0) {
640 MBMessage message = (MBMessage)context.fromXML(
641 entry.getValue());
642
643 messages.add(message);
644 }
645 }
646
647 context.addComments(className, classPK, messages);
648 }
649 }
650 catch (Exception e) {
651 throw new SystemException(e);
652 }
653 }
654
655 protected void readRatings(PortletDataContext context, Element parentEl)
656 throws SystemException {
657
658 try {
659 String xml = context.getZipEntryAsString(
660 context.getSourceRootPath() + "/ratings.xml");
661
662 if (xml == null) {
663 return;
664 }
665
666 Document doc = SAXReaderUtil.read(xml);
667
668 Element root = doc.getRootElement();
669
670 List<Element> assets = root.elements("asset");
671
672 for (Element asset : assets) {
673 String path = asset.attributeValue("path");
674 String className = asset.attributeValue("class-name");
675 long classPK = GetterUtil.getLong(
676 asset.attributeValue("class-pk"));
677
678 List<ObjectValuePair<String, byte[]>> entries =
679 context.getZipFolderEntries(path);
680
681 List<RatingsEntry> ratingsEntries =
682 new ArrayList<RatingsEntry>();
683
684 for (ObjectValuePair<String, byte[]> entry : entries) {
685 if (entry.getValue().length > 0) {
686 RatingsEntry rating = (RatingsEntry)context.fromXML(
687 entry.getValue());
688
689 ratingsEntries.add(rating);
690 }
691 }
692
693 context.addRatingsEntries(
694 className, new Long(classPK), ratingsEntries);
695 }
696 }
697 catch (Exception e) {
698 throw new SystemException(e);
699 }
700 }
701
702 protected void readCategories(PortletDataContext context, Element parentEl)
703 throws SystemException {
704
705 try {
706 String xml = context.getZipEntryAsString(
707 context.getSourceRootPath() + "/categories.xml");
708
709 if (xml == null) {
710 return;
711 }
712
713 Document doc = SAXReaderUtil.read(xml);
714
715 Element root = doc.getRootElement();
716
717 List<Element> assets = root.elements("asset");
718
719 for (Element asset : assets) {
720 String className = GetterUtil.getString(
721 asset.attributeValue("class-name"));
722 long classPK = GetterUtil.getLong(
723 asset.attributeValue("class-pk"));
724 String entries = GetterUtil.getString(
725 asset.attributeValue("entries"));
726
727 context.addTagsCategories(
728 className, new Long(classPK), StringUtil.split(entries));
729 }
730 }
731 catch (Exception e) {
732 throw new SystemException(e);
733 }
734 }
735
736 protected void readTags(PortletDataContext context, Element parentEl)
737 throws SystemException {
738
739 try {
740 String xml = context.getZipEntryAsString(
741 context.getSourceRootPath() + "/tags.xml");
742
743 if (xml == null) {
744 return;
745 }
746
747 Document doc = SAXReaderUtil.read(xml);
748
749 Element root = doc.getRootElement();
750
751 List<Element> assets = root.elements("asset");
752
753 for (Element asset : assets) {
754 String className = GetterUtil.getString(
755 asset.attributeValue("class-name"));
756 long classPK = GetterUtil.getLong(
757 asset.attributeValue("class-pk"));
758 String entries = GetterUtil.getString(
759 asset.attributeValue("entries"));
760
761 context.addTagsEntries(
762 className, new Long(classPK), StringUtil.split(entries));
763 }
764 }
765 catch (Exception e) {
766 throw new SystemException(e);
767 }
768 }
769
770 private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
771
772 }