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