1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
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.PortletIdException;
21  import com.liferay.portal.kernel.exception.PortalException;
22  import com.liferay.portal.kernel.exception.SystemException;
23  import com.liferay.portal.kernel.log.Log;
24  import com.liferay.portal.kernel.log.LogFactoryUtil;
25  import com.liferay.portal.kernel.util.ArrayUtil;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.MapUtil;
28  import com.liferay.portal.kernel.util.ReleaseInfo;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.xml.Document;
31  import com.liferay.portal.kernel.xml.DocumentException;
32  import com.liferay.portal.kernel.xml.Element;
33  import com.liferay.portal.kernel.xml.SAXReaderUtil;
34  import com.liferay.portal.kernel.zip.ZipReader;
35  import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
36  import com.liferay.portal.model.Group;
37  import com.liferay.portal.model.Layout;
38  import com.liferay.portal.model.Portlet;
39  import com.liferay.portal.model.PortletConstants;
40  import com.liferay.portal.model.PortletItem;
41  import com.liferay.portal.model.PortletPreferences;
42  import com.liferay.portal.model.User;
43  import com.liferay.portal.service.GroupLocalServiceUtil;
44  import com.liferay.portal.service.LayoutLocalServiceUtil;
45  import com.liferay.portal.service.PortletItemLocalServiceUtil;
46  import com.liferay.portal.service.PortletLocalServiceUtil;
47  import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
48  import com.liferay.portal.service.UserLocalServiceUtil;
49  import com.liferay.portal.service.persistence.PortletPreferencesUtil;
50  import com.liferay.portal.service.persistence.UserUtil;
51  import com.liferay.portal.util.PortletKeys;
52  import com.liferay.portlet.PortletPreferencesFactoryUtil;
53  import com.liferay.portlet.PortletPreferencesImpl;
54  import com.liferay.portlet.PortletPreferencesSerializer;
55  import com.liferay.portlet.asset.NoSuchCategoryException;
56  import com.liferay.portlet.asset.model.AssetCategory;
57  import com.liferay.portlet.asset.service.persistence.AssetCategoryUtil;
58  import com.liferay.portlet.messageboards.model.MBMessage;
59  import com.liferay.portlet.ratings.model.RatingsEntry;
60  import com.liferay.portlet.social.util.SocialActivityThreadLocal;
61  
62  import java.io.File;
63  
64  import java.util.ArrayList;
65  import java.util.HashSet;
66  import java.util.List;
67  import java.util.Map;
68  
69  import org.apache.commons.lang.time.StopWatch;
70  
71  /**
72   * <a href="PortletImporter.java.html"><b><i>View Source</i></b></a>
73   *
74   * @author Brian Wing Shun Chan
75   * @author Joel Kozikowski
76   * @author Charles May
77   * @author Raymond Augé
78   * @author Jorge Ferrer
79   * @author Bruno Farache
80   * @author Zsigmond Rab
81   * @author Douglas Wong
82   */
83  public class PortletImporter {
84  
85      public void importPortletInfo(
86              long userId, long plid, long groupId, String portletId,
87              Map<String, String[]> parameterMap, File file)
88          throws PortalException, SystemException {
89  
90          boolean deletePortletData = MapUtil.getBoolean(
91              parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
92          boolean importPermissions = MapUtil.getBoolean(
93              parameterMap, PortletDataHandlerKeys.PERMISSIONS);
94          boolean importPortletData = MapUtil.getBoolean(
95              parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
96          boolean importPortletArchivedSetups = MapUtil.getBoolean(
97              parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
98          boolean importPortletSetup = MapUtil.getBoolean(
99              parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
100         boolean importUserPreferences = MapUtil.getBoolean(
101             parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
102         String userIdStrategy = MapUtil.getString(
103             parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
104 
105         StopWatch stopWatch = null;
106 
107         if (_log.isInfoEnabled()) {
108             stopWatch = new StopWatch();
109 
110             stopWatch.start();
111         }
112 
113         Layout layout = LayoutLocalServiceUtil.getLayout(plid);
114 
115         long companyId = layout.getCompanyId();
116 
117         User user = UserUtil.findByPrimaryKey(userId);
118 
119         UserIdStrategy strategy = getUserIdStrategy(user, userIdStrategy);
120 
121         ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
122 
123         PortletDataContext context = new PortletDataContextImpl(
124             companyId, groupId, parameterMap, new HashSet<String>(),
125             strategy, zipReader);
126 
127         context.setPlid(plid);
128         context.setPrivateLayout(layout.isPrivateLayout());
129 
130         // Zip
131 
132         Element root = null;
133 
134         // Manifest
135 
136         String xml = context.getZipEntryAsString("/manifest.xml");
137 
138         try {
139             Document doc = SAXReaderUtil.read(xml);
140 
141             root = doc.getRootElement();
142         }
143         catch (Exception e) {
144             throw new LARFileException(
145                 "Cannot locate a manifest in this LAR file.");
146         }
147 
148         // Build compatibility
149 
150         Element header = root.element("header");
151 
152         int buildNumber = ReleaseInfo.getBuildNumber();
153 
154         int importBuildNumber = GetterUtil.getInteger(
155             header.attributeValue("build-number"));
156 
157         if (buildNumber != importBuildNumber) {
158             throw new LayoutImportException(
159                 "LAR build number " + importBuildNumber + " does not match " +
160                     "portal build number " + buildNumber);
161         }
162 
163         // Type compatibility
164 
165         String type = header.attributeValue("type");
166 
167         if (!type.equals("portlet")) {
168             throw new LARTypeException(
169                 "Invalid type of LAR file (" + type + ")");
170         }
171 
172         // Portlet compatibility
173 
174         String rootPortletId = header.attributeValue("root-portlet-id");
175 
176         if (!PortletConstants.getRootPortletId(portletId).equals(
177                 rootPortletId)) {
178 
179             throw new PortletIdException("Invalid portlet id " + rootPortletId);
180         }
181 
182         // Import group id
183 
184         long sourceGroupId = GetterUtil.getLong(
185             header.attributeValue("group-id"));
186 
187         context.setSourceGroupId(sourceGroupId);
188 
189         // Read categories, comments, ratings, and tags to make them available
190         // to the data handlers through the context
191 
192         readCategories(context, root);
193         readComments(context, root);
194         readRatings(context, root);
195         readTags(context, root);
196 
197         if (importPermissions) {
198             _permissionImporter.readPortletDataPermissions(context);
199         }
200 
201         // Delete portlet data
202 
203         if (_log.isDebugEnabled()) {
204             _log.debug("Deleting portlet data");
205         }
206 
207         if (deletePortletData) {
208             deletePortletData(context, portletId, plid);
209         }
210 
211         Element portletRefEl = root.element("portlet");
212         Element portletEl = null;
213 
214         try {
215             Document portletDoc = SAXReaderUtil.read(
216                 context.getZipEntryAsString(
217                     portletRefEl.attributeValue("path")));
218 
219             portletEl = portletDoc.getRootElement();
220         }
221         catch (DocumentException de) {
222             throw new SystemException(de);
223         }
224 
225         // Portlet preferences
226 
227         importPortletPreferences(
228             context, layout.getCompanyId(), groupId, layout, portletId,
229             portletEl, importPortletSetup, importPortletArchivedSetups,
230             importUserPreferences, true);
231 
232         // Portlet data
233 
234         if (_log.isDebugEnabled()) {
235             _log.debug("Importing portlet data");
236         }
237 
238         if (importPortletData) {
239             Element portletDataRefEl = portletEl.element("portlet-data");
240 
241             if (portletDataRefEl != null) {
242                 importPortletData(context, portletId, plid, portletDataRefEl);
243             }
244             else {
245                 if (_log.isWarnEnabled()) {
246                     _log.warn(
247                         "Could not import portlet data because it cannot be " +
248                             "found in the input");
249                 }
250             }
251         }
252 
253         if (_log.isInfoEnabled()) {
254             _log.info(
255                 "Importing portlet data takes " + stopWatch.getTime() + " ms");
256         }
257 
258         zipReader.close();
259     }
260 
261     protected void deletePortletData(
262             PortletDataContext context, String portletId, long plid)
263         throws SystemException {
264 
265         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
266         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
267 
268         PortletPreferences portletPreferences =
269             PortletPreferencesUtil.fetchByO_O_P_P(
270                 ownerId, ownerType, plid, portletId);
271 
272         if (portletPreferences == null) {
273             portletPreferences =
274                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
275         }
276 
277         String xml = deletePortletData(
278             context, portletId, portletPreferences);
279 
280         if (xml != null) {
281             PortletPreferencesLocalServiceUtil.updatePreferences(
282                 ownerId, ownerType, plid, portletId, xml);
283         }
284     }
285 
286     protected String deletePortletData(
287             PortletDataContext context, String portletId,
288             PortletPreferences portletPreferences)
289         throws SystemException {
290 
291         Portlet portlet = PortletLocalServiceUtil.getPortletById(
292             context.getCompanyId(), portletId);
293 
294         if (portlet == null) {
295             if (_log.isDebugEnabled()) {
296                 _log.debug(
297                     "Do not delete portlet data for " + portletId +
298                         " because the portlet does not exist");
299             }
300 
301             return null;
302         }
303 
304         PortletDataHandler portletDataHandler =
305             portlet.getPortletDataHandlerInstance();
306 
307         if (portletDataHandler == null) {
308             if (_log.isDebugEnabled()) {
309                 _log.debug(
310                     "Do not delete portlet data for " + portletId +
311                         " because the portlet does not have a " +
312                             "PortletDataHandler");
313             }
314 
315             return null;
316         }
317 
318         if (_log.isDebugEnabled()) {
319             _log.debug("Deleting data for " + portletId);
320         }
321 
322         PortletPreferencesImpl preferencesImpl =
323             (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
324                 portletPreferences.getPreferences());
325 
326         try {
327             preferencesImpl =
328                 (PortletPreferencesImpl)portletDataHandler.deleteData(
329                     context, 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 =
364             PortletPreferencesUtil.fetchByO_O_P_P(
365                 ownerId, ownerType, plid, portletId);
366 
367         if (portletPreferences == null) {
368             portletPreferences =
369                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
370         }
371 
372         String xml = importPortletData(
373             context, portletId, portletPreferences, portletDataRefEl);
374 
375         if (xml != null) {
376             PortletPreferencesLocalServiceUtil.updatePreferences(
377                 ownerId, ownerType, plid, portletId, xml);
378         }
379     }
380 
381     protected String importPortletData(
382             PortletDataContext context, String portletId,
383             PortletPreferences portletPreferences, Element portletDataRefEl)
384         throws SystemException {
385 
386         Portlet portlet = PortletLocalServiceUtil.getPortletById(
387             context.getCompanyId(), portletId);
388 
389         if (portlet == null) {
390             if (_log.isDebugEnabled()) {
391                 _log.debug(
392                     "Do not import portlet data for " + portletId +
393                         " because the portlet does not exist");
394             }
395 
396             return null;
397         }
398 
399         PortletDataHandler portletDataHandler =
400             portlet.getPortletDataHandlerInstance();
401 
402         if (portletDataHandler == null) {
403             if (_log.isDebugEnabled()) {
404                 _log.debug(
405                     "Do not import portlet data for " + portletId +
406                         " because the portlet does not have a " +
407                             "PortletDataHandler");
408             }
409 
410             return null;
411         }
412 
413         if (_log.isDebugEnabled()) {
414             _log.debug("Importing data for " + portletId);
415         }
416 
417         // Layout scope
418 
419         long groupId = context.getGroupId();
420 
421         long scopeLayoutId = context.getScopeLayoutId();
422 
423         if (scopeLayoutId == 0) {
424             scopeLayoutId = GetterUtil.getLong(
425                 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
426         }
427 
428         if (scopeLayoutId > 0) {
429             try {
430                 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
431                     context.getGroupId(), context.isPrivateLayout(),
432                     scopeLayoutId);
433 
434                 Group scopeGroup = null;
435 
436                 if (scopeLayout.hasScopeGroup()) {
437                     scopeGroup = scopeLayout.getScopeGroup();
438                 }
439                 else {
440                     String name = String.valueOf(scopeLayout.getPlid());
441 
442                     scopeGroup = GroupLocalServiceUtil.addGroup(
443                         context.getUserId(null), Layout.class.getName(),
444                         scopeLayout.getPlid(), name, null, 0, null, true, null);
445                 }
446 
447                 context.setGroupId(scopeGroup.getGroupId());
448             }
449             catch (PortalException pe) {
450             }
451         }
452 
453         PortletPreferencesImpl preferencesImpl = null;
454 
455         if (portletPreferences != null) {
456             preferencesImpl = (PortletPreferencesImpl)
457                 PortletPreferencesSerializer.fromDefaultXML(
458                     portletPreferences.getPreferences());
459         }
460 
461         String portletData = context.getZipEntryAsString(
462             portletDataRefEl.attributeValue("path"));
463 
464         try {
465             SocialActivityThreadLocal.setEnabled(false);
466 
467             preferencesImpl =
468                 (PortletPreferencesImpl)portletDataHandler.importData(
469                     context, portletId, preferencesImpl, portletData);
470         }
471         catch (Exception e) {
472             throw new SystemException(e);
473         }
474         finally {
475             context.setGroupId(groupId);
476 
477             SocialActivityThreadLocal.setEnabled(true);
478         }
479 
480         if (preferencesImpl == null) {
481             return null;
482         }
483 
484         return PortletPreferencesSerializer.toXML(preferencesImpl);
485     }
486 
487     protected void importPortletPreferences(
488             PortletDataContext context, long companyId, long groupId,
489             Layout layout, String portletId, Element parentEl,
490             boolean importPortletSetup, boolean importPortletArchivedSetups,
491             boolean importUserPreferences, boolean preserveScopeLayoutId)
492         throws PortalException, SystemException {
493 
494         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
495         long plid = 0;
496         long scopeLayoutId = 0;
497 
498         if (layout != null) {
499             plid = layout.getPlid();
500 
501             if (preserveScopeLayoutId && (portletId != null)) {
502                 javax.portlet.PortletPreferences jxPreferences =
503                     PortletPreferencesFactoryUtil.getLayoutPortletSetup(
504                         layout, portletId);
505 
506                 scopeLayoutId = GetterUtil.getLong(
507                     jxPreferences.getValue("lfr-scope-layout-id", null));
508 
509                 context.setScopeLayoutId(scopeLayoutId);
510             }
511         }
512 
513         List<Element> preferencesEls = parentEl.elements("portlet-preferences");
514 
515         for (Element preferencesEl : preferencesEls) {
516             String path = preferencesEl.attributeValue("path");
517 
518             if (context.isPathNotProcessed(path)) {
519                 Element el = null;
520                 String xml = null;
521 
522                 try {
523                     xml = context.getZipEntryAsString(path);
524 
525                     Document preferencesDoc = SAXReaderUtil.read(xml);
526 
527                     el = preferencesDoc.getRootElement();
528                 }
529                 catch (DocumentException de) {
530                     throw new SystemException(de);
531                 }
532 
533                 long ownerId = GetterUtil.getLong(
534                     el.attributeValue("owner-id"));
535                 int ownerType = GetterUtil.getInteger(
536                     el.attributeValue("owner-type"));
537 
538                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
539                     continue;
540                 }
541 
542                 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
543                      (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
544                     !importPortletSetup) {
545 
546                     continue;
547                 }
548 
549                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
550                     !importPortletArchivedSetups) {
551 
552                     continue;
553                 }
554 
555                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
556                     (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
557                     !importUserPreferences) {
558 
559                     continue;
560                 }
561 
562                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
563                     plid = PortletKeys.PREFS_PLID_SHARED;
564                     ownerId = context.getGroupId();
565                 }
566 
567                 boolean defaultUser = GetterUtil.getBoolean(
568                     el.attributeValue("default-user"));
569 
570                 if (portletId == null) {
571                     portletId = el.attributeValue("portlet-id");
572                 }
573 
574                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
575                     portletId = PortletConstants.getRootPortletId(portletId);
576 
577                     String userUuid = el.attributeValue("archive-user-uuid");
578                     String name = el.attributeValue("archive-name");
579 
580                     long userId = context.getUserId(userUuid);
581 
582                     PortletItem portletItem =
583                         PortletItemLocalServiceUtil.updatePortletItem(
584                             userId, groupId, name, portletId,
585                             PortletPreferences.class.getName());
586 
587                     plid = 0;
588                     ownerId = portletItem.getPortletItemId();
589                 }
590 
591                 if (defaultUser) {
592                     ownerId = defaultUserId;
593                 }
594 
595                 PortletPreferencesLocalServiceUtil.updatePreferences(
596                     ownerId, ownerType, plid, portletId, xml);
597             }
598         }
599 
600         if (preserveScopeLayoutId && (layout != null)) {
601             javax.portlet.PortletPreferences jxPreferences =
602                 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
603                     layout, portletId);
604 
605             try {
606                 jxPreferences.setValue(
607                     "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
608 
609                 jxPreferences.store();
610             }
611             catch (Exception e) {
612                 throw new PortalException(e);
613             }
614             finally {
615                 context.setScopeLayoutId(scopeLayoutId);
616             }
617         }
618     }
619 
620     protected void readComments(PortletDataContext context, Element parentEl)
621         throws SystemException {
622 
623         try {
624             String xml = context.getZipEntryAsString(
625                 context.getSourceRootPath() + "/comments.xml");
626 
627             if (xml == null) {
628                 return;
629             }
630 
631             Document doc = SAXReaderUtil.read(xml);
632 
633             Element root = doc.getRootElement();
634 
635             List<Element> assets = root.elements("asset");
636 
637             for (Element asset : assets) {
638                 String path = asset.attributeValue("path");
639                 String className = asset.attributeValue("class-name");
640                 long classPK = GetterUtil.getLong(
641                     asset.attributeValue("class-pk"));
642 
643                 List<String> zipFolderEntries = context.getZipFolderEntries(
644                     path);
645 
646                 List<MBMessage> messages = new ArrayList<MBMessage>();
647 
648                 for (String zipFolderEntry : zipFolderEntries) {
649                     MBMessage message = (MBMessage)context.getZipEntryAsObject(
650                         zipFolderEntry);
651 
652                     if (message != null) {
653                         messages.add(message);
654                     }
655                 }
656 
657                 context.addComments(className, classPK, messages);
658             }
659         }
660         catch (Exception e) {
661             throw new SystemException(e);
662         }
663     }
664 
665     protected void readRatings(PortletDataContext context, Element parentEl)
666         throws SystemException {
667 
668         try {
669             String xml = context.getZipEntryAsString(
670                 context.getSourceRootPath() + "/ratings.xml");
671 
672             if (xml == null) {
673                 return;
674             }
675 
676             Document doc = SAXReaderUtil.read(xml);
677 
678             Element root = doc.getRootElement();
679 
680             List<Element> assets = root.elements("asset");
681 
682             for (Element asset : assets) {
683                 String path = asset.attributeValue("path");
684                 String className = asset.attributeValue("class-name");
685                 long classPK = GetterUtil.getLong(
686                     asset.attributeValue("class-pk"));
687 
688                 List<String> zipFolderEntries = context.getZipFolderEntries(
689                     path);
690 
691                 List<RatingsEntry> ratingsEntries =
692                     new ArrayList<RatingsEntry>();
693 
694                 for (String zipFolderEntry : zipFolderEntries) {
695                     RatingsEntry ratingsEntry =
696                         (RatingsEntry)context.getZipEntryAsObject(
697                             zipFolderEntry);
698 
699                     if (ratingsEntry != null) {
700                         ratingsEntries.add(ratingsEntry);
701                     }
702                 }
703 
704                 context.addRatingsEntries(
705                     className, new Long(classPK), ratingsEntries);
706             }
707         }
708         catch (Exception e) {
709             throw new SystemException(e);
710         }
711     }
712 
713     protected void readCategories(PortletDataContext context, Element parentEl)
714         throws SystemException {
715 
716         try {
717             String xml = context.getZipEntryAsString(
718                 context.getSourceRootPath() + "/categories.xml");
719 
720             if (xml == null) {
721                 return;
722             }
723 
724             Document doc = SAXReaderUtil.read(xml);
725 
726             Element root = doc.getRootElement();
727 
728             List<Element> assets = root.elements("asset");
729 
730             for (Element asset : assets) {
731                 String className = GetterUtil.getString(
732                     asset.attributeValue("class-name"));
733                 long classPK = GetterUtil.getLong(
734                     asset.attributeValue("class-pk"));
735                 String[] assetCategoryUuids = StringUtil.split(
736                     GetterUtil.getString(
737                         asset.attributeValue("category-uuids")));
738 
739                 long[] assetCategoryIds = new long[0];
740 
741                 for (String assetCategoryUuid : assetCategoryUuids) {
742                     try {
743                         AssetCategory assetCategory =
744                             AssetCategoryUtil.findByUUID_G(
745                                 assetCategoryUuid, context.getScopeGroupId());
746 
747                         assetCategoryIds = ArrayUtil.append(
748                             assetCategoryIds, assetCategory.getCategoryId());
749                     }
750                     catch (NoSuchCategoryException nsce) {
751                     }
752                 }
753 
754                 context.addAssetCategories(
755                     className, new Long(classPK), assetCategoryIds);
756             }
757         }
758         catch (Exception e) {
759             throw new SystemException(e);
760         }
761     }
762 
763     protected void readTags(PortletDataContext context, Element parentEl)
764         throws SystemException {
765 
766         try {
767             String xml = context.getZipEntryAsString(
768                 context.getSourceRootPath() + "/tags.xml");
769 
770             if (xml == null) {
771                 return;
772             }
773 
774             Document doc = SAXReaderUtil.read(xml);
775 
776             Element root = doc.getRootElement();
777 
778             List<Element> assets = root.elements("asset");
779 
780             for (Element asset : assets) {
781                 String className = GetterUtil.getString(
782                     asset.attributeValue("class-name"));
783                 long classPK = GetterUtil.getLong(
784                     asset.attributeValue("class-pk"));
785                 String assetTagNames = GetterUtil.getString(
786                     asset.attributeValue("tags"));
787 
788                 context.addAssetTags(
789                     className, new Long(classPK),
790                     StringUtil.split(assetTagNames));
791             }
792         }
793         catch (Exception e) {
794             throw new SystemException(e);
795         }
796     }
797 
798     private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
799 
800     private PermissionImporter _permissionImporter = new PermissionImporter();
801 
802 }