001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.messageboards.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.increment.BufferedIncrement;
020    import com.liferay.portal.kernel.increment.NumberIncrement;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.search.Indexer;
024    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
025    import com.liferay.portal.kernel.util.CharPool;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.kernel.workflow.WorkflowConstants;
031    import com.liferay.portal.model.CompanyConstants;
032    import com.liferay.portal.model.ResourceConstants;
033    import com.liferay.portal.service.ServiceContext;
034    import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
035    import com.liferay.portlet.documentlibrary.NoSuchDirectoryException;
036    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
037    import com.liferay.portlet.messageboards.SplitThreadException;
038    import com.liferay.portlet.messageboards.model.MBCategory;
039    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
040    import com.liferay.portlet.messageboards.model.MBMessage;
041    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
042    import com.liferay.portlet.messageboards.model.MBThread;
043    import com.liferay.portlet.messageboards.model.MBThreadConstants;
044    import com.liferay.portlet.messageboards.model.MBTreeWalker;
045    import com.liferay.portlet.messageboards.service.base.MBThreadLocalServiceBaseImpl;
046    import com.liferay.portlet.messageboards.util.MBUtil;
047    
048    import java.io.File;
049    import java.io.IOException;
050    import java.io.InputStream;
051    
052    import java.util.ArrayList;
053    import java.util.List;
054    
055    /**
056     * @author Brian Wing Shun Chan
057     * @author Shuyang Zhou
058     */
059    public class MBThreadLocalServiceImpl extends MBThreadLocalServiceBaseImpl {
060    
061            @Override
062            public MBThread addThread(long categoryId, MBMessage message)
063                    throws PortalException, SystemException {
064    
065                    // Thread
066    
067                    long threadId = message.getThreadId();
068    
069                    if (!message.isRoot() || (threadId <= 0)) {
070                            threadId = counterLocalService.increment();
071                    }
072    
073                    MBThread thread = mbThreadPersistence.create(threadId);
074    
075                    thread.setGroupId(message.getGroupId());
076                    thread.setCompanyId(message.getCompanyId());
077                    thread.setCategoryId(categoryId);
078                    thread.setRootMessageId(message.getMessageId());
079                    thread.setRootMessageUserId(message.getUserId());
080    
081                    if (message.isAnonymous()) {
082                            thread.setLastPostByUserId(0);
083                    }
084                    else {
085                            thread.setLastPostByUserId(message.getUserId());
086                    }
087    
088                    thread.setLastPostDate(message.getCreateDate());
089    
090                    if (message.getPriority() != MBThreadConstants.PRIORITY_NOT_GIVEN) {
091                            thread.setPriority(message.getPriority());
092                    }
093    
094                    thread.setStatus(message.getStatus());
095                    thread.setStatusByUserId(message.getStatusByUserId());
096                    thread.setStatusByUserName(message.getStatusByUserName());
097                    thread.setStatusDate(message.getStatusDate());
098    
099                    mbThreadPersistence.update(thread, false);
100    
101                    // Asset
102    
103                    if (categoryId >= 0) {
104                            assetEntryLocalService.updateEntry(
105                                    message.getUserId(), message.getGroupId(),
106                                    thread.getStatusDate(), thread.getLastPostDate(),
107                                    MBThread.class.getName(), thread.getThreadId(), null, 0,
108                                    new long[0], new String[0], false, null, null, null, null, null,
109                                    String.valueOf(thread.getRootMessageId()), null, null, null,
110                                    null, 0, 0, null, false);
111                    }
112    
113                    return thread;
114            }
115    
116            @Override
117            public void deleteThread(long threadId)
118                    throws PortalException, SystemException {
119    
120                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
121    
122                    deleteThread(thread);
123            }
124    
125            @Override
126            public void deleteThread(MBThread thread)
127                    throws PortalException, SystemException {
128    
129                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
130                            thread.getRootMessageId());
131    
132                    // Indexer
133    
134                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
135                            MBMessage.class);
136    
137                    indexer.delete(thread);
138    
139                    // Attachments
140    
141                    long companyId = rootMessage.getCompanyId();
142                    long repositoryId = CompanyConstants.SYSTEM;
143                    String dirName = thread.getAttachmentsDir();
144    
145                    try {
146                            DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
147                    }
148                    catch (NoSuchDirectoryException nsde) {
149                    }
150    
151                    // Subscriptions
152    
153                    subscriptionLocalService.deleteSubscriptions(
154                            thread.getCompanyId(), MBThread.class.getName(),
155                            thread.getThreadId());
156    
157                    // Thread flags
158    
159                    mbThreadFlagPersistence.removeByThreadId(thread.getThreadId());
160    
161                    // Messages
162    
163                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
164                            thread.getThreadId());
165    
166                    for (MBMessage message : messages) {
167    
168                            // Ratings
169    
170                            ratingsStatsLocalService.deleteStats(
171                                    message.getWorkflowClassName(), message.getMessageId());
172    
173                            // Asset
174    
175                            assetEntryLocalService.deleteEntry(
176                                    message.getWorkflowClassName(), message.getMessageId());
177    
178                            // Resources
179    
180                            if (!message.isDiscussion()) {
181                                    resourceLocalService.deleteResource(
182                                            message.getCompanyId(), message.getWorkflowClassName(),
183                                            ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
184                            }
185    
186                            // Message
187    
188                            mbMessagePersistence.remove(message);
189    
190                            // Statistics
191    
192                            if (!message.isDiscussion()) {
193                                    mbStatsUserLocalService.updateStatsUser(
194                                            message.getGroupId(), message.getUserId());
195                            }
196    
197                            // Workflow
198    
199                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
200                                    message.getCompanyId(), message.getGroupId(),
201                                    message.getWorkflowClassName(), message.getMessageId());
202                    }
203    
204                    // Category
205    
206                    if ((rootMessage.getCategoryId() !=
207                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
208                            (rootMessage.getCategoryId() !=
209                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
210    
211                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
212                                    thread.getCategoryId());
213    
214                            MBUtil.updateCategoryStatistics(
215                                    category.getCompanyId(), category.getCategoryId());
216                    }
217    
218                    // Thread Asset
219    
220                    assetEntryLocalService.deleteEntry(
221                            MBThread.class.getName(), thread.getThreadId());
222    
223                    // Thread
224    
225                    mbThreadPersistence.remove(thread);
226            }
227    
228            @Override
229            public void deleteThreads(long groupId, long categoryId)
230                    throws PortalException, SystemException {
231    
232                    List<MBThread> threads = mbThreadPersistence.findByG_C(
233                            groupId, categoryId);
234    
235                    for (MBThread thread : threads) {
236                            deleteThread(thread);
237                    }
238            }
239    
240            @Override
241            public MBThread fetchThread(long threadId) throws SystemException {
242                    return mbThreadPersistence.fetchByPrimaryKey(threadId);
243            }
244    
245            @Override
246            public int getCategoryThreadsCount(
247                            long groupId, long categoryId, int status)
248                    throws SystemException {
249    
250                    if (status == WorkflowConstants.STATUS_ANY) {
251                            return mbThreadPersistence.countByG_C(groupId, categoryId);
252                    }
253                    else {
254                            return mbThreadPersistence.countByG_C_S(
255                                    groupId, categoryId, status);
256                    }
257            }
258    
259            @Override
260            public List<MBThread> getGroupThreads(
261                            long groupId, int status, int start, int end)
262                    throws SystemException {
263    
264                    if (status == WorkflowConstants.STATUS_ANY) {
265                            return mbThreadPersistence.findByG_NotC(
266                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, start,
267                                    end);
268                    }
269                    else {
270                            return mbThreadPersistence.findByG_NotC_S(
271                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, status,
272                                    start, end);
273                    }
274            }
275    
276            @Override
277            public List<MBThread> getGroupThreads(
278                            long groupId, long userId, int status, boolean subscribed,
279                            boolean includeAnonymous, int start, int end)
280                    throws PortalException, SystemException {
281    
282                    if (userId <= 0) {
283                            if (status == WorkflowConstants.STATUS_ANY) {
284                                    return mbThreadPersistence.findByG_NotC(
285                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, start,
286                                            end);
287                            }
288                            else {
289                                    return mbThreadPersistence.findByG_NotC_S(
290                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, status,
291                                            start, end);
292                            }
293                    }
294                    else {
295                            if (subscribed) {
296                                    return mbThreadFinder.findByS_G_U_C_S(
297                                            groupId, userId, null, status, start, end);
298                            }
299                            else {
300                                    List<Long> threadIds = null;
301    
302                                    if (includeAnonymous) {
303                                            threadIds = mbMessageFinder.findByG_U_C_S(
304                                                    groupId, userId, null, status, start, end);
305                                    }
306                                    else {
307                                            threadIds = mbMessageFinder.findByG_U_C_A_S(
308                                                    groupId, userId, null, false, status, start, end);
309                                    }
310    
311                                    List<MBThread> threads = new ArrayList<MBThread>(
312                                            threadIds.size());
313    
314                                    for (long threadId : threadIds) {
315                                            MBThread thread = mbThreadPersistence.findByPrimaryKey(
316                                                    threadId);
317    
318                                            threads.add(thread);
319                                    }
320    
321                                    return threads;
322                            }
323                    }
324            }
325    
326            @Override
327            public List<MBThread> getGroupThreads(
328                            long groupId, long userId, int status, boolean subscribed,
329                            int start, int end)
330                    throws PortalException, SystemException {
331    
332                    return getGroupThreads(
333                            groupId, userId, status, subscribed, true, start, end);
334            }
335    
336            @Override
337            public List<MBThread> getGroupThreads(
338                            long groupId, long userId, int status, int start, int end)
339                    throws PortalException, SystemException {
340    
341                    return getGroupThreads(groupId, userId, status, false, start, end);
342            }
343    
344            @Override
345            public int getGroupThreadsCount(long groupId, int status)
346                    throws SystemException {
347    
348                    if (status == WorkflowConstants.STATUS_ANY) {
349                            return mbThreadPersistence.countByG_NotC(
350                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID);
351                    }
352                    else {
353                            return mbThreadPersistence.countByG_NotC_S(
354                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, status);
355                    }
356            }
357    
358            @Override
359            public int getGroupThreadsCount(long groupId, long userId, int status)
360                    throws SystemException {
361    
362                    return getGroupThreadsCount(groupId, userId, status, false);
363            }
364    
365            @Override
366            public int getGroupThreadsCount(
367                            long groupId, long userId, int status, boolean subscribed)
368                    throws SystemException {
369    
370                    return getGroupThreadsCount(groupId, userId, status, subscribed, true);
371            }
372    
373            @Override
374            public int getGroupThreadsCount(
375                            long groupId, long userId, int status, boolean subscribed,
376                            boolean includeAnonymous)
377                    throws SystemException {
378    
379                    if (userId <= 0) {
380                            if (status == WorkflowConstants.STATUS_ANY) {
381                                    return mbThreadPersistence.countByG_NotC(
382                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID);
383                            }
384                            else {
385                                    return mbThreadPersistence.countByG_NotC_S(
386                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
387                                            status);
388                            }
389                    }
390                    else {
391                            if (subscribed) {
392                                    return mbThreadFinder.countByS_G_U_C_S(
393                                            groupId, userId, null, status);
394                            }
395                            else {
396                                    if (includeAnonymous) {
397                                            return mbMessageFinder.countByG_U_C_S(
398                                                    groupId, userId, null, status);
399                                    }
400                                    else {
401                                            return mbMessageFinder.countByG_U_C_A_S(
402                                                    groupId, userId, null, false, status);
403                                    }
404                            }
405                    }
406            }
407    
408            @Override
409            public List<MBThread> getNoAssetThreads() throws SystemException {
410                    return mbThreadFinder.findByNoAssets();
411            }
412    
413            @Override
414            public List<MBThread> getPriorityThreads(long categoryId, double priority)
415                    throws PortalException, SystemException {
416    
417                    return getPriorityThreads(categoryId, priority, false);
418            }
419    
420            @Override
421            public List<MBThread> getPriorityThreads(
422                            long categoryId, double priority, boolean inherit)
423                    throws PortalException, SystemException {
424    
425                    if (!inherit) {
426                            return mbThreadPersistence.findByC_P(categoryId, priority);
427                    }
428    
429                    List<MBThread> threads = new ArrayList<MBThread>();
430    
431                    while ((categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
432                               (categoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
433    
434                            threads.addAll(
435                                    0, mbThreadPersistence.findByC_P(categoryId, priority));
436    
437                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
438                                    categoryId);
439    
440                            categoryId = category.getParentCategoryId();
441                    }
442    
443                    return threads;
444            }
445    
446            @Override
447            public MBThread getThread(long threadId)
448                    throws PortalException, SystemException {
449    
450                    return mbThreadPersistence.findByPrimaryKey(threadId);
451            }
452    
453            @Override
454            public List<MBThread> getThreads(
455                            long groupId, long categoryId, int status, int start, int end)
456                    throws SystemException {
457    
458                    if (status == WorkflowConstants.STATUS_ANY) {
459                            return mbThreadPersistence.findByG_C(
460                                    groupId, categoryId, start, end);
461                    }
462                    else {
463                            return mbThreadPersistence.findByG_C_S(
464                                    groupId, categoryId, status, start, end);
465                    }
466            }
467    
468            @Override
469            public int getThreadsCount(long groupId, long categoryId, int status)
470                    throws SystemException {
471    
472                    if (status == WorkflowConstants.STATUS_ANY) {
473                            return mbThreadPersistence.countByG_C(groupId, categoryId);
474                    }
475                    else {
476                            return mbThreadPersistence.countByG_C_S(
477                                    groupId, categoryId, status);
478                    }
479            }
480    
481            @Override
482            public boolean hasAnswerMessage(long threadId) throws SystemException {
483                    int count = mbMessagePersistence.countByT_A(threadId, true);
484    
485                    if (count > 0) {
486                            return true;
487                    }
488                    else {
489                            return false;
490                    }
491            }
492    
493            @BufferedIncrement(incrementClass = NumberIncrement.class)
494            @Override
495            public MBThread incrementViewCounter(long threadId, int increment)
496                    throws PortalException, SystemException {
497    
498                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
499    
500                    thread.setViewCount(thread.getViewCount() + increment);
501    
502                    mbThreadPersistence.update(thread, false);
503    
504                    return thread;
505            }
506    
507            @Override
508            public MBThread moveThread(long groupId, long categoryId, long threadId)
509                    throws PortalException, SystemException {
510    
511                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
512    
513                    long oldCategoryId = thread.getCategoryId();
514    
515                    MBCategory oldCategory = null;
516    
517                    if (oldCategoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
518                            oldCategory = mbCategoryPersistence.findByPrimaryKey(oldCategoryId);
519                    }
520    
521                    MBCategory category = null;
522    
523                    if (categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
524                            category = mbCategoryPersistence.findByPrimaryKey(categoryId);
525                    }
526    
527                    // Messages
528    
529                    List<MBMessage> messages = mbMessagePersistence.findByG_C_T(
530                            groupId, oldCategoryId, thread.getThreadId());
531    
532                    for (MBMessage message : messages) {
533                            message.setCategoryId(categoryId);
534    
535                            mbMessagePersistence.update(message, false);
536    
537                            // Indexer
538    
539                            if (!message.isDiscussion()) {
540                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
541                                            MBMessage.class);
542    
543                                    indexer.reindex(message);
544                            }
545                    }
546    
547                    // Thread
548    
549                    thread.setCategoryId(categoryId);
550    
551                    mbThreadPersistence.update(thread, false);
552    
553                    // Category
554    
555                    if ((oldCategory != null) && (categoryId != oldCategoryId)) {
556                            MBUtil.updateCategoryStatistics(
557                                    oldCategory.getCompanyId(), oldCategory.getCategoryId());
558                    }
559    
560                    if ((category != null) && (categoryId != oldCategoryId)) {
561                            MBUtil.updateCategoryStatistics(
562                                    category.getCompanyId(), category.getCategoryId());
563                    }
564    
565                    return thread;
566            }
567    
568            @Override
569            public MBThread splitThread(
570                            long messageId, String subject, ServiceContext serviceContext)
571                    throws PortalException, SystemException {
572    
573                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
574    
575                    if (message.isRoot()) {
576                            throw new SplitThreadException();
577                    }
578    
579                    MBCategory category = message.getCategory();
580                    MBThread oldThread = message.getThread();
581                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
582                            oldThread.getRootMessageId());
583                    String oldAttachmentsDir = message.getAttachmentsDir();
584    
585                    // Message flags
586    
587                    mbMessageLocalService.updateAnswer(message, false, true);
588    
589                    // Create new thread
590    
591                    MBThread thread = addThread(message.getCategoryId(), message);
592    
593                    // Update messages
594    
595                    if (Validator.isNotNull(subject)) {
596                            MBMessageDisplay messageDisplay =
597                                    mbMessageService.getMessageDisplay(
598                                            messageId, WorkflowConstants.STATUS_ANY,
599                                            MBThreadConstants.THREAD_VIEW_TREE, false);
600    
601                            MBTreeWalker treeWalker = messageDisplay.getTreeWalker();
602    
603                            List<MBMessage> messages = treeWalker.getMessages();
604    
605                            int[] range = treeWalker.getChildrenRange(message);
606    
607                            for (int i = range[0]; i < range[1]; i++) {
608                                    MBMessage curMessage = messages.get(i);
609    
610                                    String oldSubject = message.getSubject();
611                                    String curSubject = curMessage.getSubject();
612    
613                                    if (oldSubject.startsWith("RE: ")) {
614                                            curSubject = StringUtil.replace(
615                                                    curSubject, rootMessage.getSubject(), subject);
616                                    }
617                                    else {
618                                            curSubject = StringUtil.replace(
619                                                    curSubject, oldSubject, subject);
620                                    }
621    
622                                    curMessage.setSubject(curSubject);
623    
624                                    mbMessagePersistence.update(curMessage, false);
625                            }
626    
627                            message.setSubject(subject);
628                    }
629    
630                    message.setThreadId(thread.getThreadId());
631                    message.setRootMessageId(thread.getRootMessageId());
632                    message.setParentMessageId(0);
633                    message.setAttachmentsDir(null);
634    
635                    mbMessagePersistence.update(message, false);
636    
637                    // Attachments
638    
639                    moveAttachmentsFromOldThread(message, oldAttachmentsDir);
640    
641                    // Indexer
642    
643                    if (!message.isDiscussion()) {
644                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
645                                    MBMessage.class);
646    
647                            indexer.reindex(message);
648                    }
649    
650                    // Update children
651    
652                    moveChildrenMessages(message, category, oldThread.getThreadId());
653    
654                    // Update new thread
655    
656                    MBUtil.updateThreadMessageCount(
657                            thread.getCompanyId(), thread.getThreadId());
658    
659                    // Update old thread
660    
661                    MBUtil.updateThreadMessageCount(
662                            oldThread.getCompanyId(), oldThread.getThreadId());
663    
664                    // Category
665    
666                    if ((message.getCategoryId() !=
667                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
668                            (message.getCategoryId() !=
669                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
670    
671                            MBUtil.updateCategoryThreadCount(
672                                    category.getCompanyId(), category.getCategoryId());
673                    }
674    
675                    return thread;
676            }
677    
678            @Override
679            public void updateQuestion(long threadId, boolean question)
680                    throws PortalException, SystemException {
681    
682                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
683    
684                    if (thread.isQuestion() == question) {
685                            return;
686                    }
687    
688                    thread.setQuestion(question);
689    
690                    mbThreadPersistence.update(thread, false);
691    
692                    if (!question) {
693                            MBMessage message = mbMessagePersistence.findByPrimaryKey(
694                                    thread.getRootMessageId());
695    
696                            mbMessageLocalService.updateAnswer(message, false, true);
697                    }
698            }
699    
700            /**
701             * @deprecated {@link #incrementViewCounter(long, int)}
702             */
703            @Override
704            public MBThread updateThread(long threadId, int viewCount)
705                    throws PortalException, SystemException {
706    
707                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
708    
709                    thread.setViewCount(viewCount);
710    
711                    mbThreadPersistence.update(thread, false);
712    
713                    return thread;
714            }
715    
716            protected void moveAttachmentFromOldThread(
717                            long companyId, String fileName, String newAttachmentsDir)
718                    throws PortalException, SystemException {
719    
720                    long repositoryId = CompanyConstants.SYSTEM;
721    
722                    StringBundler sb = new StringBundler(4);
723    
724                    sb.append(newAttachmentsDir);
725                    sb.append(StringPool.SLASH);
726                    sb.append(StringUtil.extractLast(fileName, CharPool.SLASH));
727    
728                    String newFileName = sb.toString();
729    
730                    try {
731                            File file = DLStoreUtil.getFile(companyId, repositoryId, fileName);
732    
733                            DLStoreUtil.addFile(
734                                    companyId, repositoryId, newFileName, false, file);
735                    }
736                    catch (UnsupportedOperationException uoe) {
737                            InputStream is = DLStoreUtil.getFileAsStream(
738                                    companyId, repositoryId, fileName);
739    
740                            try {
741                                    DLStoreUtil.addFile(
742                                            companyId, repositoryId, newFileName, false, is);
743                            }
744                            finally {
745                                    try {
746                                            is.close();
747                                    }
748                                    catch (IOException ioe) {
749                                            _log.error(ioe);
750                                    }
751                            }
752                    }
753    
754                    DLStoreUtil.deleteFile(companyId, repositoryId, fileName);
755            }
756    
757            protected void moveAttachmentsFromOldThread(
758                            MBMessage message, String oldAttachmentsDir)
759                    throws PortalException, SystemException {
760    
761                    if (!message.getAttachments()) {
762                            return;
763                    }
764    
765                    long companyId = message.getCompanyId();
766                    long repositoryId = CompanyConstants.SYSTEM;
767                    String newAttachmentsDir = message.getAttachmentsDir();
768    
769                    try {
770                            DLStoreUtil.addDirectory(
771                                    companyId, repositoryId, newAttachmentsDir);
772                    }
773                    catch (DuplicateDirectoryException dde) {
774                    }
775    
776                    String[] fileNames = DLStoreUtil.getFileNames(
777                            companyId, repositoryId, oldAttachmentsDir);
778    
779                    for (String fileName : fileNames) {
780                            moveAttachmentFromOldThread(companyId, fileName, newAttachmentsDir);
781                    }
782    
783                    try {
784                            DLStoreUtil.deleteDirectory(
785                                    companyId, repositoryId, oldAttachmentsDir);
786                    }
787                    catch (NoSuchDirectoryException nsde) {
788                    }
789            }
790    
791            protected void moveChildrenMessages(
792                            MBMessage parentMessage, MBCategory category, long oldThreadId)
793                    throws PortalException, SystemException {
794    
795                    List<MBMessage> messages = mbMessagePersistence.findByT_P(
796                            oldThreadId, parentMessage.getMessageId());
797    
798                    for (MBMessage message : messages) {
799                            String oldAttachmentsDir = message.getAttachmentsDir();
800    
801                            message.setCategoryId(parentMessage.getCategoryId());
802                            message.setThreadId(parentMessage.getThreadId());
803                            message.setRootMessageId(parentMessage.getRootMessageId());
804                            message.setAttachmentsDir(null);
805    
806                            mbMessagePersistence.update(message, false);
807    
808                            moveAttachmentsFromOldThread(message, oldAttachmentsDir);
809    
810                            if (!message.isDiscussion()) {
811                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
812                                            MBMessage.class);
813    
814                                    indexer.reindex(message);
815                            }
816    
817                            moveChildrenMessages(message, category, oldThreadId);
818                    }
819            }
820    
821            private static Log _log = LogFactoryUtil.getLog(
822                    MBThreadLocalServiceImpl.class);
823    
824    }