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.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  /**
78   * <a href="PortletImporter.java.html"><b><i>View Source</i></b></a>
79   *
80   * @author Brian Wing Shun Chan
81   * @author Joel Kozikowski
82   * @author Charles May
83   * @author Raymond Augé
84   * @author Jorge Ferrer
85   * @author Bruno Farache
86   *
87   */
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         // Zip
134 
135         Element root = null;
136 
137         // Manifest
138 
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         // Build compatibility
152 
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         // Type compatibility
167 
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         // Portlet compatibility
176 
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         // Import GroupId
186 
187         long sourceGroupId = GetterUtil.getLong(
188             header.attributeValue("group-id"));
189 
190         context.setSourceGroupId(sourceGroupId);
191 
192         // Read categories, comments, ratings, and tags to make them available
193         // to the data handlers through the context
194 
195         readCategories(context, root);
196         readComments(context, root);
197         readRatings(context, root);
198         readTags(context, root);
199 
200         // Delete portlet data
201 
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         // Portlet preferences
225 
226         importPortletPreferences(
227             context, layout.getCompanyId(), groupId, layout, portletId,
228             portletEl, importPortletSetup, importPortletArchivedSetups,
229             importUserPreferences, true);
230 
231         // Portlet data
232 
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         // Layout scope
420 
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 }