1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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  public class PortletImporter {
86  
87      public void importPortletInfo(
88              long userId, long plid, long groupId, String portletId,
89              Map<String, String[]> parameterMap, InputStream is)
90          throws PortalException, SystemException {
91  
92          boolean deletePortletData = MapUtil.getBoolean(
93              parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
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 = new ZipReader(is);
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 GroupId
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         // Delete portlet data
198 
199         if (_log.isDebugEnabled()) {
200             _log.debug("Deleting portlet data");
201         }
202 
203         if (deletePortletData) {
204             deletePortletData(context, portletId, plid);
205         }
206 
207         Element portletRefEl = root.element("portlet");
208         Element portletEl = null;
209 
210         try {
211             Document portletDoc = SAXReaderUtil.read(
212                 context.getZipEntryAsString(
213                     portletRefEl.attributeValue("path")));
214 
215             portletEl = portletDoc.getRootElement();
216         }
217         catch (DocumentException de) {
218             throw new SystemException(de);
219         }
220 
221         // Portlet preferences
222 
223         importPortletPreferences(
224             context, layout.getCompanyId(), groupId, layout, portletId,
225             portletEl, importPortletSetup, importPortletArchivedSetups,
226             importUserPreferences, true);
227 
228         // Portlet data
229 
230         if (_log.isDebugEnabled()) {
231             _log.debug("Importing portlet data");
232         }
233 
234         if (importPortletData) {
235             Element portletDataRefEl = portletEl.element("portlet-data");
236 
237             if (portletDataRefEl != null) {
238                 importPortletData(context, portletId, plid, portletDataRefEl);
239             }
240             else {
241                 if (_log.isWarnEnabled()) {
242                     _log.warn(
243                         "Could not import portlet data because it cannot be " +
244                             "found in the input");
245                 }
246             }
247         }
248 
249         if (_log.isInfoEnabled()) {
250             _log.info(
251                 "Importing portlet data takes " + stopWatch.getTime() + " ms");
252         }
253     }
254 
255     protected void deletePortletData(
256             PortletDataContext context, String portletId, long plid)
257         throws SystemException {
258 
259         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
260         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
261 
262         PortletPreferences portletPreferences =
263             PortletPreferencesUtil.fetchByO_O_P_P(
264                 ownerId, ownerType, plid, portletId);
265 
266         if (portletPreferences == null) {
267             portletPreferences =
268                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
269         }
270 
271         String xml = deletePortletData(
272             context, portletId, portletPreferences);
273 
274         if (xml != null) {
275             PortletPreferencesLocalServiceUtil.updatePreferences(
276                 ownerId, ownerType, plid, portletId, xml);
277         }
278     }
279 
280     protected String deletePortletData(
281             PortletDataContext context, String portletId,
282             PortletPreferences portletPreferences)
283         throws SystemException {
284 
285         Portlet portlet = PortletLocalServiceUtil.getPortletById(
286             context.getCompanyId(), portletId);
287 
288         if (portlet == null) {
289             if (_log.isDebugEnabled()) {
290                 _log.debug(
291                     "Do not delete portlet data for " + portletId +
292                         " because the portlet does not exist");
293             }
294 
295             return null;
296         }
297 
298         PortletDataHandler portletDataHandler =
299             portlet.getPortletDataHandlerInstance();
300 
301         if (portletDataHandler == null) {
302             if (_log.isDebugEnabled()) {
303                 _log.debug(
304                     "Do not delete portlet data for " + portletId +
305                         " because the portlet does not have a " +
306                             "PortletDataHandler");
307             }
308 
309             return null;
310         }
311 
312         if (_log.isDebugEnabled()) {
313             _log.debug("Deleting data for " + portletId);
314         }
315 
316         PortletPreferencesImpl preferencesImpl =
317             (PortletPreferencesImpl)PortletPreferencesSerializer.fromDefaultXML(
318                 portletPreferences.getPreferences());
319 
320         try {
321             preferencesImpl =
322                 (PortletPreferencesImpl)portletDataHandler.deleteData(
323                     context, portletId, preferencesImpl);
324         }
325         catch (Exception e) {
326             throw new SystemException(e);
327         }
328         finally {
329             context.setGroupId(context.getScopeGroupId());
330         }
331 
332         if (preferencesImpl == null) {
333             return null;
334         }
335 
336         return PortletPreferencesSerializer.toXML(preferencesImpl);
337     }
338 
339     protected UserIdStrategy getUserIdStrategy(
340         User user, String userIdStrategy) {
341 
342         if (UserIdStrategy.ALWAYS_CURRENT_USER_ID.equals(userIdStrategy)) {
343             return new AlwaysCurrentUserIdStrategy(user);
344         }
345 
346         return new CurrentUserIdStrategy(user);
347     }
348 
349     protected void importPortletData(
350             PortletDataContext context, String portletId, long plid,
351             Element portletDataRefEl)
352         throws SystemException {
353 
354         long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
355         int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
356 
357         PortletPreferences portletPreferences =
358             PortletPreferencesUtil.fetchByO_O_P_P(
359                 ownerId, ownerType, plid, portletId);
360 
361         if (portletPreferences == null) {
362             portletPreferences =
363                 new com.liferay.portal.model.impl.PortletPreferencesImpl();
364         }
365 
366         String xml = importPortletData(
367             context, portletId, portletPreferences, portletDataRefEl);
368 
369         if (xml != null) {
370             PortletPreferencesLocalServiceUtil.updatePreferences(
371                 ownerId, ownerType, plid, portletId, xml);
372         }
373     }
374 
375     protected String importPortletData(
376             PortletDataContext context, String portletId,
377             PortletPreferences portletPreferences, Element portletDataRefEl)
378         throws SystemException {
379 
380         Portlet portlet = PortletLocalServiceUtil.getPortletById(
381             context.getCompanyId(), portletId);
382 
383         if (portlet == null) {
384             if (_log.isDebugEnabled()) {
385                 _log.debug(
386                     "Do not import portlet data for " + portletId +
387                         " because the portlet does not exist");
388             }
389 
390             return null;
391         }
392 
393         PortletDataHandler portletDataHandler =
394             portlet.getPortletDataHandlerInstance();
395 
396         if (portletDataHandler == null) {
397             if (_log.isDebugEnabled()) {
398                 _log.debug(
399                     "Do not import portlet data for " + portletId +
400                         " because the portlet does not have a " +
401                             "PortletDataHandler");
402             }
403 
404             return null;
405         }
406 
407         if (_log.isDebugEnabled()) {
408             _log.debug("Importing data for " + portletId);
409         }
410 
411         // Layout scope
412 
413         long groupId = context.getGroupId();
414 
415         long scopeLayoutId = context.getScopeLayoutId();
416 
417         if (scopeLayoutId == 0) {
418             scopeLayoutId = GetterUtil.getLong(
419                 portletDataRefEl.getParent().attributeValue("scope-layout-id"));
420         }
421 
422         if (scopeLayoutId > 0) {
423             try {
424                 Layout scopeLayout = LayoutLocalServiceUtil.getLayout(
425                     context.getGroupId(), context.isPrivateLayout(),
426                     scopeLayoutId);
427 
428                 Group scopeGroup = null;
429 
430                 if (scopeLayout.hasScopeGroup()) {
431                     scopeGroup = scopeLayout.getScopeGroup();
432                 }
433                 else {
434                     String name = String.valueOf(scopeLayout.getPlid());
435 
436                     scopeGroup = GroupLocalServiceUtil.addGroup(
437                         context.getUserId(null), Layout.class.getName(),
438                         scopeLayout.getPlid(), name, null, 0, null, true, null);
439                 }
440 
441                 context.setGroupId(scopeGroup.getGroupId());
442             }
443             catch (PortalException pe) {
444             }
445         }
446 
447         PortletPreferencesImpl preferencesImpl = null;
448 
449         if (portletPreferences != null) {
450             preferencesImpl = (PortletPreferencesImpl)
451                 PortletPreferencesSerializer.fromDefaultXML(
452                     portletPreferences.getPreferences());
453         }
454 
455         String portletData = context.getZipEntryAsString(
456             portletDataRefEl.attributeValue("path"));
457 
458         try {
459             SocialActivityThreadLocal.setEnabled(false);
460 
461             preferencesImpl =
462                 (PortletPreferencesImpl)portletDataHandler.importData(
463                     context, portletId, preferencesImpl, portletData);
464         }
465         catch (Exception e) {
466             throw new SystemException(e);
467         }
468         finally {
469             context.setGroupId(groupId);
470 
471             SocialActivityThreadLocal.setEnabled(true);
472         }
473 
474         if (preferencesImpl == null) {
475             return null;
476         }
477 
478         return PortletPreferencesSerializer.toXML(preferencesImpl);
479     }
480 
481     protected void importPortletPreferences(
482             PortletDataContext context, long companyId, long groupId,
483             Layout layout, String portletId, Element parentEl,
484             boolean importPortletSetup, boolean importPortletArchivedSetups,
485             boolean importUserPreferences, boolean preserveScopeLayoutId)
486         throws PortalException, SystemException {
487 
488         long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
489         long plid = 0;
490         long scopeLayoutId = 0;
491 
492         if (layout != null) {
493             plid = layout.getPlid();
494 
495             if (preserveScopeLayoutId && (portletId != null)) {
496                 javax.portlet.PortletPreferences jxPreferences =
497                     PortletPreferencesFactoryUtil.getLayoutPortletSetup(
498                         layout, portletId);
499 
500                 scopeLayoutId = GetterUtil.getLong(
501                     jxPreferences.getValue("lfr-scope-layout-id", null));
502 
503                 context.setScopeLayoutId(scopeLayoutId);
504             }
505         }
506 
507         List<Element> preferencesEls = parentEl.elements("portlet-preferences");
508 
509         for (Element preferencesEl : preferencesEls) {
510             String path = preferencesEl.attributeValue("path");
511 
512             if (context.isPathNotProcessed(path)) {
513                 Element el = null;
514                 String xml = null;
515 
516                 try {
517                     xml = context.getZipEntryAsString(path);
518 
519                     Document preferencesDoc = SAXReaderUtil.read(xml);
520 
521                     el = preferencesDoc.getRootElement();
522                 }
523                 catch (DocumentException de) {
524                     throw new SystemException(de);
525                 }
526 
527                 long ownerId = GetterUtil.getLong(
528                     el.attributeValue("owner-id"));
529                 int ownerType = GetterUtil.getInteger(
530                     el.attributeValue("owner-type"));
531 
532                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_COMPANY) {
533                     continue;
534                 }
535 
536                 if (((ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) ||
537                      (ownerType == PortletKeys.PREFS_OWNER_TYPE_LAYOUT)) &&
538                     !importPortletSetup) {
539 
540                     continue;
541                 }
542 
543                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) &&
544                     !importPortletArchivedSetups) {
545 
546                     continue;
547                 }
548 
549                 if ((ownerType == PortletKeys.PREFS_OWNER_TYPE_USER) &&
550                     (ownerId != PortletKeys.PREFS_OWNER_ID_DEFAULT) &&
551                     !importUserPreferences) {
552 
553                     continue;
554                 }
555 
556                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_GROUP) {
557                     plid = PortletKeys.PREFS_PLID_SHARED;
558                     ownerId = context.getGroupId();
559                 }
560 
561                 boolean defaultUser = GetterUtil.getBoolean(
562                     el.attributeValue("default-user"));
563 
564                 if (portletId == null) {
565                     portletId = el.attributeValue("portlet-id");
566                 }
567 
568                 if (ownerType == PortletKeys.PREFS_OWNER_TYPE_ARCHIVED) {
569                     String userUuid = el.attributeValue("archive-user-uuid");
570                     String name = el.attributeValue("archive-name");
571 
572                     long userId = context.getUserId(userUuid);
573 
574                     PortletItem portletItem =
575                         PortletItemLocalServiceUtil.updatePortletItem(
576                             userId, groupId, name, portletId,
577                             PortletPreferences.class.getName());
578 
579                     plid = 0;
580                     ownerId = portletItem.getPortletItemId();
581                 }
582 
583                 if (defaultUser) {
584                     ownerId = defaultUserId;
585                 }
586 
587                 PortletPreferencesLocalServiceUtil.updatePreferences(
588                     ownerId, ownerType, plid, portletId, xml);
589             }
590         }
591 
592         if (preserveScopeLayoutId && (layout != null)) {
593             javax.portlet.PortletPreferences jxPreferences =
594                 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
595                     layout, portletId);
596 
597             try {
598                 jxPreferences.setValue(
599                     "lfr-scope-layout-id", String.valueOf(scopeLayoutId));
600 
601                 jxPreferences.store();
602             }
603             catch (Exception e) {
604                 throw new PortalException(e);
605             }
606             finally {
607                 context.setScopeLayoutId(scopeLayoutId);
608             }
609         }
610     }
611 
612     protected void readComments(PortletDataContext context, Element parentEl)
613         throws SystemException {
614 
615         try {
616             String xml = context.getZipEntryAsString(
617                 context.getSourceRootPath() + "/comments.xml");
618 
619             if (xml == null) {
620                 return;
621             }
622 
623             Document doc = SAXReaderUtil.read(xml);
624 
625             Element root = doc.getRootElement();
626 
627             List<Element> assets = root.elements("asset");
628 
629             for (Element asset : assets) {
630                 String path = asset.attributeValue("path");
631                 String className = asset.attributeValue("class-name");
632                 long classPK = GetterUtil.getLong(
633                     asset.attributeValue("class-pk"));
634 
635                 List<ObjectValuePair<String, byte[]>> entries =
636                     context.getZipFolderEntries(path);
637 
638                 List<MBMessage> messages = new ArrayList<MBMessage>();
639 
640                 for (ObjectValuePair<String, byte[]> entry : entries) {
641                     if (entry.getValue().length > 0) {
642                         MBMessage message = (MBMessage)context.fromXML(
643                             entry.getValue());
644 
645                         messages.add(message);
646                     }
647                 }
648 
649                 context.addComments(className, classPK, messages);
650             }
651         }
652         catch (Exception e) {
653             throw new SystemException(e);
654         }
655     }
656 
657     protected void readRatings(PortletDataContext context, Element parentEl)
658         throws SystemException {
659 
660         try {
661             String xml = context.getZipEntryAsString(
662                 context.getSourceRootPath() + "/ratings.xml");
663 
664             if (xml == null) {
665                 return;
666             }
667 
668             Document doc = SAXReaderUtil.read(xml);
669 
670             Element root = doc.getRootElement();
671 
672             List<Element> assets = root.elements("asset");
673 
674             for (Element asset : assets) {
675                 String path = asset.attributeValue("path");
676                 String className = asset.attributeValue("class-name");
677                 long classPK = GetterUtil.getLong(
678                     asset.attributeValue("class-pk"));
679 
680                 List<ObjectValuePair<String, byte[]>> entries =
681                     context.getZipFolderEntries(path);
682 
683                 List<RatingsEntry> ratingsEntries =
684                     new ArrayList<RatingsEntry>();
685 
686                 for (ObjectValuePair<String, byte[]> entry : entries) {
687                     if (entry.getValue().length > 0) {
688                         RatingsEntry rating = (RatingsEntry)context.fromXML(
689                             entry.getValue());
690 
691                         ratingsEntries.add(rating);
692                     }
693                 }
694 
695                 context.addRatingsEntries(
696                     className, new Long(classPK), ratingsEntries);
697             }
698         }
699         catch (Exception e) {
700             throw new SystemException(e);
701         }
702     }
703 
704     protected void readCategories(PortletDataContext context, Element parentEl)
705         throws SystemException {
706 
707         try {
708             String xml = context.getZipEntryAsString(
709                 context.getSourceRootPath() + "/categories.xml");
710 
711             if (xml == null) {
712                 return;
713             }
714 
715             Document doc = SAXReaderUtil.read(xml);
716 
717             Element root = doc.getRootElement();
718 
719             List<Element> assets = root.elements("asset");
720 
721             for (Element asset : assets) {
722                 String className = GetterUtil.getString(
723                     asset.attributeValue("class-name"));
724                 long classPK = GetterUtil.getLong(
725                     asset.attributeValue("class-pk"));
726                 String entries = GetterUtil.getString(
727                     asset.attributeValue("entries"));
728 
729                 context.addTagsCategories(
730                     className, new Long(classPK), StringUtil.split(entries));
731             }
732         }
733         catch (Exception e) {
734             throw new SystemException(e);
735         }
736     }
737 
738     protected void readTags(PortletDataContext context, Element parentEl)
739         throws SystemException {
740 
741         try {
742             String xml = context.getZipEntryAsString(
743                 context.getSourceRootPath() + "/tags.xml");
744 
745             if (xml == null) {
746                 return;
747             }
748 
749             Document doc = SAXReaderUtil.read(xml);
750 
751             Element root = doc.getRootElement();
752 
753             List<Element> assets = root.elements("asset");
754 
755             for (Element asset : assets) {
756                 String className = GetterUtil.getString(
757                     asset.attributeValue("class-name"));
758                 long classPK = GetterUtil.getLong(
759                     asset.attributeValue("class-pk"));
760                 String entries = GetterUtil.getString(
761                     asset.attributeValue("entries"));
762 
763                 context.addTagsEntries(
764                     className, new Long(classPK), StringUtil.split(entries));
765             }
766         }
767         catch (Exception e) {
768             throw new SystemException(e);
769         }
770     }
771 
772     private static Log _log = LogFactoryUtil.getLog(PortletImporter.class);
773 
774 }