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