1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
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.ObjectValuePair;
36  import com.liferay.portal.kernel.util.ReleaseInfo;
37  import com.liferay.portal.kernel.util.StringUtil;
38  import com.liferay.portal.kernel.xml.Document;
39  import com.liferay.portal.kernel.xml.DocumentException;
40  import com.liferay.portal.kernel.xml.Element;
41  import com.liferay.portal.kernel.xml.SAXReaderUtil;
42  import com.liferay.portal.kernel.zip.ZipReader;
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.InputStream;
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  /**
76   * <a href="PortletImporter.java.html"><b><i>View Source</i></b></a>
77   *
78   * @author Brian Wing Shun Chan
79   * @author Joel Kozikowski
80   * @author Charles May
81   * @author Raymond Augé
82   * @author Jorge Ferrer
83   * @author Bruno Farache
84   *
85   */
86  public class PortletImporter {
87  
88      public void importPortletInfo(
89              long userId, long plid, long groupId, String portletId,
90              Map<String, String[]> parameterMap, InputStream is)
91          throws PortalException, SystemException {
92  
93          boolean deletePortletData = MapUtil.getBoolean(
94              parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
95          boolean importPortletData = MapUtil.getBoolean(
96              parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
97          boolean importPortletArchivedSetups = MapUtil.getBoolean(
98              parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
99          boolean importPortletSetup = MapUtil.getBoolean(
100             parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
101         boolean importUserPreferences = MapUtil.getBoolean(
102             parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
103         String userIdStrategy = MapUtil.getString(
104             parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
105 
106         StopWatch stopWatch = null;
107 
108         if (_log.isInfoEnabled()) {
109             stopWatch = new StopWatch();
110 
111             stopWatch.start();
112         }
113 
114         Layout layout = LayoutLocalServiceUtil.getLayout(plid);
115 
116         long companyId = layout.getCompanyId();
117 
118         User user = UserUtil.findByPrimaryKey(userId);
119 
120         UserIdStrategy strategy = getUserIdStrategy(user, userIdStrategy);
121 
122         ZipReader zipReader = new ZipReader(is);
123 
124         PortletDataContext context = new PortletDataContextImpl(
125             companyId, groupId, parameterMap, new HashSet<String>(),
126             strategy, zipReader);
127 
128         context.setPlid(plid);
129         context.setPrivateLayout(layout.isPrivateLayout());
130 
131         // Zip
132 
133         Element root = null;
134 
135         // Manifest
136 
137         String xml = context.getZipEntryAsString("/manifest.xml");
138 
139         try {
140             Document doc = SAXReaderUtil.read(xml);
141 
142             root = doc.getRootElement();
143         }
144         catch (Exception e) {
145             throw new LARFileException(
146                 "Cannot locate a manifest in this LAR file.");
147         }
148 
149         // Build compatibility
150 
151         Element header = root.element("header");
152 
153         int buildNumber = ReleaseInfo.getBuildNumber();
154 
155         int importBuildNumber = GetterUtil.getInteger(
156             header.attributeValue("build-number"));
157 
158         if (buildNumber != importBuildNumber) {
159             throw new LayoutImportException(
160                 "LAR build number " + importBuildNumber + " does not match " +
161                     "portal build number " + buildNumber);
162         }
163 
164         // Type compatibility
165 
166         String type = header.attributeValue("type");
167 
168         if (!type.equals("portlet")) {
169             throw new LARTypeException(
170                 "Invalid type of LAR file (" + type + ")");
171         }
172 
173         // Portlet compatibility
174 
175         String rootPortletId = header.attributeValue("root-portlet-id");
176 
177         if (!PortletConstants.getRootPortletId(portletId).equals(
178                 rootPortletId)) {
179 
180             throw new PortletIdException("Invalid portlet id " + rootPortletId);
181         }
182 
183         // Import GroupId
184 
185         long sourceGroupId = GetterUtil.getLong(
186             header.attributeValue("group-id"));
187 
188         context.setSourceGroupId(sourceGroupId);
189 
190         // Read categories, comments, ratings, and tags to make them available
191         // to the data handlers through the context
192 
193         readCategories(context, root);
194         readComments(context, root);
195         readRatings(context, root);
196         readTags(context, root);
197 
198         // Delete portlet data
199 
200         if (_log.isDebugEnabled()) {
201             _log.debug("Deleting portlet data");
202         }
203 
204         if (deletePortletData) {
205             deletePortletData(context, portletId, plid);
206         }
207 
208         Element portletRefEl = root.element("portlet");
209         Element portletEl = null;
210 
211         try {
212             Document portletDoc = SAXReaderUtil.read(
213                 context.getZipEntryAsString(
214                     portletRefEl.attributeValue("path")));
215 
216             portletEl = portletDoc.getRootElement();
217         }
218         catch (DocumentException de) {
219             throw new SystemException(de);
220         }
221 
222         // Portlet preferences
223 
224         importPortletPreferences(
225             context, layout.getCompanyId(), groupId, layout, portletId,
226             portletEl, importPortletSetup, importPortletArchivedSetups,
227             importUserPreferences, true);
228 
229         // Portlet data
230 
231         if (_log.isDebugEnabled()) {
232             _log.debug("Importing portlet data");
233         }
234 
235         if (importPortletData) {
236             Element portletDataRefEl = portletEl.element("portlet-data");
237 
238             if (portletDataRefEl != null) {
239                 importPortletData(context, portletId, plid, portletDataRefEl);
240             }
241             else {
242                 if (_log.isWarnEnabled()) {
243                     _log.warn(
244                         "Could not import portlet data because it cannot be " +
245                             "found in the input");
246                 }
247             }
248         }
249 
250         if (_log.isInfoEnabled()) {
251             _log.info(
252                 "Importing portlet data takes " + stopWatch.getTime() + " ms");
253         }
254     }
255 
256     protected void deletePortletData(
257             PortletDataContext context, String portletId, long plid)
258         throws SystemException {
259 
260         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
261         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
262 
263         PortletPreferences portletPreferences =
264             PortletPreferencesUtil.fetchByO_O_P_P(
265                 ownerId, ownerType, plid, portletId);
266 
267         if (portletPreferences == null) {
268             portletPreferences =
269                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
270         }
271 
272         String xml = deletePortletData(
273             context, portletId, portletPreferences);
274 
275         if (xml != null) {
276             PortletPreferencesLocalServiceUtil.updatePreferences(
277                 ownerId, ownerType, plid, portletId, xml);
278         }
279     }
280 
281     protected String deletePortletData(
282             PortletDataContext context, String portletId,
283             PortletPreferences portletPreferences)
284         throws SystemException {
285 
286         Portlet portlet = PortletLocalServiceUtil.getPortletById(
287             context.getCompanyId(), portletId);
288 
289         if (portlet == null) {
290             if (_log.isDebugEnabled()) {
291                 _log.debug(
292                     "Do not delete portlet data for " + portletId +
293                         " because the portlet does not exist");
294             }
295 
296             return null;
297         }
298 
299         PortletDataHandler portletDataHandler =
300             portlet.getPortletDataHandlerInstance();
301 
302         if (portletDataHandler == null) {
303             if (_log.isDebugEnabled()) {
304                 _log.debug(
305                     "Do not delete portlet data for " + portletId +
306                         " because the portlet does not have a " +
307                             "PortletDataHandler");
308             }
309 
310             return null;
311         }
312 
313         if (_log.isDebugEnabled()) {
314             _log.debug("Deleting data for " + portletId);
315         }
316 
317         PortletPreferencesImpl preferencesImpl =
318             (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
319                 portletPreferences.getPreferences());
320 
321         try {
322             preferencesImpl =
323                 (PortletPreferencesImpl)portletDataHandler.deleteData(
324                     context, portletId, preferencesImpl);
325         }
326         catch (Exception e) {
327             throw new SystemException(e);
328         }
329         finally {
330             context.setGroupId(context.getScopeGroupId());
331         }
332 
333         if (preferencesImpl == null) {
334             return null;
335         }
336 
337         return PortletPreferencesSerializer.toXML(preferencesImpl);
338     }
339 
340     protected UserIdStrategy getUserIdStrategy(
341         User user, String userIdStrategy) {
342 
343         if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
344             return new AlwaysCurrentUserIdStrategy(user);
345         }
346 
347         return new CurrentUserIdStrategy(user);
348     }
349 
350     protected void importPortletData(
351             PortletDataContext context, String portletId, long plid,
352             Element portletDataRefEl)
353         throws SystemException {
354 
355         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
356         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
357 
358         PortletPreferences portletPreferences =
359             PortletPreferencesUtil.fetchByO_O_P_P(
360                 ownerId, ownerType, plid, portletId);
361 
362         if (portletPreferences == null) {
363             portletPreferences =
364                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
365         }
366 
367         String xml = importPortletData(
368             context, portletId, portletPreferences, portletDataRefEl);
369 
370         if (xml != null) {
371             PortletPreferencesLocalServiceUtil.updatePreferences(
372                 ownerId, ownerType, plid, portletId, xml);
373         }
374     }
375 
376     protected String importPortletData(
377             PortletDataContext context, String portletId,
378             PortletPreferences portletPreferences, Element portletDataRefEl)
379         throws SystemException {
380 
381         Portlet portlet = PortletLocalServiceUtil.getPortletById(
382             context.getCompanyId(), portletId);
383 
384         if (portlet == null) {
385             if (_log.isDebugEnabled()) {
386                 _log.debug(
387                     "Do not import portlet data for " + portletId +
388                         " because the portlet does not exist");
389             }
390 
391             return null;
392         }
393 
394         PortletDataHandler portletDataHandler =
395             portlet.getPortletDataHandlerInstance();
396 
397         if (portletDataHandler == null) {
398             if (_log.isDebugEnabled()) {
399                 _log.debug(
400                     "Do not import portlet data for " + portletId +
401                         " because the portlet does not have a " +
402                             "PortletDataHandler");
403             }
404 
405             return null;
406         }
407 
408         if (_log.isDebugEnabled()) {
409             _log.debug("Importing data for " + portletId);
410         }
411 
412         // Layout scope
413 
414         long groupId = context.getGroupId();
415 
416         long scopeLayoutId = context.getScopeLayoutId();
417 
418         if (scopeLayoutId == 0) {
419             scopeLayoutId = GetterUtil.getLong(
420                 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
421         }
422 
423         if (scopeLayoutId > 0) {
424             try {
425                 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
426                     context.getGroupId(), context.isPrivateLayout(),
427                     scopeLayoutId);
428 
429                 Group scopeGroup = null;
430 
431                 if (scopeLayout.hasScopeGroup()) {
432                     scopeGroup = scopeLayout.getScopeGroup();
433                 }
434                 else {
435                     String name = String.valueOf(scopeLayout.getPlid());
436 
437                     scopeGroup = GroupLocalServiceUtil.addGroup(
438                         context.getUserId(null), Layout.class.getName(),
439                         scopeLayout.getPlid(), name, null, 0, null, true, null);
440                 }
441 
442                 context.setGroupId(scopeGroup.getGroupId());
443             }
444             catch (PortalException pe) {
445             }
446         }
447 
448         PortletPreferencesImpl preferencesImpl = null;
449 
450         if (portletPreferences != null) {
451             preferencesImpl = (PortletPreferencesImpl)
452                 PortletPreferencesSerializer.fromDefaultXML(
453                     portletPreferences.getPreferences());
454         }
455 
456         String portletData = context.getZipEntryAsString(
457             portletDataRefEl.attributeValue("path"));
458 
459         try {
460             SocialActivityThreadLocal.setEnabled(false);
461 
462             preferencesImpl =
463                 (PortletPreferencesImpl)portletDataHandler.importData(
464                     context, portletId, preferencesImpl, portletData);
465         }
466         catch (Exception e) {
467             throw new SystemException(e);
468         }
469         finally {
470             context.setGroupId(groupId);
471 
472             SocialActivityThreadLocal.setEnabled(true);
473         }
474 
475         if (preferencesImpl == null) {
476             return null;
477         }
478 
479         return PortletPreferencesSerializer.toXML(preferencesImpl);
480     }
481 
482     protected void importPortletPreferences(
483             PortletDataContext context, long companyId, long groupId,
484             Layout layout, String portletId, Element parentEl,
485             boolean importPortletSetup, boolean importPortletArchivedSetups,
486             boolean importUserPreferences, boolean preserveScopeLayoutId)
487         throws PortalException, SystemException {
488 
489         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
490         long plid = 0;
491         long scopeLayoutId = 0;
492 
493         if (layout != null) {
494             plid = layout.getPlid();
495 
496             if (preserveScopeLayoutId && (portletId != null)) {
497                 javax.portlet.PortletPreferences jxPreferences =
498                     PortletPreferencesFactoryUtil.getLayoutPortletSetup(
499                         layout, portletId);
500 
501                 scopeLayoutId = GetterUtil.getLong(
502                     jxPreferences.getValue("lfr-scope-layout-id", null));
503 
504                 context.setScopeLayoutId(scopeLayoutId);
505             }
506         }
507 
508         List<Element> preferencesEls = parentEl.elements("portlet-preferences");
509 
510         for (Element preferencesEl : preferencesEls) {
511             String path = preferencesEl.attributeValue("path");
512 
513             if (context.isPathNotProcessed(path)) {
514                 Element el = null;
515                 String xml = null;
516 
517                 try {
518                     xml = context.getZipEntryAsString(path);
519 
520                     Document preferencesDoc = SAXReaderUtil.read(xml);
521 
522                     el = preferencesDoc.getRootElement();
523                 }
524                 catch (DocumentException de) {
525                     throw new SystemException(de);
526                 }
527 
528                 long ownerId = GetterUtil.getLong(
529                     el.attributeValue("owner-id"));
530                 int ownerType = GetterUtil.getInteger(
531                     el.attributeValue("owner-type"));
532 
533                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
534                     continue;
535                 }
536 
537                 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
538                      (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
539                     !importPortletSetup) {
540 
541                     continue;
542                 }
543 
544                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
545                     !importPortletArchivedSetups) {
546 
547                     continue;
548                 }
549 
550                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
551                     (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
552                     !importUserPreferences) {
553 
554                     continue;
555                 }
556 
557                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
558                     plid = PortletKeys.PREFS_PLID_SHARED;
559                     ownerId = context.getGroupId();
560                 }
561 
562                 boolean defaultUser = GetterUtil.getBoolean(
563                     el.attributeValue("default-user"));
564 
565                 if (portletId == null) {
566                     portletId = el.attributeValue("portlet-id");
567                 }
568 
569                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
570                     String userUuid = el.attributeValue("archive-user-uuid");
571                     String name = el.attributeValue("archive-name");
572 
573                     long userId = context.getUserId(userUuid);
574 
575                     PortletItem portletItem =
576                         PortletItemLocalServiceUtil.updatePortletItem(
577                             userId, groupId, name, portletId,
578                             PortletPreferences.class.getName());
579 
580                     plid = 0;
581                     ownerId = portletItem.getPortletItemId();
582                 }
583 
584                 if (defaultUser) {
585                     ownerId = defaultUserId;
586                 }
587 
588                 PortletPreferencesLocalServiceUtil.updatePreferences(
589                     ownerId, ownerType, plid, portletId, xml);
590             }
591         }
592 
593         if (preserveScopeLayoutId && (layout != null)) {
594             javax.portlet.PortletPreferences jxPreferences =
595                 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
596                     layout, portletId);
597 
598             try {
599                 jxPreferences.setValue(
600                     "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
601 
602                 jxPreferences.store();
603             }
604             catch (Exception e) {
605                 throw new PortalException(e);
606             }
607             finally {
608                 context.setScopeLayoutId(scopeLayoutId);
609             }
610         }
611     }
612 
613     protected void readComments(PortletDataContext context, Element parentEl)
614         throws SystemException {
615 
616         try {
617             String xml = context.getZipEntryAsString(
618                 context.getSourceRootPath() + "/comments.xml");
619 
620             if (xml == null) {
621                 return;
622             }
623 
624             Document doc = SAXReaderUtil.read(xml);
625 
626             Element root = doc.getRootElement();
627 
628             List<Element> assets = root.elements("asset");
629 
630             for (Element asset : assets) {
631                 String path = asset.attributeValue("path");
632                 String className = asset.attributeValue("class-name");
633                 long classPK = GetterUtil.getLong(
634                     asset.attributeValue("class-pk"));
635 
636                 List<ObjectValuePair<String, byte[]>> entries =
637                     context.getZipFolderEntries(path);
638 
639                 List<MBMessage> messages = new ArrayList<MBMessage>();
640 
641                 for (ObjectValuePair<String, byte[]> entry : entries) {
642                     if (entry.getValue().length > 0) {
643                         MBMessage message = (MBMessage)context.fromXML(
644                             entry.getValue());
645 
646                         messages.add(message);
647                     }
648                 }
649 
650                 context.addComments(className, classPK, messages);
651             }
652         }
653         catch (Exception e) {
654             throw new SystemException(e);
655         }
656     }
657 
658     protected void readRatings(PortletDataContext context, Element parentEl)
659         throws SystemException {
660 
661         try {
662             String xml = context.getZipEntryAsString(
663                 context.getSourceRootPath() + "/ratings.xml");
664 
665             if (xml == null) {
666                 return;
667             }
668 
669             Document doc = SAXReaderUtil.read(xml);
670 
671             Element root = doc.getRootElement();
672 
673             List<Element> assets = root.elements("asset");
674 
675             for (Element asset : assets) {
676                 String path = asset.attributeValue("path");
677                 String className = asset.attributeValue("class-name");
678                 long classPK = GetterUtil.getLong(
679                     asset.attributeValue("class-pk"));
680 
681                 List<ObjectValuePair<String, byte[]>> entries =
682                     context.getZipFolderEntries(path);
683 
684                 List<RatingsEntry> ratingsEntries =
685                     new ArrayList<RatingsEntry>();
686 
687                 for (ObjectValuePair<String, byte[]> entry : entries) {
688                     if (entry.getValue().length > 0) {
689                         RatingsEntry rating = (RatingsEntry)context.fromXML(
690                             entry.getValue());
691 
692                         ratingsEntries.add(rating);
693                     }
694                 }
695 
696                 context.addRatingsEntries(
697                     className, new Long(classPK), ratingsEntries);
698             }
699         }
700         catch (Exception e) {
701             throw new SystemException(e);
702         }
703     }
704 
705     protected void readCategories(PortletDataContext context, Element parentEl)
706         throws SystemException {
707 
708         try {
709             String xml = context.getZipEntryAsString(
710                 context.getSourceRootPath() + "/categories.xml");
711 
712             if (xml == null) {
713                 return;
714             }
715 
716             Document doc = SAXReaderUtil.read(xml);
717 
718             Element root = doc.getRootElement();
719 
720             List<Element> assets = root.elements("asset");
721 
722             for (Element asset : assets) {
723                 String className = GetterUtil.getString(
724                     asset.attributeValue("class-name"));
725                 long classPK = GetterUtil.getLong(
726                     asset.attributeValue("class-pk"));
727                 String entries = GetterUtil.getString(
728                     asset.attributeValue("entries"));
729 
730                 context.addTagsCategories(
731                     className, new Long(classPK), StringUtil.split(entries));
732             }
733         }
734         catch (Exception e) {
735             throw new SystemException(e);
736         }
737     }
738 
739     protected void readTags(PortletDataContext context, Element parentEl)
740         throws SystemException {
741 
742         try {
743             String xml = context.getZipEntryAsString(
744                 context.getSourceRootPath() + "/tags.xml");
745 
746             if (xml == null) {
747                 return;
748             }
749 
750             Document doc = SAXReaderUtil.read(xml);
751 
752             Element root = doc.getRootElement();
753 
754             List<Element> assets = root.elements("asset");
755 
756             for (Element asset : assets) {
757                 String className = GetterUtil.getString(
758                     asset.attributeValue("class-name"));
759                 long classPK = GetterUtil.getLong(
760                     asset.attributeValue("class-pk"));
761                 String entries = GetterUtil.getString(
762                     asset.attributeValue("entries"));
763 
764                 context.addTagsEntries(
765                     className, new Long(classPK), StringUtil.split(entries));
766             }
767         }
768         catch (Exception e) {
769             throw new SystemException(e);
770         }
771     }
772 
773     private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
774 
775 }