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.ReleaseInfo;
36 import com.liferay.portal.kernel.util.StringUtil;
37 import com.liferay.portal.kernel.xml.Document;
38 import com.liferay.portal.kernel.xml.DocumentException;
39 import com.liferay.portal.kernel.xml.Element;
40 import com.liferay.portal.kernel.xml.SAXReaderUtil;
41 import com.liferay.portal.kernel.zip.ZipReader;
42 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
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.File;
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, File file)
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 = 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
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 zipReader.close();
255 }
256
257 protected void deletePortletData(
258 PortletDataContext context, String portletId, long plid)
259 throws SystemException {
260
261 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
262 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
263
264 PortletPreferences portletPreferences =
265 PortletPreferencesUtil.fetchByO_O_P_P(
266 ownerId, ownerType, plid, portletId);
267
268 if (portletPreferences == null) {
269 portletPreferences =
270 new com.liferay.portal.model.impl.PortletPreferencesImpl();
271 }
272
273 String xml = deletePortletData(
274 context, portletId, portletPreferences);
275
276 if (xml != null) {
277 PortletPreferencesLocalServiceUtil.updatePreferences(
278 ownerId, ownerType, plid, portletId, xml);
279 }
280 }
281
282 protected String deletePortletData(
283 PortletDataContext context, String portletId,
284 PortletPreferences portletPreferences)
285 throws SystemException {
286
287 Portlet portlet = PortletLocalServiceUtil.getPortletById(
288 context.getCompanyId(), portletId);
289
290 if (portlet == null) {
291 if (_log.isDebugEnabled()) {
292 _log.debug(
293 "Do not delete portlet data for " + portletId +
294 " because the portlet does not exist");
295 }
296
297 return null;
298 }
299
300 PortletDataHandler portletDataHandler =
301 portlet.getPortletDataHandlerInstance();
302
303 if (portletDataHandler == null) {
304 if (_log.isDebugEnabled()) {
305 _log.debug(
306 "Do not delete portlet data for " + portletId +
307 " because the portlet does not have a " +
308 "PortletDataHandler");
309 }
310
311 return null;
312 }
313
314 if (_log.isDebugEnabled()) {
315 _log.debug("Deleting data for " + portletId);
316 }
317
318 PortletPreferencesImpl preferencesImpl =
319 (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
320 portletPreferences.getPreferences());
321
322 try {
323 preferencesImpl =
324 (PortletPreferencesImpl)portletDataHandler.deleteData(
325 context, portletId, preferencesImpl);
326 }
327 catch (Exception e) {
328 throw new SystemException(e);
329 }
330 finally {
331 context.setGroupId(context.getScopeGroupId());
332 }
333
334 if (preferencesImpl == null) {
335 return null;
336 }
337
338 return PortletPreferencesSerializer.toXML(preferencesImpl);
339 }
340
341 protected UserIdStrategy getUserIdStrategy(
342 User user, String userIdStrategy) {
343
344 if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
345 return new AlwaysCurrentUserIdStrategy(user);
346 }
347
348 return new CurrentUserIdStrategy(user);
349 }
350
351 protected void importPortletData(
352 PortletDataContext context, String portletId, long plid,
353 Element portletDataRefEl)
354 throws SystemException {
355
356 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
357 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
358
359 PortletPreferences portletPreferences =
360 PortletPreferencesUtil.fetchByO_O_P_P(
361 ownerId, ownerType, plid, portletId);
362
363 if (portletPreferences == null) {
364 portletPreferences =
365 new com.liferay.portal.model.impl.PortletPreferencesImpl();
366 }
367
368 String xml = importPortletData(
369 context, portletId, portletPreferences, portletDataRefEl);
370
371 if (xml != null) {
372 PortletPreferencesLocalServiceUtil.updatePreferences(
373 ownerId, ownerType, plid, portletId, xml);
374 }
375 }
376
377 protected String importPortletData(
378 PortletDataContext context, String portletId,
379 PortletPreferences portletPreferences, Element portletDataRefEl)
380 throws SystemException {
381
382 Portlet portlet = PortletLocalServiceUtil.getPortletById(
383 context.getCompanyId(), portletId);
384
385 if (portlet == null) {
386 if (_log.isDebugEnabled()) {
387 _log.debug(
388 "Do not import portlet data for " + portletId +
389 " because the portlet does not exist");
390 }
391
392 return null;
393 }
394
395 PortletDataHandler portletDataHandler =
396 portlet.getPortletDataHandlerInstance();
397
398 if (portletDataHandler == null) {
399 if (_log.isDebugEnabled()) {
400 _log.debug(
401 "Do not import portlet data for " + portletId +
402 " because the portlet does not have a " +
403 "PortletDataHandler");
404 }
405
406 return null;
407 }
408
409 if (_log.isDebugEnabled()) {
410 _log.debug("Importing data for " + portletId);
411 }
412
413
415 long groupId = context.getGroupId();
416
417 long scopeLayoutId = context.getScopeLayoutId();
418
419 if (scopeLayoutId == 0) {
420 scopeLayoutId = GetterUtil.getLong(
421 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
422 }
423
424 if (scopeLayoutId > 0) {
425 try {
426 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
427 context.getGroupId(), context.isPrivateLayout(),
428 scopeLayoutId);
429
430 Group scopeGroup = null;
431
432 if (scopeLayout.hasScopeGroup()) {
433 scopeGroup = scopeLayout.getScopeGroup();
434 }
435 else {
436 String name = String.valueOf(scopeLayout.getPlid());
437
438 scopeGroup = GroupLocalServiceUtil.addGroup(
439 context.getUserId(null), Layout.class.getName(),
440 scopeLayout.getPlid(), name, null, 0, null, true, null);
441 }
442
443 context.setGroupId(scopeGroup.getGroupId());
444 }
445 catch (PortalException pe) {
446 }
447 }
448
449 PortletPreferencesImpl preferencesImpl = null;
450
451 if (portletPreferences != null) {
452 preferencesImpl = (PortletPreferencesImpl)
453 PortletPreferencesSerializer.fromDefaultXML(
454 portletPreferences.getPreferences());
455 }
456
457 String portletData = context.getZipEntryAsString(
458 portletDataRefEl.attributeValue("path"));
459
460 try {
461 SocialActivityThreadLocal.setEnabled(false);
462
463 preferencesImpl =
464 (PortletPreferencesImpl)portletDataHandler.importData(
465 context, portletId, preferencesImpl, portletData);
466 }
467 catch (Exception e) {
468 throw new SystemException(e);
469 }
470 finally {
471 context.setGroupId(groupId);
472
473 SocialActivityThreadLocal.setEnabled(true);
474 }
475
476 if (preferencesImpl == null) {
477 return null;
478 }
479
480 return PortletPreferencesSerializer.toXML(preferencesImpl);
481 }
482
483 protected void importPortletPreferences(
484 PortletDataContext context, long companyId, long groupId,
485 Layout layout, String portletId, Element parentEl,
486 boolean importPortletSetup, boolean importPortletArchivedSetups,
487 boolean importUserPreferences, boolean preserveScopeLayoutId)
488 throws PortalException, SystemException {
489
490 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
491 long plid = 0;
492 long scopeLayoutId = 0;
493
494 if (layout != null) {
495 plid = layout.getPlid();
496
497 if (preserveScopeLayoutId && (portletId != null)) {
498 javax.portlet.PortletPreferences jxPreferences =
499 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
500 layout, portletId);
501
502 scopeLayoutId = GetterUtil.getLong(
503 jxPreferences.getValue("lfr-scope-layout-id", null));
504
505 context.setScopeLayoutId(scopeLayoutId);
506 }
507 }
508
509 List<Element> preferencesEls = parentEl.elements("portlet-preferences");
510
511 for (Element preferencesEl : preferencesEls) {
512 String path = preferencesEl.attributeValue("path");
513
514 if (context.isPathNotProcessed(path)) {
515 Element el = null;
516 String xml = null;
517
518 try {
519 xml = context.getZipEntryAsString(path);
520
521 Document preferencesDoc = SAXReaderUtil.read(xml);
522
523 el = preferencesDoc.getRootElement();
524 }
525 catch (DocumentException de) {
526 throw new SystemException(de);
527 }
528
529 long ownerId = GetterUtil.getLong(
530 el.attributeValue("owner-id"));
531 int ownerType = GetterUtil.getInteger(
532 el.attributeValue("owner-type"));
533
534 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
535 continue;
536 }
537
538 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
539 (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
540 !importPortletSetup) {
541
542 continue;
543 }
544
545 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
546 !importPortletArchivedSetups) {
547
548 continue;
549 }
550
551 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
552 (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
553 !importUserPreferences) {
554
555 continue;
556 }
557
558 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
559 plid = PortletKeys.PREFS_PLID_SHARED;
560 ownerId = context.getGroupId();
561 }
562
563 boolean defaultUser = GetterUtil.getBoolean(
564 el.attributeValue("default-user"));
565
566 if (portletId == null) {
567 portletId = el.attributeValue("portlet-id");
568 }
569
570 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
571 portletId = PortletConstants.getRootPortletId(portletId);
572
573 String userUuid = el.attributeValue("archive-user-uuid");
574 String name = el.attributeValue("archive-name");
575
576 long userId = context.getUserId(userUuid);
577
578 PortletItem portletItem =
579 PortletItemLocalServiceUtil.updatePortletItem(
580 userId, groupId, name, portletId,
581 PortletPreferences.class.getName());
582
583 plid = 0;
584 ownerId = portletItem.getPortletItemId();
585 }
586
587 if (defaultUser) {
588 ownerId = defaultUserId;
589 }
590
591 PortletPreferencesLocalServiceUtil.updatePreferences(
592 ownerId, ownerType, plid, portletId, xml);
593 }
594 }
595
596 if (preserveScopeLayoutId && (layout != null)) {
597 javax.portlet.PortletPreferences jxPreferences =
598 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
599 layout, portletId);
600
601 try {
602 jxPreferences.setValue(
603 "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
604
605 jxPreferences.store();
606 }
607 catch (Exception e) {
608 throw new PortalException(e);
609 }
610 finally {
611 context.setScopeLayoutId(scopeLayoutId);
612 }
613 }
614 }
615
616 protected void readComments(PortletDataContext context, Element parentEl)
617 throws SystemException {
618
619 try {
620 String xml = context.getZipEntryAsString(
621 context.getSourceRootPath() + "/comments.xml");
622
623 if (xml == null) {
624 return;
625 }
626
627 Document doc = SAXReaderUtil.read(xml);
628
629 Element root = doc.getRootElement();
630
631 List<Element> assets = root.elements("asset");
632
633 for (Element asset : assets) {
634 String path = asset.attributeValue("path");
635 String className = asset.attributeValue("class-name");
636 long classPK = GetterUtil.getLong(
637 asset.attributeValue("class-pk"));
638
639 List<String> zipFolderEntries = context.getZipFolderEntries(
640 path);
641
642 List<MBMessage> messages = new ArrayList<MBMessage>();
643
644 for (String zipFolderEntry : zipFolderEntries) {
645 MBMessage message = (MBMessage)context.getZipEntryAsObject(
646 zipFolderEntry);
647
648 if (message != null) {
649 messages.add(message);
650 }
651 }
652
653 context.addComments(className, classPK, messages);
654 }
655 }
656 catch (Exception e) {
657 throw new SystemException(e);
658 }
659 }
660
661 protected void readRatings(PortletDataContext context, Element parentEl)
662 throws SystemException {
663
664 try {
665 String xml = context.getZipEntryAsString(
666 context.getSourceRootPath() + "/ratings.xml");
667
668 if (xml == null) {
669 return;
670 }
671
672 Document doc = SAXReaderUtil.read(xml);
673
674 Element root = doc.getRootElement();
675
676 List<Element> assets = root.elements("asset");
677
678 for (Element asset : assets) {
679 String path = asset.attributeValue("path");
680 String className = asset.attributeValue("class-name");
681 long classPK = GetterUtil.getLong(
682 asset.attributeValue("class-pk"));
683
684 List<String> zipFolderEntries = context.getZipFolderEntries(
685 path);
686
687 List<RatingsEntry> ratingsEntries =
688 new ArrayList<RatingsEntry>();
689
690 for (String zipFolderEntry : zipFolderEntries) {
691 RatingsEntry ratingsEntry =
692 (RatingsEntry)context.getZipEntryAsObject(
693 zipFolderEntry);
694
695 if (ratingsEntry != null) {
696 ratingsEntries.add(ratingsEntry);
697 }
698 }
699
700 context.addRatingsEntries(
701 className, new Long(classPK), ratingsEntries);
702 }
703 }
704 catch (Exception e) {
705 throw new SystemException(e);
706 }
707 }
708
709 protected void readCategories(PortletDataContext context, Element parentEl)
710 throws SystemException {
711
712 try {
713 String xml = context.getZipEntryAsString(
714 context.getSourceRootPath() + "/categories.xml");
715
716 if (xml == null) {
717 return;
718 }
719
720 Document doc = SAXReaderUtil.read(xml);
721
722 Element root = doc.getRootElement();
723
724 List<Element> assets = root.elements("asset");
725
726 for (Element asset : assets) {
727 String className = GetterUtil.getString(
728 asset.attributeValue("class-name"));
729 long classPK = GetterUtil.getLong(
730 asset.attributeValue("class-pk"));
731 String entries = GetterUtil.getString(
732 asset.attributeValue("entries"));
733
734 context.addTagsCategories(
735 className, new Long(classPK), StringUtil.split(entries));
736 }
737 }
738 catch (Exception e) {
739 throw new SystemException(e);
740 }
741 }
742
743 protected void readTags(PortletDataContext context, Element parentEl)
744 throws SystemException {
745
746 try {
747 String xml = context.getZipEntryAsString(
748 context.getSourceRootPath() + "/tags.xml");
749
750 if (xml == null) {
751 return;
752 }
753
754 Document doc = SAXReaderUtil.read(xml);
755
756 Element root = doc.getRootElement();
757
758 List<Element> assets = root.elements("asset");
759
760 for (Element asset : assets) {
761 String className = GetterUtil.getString(
762 asset.attributeValue("class-name"));
763 long classPK = GetterUtil.getLong(
764 asset.attributeValue("class-pk"));
765 String entries = GetterUtil.getString(
766 asset.attributeValue("entries"));
767
768 context.addTagsEntries(
769 className, new Long(classPK), StringUtil.split(entries));
770 }
771 }
772 catch (Exception e) {
773 throw new SystemException(e);
774 }
775 }
776
777 private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
778
779 }