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.ObjectValuePair;
36 import com.liferay.portal.kernel.util.PortletClassInvoker;
37 import com.liferay.portal.kernel.util.ReleaseInfo;
38 import com.liferay.portal.kernel.util.StringUtil;
39 import com.liferay.portal.kernel.util.Validator;
40 import com.liferay.portal.kernel.xml.Document;
41 import com.liferay.portal.kernel.xml.DocumentException;
42 import com.liferay.portal.kernel.xml.Element;
43 import com.liferay.portal.kernel.xml.SAXReaderUtil;
44 import com.liferay.portal.kernel.zip.ZipReader;
45 import com.liferay.portal.model.Group;
46 import com.liferay.portal.model.Layout;
47 import com.liferay.portal.model.Portlet;
48 import com.liferay.portal.model.PortletConstants;
49 import com.liferay.portal.model.PortletItem;
50 import com.liferay.portal.model.PortletPreferences;
51 import com.liferay.portal.model.User;
52 import com.liferay.portal.service.GroupLocalServiceUtil;
53 import com.liferay.portal.service.LayoutLocalServiceUtil;
54 import com.liferay.portal.service.PortletItemLocalServiceUtil;
55 import com.liferay.portal.service.PortletLocalServiceUtil;
56 import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
57 import com.liferay.portal.service.UserLocalServiceUtil;
58 import com.liferay.portal.service.persistence.PortletPreferencesUtil;
59 import com.liferay.portal.service.persistence.UserUtil;
60 import com.liferay.portal.util.PortletKeys;
61 import com.liferay.portlet.PortletPreferencesFactoryUtil;
62 import com.liferay.portlet.PortletPreferencesImpl;
63 import com.liferay.portlet.PortletPreferencesSerializer;
64 import com.liferay.portlet.messageboards.model.MBMessage;
65 import com.liferay.portlet.ratings.model.RatingsEntry;
66 import com.liferay.util.MapUtil;
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 importPortletData(
239 context, portletId, plid, portletEl.element("portlet-data"));
240 }
241
242 if (_log.isInfoEnabled()) {
243 _log.info(
244 "Importing portlet data takes " + stopWatch.getTime() + " ms");
245 }
246 }
247
248 protected void deletePortletData(
249 PortletDataContext context, String portletId, long plid)
250 throws SystemException {
251
252 long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
253 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
254
255 PortletPreferences portletPreferences = null;
256
257 try {
258 portletPreferences = PortletPreferencesUtil.findByO_O_P_P(
259 ownerId, ownerType, plid, portletId);
260 }
261 catch (NoSuchPortletPreferencesException nsppe) {
262 portletPreferences =
263 new com.liferay.portal.model.impl.PortletPreferencesImpl();
264 }
265
266 String xml = deletePortletData(
267 context, portletId, portletPreferences);
268
269 if (xml != null) {
270 PortletPreferencesLocalServiceUtil.updatePreferences(
271 ownerId, ownerType, plid, portletId, xml);
272 }
273 }
274
275 protected String deletePortletData(
276 PortletDataContext context, String portletId,
277 PortletPreferences portletPreferences)
278 throws SystemException {
279
280 Portlet portlet = PortletLocalServiceUtil.getPortletById(
281 context.getCompanyId(), portletId);
282
283 if (portlet == null) {
284 if (_log.isDebugEnabled()) {
285 _log.debug(
286 "Do not delete portlet data for " + portletId +
287 " because the portlet does not exist");
288 }
289
290 return null;
291 }
292
293 String portletDataHandlerClass =
294 portlet.getPortletDataHandlerClass();
295
296 if (Validator.isNull(portletDataHandlerClass)) {
297 if (_log.isDebugEnabled()) {
298 _log.debug(
299 "Do not delete portlet data for " + portletId +
300 " because the portlet does not have a " +
301 "PortletDataHandler");
302 }
303
304 return null;
305 }
306
307 if (_log.isDebugEnabled()) {
308 _log.debug("Deleting data for " + portletId);
309 }
310
311 PortletPreferencesImpl preferencesImpl =
312 (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
313 portletPreferences.getPreferences());
314
315 try {
316 preferencesImpl =
317 (PortletPreferencesImpl)PortletClassInvoker.invoke(
318 portletId, portletDataHandlerClass, "deleteData", context,
319 portletId, preferencesImpl);
320 }
321 catch (Exception e) {
322 throw new SystemException(e);
323 }
324 finally {
325 context.setGroupId(context.getScopeGroupId());
326 }
327
328 if (preferencesImpl == null) {
329 return null;
330 }
331
332 return PortletPreferencesSerializer.toXML(preferencesImpl);
333 }
334
335 protected UserIdStrategy getUserIdStrategy(
336 User user, String userIdStrategy) {
337
338 if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
339 return new AlwaysCurrentUserIdStrategy(user);
340 }
341
342 return new CurrentUserIdStrategy(user);
343 }
344
345 protected void importPortletData(
346 PortletDataContext context, String portletId, long plid,
347 Element portletDataRefEl)
348 throws SystemException {
349
350 long ownerId = PortletKeys. PREFS_OWNER_ID_DEFAULT;
351 int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
352
353 PortletPreferences portletPreferences = null;
354
355 try {
356 portletPreferences = PortletPreferencesUtil.findByO_O_P_P(
357 ownerId, ownerType, plid, portletId);
358 }
359 catch (NoSuchPortletPreferencesException nsppe) {
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 String portletDataHandlerClass =
392 portlet.getPortletDataHandlerClass();
393
394 if (Validator.isNull(portletDataHandlerClass)) {
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);
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 preferencesImpl =
458 (PortletPreferencesImpl)PortletClassInvoker.invoke(
459 portletId, portletDataHandlerClass, "importData", context,
460 portletId, preferencesImpl, portletData);
461 }
462 catch (Exception e) {
463 throw new SystemException(e);
464 }
465 finally {
466 context.setGroupId(groupId);
467 }
468
469 if (preferencesImpl == null) {
470 return null;
471 }
472
473 return PortletPreferencesSerializer.toXML(preferencesImpl);
474 }
475
476 protected void importPortletPreferences(
477 PortletDataContext context, long companyId, long groupId,
478 Layout layout, String portletId, Element parentEl,
479 boolean importPortletSetup, boolean importPortletArchivedSetups,
480 boolean importUserPreferences, boolean preserveScopeLayoutId)
481 throws PortalException, SystemException {
482
483 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
484 long plid = 0;
485 long scopeLayoutId = 0;
486
487 if (layout != null) {
488 plid = layout.getPlid();
489
490 if (preserveScopeLayoutId && (portletId != null)) {
491 javax.portlet.PortletPreferences jxPreferences =
492 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
493 layout, portletId);
494
495 scopeLayoutId = GetterUtil.getLong(
496 jxPreferences.getValue("lfr-scope-layout-id", null));
497
498 context.setScopeLayoutId(scopeLayoutId);
499 }
500 }
501
502 List<Element> preferencesEls = parentEl.elements("portlet-preferences");
503
504 for (Element preferencesEl : preferencesEls) {
505 String path = preferencesEl.attributeValue("path");
506
507 if (context.isPathNotProcessed(path)) {
508 Element el = null;
509 String xml = null;
510
511 try {
512 xml = context.getZipEntryAsString(path);
513
514 Document preferencesDoc = SAXReaderUtil.read(xml);
515
516 el = preferencesDoc.getRootElement();
517 }
518 catch (DocumentException de) {
519 throw new SystemException(de);
520 }
521
522 long ownerId = GetterUtil.getLong(
523 el.attributeValue("owner-id"));
524 int ownerType = GetterUtil.getInteger(
525 el.attributeValue("owner-type"));
526
527 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
528 continue;
529 }
530
531 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
532 (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
533 !importPortletSetup) {
534
535 continue;
536 }
537
538 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
539 !importPortletArchivedSetups) {
540
541 continue;
542 }
543
544 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
545 (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
546 !importUserPreferences) {
547
548 continue;
549 }
550
551 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
552 plid = PortletKeys.PREFS_PLID_SHARED;
553 ownerId = context.getGroupId();
554 }
555
556 boolean defaultUser = GetterUtil.getBoolean(
557 el.attributeValue("default-user"));
558
559 if (portletId == null) {
560 portletId = el.attributeValue("portlet-id");
561 }
562
563 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
564 String userUuid = el.attributeValue("archive-user-uuid");
565 String name = el.attributeValue("archive-name");
566
567 long userId = context.getUserId(userUuid);
568
569 PortletItem portletItem =
570 PortletItemLocalServiceUtil.updatePortletItem(
571 userId, groupId, name, portletId,
572 PortletPreferences.class.getName());
573
574 plid = 0;
575 ownerId = portletItem.getPortletItemId();
576 }
577
578 if (defaultUser) {
579 ownerId = defaultUserId;
580 }
581
582 PortletPreferencesLocalServiceUtil.updatePreferences(
583 ownerId, ownerType, plid, portletId, xml);
584 }
585 }
586
587 if (preserveScopeLayoutId && (layout != null)) {
588 javax.portlet.PortletPreferences jxPreferences =
589 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
590 layout, portletId);
591
592 try {
593 jxPreferences.setValue(
594 "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
595
596 jxPreferences.store();
597 }
598 catch (Exception e) {
599 throw new PortalException(e);
600 }
601 finally {
602 context.setScopeLayoutId(scopeLayoutId);
603 }
604 }
605 }
606
607 protected void readComments(PortletDataContext context, Element parentEl)
608 throws SystemException {
609
610 try {
611 String xml = context.getZipEntryAsString(
612 context.getSourceRootPath() + "/comments.xml");
613
614 if (xml == null) {
615 return;
616 }
617
618 Document doc = SAXReaderUtil.read(xml);
619
620 Element root = doc.getRootElement();
621
622 List<Element> assets = root.elements("asset");
623
624 for (Element asset : assets) {
625 String path = asset.attributeValue("path");
626 String className = asset.attributeValue("class-name");
627 long classPK = GetterUtil.getLong(
628 asset.attributeValue("class-pk"));
629
630 List<ObjectValuePair<String, byte[]>> entries =
631 context.getZipFolderEntries(path);
632
633 List<MBMessage> messages = new ArrayList<MBMessage>();
634
635 for (ObjectValuePair<String, byte[]> entry : entries) {
636 if (entry.getValue().length > 0) {
637 MBMessage message = (MBMessage)context.fromXML(
638 entry.getValue());
639
640 messages.add(message);
641 }
642 }
643
644 context.addComments(className, classPK, messages);
645 }
646 }
647 catch (Exception e) {
648 throw new SystemException(e);
649 }
650 }
651
652 protected void readRatings(PortletDataContext context, Element parentEl)
653 throws SystemException {
654
655 try {
656 String xml = context.getZipEntryAsString(
657 context.getSourceRootPath() + "/ratings.xml");
658
659 if (xml == null) {
660 return;
661 }
662
663 Document doc = SAXReaderUtil.read(xml);
664
665 Element root = doc.getRootElement();
666
667 List<Element> assets = root.elements("asset");
668
669 for (Element asset : assets) {
670 String path = asset.attributeValue("path");
671 String className = asset.attributeValue("class-name");
672 long classPK = GetterUtil.getLong(
673 asset.attributeValue("class-pk"));
674
675 List<ObjectValuePair<String, byte[]>> entries =
676 context.getZipFolderEntries(path);
677
678 List<RatingsEntry> ratingsEntries =
679 new ArrayList<RatingsEntry>();
680
681 for (ObjectValuePair<String, byte[]> entry : entries) {
682 if (entry.getValue().length > 0) {
683 RatingsEntry rating = (RatingsEntry)context.fromXML(
684 entry.getValue());
685
686 ratingsEntries.add(rating);
687 }
688 }
689
690 context.addRatingsEntries(
691 className, new Long(classPK), ratingsEntries);
692 }
693 }
694 catch (Exception e) {
695 throw new SystemException(e);
696 }
697 }
698
699 protected void readCategories(PortletDataContext context, Element parentEl)
700 throws SystemException {
701
702 try {
703 String xml = context.getZipEntryAsString(
704 context.getSourceRootPath() + "/categories.xml");
705
706 if (xml == null) {
707 return;
708 }
709
710 Document doc = SAXReaderUtil.read(xml);
711
712 Element root = doc.getRootElement();
713
714 List<Element> assets = root.elements("asset");
715
716 for (Element asset : assets) {
717 String className = GetterUtil.getString(
718 asset.attributeValue("class-name"));
719 long classPK = GetterUtil.getLong(
720 asset.attributeValue("class-pk"));
721 String entries = GetterUtil.getString(
722 asset.attributeValue("entries"));
723
724 context.addTagsCategories(
725 className, new Long(classPK), StringUtil.split(entries));
726 }
727 }
728 catch (Exception e) {
729 throw new SystemException(e);
730 }
731 }
732
733 protected void readTags(PortletDataContext context, Element parentEl)
734 throws SystemException {
735
736 try {
737 String xml = context.getZipEntryAsString(
738 context.getSourceRootPath() + "/tags.xml");
739
740 if (xml == null) {
741 return;
742 }
743
744 Document doc = SAXReaderUtil.read(xml);
745
746 Element root = doc.getRootElement();
747
748 List<Element> assets = root.elements("asset");
749
750 for (Element asset : assets) {
751 String className = GetterUtil.getString(
752 asset.attributeValue("class-name"));
753 long classPK = GetterUtil.getLong(
754 asset.attributeValue("class-pk"));
755 String entries = GetterUtil.getString(
756 asset.attributeValue("entries"));
757
758 context.addTagsEntries(
759 className, new Long(classPK), StringUtil.split(entries));
760 }
761 }
762 catch (Exception e) {
763 throw new SystemException(e);
764 }
765 }
766
767 private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
768
769 }