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.portlet.messageboards.lar;
24  
25  import com.liferay.documentlibrary.service.DLServiceUtil;
26  import com.liferay.portal.PortalException;
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.MapUtil;
31  import com.liferay.portal.kernel.util.ObjectValuePair;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.xml.Document;
34  import com.liferay.portal.kernel.xml.Element;
35  import com.liferay.portal.kernel.xml.SAXReaderUtil;
36  import com.liferay.portal.lar.BasePortletDataHandler;
37  import com.liferay.portal.lar.PortletDataContext;
38  import com.liferay.portal.lar.PortletDataException;
39  import com.liferay.portal.lar.PortletDataHandlerBoolean;
40  import com.liferay.portal.lar.PortletDataHandlerControl;
41  import com.liferay.portal.lar.PortletDataHandlerKeys;
42  import com.liferay.portal.model.CompanyConstants;
43  import com.liferay.portal.model.User;
44  import com.liferay.portal.service.ServiceContext;
45  import com.liferay.portal.service.persistence.UserUtil;
46  import com.liferay.portal.util.PortletKeys;
47  import com.liferay.portlet.messageboards.NoSuchCategoryException;
48  import com.liferay.portlet.messageboards.NoSuchMessageException;
49  import com.liferay.portlet.messageboards.NoSuchThreadException;
50  import com.liferay.portlet.messageboards.model.MBBan;
51  import com.liferay.portlet.messageboards.model.MBCategory;
52  import com.liferay.portlet.messageboards.model.MBMessage;
53  import com.liferay.portlet.messageboards.model.MBMessageFlag;
54  import com.liferay.portlet.messageboards.model.MBThread;
55  import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
56  import com.liferay.portlet.messageboards.model.impl.MBMessageImpl;
57  import com.liferay.portlet.messageboards.service.MBBanLocalServiceUtil;
58  import com.liferay.portlet.messageboards.service.MBCategoryLocalServiceUtil;
59  import com.liferay.portlet.messageboards.service.MBMessageFlagLocalServiceUtil;
60  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
61  import com.liferay.portlet.messageboards.service.persistence.MBBanUtil;
62  import com.liferay.portlet.messageboards.service.persistence.MBCategoryUtil;
63  import com.liferay.portlet.messageboards.service.persistence.MBMessageFlagUtil;
64  import com.liferay.portlet.messageboards.service.persistence.MBMessageUtil;
65  import com.liferay.portlet.messageboards.service.persistence.MBThreadUtil;
66  
67  import java.util.ArrayList;
68  import java.util.Iterator;
69  import java.util.List;
70  import java.util.Map;
71  
72  import javax.portlet.PortletPreferences;
73  
74  /**
75   * <a href="MBPortletDataHandlerImpl.java.html"><b><i>View Source</i></b></a>
76   *
77   * @author Bruno Farache
78   * @author Raymond Augé
79   *
80   */
81  public class MBPortletDataHandlerImpl extends BasePortletDataHandler {
82  
83      public PortletPreferences deleteData(
84              PortletDataContext context, String portletId,
85              PortletPreferences preferences)
86          throws PortletDataException {
87  
88          try {
89              if (!context.addPrimaryKey(
90                      MBPortletDataHandlerImpl.class, "deleteData")) {
91  
92                  MBCategoryLocalServiceUtil.deleteCategories(
93                      context.getGroupId());
94              }
95  
96              return null;
97          }
98          catch (Exception e) {
99              throw new PortletDataException(e);
100         }
101     }
102 
103     public String exportData(
104             PortletDataContext context, String portletId,
105             PortletPreferences preferences)
106         throws PortletDataException {
107 
108         try {
109             Document doc = SAXReaderUtil.createDocument();
110 
111             Element root = doc.addElement("message-boards-data");
112 
113             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
114 
115             Element categoriesEl = root.addElement("categories");
116             Element messagesEl = root.addElement("messages");
117             Element messageFlagsEl = root.addElement("message-flags");
118             Element userBansEl = root.addElement("user-bans");
119 
120             List<MBCategory> categories = MBCategoryUtil.findByGroupId(
121                 context.getGroupId());
122 
123             for (MBCategory category : categories) {
124                 exportCategory(
125                     context, categoriesEl, messagesEl, messageFlagsEl,
126                     category);
127             }
128 
129             if (context.getBooleanParameter(_NAMESPACE, "user-bans")) {
130                 List<MBBan> bans = MBBanUtil.findByGroupId(
131                     context.getGroupId());
132 
133                 for (MBBan ban : bans) {
134                     exportUserBan(context, userBansEl, ban);
135                 }
136             }
137 
138             return doc.formattedString();
139         }
140         catch (Exception e) {
141             throw new PortletDataException(e);
142         }
143     }
144 
145     public PortletDataHandlerControl[] getExportControls() {
146         return new PortletDataHandlerControl[] {
147             _categoriesAndMessages, _attachments, _userBans, _flags, _ratings,
148             _tags
149         };
150     }
151 
152     public PortletDataHandlerControl[] getImportControls() {
153         return new PortletDataHandlerControl[] {
154             _categoriesAndMessages, _attachments, _userBans, _flags, _ratings,
155             _tags
156         };
157     }
158 
159     public PortletPreferences importData(
160             PortletDataContext context, String portletId,
161             PortletPreferences preferences, String data)
162         throws PortletDataException {
163 
164         try {
165             Document doc = SAXReaderUtil.read(data);
166 
167             Element root = doc.getRootElement();
168 
169             List<Element> categoryEls = root.element("categories").elements(
170                 "category");
171 
172             Map<Long, Long> categoryPKs =
173                 (Map<Long, Long>)context.getNewPrimaryKeysMap(MBCategory.class);
174 
175             for (Element categoryEl : categoryEls) {
176                 String path = categoryEl.attributeValue("path");
177 
178                 if (!context.isPathNotProcessed(path)) {
179                     continue;
180                 }
181 
182                 MBCategory category = (MBCategory)context.getZipEntryAsObject(
183                     path);
184 
185                 importCategory(context, categoryPKs, category);
186             }
187 
188             List<Element> messageEls = root.element("messages").elements(
189                 "message");
190 
191             Map<Long, Long> threadPKs =
192                 (Map<Long, Long>)context.getNewPrimaryKeysMap(MBThread.class);
193             Map<Long, Long> messagePKs =
194                 (Map<Long, Long>)context.getNewPrimaryKeysMap(MBMessage.class);
195 
196             for (Element messageEl : messageEls) {
197                 String path = messageEl.attributeValue("path");
198 
199                 if (!context.isPathNotProcessed(path)) {
200                     continue;
201                 }
202 
203                 MBMessage message = (MBMessage)context.getZipEntryAsObject(
204                     path);
205 
206                 importMessage(
207                     context, categoryPKs, threadPKs, messagePKs, messageEl,
208                     message);
209             }
210 
211             if (context.getBooleanParameter(_NAMESPACE, "flags")) {
212                 List<Element> flagEls = root.element("message-flags").elements(
213                     "flag");
214 
215                 for (Element flagEl : flagEls) {
216                     String path = flagEl.attributeValue("path");
217 
218                     if (!context.isPathNotProcessed(path)) {
219                         continue;
220                     }
221 
222                     MBMessageFlag flag =
223                         (MBMessageFlag)context.getZipEntryAsObject(path);
224 
225                     importFlag(context, messagePKs, flag);
226                 }
227             }
228 
229             if (context.getBooleanParameter(_NAMESPACE, "user-bans")) {
230                 List<Element> banEls = root.element("user-bans").elements(
231                     "user-ban");
232 
233                 for (Element banEl : banEls) {
234                     String path = banEl.attributeValue("path");
235 
236                     if (!context.isPathNotProcessed(path)) {
237                         continue;
238                     }
239 
240                     MBBan ban = (MBBan)context.getZipEntryAsObject(path);
241 
242                     importBan(context, ban);
243                 }
244             }
245 
246             return null;
247         }
248         catch (Exception e) {
249             throw new PortletDataException(e);
250         }
251     }
252 
253     protected void exportCategory(
254             PortletDataContext context, Element categoriesEl,
255             Element messagesEl, Element messageFlagsEl, MBCategory category)
256         throws PortalException, SystemException {
257 
258         if (context.isWithinDateRange(category.getModifiedDate())) {
259             exportParentCategory(
260                 context, categoriesEl, category.getParentCategoryId());
261 
262             String path = getCategoryPath(context, category);
263 
264             if (context.isPathNotProcessed(path)) {
265                 Element categoryEl = categoriesEl.addElement("category");
266 
267                 categoryEl.addAttribute("path", path);
268 
269                 category.setUserUuid(category.getUserUuid());
270 
271                 context.addZipEntry(path, category);
272             }
273         }
274 
275         List<MBMessage> messages = MBMessageUtil.findByCategoryId(
276             category.getCategoryId());
277 
278         for (MBMessage message : messages) {
279             exportMessage(
280                 context, categoriesEl, messagesEl, messageFlagsEl, message);
281         }
282     }
283 
284     protected void exportMessage(
285             PortletDataContext context, Element categoriesEl,
286             Element messagesEl, Element messageFlagsEl, MBMessage message)
287         throws PortalException, SystemException {
288 
289         if (!context.isWithinDateRange(message.getModifiedDate())) {
290             return;
291         }
292 
293         exportParentCategory(context, categoriesEl, message.getCategoryId());
294 
295         String path = getMessagePath(context, message);
296 
297         if (context.isPathNotProcessed(path)) {
298             Element messageEl = messagesEl.addElement("message");
299 
300             messageEl.addAttribute("path", path);
301 
302             message.setUserUuid(message.getUserUuid());
303             message.setPriority(message.getPriority());
304 
305             if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
306                 context.addRatingsEntries(
307                     MBMessage.class, message.getMessageId());
308             }
309 
310             if (context.getBooleanParameter(_NAMESPACE, "tags")) {
311                 context.addTagsEntries(
312                     MBMessage.class, message.getMessageId());
313             }
314 
315             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
316                 message.isAttachments()) {
317 
318                 for (String attachment : message.getAttachmentsFiles()) {
319                     int pos = attachment.lastIndexOf(StringPool.FORWARD_SLASH);
320 
321                     String name = attachment.substring(pos + 1);
322                     String binPath = getMessageAttachementBinPath(
323                         context, message, name);
324 
325                     Element attachmentEl = messageEl.addElement("attachment");
326 
327                     attachmentEl.addAttribute("name", name);
328                     attachmentEl.addAttribute("bin-path", binPath);
329 
330                     byte[] bytes = DLServiceUtil.getFile(
331                         context.getCompanyId(), CompanyConstants.SYSTEM,
332                         attachment);
333 
334                     context.addZipEntry(binPath, bytes);
335                 }
336 
337                 message.setAttachmentsDir(message.getAttachmentsDir());
338             }
339 
340             if (context.getBooleanParameter(_NAMESPACE, "flags")) {
341                 List<MBMessageFlag> messageFlags =
342                     MBMessageFlagUtil.findByMessageId(
343                         message.getMessageId());
344 
345                 for (MBMessageFlag messageFlag : messageFlags) {
346                     exportMessageFlag(context, messageFlagsEl, messageFlag);
347                 }
348             }
349 
350             context.addZipEntry(path, message);
351         }
352     }
353 
354     protected void exportMessageFlag(
355             PortletDataContext context, Element messageFlagsEl,
356             MBMessageFlag messageFlag)
357         throws SystemException {
358 
359         String path = getMessageFlagPath(context, messageFlag);
360 
361         if (!context.isPathNotProcessed(path)) {
362             return;
363         }
364 
365         Element messageFlagEl = messageFlagsEl.addElement("message-flag");
366 
367         messageFlagEl.addAttribute("path", path);
368 
369         messageFlag.setUserUuid(messageFlag.getUserUuid());
370 
371         context.addZipEntry(path, messageFlag);
372     }
373 
374     protected void exportParentCategory(
375             PortletDataContext context, Element categoriesEl, long categoryId)
376         throws PortalException, SystemException {
377 
378         if ((!context.hasDateRange()) ||
379             (categoryId == MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID)) {
380 
381             return;
382         }
383 
384         MBCategory category = MBCategoryUtil.findByPrimaryKey(categoryId);
385 
386         exportParentCategory(
387             context, categoriesEl, category.getParentCategoryId());
388 
389         String path = getCategoryPath(context, category);
390 
391         if (context.isPathNotProcessed(path)) {
392             Element categoryEl = categoriesEl.addElement("category");
393 
394             categoryEl.addAttribute("path", path);
395 
396             category.setUserUuid(category.getUserUuid());
397 
398             context.addZipEntry(path, category);
399         }
400     }
401 
402     protected void exportUserBan(
403             PortletDataContext context, Element userBansEl, MBBan ban)
404         throws SystemException {
405 
406         if (!context.isWithinDateRange(ban.getModifiedDate())) {
407             return;
408         }
409 
410         String path = getUserBanPath(context, ban);
411 
412         if (!context.isPathNotProcessed(path)) {
413             return;
414         }
415 
416         Element userBanEl = userBansEl.addElement("user-ban");
417 
418         userBanEl.addAttribute("path", path);
419 
420         ban.setBanUserUuid(ban.getBanUserUuid());
421         ban.setUserUuid(ban.getUserUuid());
422 
423         context.addZipEntry(path, ban);
424     }
425 
426     protected void importBan(PortletDataContext context, MBBan ban)
427         throws Exception {
428 
429         long userId = context.getUserId(ban.getUserUuid());
430 
431         ServiceContext serviceContext = new ServiceContext();
432 
433         serviceContext.setScopeGroupId(context.getGroupId());
434 
435         List<User> users = UserUtil.findByUuid(ban.getBanUserUuid());
436 
437         Iterator<User> itr = users.iterator();
438 
439         if (itr.hasNext()) {
440             User user = itr.next();
441 
442             MBBanLocalServiceUtil.addBan(
443                 userId, user.getUserId(), serviceContext);
444         }
445         else {
446             _log.error(
447                 "Could not find banned user with uuid " + ban.getBanUserUuid());
448         }
449     }
450 
451     protected void importCategory(
452             PortletDataContext context, Map<Long, Long> categoryPKs,
453             MBCategory category)
454         throws Exception {
455 
456         long userId = context.getUserId(category.getUserUuid());
457         long parentCategoryId = MapUtil.getLong(
458             categoryPKs, category.getParentCategoryId(),
459             category.getParentCategoryId());
460 
461         String emailAddress = null;
462         String inProtocol = null;
463         String inServerName = null;
464         int inServerPort = 0;
465         boolean inUseSSL = false;
466         String inUserName = null;
467         String inPassword = null;
468         int inReadInterval = 0;
469         String outEmailAddress = null;
470         boolean outCustom = false;
471         String outServerName = null;
472         int outServerPort = 0;
473         boolean outUseSSL = false;
474         String outUserName = null;
475         String outPassword = null;
476         boolean mailingListActive = false;
477 
478         ServiceContext serviceContext = new ServiceContext();
479 
480         serviceContext.setAddCommunityPermissions(true);
481         serviceContext.setAddGuestPermissions(true);
482         serviceContext.setScopeGroupId(context.getGroupId());
483 
484         if ((parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) &&
485             (parentCategoryId == category.getParentCategoryId())) {
486 
487             String path = getImportCategoryPath(context, parentCategoryId);
488 
489             MBCategory parentCategory =
490                 (MBCategory)context.getZipEntryAsObject(path);
491 
492             importCategory(context, categoryPKs, parentCategory);
493 
494             parentCategoryId = MapUtil.getLong(
495                 categoryPKs, category.getParentCategoryId(),
496                 category.getParentCategoryId());
497         }
498 
499         MBCategory existingCategory = null;
500 
501         try {
502             if (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
503                 MBCategoryUtil.findByPrimaryKey(parentCategoryId);
504             }
505 
506             if (context.getDataStrategy().equals(
507                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
508 
509                 existingCategory = MBCategoryUtil.fetchByUUID_G(
510                     category.getUuid(), context.getGroupId());
511 
512                 if (existingCategory == null) {
513                     existingCategory = MBCategoryLocalServiceUtil.addCategory(
514                         category.getUuid(), userId, parentCategoryId,
515                         category.getName(), category.getDescription(),
516                         emailAddress, inProtocol, inServerName, inServerPort,
517                         inUseSSL, inUserName, inPassword, inReadInterval,
518                         outEmailAddress, outCustom, outServerName,
519                         outServerPort, outUseSSL, outUserName, outPassword,
520                         mailingListActive, serviceContext);
521                 }
522                 else {
523                     existingCategory =
524                         MBCategoryLocalServiceUtil.updateCategory(
525                             existingCategory.getCategoryId(), parentCategoryId,
526                             category.getName(), category.getDescription(),
527                             emailAddress, inProtocol, inServerName,
528                             inServerPort, inUseSSL, inUserName, inPassword,
529                             inReadInterval, outEmailAddress, outCustom,
530                             outServerName, outServerPort, outUseSSL,
531                             outUserName, outPassword, mailingListActive, false);
532                 }
533             }
534             else {
535                 existingCategory = MBCategoryLocalServiceUtil.addCategory(
536                     userId, parentCategoryId, category.getName(),
537                     category.getDescription(), emailAddress, inProtocol,
538                     inServerName, inServerPort, inUseSSL, inUserName,
539                     inPassword, inReadInterval, outEmailAddress, outCustom,
540                     outServerName, outServerPort, outUseSSL, outUserName,
541                     outPassword, mailingListActive, serviceContext);
542             }
543 
544             categoryPKs.put(
545                 category.getCategoryId(), existingCategory.getCategoryId());
546         }
547         catch (NoSuchCategoryException nsce) {
548             _log.error(
549                 "Could not find the parent category for category " +
550                     category.getCategoryId());
551         }
552     }
553 
554     protected void importFlag(
555             PortletDataContext context, Map<Long, Long> messagePKs,
556             MBMessageFlag flag)
557         throws Exception {
558 
559         long userId = context.getUserId(flag.getUserUuid());
560         long messageId = MapUtil.getLong(
561             messagePKs, flag.getMessageId(), flag.getMessageId());
562 
563         try {
564             MBMessage message = MBMessageUtil.findByPrimaryKey(messageId);
565 
566             MBThread thread = message.getThread();
567 
568             MBMessageFlagLocalServiceUtil.addReadFlags(userId, thread);
569         }
570         catch (NoSuchMessageException nsme) {
571             _log.error(
572                 "Could not find the message for flag " +
573                     flag.getMessageFlagId());
574         }
575     }
576 
577     protected void importMessage(
578             PortletDataContext context, Map<Long, Long> categoryPKs,
579             Map<Long, Long> threadPKs, Map<Long, Long> messagePKs,
580             Element messageEl, MBMessage message)
581         throws Exception {
582 
583         long userId = context.getUserId(message.getUserUuid());
584         String userName = message.getUserName();
585         long categoryId = MapUtil.getLong(
586             categoryPKs, message.getCategoryId(), message.getCategoryId());
587         long threadId = MapUtil.getLong(
588             threadPKs, message.getThreadId(), message.getThreadId());
589         long parentMessageId = MapUtil.getLong(
590             messagePKs, message.getParentMessageId(),
591             message.getParentMessageId());
592 
593         List<ObjectValuePair<String, byte[]>> files =
594             new ArrayList<ObjectValuePair<String, byte[]>>();
595         List<String> existingFiles = new ArrayList<String>();
596 
597         if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
598             message.isAttachments()) {
599 
600             List<Element> attachmentEls = messageEl.elements("attachment");
601 
602             for (Element attachmentEl : attachmentEls) {
603                 String name = attachmentEl.attributeValue("name");
604                 String binPath = attachmentEl.attributeValue("bin-path");
605 
606                 byte[] bytes = context.getZipEntryAsByteArray(binPath);
607 
608                 files.add(new ObjectValuePair<String, byte[]>(name, bytes));
609             }
610 
611             if (files.size() <= 0) {
612                 _log.error(
613                     "Could not find attachments for message " +
614                         message.getMessageId());
615             }
616         }
617 
618         String[] tagsEntries = null;
619 
620         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
621             tagsEntries = context.getTagsEntries(
622                 MBMessage.class, message.getMessageId());
623         }
624 
625         ServiceContext serviceContext = new ServiceContext();
626 
627         serviceContext.setAddCommunityPermissions(true);
628         serviceContext.setAddGuestPermissions(true);
629         serviceContext.setScopeGroupId(context.getGroupId());
630         serviceContext.setTagsEntries(tagsEntries);
631 
632         if ((categoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) &&
633             (categoryId == message.getCategoryId())) {
634 
635             String path = getImportCategoryPath(context, categoryId);
636 
637             MBCategory category = (MBCategory)context.getZipEntryAsObject(path);
638 
639             importCategory(context, categoryPKs, category);
640 
641             categoryId = MapUtil.getLong(
642                 categoryPKs, message.getCategoryId(), message.getCategoryId());
643         }
644 
645         MBMessage existingMessage = null;
646 
647         try {
648             MBCategoryUtil.findByPrimaryKey(categoryId);
649 
650             if (parentMessageId != MBMessageImpl.DEFAULT_PARENT_MESSAGE_ID) {
651                 MBMessageUtil.findByPrimaryKey(parentMessageId);
652                 MBThreadUtil.findByPrimaryKey(threadId);
653             }
654 
655             if (context.getDataStrategy().equals(
656                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
657 
658                 try {
659                     existingMessage = MBMessageUtil.findByUUID_G(
660                         message.getUuid(), context.getGroupId());
661 
662                     MBMessageLocalServiceUtil.updateMessage(
663                         userId, existingMessage.getMessageId(),
664                         message.getSubject(), message.getBody(), files,
665                         existingFiles, message.getPriority(), serviceContext);
666                 }
667                 catch (NoSuchMessageException nsme) {
668                     existingMessage = MBMessageLocalServiceUtil.addMessage(
669                         message.getUuid(), userId, userName, categoryId,
670                         threadId, parentMessageId, message.getSubject(),
671                         message.getBody(), files, message.getAnonymous(),
672                         message.getPriority(), serviceContext);
673                 }
674             }
675             else {
676                 existingMessage = MBMessageLocalServiceUtil.addMessage(
677                     userId, userName, categoryId, threadId, parentMessageId,
678                     message.getSubject(), message.getBody(), files,
679                     message.getAnonymous(), message.getPriority(),
680                     serviceContext);
681             }
682 
683             threadPKs.put(message.getThreadId(), existingMessage.getThreadId());
684             messagePKs.put(
685                 message.getMessageId(), existingMessage.getMessageId());
686 
687             if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
688                 context.importRatingsEntries(
689                     MBMessage.class, message.getMessageId(),
690                     existingMessage.getMessageId());
691             }
692         }
693         catch (NoSuchCategoryException nsce) {
694             _log.error(
695                 "Could not find the parent category for message " +
696                     message.getMessageId());
697         }
698         catch (NoSuchMessageException nsme) {
699             _log.error(
700                 "Could not find the parent message for message " +
701                     message.getMessageId());
702         }
703         catch (NoSuchThreadException nste) {
704             _log.error(
705                 "Could not find the thread for message " +
706                     message.getMessageId());
707         }
708     }
709 
710     protected String getCategoryPath(
711         PortletDataContext context, MBCategory category) {
712 
713         StringBuilder sb = new StringBuilder();
714 
715         sb.append(context.getPortletPath(PortletKeys.MESSAGE_BOARDS));
716         sb.append("/categories/");
717         sb.append(category.getCategoryId());
718         sb.append(".xml");
719 
720         return sb.toString();
721     }
722 
723     protected String getImportCategoryPath(
724         PortletDataContext context, long categoryId) {
725 
726         StringBuilder sb = new StringBuilder();
727 
728         sb.append(context.getSourcePortletPath(PortletKeys.MESSAGE_BOARDS));
729         sb.append("/categories/");
730         sb.append(categoryId);
731         sb.append(".xml");
732 
733         return sb.toString();
734     }
735 
736     protected String getMessageAttachementBinPath(
737         PortletDataContext context, MBMessage message, String attachment) {
738 
739         StringBuilder sb = new StringBuilder();
740 
741         sb.append(context.getPortletPath(PortletKeys.MESSAGE_BOARDS));
742         sb.append("/bin/");
743         sb.append(message.getMessageId());
744         sb.append(StringPool.SLASH);
745         sb.append(attachment);
746 
747         return sb.toString();
748     }
749 
750     protected String getMessageFlagPath(
751         PortletDataContext context, MBMessageFlag messageFlag) {
752 
753         StringBuilder sb = new StringBuilder();
754 
755         sb.append(context.getPortletPath(PortletKeys.MESSAGE_BOARDS));
756         sb.append("/message-flags/");
757         sb.append(messageFlag.getMessageFlagId());
758         sb.append(".xml");
759 
760         return sb.toString();
761     }
762 
763     protected String getMessagePath(
764         PortletDataContext context, MBMessage message) {
765 
766         StringBuilder sb = new StringBuilder();
767 
768         sb.append(context.getPortletPath(PortletKeys.MESSAGE_BOARDS));
769         sb.append("/messages/");
770         sb.append(message.getMessageId());
771         sb.append(".xml");
772 
773         return sb.toString();
774     }
775 
776     protected String getUserBanPath(PortletDataContext context, MBBan ban) {
777         StringBuilder sb = new StringBuilder();
778 
779         sb.append(context.getPortletPath(PortletKeys.MESSAGE_BOARDS));
780         sb.append("/user-bans/");
781         sb.append(ban.getBanId());
782         sb.append(".xml");
783 
784         return sb.toString();
785     }
786 
787     private static final String _NAMESPACE = "message_board";
788 
789     private static final PortletDataHandlerBoolean _categoriesAndMessages =
790         new PortletDataHandlerBoolean(
791             _NAMESPACE, "categories-and-messages", true, true);
792 
793     private static final PortletDataHandlerBoolean _attachments =
794         new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
795 
796     private static final PortletDataHandlerBoolean _userBans =
797         new PortletDataHandlerBoolean(_NAMESPACE, "user-bans");
798 
799     private static final PortletDataHandlerBoolean _flags =
800         new PortletDataHandlerBoolean(_NAMESPACE, "flags");
801 
802     private static final PortletDataHandlerBoolean _ratings =
803         new PortletDataHandlerBoolean(_NAMESPACE, "ratings");
804 
805     private static final PortletDataHandlerBoolean _tags =
806         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
807 
808     private static Log _log =
809         LogFactoryUtil.getLog(MBPortletDataHandlerImpl.class);
810 
811 }