1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   * 
13   */
14  
15  package com.liferay.portal.lar;
16  
17  import com.liferay.portal.LARFileException;
18  import com.liferay.portal.LARTypeException;
19  import com.liferay.portal.LayoutImportException;
20  import com.liferay.portal.PortalException;
21  import com.liferay.portal.PortletIdException;
22  import com.liferay.portal.SystemException;
23  import com.liferay.portal.kernel.log.Log;
24  import com.liferay.portal.kernel.log.LogFactoryUtil;
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.MapUtil;
27  import com.liferay.portal.kernel.util.ReleaseInfo;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.xml.Document;
30  import com.liferay.portal.kernel.xml.DocumentException;
31  import com.liferay.portal.kernel.xml.Element;
32  import com.liferay.portal.kernel.xml.SAXReaderUtil;
33  import com.liferay.portal.kernel.zip.ZipReader;
34  import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
35  import com.liferay.portal.model.Layout;
36  import com.liferay.portal.model.Portlet;
37  import com.liferay.portal.model.PortletConstants;
38  import com.liferay.portal.model.PortletItem;
39  import com.liferay.portal.model.PortletPreferences;
40  import com.liferay.portal.model.User;
41  import com.liferay.portal.service.LayoutLocalServiceUtil;
42  import com.liferay.portal.service.PortletItemLocalServiceUtil;
43  import com.liferay.portal.service.PortletLocalServiceUtil;
44  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
45  import com.liferay.portal.service.UserLocalServiceUtil;
46  import com.liferay.portal.service.persistence.PortletPreferencesUtil;
47  import com.liferay.portal.service.persistence.UserUtil;
48  import com.liferay.portal.util.PortletKeys;
49  import com.liferay.portlet.PortletPreferencesImpl;
50  import com.liferay.portlet.PortletPreferencesSerializer;
51  import com.liferay.portlet.messageboards.model.MBMessage;
52  import com.liferay.portlet.ratings.model.RatingsEntry;
53  import com.liferay.portlet.social.util.SocialActivityThreadLocal;
54  
55  import java.io.File;
56  
57  import java.util.ArrayList;
58  import java.util.HashSet;
59  import java.util.List;
60  import java.util.Map;
61  
62  import org.apache.commons.lang.time.StopWatch;
63  
64  /**
65   * <a href="PortletImporter.java.html"><b><i>View Source</i></b></a>
66   *
67   * @author Brian Wing Shun Chan
68   * @author Joel Kozikowski
69   * @author Charles May
70   * @author Raymond Augé
71   * @author Jorge Ferrer
72   * @author Bruno Farache
73   */
74  public class PortletImporter {
75  
76      public void importPortletInfo(
77              long userId, long plid, long groupId, String portletId,
78              Map<String, String[]> parameterMap, File file)
79          throws PortalException, SystemException {
80  
81          boolean deletePortletData = MapUtil.getBoolean(
82              parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
83          boolean importPortletData = MapUtil.getBoolean(
84              parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
85          boolean importPortletArchivedSetups = MapUtil.getBoolean(
86              parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
87          boolean importPortletSetup = MapUtil.getBoolean(
88              parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
89          boolean importUserPreferences = MapUtil.getBoolean(
90              parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
91          String userIdStrategy = MapUtil.getString(
92              parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
93  
94          StopWatch stopWatch = null;
95  
96          if (_log.isInfoEnabled()) {
97              stopWatch = new StopWatch();
98  
99              stopWatch.start();
100         }
101 
102         Layout layout = LayoutLocalServiceUtil.getLayout(plid);
103 
104         long companyId = layout.getCompanyId();
105 
106         User user = UserUtil.findByPrimaryKey(userId);
107 
108         UserIdStrategy strategy = getUserIdStrategy(user, userIdStrategy);
109 
110         ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
111 
112         PortletDataContext context = new PortletDataContextImpl(
113             companyId, groupId, parameterMap, new HashSet<String>(), strategy,
114             zipReader);
115 
116         context.setPlid(plid);
117 
118         // Zip
119 
120         Element root = null;
121 
122         // Manifest
123 
124         String xml = context.getZipEntryAsString("/manifest.xml");
125 
126         try {
127             Document doc = SAXReaderUtil.read(xml);
128 
129             root = doc.getRootElement();
130         }
131         catch (Exception e) {
132             throw new LARFileException(
133                 "Cannot locate a manifest in this LAR file.");
134         }
135 
136         // Build compatibility
137 
138         Element header = root.element("header");
139 
140         int buildNumber = ReleaseInfo.getBuildNumber();
141 
142         int importBuildNumber = GetterUtil.getInteger(
143             header.attributeValue("build-number"));
144 
145         if (buildNumber != importBuildNumber) {
146             throw new LayoutImportException(
147                 "LAR build number " + importBuildNumber + " does not match " +
148                     "portal build number " + buildNumber);
149         }
150 
151         // Type compatibility
152 
153         String type = header.attributeValue("type");
154 
155         if (!type.equals("portlet")) {
156             throw new LARTypeException(
157                 "Invalid type of LAR file (" + type + ")");
158         }
159 
160         // Portlet compatibility
161 
162         String rootPortletId = header.attributeValue("root-portlet-id");
163 
164         if (!PortletConstants.getRootPortletId(portletId).equals(
165                 rootPortletId)) {
166 
167             throw new PortletIdException("Invalid portlet id " + rootPortletId);
168         }
169 
170         // Import GroupId
171 
172         long importGroupId = GetterUtil.getLong(
173             header.attributeValue("group-id"));
174 
175         context.setImportGroupId(importGroupId);
176 
177         // Read comments, ratings, and tags to make them available to the data
178         // handlers through the context
179 
180         readComments(context, root);
181         readRatings(context, root);
182         readTags(context, root);
183 
184         // Delete portlet data
185 
186         if (_log.isDebugEnabled()) {
187             _log.debug("Deleting portlet data");
188         }
189 
190         if (deletePortletData) {
191             deletePortletData(context, portletId, plid);
192         }
193 
194         Element portletRefEl = root.element("portlet");
195         Element portletEl = null;
196 
197         try {
198             Document portletDoc = SAXReaderUtil.read(
199                 context.getZipEntryAsString(
200                     portletRefEl.attributeValue("path")));
201 
202             portletEl = portletDoc.getRootElement();
203         }
204         catch (DocumentException de) {
205             throw new SystemException(de);
206         }
207 
208         // Portlet preferences
209 
210         importPortletPreferences(
211             context, layout.getCompanyId(), groupId, plid, portletId, portletEl,
212             importPortletSetup, importPortletArchivedSetups,
213             importUserPreferences);
214 
215         // Portlet data
216 
217         if (_log.isDebugEnabled()) {
218             _log.debug("Importing portlet data");
219         }
220 
221         if (importPortletData) {
222             Element portletDataRefEl = portletEl.element("portlet-data");
223 
224             if (portletDataRefEl != null) {
225                 importPortletData(
226                     context, portletId, plid, portletDataRefEl);
227             }
228             else {
229                 _log.warn(
230                     "Could not import portlet data because it cannot be " +
231                         "found in the input");
232             }
233         }
234 
235         if (_log.isInfoEnabled()) {
236             _log.info(
237                 "Importing portlet data takes " + stopWatch.getTime() + " ms");
238         }
239 
240         zipReader.close();
241     }
242 
243     protected void deletePortletData(
244             PortletDataContext context, String portletId, long plid)
245         throws SystemException {
246 
247         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
248         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
249 
250         PortletPreferences portletPreferences =
251             PortletPreferencesUtil.fetchByO_O_P_P(
252                 ownerId, ownerType, plid, portletId);
253 
254         if (portletPreferences == null) {
255             portletPreferences =
256                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
257         }
258 
259         String xml = deletePortletData(
260             context, portletId, portletPreferences);
261 
262         if (xml != null) {
263             PortletPreferencesLocalServiceUtil.updatePreferences(
264                 ownerId, ownerType, plid, portletId, xml);
265         }
266     }
267 
268     protected String deletePortletData(
269             PortletDataContext context, String portletId,
270             PortletPreferences portletPreferences)
271         throws SystemException {
272 
273         Portlet portlet = PortletLocalServiceUtil.getPortletById(
274             context.getCompanyId(), portletId);
275 
276         if (portlet == null) {
277             if (_log.isDebugEnabled()) {
278                 _log.debug(
279                     "Do not delete portlet data for " + portletId +
280                         " because the portlet does not exist");
281             }
282 
283             return null;
284         }
285 
286         PortletDataHandler portletDataHandler =
287             portlet.getPortletDataHandlerInstance();
288 
289         if (portletDataHandler == null) {
290             if (_log.isDebugEnabled()) {
291                 _log.debug(
292                     "Do not delete portlet data for " + portletId +
293                         " because the portlet does not have a " +
294                             "PortletDataHandler");
295             }
296 
297             return null;
298         }
299 
300         if (_log.isDebugEnabled()) {
301             _log.debug("Deleting data for " + portletId);
302         }
303 
304         PortletPreferencesImpl prefsImpl =
305             (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
306                 portletPreferences.getPreferences());
307 
308         try {
309             prefsImpl =
310                 (PortletPreferencesImpl)portletDataHandler.deleteData(
311                     context, portletId, prefsImpl);
312         }
313         catch (Exception e) {
314             throw new SystemException(e);
315         }
316 
317         if (prefsImpl == null) {
318             return null;
319         }
320 
321         return PortletPreferencesSerializer.toXML(prefsImpl);
322     }
323 
324     protected UserIdStrategy getUserIdStrategy(
325         User user, String userIdStrategy) {
326 
327         if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
328             return new AlwaysCurrentUserIdStrategy(user);
329         }
330 
331         return new CurrentUserIdStrategy(user);
332     }
333 
334     protected void importPortletData(
335             PortletDataContext context, String portletId, long plid,
336             Element portletDataRefEl)
337         throws SystemException {
338 
339         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
340         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
341 
342         PortletPreferences portletPreferences =
343             PortletPreferencesUtil.fetchByO_O_P_P(
344                 ownerId, ownerType, plid, portletId);
345 
346         if (portletPreferences == null) {
347             portletPreferences =
348                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
349         }
350 
351         String xml = importPortletData(
352             context, portletId, portletPreferences, portletDataRefEl);
353 
354         if (xml != null) {
355             PortletPreferencesLocalServiceUtil.updatePreferences(
356                 ownerId, ownerType, plid, portletId, xml);
357         }
358     }
359 
360     protected String importPortletData(
361             PortletDataContext context, String portletId,
362             PortletPreferences portletPreferences, Element portletDataRefEl)
363         throws SystemException {
364 
365         Portlet portlet = PortletLocalServiceUtil.getPortletById(
366             context.getCompanyId(), portletId);
367 
368         if (portlet == null) {
369             if (_log.isDebugEnabled()) {
370                 _log.debug(
371                     "Do not import portlet data for " + portletId +
372                         " because the portlet does not exist");
373             }
374 
375             return null;
376         }
377 
378         PortletDataHandler portletDataHandler =
379             portlet.getPortletDataHandlerInstance();
380 
381         if (portletDataHandler == null) {
382             if (_log.isDebugEnabled()) {
383                 _log.debug(
384                     "Do not import portlet data for " + portletId +
385                         " because the portlet does not have a " +
386                             "PortletDataHandler");
387             }
388 
389             return null;
390         }
391 
392         if (_log.isDebugEnabled()) {
393             _log.debug("Importing data for " + portletId);
394         }
395 
396         PortletPreferencesImpl prefsImpl = null;
397 
398         if (portletPreferences != null) {
399             prefsImpl = (PortletPreferencesImpl)
400                 PortletPreferencesSerializer.fromDefaultXML(
401                     portletPreferences.getPreferences());
402         }
403 
404         String portletData = context.getZipEntryAsString(
405             portletDataRefEl.attributeValue("path"));
406 
407         try {
408             SocialActivityThreadLocal.setEnabled(false);
409 
410             prefsImpl =
411                 (PortletPreferencesImpl)portletDataHandler.importData(
412                     context, portletId, prefsImpl, portletData);
413         }
414         catch (Exception e) {
415             throw new SystemException(e);
416         }
417         finally {
418             SocialActivityThreadLocal.setEnabled(true);
419         }
420 
421         if (prefsImpl == null) {
422             return null;
423         }
424 
425         return PortletPreferencesSerializer.toXML(prefsImpl);
426     }
427 
428     protected void importPortletPreferences(
429             PortletDataContext context, long companyId, long groupId, long plid,
430             String portletId, Element parentEl, boolean importPortletSetup,
431             boolean importPortletArchivedSetups, boolean importUserPreferences)
432         throws PortalException, SystemException {
433 
434         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
435 
436         List<Element> prefsEls = parentEl.elements("portlet-preferences");
437 
438         for (Element prefEl : prefsEls) {
439             String path = prefEl.attributeValue("path");
440 
441             if (context.isPathNotProcessed(path)) {
442                 Element el = null;
443                 String xml = null;
444 
445                 try {
446                     xml = context.getZipEntryAsString(path);
447 
448                     Document prefsDoc = SAXReaderUtil.read(xml);
449 
450                     el = prefsDoc.getRootElement();
451                 }
452                 catch (DocumentException de) {
453                     throw new SystemException(de);
454                 }
455 
456                 long ownerId = GetterUtil.getLong(
457                     el.attributeValue("owner-id"));
458                 int ownerType = GetterUtil.getInteger(
459                     el.attributeValue("owner-type"));
460 
461                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
462                     continue;
463                 }
464 
465                 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
466                      (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
467                     !importPortletSetup) {
468 
469                     continue;
470                 }
471 
472                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
473                     !importPortletArchivedSetups) {
474 
475                     continue;
476                 }
477 
478                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
479                     (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
480                     !importUserPreferences) {
481 
482                     continue;
483                 }
484 
485                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
486                     plid = PortletKeys.PREFS_PLID_SHARED;
487                     ownerId = context.getGroupId();
488                 }
489 
490                 boolean defaultUser = GetterUtil.getBoolean(
491                     el.attributeValue("default-user"));
492 
493                 if (portletId == null) {
494                     portletId = el.attributeValue("portlet-id");
495                 }
496 
497                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
498                     portletId = PortletConstants.getRootPortletId(portletId);
499 
500                     String userUuid = el.attributeValue("archive-user-uuid");
501                     String name = el.attributeValue("archive-name");
502 
503                     long userId = context.getUserId(userUuid);
504 
505                     PortletItem portletItem =
506                         PortletItemLocalServiceUtil.updatePortletItem(
507                             userId, groupId, name, portletId,
508                             PortletPreferences.class.getName());
509 
510                     plid = 0;
511                     ownerId = portletItem.getPortletItemId();
512                 }
513 
514                 if (defaultUser) {
515                     ownerId = defaultUserId;
516                 }
517 
518                 PortletPreferencesLocalServiceUtil.updatePreferences(
519                     ownerId, ownerType, plid, portletId, xml);
520             }
521         }
522     }
523 
524     protected void readComments(PortletDataContext context, Element parentEl)
525         throws SystemException {
526 
527         try {
528             String xml = context.getZipEntryAsString(
529                 context.getImportRootPath() + "/comments.xml");
530 
531             Document doc = SAXReaderUtil.read(xml);
532 
533             Element root = doc.getRootElement();
534 
535             List<Element> assets = root.elements("asset");
536 
537             for (Element asset : assets) {
538                 String path = asset.attributeValue("path");
539                 String className = asset.attributeValue("class-name");
540                 long classPK = GetterUtil.getLong(
541                     asset.attributeValue("class-pk"));
542 
543                 List<String> zipFolderEntries = context.getZipFolderEntries(
544                     path);
545 
546                 List<MBMessage> messages = new ArrayList<MBMessage>();
547 
548                 for (String zipFolderEntry : zipFolderEntries) {
549                     MBMessage message = (MBMessage)context.getZipEntryAsObject(
550                         zipFolderEntry);
551 
552                     if (message != null) {
553                         messages.add(message);
554                     }
555                 }
556 
557                 context.addComments(className, classPK, messages);
558             }
559         }
560         catch (Exception e) {
561             throw new SystemException(e);
562         }
563     }
564 
565     protected void readRatings(PortletDataContext context, Element parentEl)
566         throws SystemException {
567 
568         try {
569             String xml = context.getZipEntryAsString(
570                 context.getImportRootPath() + "/ratings.xml");
571 
572             Document doc = SAXReaderUtil.read(xml);
573 
574             Element root = doc.getRootElement();
575 
576             List<Element> assets = root.elements("asset");
577 
578             for (Element asset : assets) {
579                 String path = asset.attributeValue("path");
580                 String className = asset.attributeValue("class-name");
581                 long classPK = GetterUtil.getLong(
582                     asset.attributeValue("class-pk"));
583 
584                 List<String> zipFolderEntries = context.getZipFolderEntries(
585                     path);
586 
587                 List<RatingsEntry> ratingsEntries =
588                     new ArrayList<RatingsEntry>();
589 
590                 for (String zipFolderEntry : zipFolderEntries) {
591                     RatingsEntry ratingsEntry =
592                         (RatingsEntry)context.getZipEntryAsObject(
593                             zipFolderEntry);
594 
595                     if (ratingsEntry != null) {
596                         ratingsEntries.add(ratingsEntry);
597                     }
598                 }
599 
600                 context.addRatingsEntries(
601                     className, new Long(classPK), ratingsEntries);
602             }
603         }
604         catch (Exception e) {
605             throw new SystemException(e);
606         }
607     }
608 
609     protected void readTags(PortletDataContext context, Element parentEl)
610         throws SystemException {
611 
612         try {
613             String xml = context.getZipEntryAsString(
614                 context.getImportRootPath() + "/tags.xml");
615 
616             Document doc = SAXReaderUtil.read(xml);
617 
618             Element root = doc.getRootElement();
619 
620             List<Element> assets = root.elements("asset");
621 
622             for (Element asset : assets) {
623                 String className = GetterUtil.getString(
624                     asset.attributeValue("class-name"));
625                 long classPK = GetterUtil.getLong(
626                     asset.attributeValue("class-pk"));
627                 String entries = GetterUtil.getString(
628                     asset.attributeValue("entries"));
629 
630                 context.addTagsEntries(
631                     className, new Long(classPK),
632                     StringUtil.split(entries, ","));
633             }
634         }
635         catch (Exception e) {
636             throw new SystemException(e);
637         }
638     }
639 
640     private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
641 
642 }