001    /**
002     * Copyright (c) 2000-2012 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.model.User;
034    import com.liferay.portal.model.WorkflowInstanceLink;
035    import com.liferay.portal.service.ServiceContext;
036    import com.liferay.portlet.documentlibrary.DuplicateDirectoryException;
037    import com.liferay.portlet.documentlibrary.NoSuchDirectoryException;
038    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
039    import com.liferay.portlet.messageboards.SplitThreadException;
040    import com.liferay.portlet.messageboards.model.MBCategory;
041    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
042    import com.liferay.portlet.messageboards.model.MBMessage;
043    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
044    import com.liferay.portlet.messageboards.model.MBThread;
045    import com.liferay.portlet.messageboards.model.MBThreadConstants;
046    import com.liferay.portlet.messageboards.model.MBTreeWalker;
047    import com.liferay.portlet.messageboards.service.base.MBThreadLocalServiceBaseImpl;
048    import com.liferay.portlet.social.model.SocialActivityConstants;
049    import com.liferay.portlet.trash.model.TrashEntry;
050    
051    import java.io.File;
052    import java.io.IOException;
053    import java.io.InputStream;
054    
055    import java.util.ArrayList;
056    import java.util.Date;
057    import java.util.List;
058    
059    /**
060     * @author Brian Wing Shun Chan
061     * @author Shuyang Zhou
062     */
063    public class MBThreadLocalServiceImpl extends MBThreadLocalServiceBaseImpl {
064    
065            public MBThread addThread(long categoryId, MBMessage message)
066                    throws PortalException, SystemException {
067    
068                    // Thread
069    
070                    long threadId = message.getThreadId();
071    
072                    if (!message.isRoot() || (threadId <= 0)) {
073                            threadId = counterLocalService.increment();
074                    }
075    
076                    MBThread thread = mbThreadPersistence.create(threadId);
077    
078                    thread.setGroupId(message.getGroupId());
079                    thread.setCompanyId(message.getCompanyId());
080                    thread.setCategoryId(categoryId);
081                    thread.setRootMessageId(message.getMessageId());
082                    thread.setRootMessageUserId(message.getUserId());
083    
084                    if (message.isAnonymous()) {
085                            thread.setLastPostByUserId(0);
086                    }
087                    else {
088                            thread.setLastPostByUserId(message.getUserId());
089                    }
090    
091                    thread.setLastPostDate(message.getCreateDate());
092    
093                    if (message.getPriority() != MBThreadConstants.PRIORITY_NOT_GIVEN) {
094                            thread.setPriority(message.getPriority());
095                    }
096    
097                    thread.setStatus(message.getStatus());
098                    thread.setStatusByUserId(message.getStatusByUserId());
099                    thread.setStatusByUserName(message.getStatusByUserName());
100                    thread.setStatusDate(message.getStatusDate());
101    
102                    mbThreadPersistence.update(thread);
103    
104                    // Asset
105    
106                    if (categoryId >= 0) {
107                            assetEntryLocalService.updateEntry(
108                                    message.getUserId(), message.getGroupId(),
109                                    thread.getStatusDate(), thread.getLastPostDate(),
110                                    MBThread.class.getName(), thread.getThreadId(), null, 0,
111                                    new long[0], new String[0], false, null, null, null, null,
112                                    String.valueOf(thread.getRootMessageId()), null, null, null,
113                                    null, 0, 0, null, false);
114                    }
115    
116                    return thread;
117            }
118    
119            public void deleteThread(long threadId)
120                    throws PortalException, SystemException {
121    
122                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
123    
124                    deleteThread(thread);
125            }
126    
127            public void deleteThread(MBThread thread)
128                    throws PortalException, SystemException {
129    
130                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
131                            thread.getRootMessageId());
132    
133                    // Indexer
134    
135                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
136                            MBMessage.class);
137    
138                    indexer.delete(thread);
139    
140                    // Attachments
141    
142                    long companyId = rootMessage.getCompanyId();
143                    long repositoryId = CompanyConstants.SYSTEM;
144                    String dirName = thread.getAttachmentsDir();
145    
146                    try {
147                            DLStoreUtil.deleteDirectory(companyId, repositoryId, dirName);
148                    }
149                    catch (NoSuchDirectoryException nsde) {
150                    }
151    
152                    // Subscriptions
153    
154                    subscriptionLocalService.deleteSubscriptions(
155                            thread.getCompanyId(), MBThread.class.getName(),
156                            thread.getThreadId());
157    
158                    // Thread flags
159    
160                    mbThreadFlagPersistence.removeByThreadId(thread.getThreadId());
161    
162                    // Messages
163    
164                    List<MBMessage> messages = mbMessagePersistence.findByThreadId(
165                            thread.getThreadId());
166    
167                    for (MBMessage message : messages) {
168    
169                            // Ratings
170    
171                            ratingsStatsLocalService.deleteStats(
172                                    message.getWorkflowClassName(), message.getMessageId());
173    
174                            // Asset
175    
176                            assetEntryLocalService.deleteEntry(
177                                    message.getWorkflowClassName(), message.getMessageId());
178    
179                            // Resources
180    
181                            if (!message.isDiscussion()) {
182                                    resourceLocalService.deleteResource(
183                                            message.getCompanyId(), message.getWorkflowClassName(),
184                                            ResourceConstants.SCOPE_INDIVIDUAL, message.getMessageId());
185                            }
186    
187                            // Message
188    
189                            mbMessagePersistence.remove(message);
190    
191                            // Statistics
192    
193                            if (!message.isDiscussion()) {
194                                    mbStatsUserLocalService.updateStatsUser(
195                                            message.getGroupId(), message.getUserId());
196                            }
197    
198                            // Workflow
199    
200                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
201                                    message.getCompanyId(), message.getGroupId(),
202                                    message.getWorkflowClassName(), message.getMessageId());
203                    }
204    
205                    // Category
206    
207                    if ((rootMessage.getCategoryId() !=
208                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
209                            (rootMessage.getCategoryId() !=
210                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
211    
212                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
213                                    thread.getCategoryId());
214    
215                            category.setThreadCount(category.getThreadCount() - 1);
216                            category.setMessageCount(
217                                    category.getMessageCount() - thread.getMessageCount());
218    
219                            mbCategoryPersistence.update(category);
220                    }
221    
222                    // Thread Asset
223    
224                    assetEntryLocalService.deleteEntry(
225                            MBThread.class.getName(), thread.getThreadId());
226    
227                    // Thread
228    
229                    mbThreadPersistence.remove(thread);
230            }
231    
232            public void deleteThreads(long groupId, long categoryId)
233                    throws PortalException, SystemException {
234    
235                    List<MBThread> threads = mbThreadPersistence.findByG_C(
236                            groupId, categoryId);
237    
238                    for (MBThread thread : threads) {
239                            deleteThread(thread);
240                    }
241            }
242    
243            public MBThread fetchThread(long threadId) throws SystemException {
244                    return mbThreadPersistence.fetchByPrimaryKey(threadId);
245            }
246    
247            public int getCategoryThreadsCount(
248                            long groupId, long categoryId, int status)
249                    throws SystemException {
250    
251                    if (status == WorkflowConstants.STATUS_ANY) {
252                            return mbThreadPersistence.countByG_C(groupId, categoryId);
253                    }
254                    else {
255                            return mbThreadPersistence.countByG_C_S(
256                                    groupId, categoryId, status);
257                    }
258            }
259    
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            public List<MBThread> getGroupThreads(
277                            long groupId, long userId, int status, boolean subscribed,
278                            boolean includeAnonymous, int start, int end)
279                    throws PortalException, SystemException {
280    
281                    if (userId <= 0) {
282                            if (status == WorkflowConstants.STATUS_ANY) {
283                                    return mbThreadPersistence.findByG_NotC(
284                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, start,
285                                            end);
286                            }
287                            else {
288                                    return mbThreadPersistence.findByG_NotC_S(
289                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, status,
290                                            start, end);
291                            }
292                    }
293                    else {
294                            if (subscribed) {
295                                    return mbThreadFinder.findByS_G_U_C_S(
296                                            groupId, userId, null, status, start, end);
297                            }
298                            else {
299                                    List<Long> threadIds = null;
300    
301                                    if (includeAnonymous) {
302                                            threadIds = mbMessageFinder.findByG_U_C_S(
303                                                    groupId, userId, null, status, start, end);
304                                    }
305                                    else {
306                                            threadIds = mbMessageFinder.findByG_U_C_A_S(
307                                                    groupId, userId, null, false, status, start, end);
308                                    }
309    
310                                    List<MBThread> threads = new ArrayList<MBThread>(
311                                            threadIds.size());
312    
313                                    for (long threadId : threadIds) {
314                                            MBThread thread = mbThreadPersistence.findByPrimaryKey(
315                                                    threadId);
316    
317                                            threads.add(thread);
318                                    }
319    
320                                    return threads;
321                            }
322                    }
323            }
324    
325            public List<MBThread> getGroupThreads(
326                            long groupId, long userId, int status, boolean subscribed,
327                            int start, int end)
328                    throws PortalException, SystemException {
329    
330                    return getGroupThreads(
331                            groupId, userId, status, subscribed, true, start, end);
332            }
333    
334            public List<MBThread> getGroupThreads(
335                            long groupId, long userId, int status, int start, int end)
336                    throws PortalException, SystemException {
337    
338                    return getGroupThreads(groupId, userId, status, false, start, end);
339            }
340    
341            public int getGroupThreadsCount(long groupId, int status)
342                    throws SystemException {
343    
344                    if (status == WorkflowConstants.STATUS_ANY) {
345                            return mbThreadPersistence.countByG_NotC(
346                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID);
347                    }
348                    else {
349                            return mbThreadPersistence.countByG_NotC_S(
350                                    groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID, status);
351                    }
352            }
353    
354            public int getGroupThreadsCount(long groupId, long userId, int status)
355                    throws SystemException {
356    
357                    return getGroupThreadsCount(groupId, userId, status, false);
358            }
359    
360            public int getGroupThreadsCount(
361                            long groupId, long userId, int status, boolean subscribed)
362                    throws SystemException {
363    
364                    return getGroupThreadsCount(groupId, userId, status, subscribed, true);
365            }
366    
367            public int getGroupThreadsCount(
368                            long groupId, long userId, int status, boolean subscribed,
369                            boolean includeAnonymous)
370                    throws SystemException {
371    
372                    if (userId <= 0) {
373                            if (status == WorkflowConstants.STATUS_ANY) {
374                                    return mbThreadPersistence.countByG_NotC(
375                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID);
376                            }
377                            else {
378                                    return mbThreadPersistence.countByG_NotC_S(
379                                            groupId, MBCategoryConstants.DISCUSSION_CATEGORY_ID,
380                                            status);
381                            }
382                    }
383                    else {
384                            if (subscribed) {
385                                    return mbThreadFinder.countByS_G_U_C_S(
386                                            groupId, userId, null, status);
387                            }
388                            else {
389                                    if (includeAnonymous) {
390                                            return mbMessageFinder.countByG_U_C_S(
391                                                    groupId, userId, null, status);
392                                    }
393                                    else {
394                                            return mbMessageFinder.countByG_U_C_A_S(
395                                                    groupId, userId, null, false, status);
396                                    }
397                            }
398                    }
399            }
400    
401            public List<MBThread> getNoAssetThreads() throws SystemException {
402                    return mbThreadFinder.findByNoAssets();
403            }
404    
405            public List<MBThread> getPriorityThreads(long categoryId, double priority)
406                    throws PortalException, SystemException {
407    
408                    return getPriorityThreads(categoryId, priority, false);
409            }
410    
411            public List<MBThread> getPriorityThreads(
412                            long categoryId, double priority, boolean inherit)
413                    throws PortalException, SystemException {
414    
415                    if (!inherit) {
416                            return mbThreadPersistence.findByC_P(categoryId, priority);
417                    }
418    
419                    List<MBThread> threads = new ArrayList<MBThread>();
420    
421                    while ((categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
422                               (categoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
423    
424                            threads.addAll(
425                                    0, mbThreadPersistence.findByC_P(categoryId, priority));
426    
427                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
428                                    categoryId);
429    
430                            categoryId = category.getParentCategoryId();
431                    }
432    
433                    return threads;
434            }
435    
436            public MBThread getThread(long threadId)
437                    throws PortalException, SystemException {
438    
439                    return mbThreadPersistence.findByPrimaryKey(threadId);
440            }
441    
442            public List<MBThread> getThreads(
443                            long groupId, long categoryId, int status, int start, int end)
444                    throws SystemException {
445    
446                    if (status == WorkflowConstants.STATUS_ANY) {
447                            return mbThreadPersistence.findByG_C(
448                                    groupId, categoryId, start, end);
449                    }
450                    else {
451                            return mbThreadPersistence.findByG_C_S(
452                                    groupId, categoryId, status, start, end);
453                    }
454            }
455    
456            public int getThreadsCount(long groupId, long categoryId, int status)
457                    throws SystemException {
458    
459                    if (status == WorkflowConstants.STATUS_ANY) {
460                            return mbThreadPersistence.countByG_C(groupId, categoryId);
461                    }
462                    else {
463                            return mbThreadPersistence.countByG_C_S(
464                                    groupId, categoryId, status);
465                    }
466            }
467    
468            public boolean hasAnswerMessage(long threadId) throws SystemException {
469                    int count = mbMessagePersistence.countByT_A(threadId, true);
470    
471                    if (count > 0) {
472                            return true;
473                    }
474                    else {
475                            return false;
476                    }
477            }
478    
479            @BufferedIncrement(incrementClass = NumberIncrement.class)
480            public MBThread incrementViewCounter(long threadId, int increment)
481                    throws PortalException, SystemException {
482    
483                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
484    
485                    thread.setViewCount(thread.getViewCount() + increment);
486    
487                    mbThreadPersistence.update(thread);
488    
489                    return thread;
490            }
491    
492            public MBThread moveThread(long groupId, long categoryId, long threadId)
493                    throws PortalException, SystemException {
494    
495                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
496    
497                    long oldCategoryId = thread.getCategoryId();
498    
499                    MBCategory oldCategory = null;
500    
501                    if (oldCategoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
502                            oldCategory = mbCategoryPersistence.findByPrimaryKey(oldCategoryId);
503                    }
504    
505                    MBCategory category = null;
506    
507                    if (categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
508                            category = mbCategoryPersistence.findByPrimaryKey(categoryId);
509                    }
510    
511                    // Messages
512    
513                    List<MBMessage> messages = mbMessagePersistence.findByG_C_T(
514                            groupId, oldCategoryId, thread.getThreadId());
515    
516                    for (MBMessage message : messages) {
517                            message.setCategoryId(categoryId);
518    
519                            mbMessagePersistence.update(message);
520    
521                            // Indexer
522    
523                            if (!message.isDiscussion()) {
524                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
525                                            MBMessage.class);
526    
527                                    indexer.reindex(message);
528                            }
529                    }
530    
531                    // Thread
532    
533                    thread.setCategoryId(categoryId);
534    
535                    mbThreadPersistence.update(thread);
536    
537                    // Category
538    
539                    if ((oldCategory != null) && (categoryId != oldCategoryId)) {
540                            oldCategory.setThreadCount(oldCategory.getThreadCount() - 1);
541                            oldCategory.setMessageCount(
542                                    oldCategory.getMessageCount() - thread.getMessageCount());
543    
544                            mbCategoryPersistence.update(oldCategory);
545                    }
546    
547                    if ((category != null) && (categoryId != oldCategoryId)) {
548                            category.setThreadCount(category.getThreadCount() + 1);
549                            category.setMessageCount(
550                                    category.getMessageCount() + thread.getMessageCount());
551    
552                            mbCategoryPersistence.update(category);
553                    }
554    
555                    return thread;
556            }
557    
558            public void moveThreadsToTrash(long groupId, long userId)
559                    throws PortalException, SystemException {
560    
561                    List<MBThread> threads = mbThreadPersistence.findByGroupId(groupId);
562    
563                    for (MBThread thread : threads) {
564                            moveThreadToTrash(userId, thread);
565                    }
566            }
567    
568            public MBThread moveThreadToTrash(long userId, long entryId)
569                    throws PortalException, SystemException {
570    
571                    MBThread thread = mbThreadPersistence.findByPrimaryKey(entryId);
572    
573                    return moveThreadToTrash(userId, thread);
574            }
575    
576            public MBThread moveThreadToTrash(long userId, MBThread thread)
577                    throws PortalException, SystemException {
578    
579                    if (thread.getCategoryId() ==
580                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
581    
582                            return thread;
583                    }
584    
585                    // Thread
586    
587                    User user = userPersistence.findByPrimaryKey(userId);
588                    Date now = new Date();
589                    int oldStatus = thread.getStatus();
590    
591                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
592                            MBMessage rootMessage = mbMessageLocalService.getMBMessage(
593                                    thread.getRootMessageId());
594    
595                            rootMessage.setStatus(WorkflowConstants.STATUS_DRAFT);
596    
597                            mbMessagePersistence.update(rootMessage);
598                    }
599    
600                    thread.setStatus(WorkflowConstants.STATUS_IN_TRASH);
601                    thread.setStatusByUserId(user.getUserId());
602                    thread.setStatusByUserName(user.getFullName());
603                    thread.setStatusDate(now);
604    
605                    mbThreadPersistence.update(thread);
606    
607                    // Messages
608    
609                    moveThreadMessagesToTrash(thread);
610    
611                    // Category
612    
613                    if (thread.getCategoryId() !=
614                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
615    
616                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
617                                    thread.getCategoryId());
618    
619                            category.setThreadCount(category.getThreadCount() - 1);
620                            category.setMessageCount(
621                                    category.getMessageCount() - thread.getMessageCount());
622    
623                            mbCategoryPersistence.update(category);
624                    }
625    
626                    // Stats
627    
628                    mbStatsUserLocalService.updateStatsUser(thread.getGroupId(), userId);
629    
630                    // Social
631    
632                    socialActivityLocalService.addActivity(
633                            userId, thread.getGroupId(), MBThread.class.getName(),
634                            thread.getThreadId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
635                            StringPool.BLANK, 0);
636    
637                    // Trash
638    
639                    trashEntryLocalService.addTrashEntry(
640                            userId, thread.getGroupId(), MBThread.class.getName(),
641                            thread.getThreadId(), oldStatus, null, null);
642    
643                    return thread;
644            }
645    
646            public void restoreThreadFromTrash(long userId, long threadId)
647                    throws PortalException, SystemException {
648    
649                    // Thread
650    
651                    User user = userPersistence.findByPrimaryKey(userId);
652                    Date now = new Date();
653    
654                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
655                            MBThread.class.getName(), threadId);
656    
657                    MBThread thread = getThread(threadId);
658    
659                    if (thread.getCategoryId() ==
660                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID) {
661    
662                            return;
663                    }
664    
665                    thread.setStatus(trashEntry.getStatus());
666                    thread.setStatusByUserId(user.getUserId());
667                    thread.setStatusByUserName(user.getFullName());
668                    thread.setStatusDate(now);
669    
670                    mbThreadPersistence.update(thread);
671    
672                    // Messages
673    
674                    restoreThreadMessagesFromTrash(thread);
675    
676                    // Category
677    
678                    if (thread.getCategoryId() !=
679                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
680    
681                            MBCategory category = mbCategoryPersistence.findByPrimaryKey(
682                                    thread.getCategoryId());
683    
684                            category.setThreadCount(category.getThreadCount() + 1);
685                            category.setMessageCount(
686                                    category.getMessageCount() + thread.getMessageCount());
687    
688                            mbCategoryPersistence.update(category);
689                    }
690    
691                    // Stats
692    
693                    mbStatsUserLocalService.updateStatsUser(thread.getGroupId(), userId);
694    
695                    // Trash
696    
697                    trashEntryLocalService.deleteEntry(MBThread.class.getName(), threadId);
698    
699                    // Social
700    
701                    socialActivityLocalService.addActivity(
702                            userId, trashEntry.getGroupId(), MBThread.class.getName(), threadId,
703                            SocialActivityConstants.TYPE_RESTORE_FROM_TRASH, StringPool.BLANK,
704                            0);
705            }
706    
707            public MBThread splitThread(
708                            long messageId, String subject, ServiceContext serviceContext)
709                    throws PortalException, SystemException {
710    
711                    MBMessage message = mbMessagePersistence.findByPrimaryKey(messageId);
712    
713                    if (message.isRoot()) {
714                            throw new SplitThreadException();
715                    }
716    
717                    MBCategory category = message.getCategory();
718                    MBThread oldThread = message.getThread();
719                    MBMessage rootMessage = mbMessagePersistence.findByPrimaryKey(
720                            oldThread.getRootMessageId());
721                    String oldAttachmentsDir = message.getAttachmentsDir();
722    
723                    // Message flags
724    
725                    mbMessageLocalService.updateAnswer(message, false, true);
726    
727                    // Create new thread
728    
729                    MBThread thread = addThread(message.getCategoryId(), message);
730    
731                    // Update messages
732    
733                    if (Validator.isNotNull(subject)) {
734                            MBMessageDisplay messageDisplay =
735                                    mbMessageService.getMessageDisplay(
736                                            messageId, WorkflowConstants.STATUS_ANY,
737                                            MBThreadConstants.THREAD_VIEW_TREE, false);
738    
739                            MBTreeWalker treeWalker = messageDisplay.getTreeWalker();
740    
741                            List<MBMessage> messages = treeWalker.getMessages();
742    
743                            int[] range = treeWalker.getChildrenRange(message);
744    
745                            for (int i = range[0]; i < range[1]; i++) {
746                                    MBMessage curMessage = messages.get(i);
747    
748                                    String oldSubject = message.getSubject();
749                                    String curSubject = curMessage.getSubject();
750    
751                                    if (oldSubject.startsWith("RE: ")) {
752                                            curSubject = StringUtil.replace(
753                                                    curSubject, rootMessage.getSubject(), subject);
754                                    }
755                                    else {
756                                            curSubject = StringUtil.replace(
757                                                    curSubject, oldSubject, subject);
758                                    }
759    
760                                    curMessage.setSubject(curSubject);
761    
762                                    mbMessagePersistence.update(curMessage);
763                            }
764    
765                            message.setSubject(subject);
766                    }
767    
768                    message.setThreadId(thread.getThreadId());
769                    message.setRootMessageId(thread.getRootMessageId());
770                    message.setParentMessageId(0);
771                    message.setAttachmentsDir(null);
772    
773                    mbMessagePersistence.update(message);
774    
775                    // Attachments
776    
777                    moveAttachmentsFromOldThread(message, oldAttachmentsDir);
778    
779                    // Indexer
780    
781                    if (!message.isDiscussion()) {
782                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
783                                    MBMessage.class);
784    
785                            indexer.reindex(message);
786                    }
787    
788                    // Update children
789    
790                    int messagesMoved = 1;
791    
792                    messagesMoved += moveChildrenMessages(
793                            message, category, oldThread.getThreadId());
794    
795                    // Update new thread
796    
797                    thread.setMessageCount(messagesMoved);
798    
799                    mbThreadPersistence.update(thread);
800    
801                    // Update old thread
802    
803                    oldThread.setMessageCount(oldThread.getMessageCount() - messagesMoved);
804    
805                    mbThreadPersistence.update(oldThread);
806    
807                    // Category
808    
809                    if ((message.getCategoryId() !=
810                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
811                            (message.getCategoryId() !=
812                                    MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
813    
814                            category.setThreadCount(category.getThreadCount() + 1);
815    
816                            mbCategoryPersistence.update(category);
817                    }
818    
819                    return thread;
820            }
821    
822            public void updateQuestion(long threadId, boolean question)
823                    throws PortalException, SystemException {
824    
825                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
826    
827                    if (thread.isQuestion() == question) {
828                            return;
829                    }
830    
831                    thread.setQuestion(question);
832    
833                    mbThreadPersistence.update(thread);
834    
835                    if (!question) {
836                            MBMessage message = mbMessagePersistence.findByPrimaryKey(
837                                    thread.getRootMessageId());
838    
839                            mbMessageLocalService.updateAnswer(message, false, true);
840                    }
841            }
842    
843            /**
844             * @deprecated {@link #incrementViewCounter(long, int)}
845             */
846            public MBThread updateThread(long threadId, int viewCount)
847                    throws PortalException, SystemException {
848    
849                    MBThread thread = mbThreadPersistence.findByPrimaryKey(threadId);
850    
851                    thread.setViewCount(viewCount);
852    
853                    mbThreadPersistence.update(thread);
854    
855                    return thread;
856            }
857    
858            protected void moveAttachmentFromOldThread(
859                            long companyId, String fileName, String newAttachmentsDir)
860                    throws PortalException, SystemException {
861    
862                    long repositoryId = CompanyConstants.SYSTEM;
863    
864                    StringBundler sb = new StringBundler(4);
865    
866                    sb.append(newAttachmentsDir);
867                    sb.append(StringPool.SLASH);
868                    sb.append(StringUtil.extractLast(fileName, CharPool.SLASH));
869    
870                    String newFileName = sb.toString();
871    
872                    try {
873                            File file = DLStoreUtil.getFile(companyId, repositoryId, fileName);
874    
875                            DLStoreUtil.addFile(
876                                    companyId, repositoryId, newFileName, false, file);
877                    }
878                    catch (UnsupportedOperationException uoe) {
879                            InputStream is = DLStoreUtil.getFileAsStream(
880                                    companyId, repositoryId, fileName);
881    
882                            try {
883                                    DLStoreUtil.addFile(
884                                            companyId, repositoryId, newFileName, false, is);
885                            }
886                            finally {
887                                    try {
888                                            is.close();
889                                    }
890                                    catch (IOException ioe) {
891                                            _log.error(ioe);
892                                    }
893                            }
894                    }
895    
896                    DLStoreUtil.deleteFile(companyId, repositoryId, fileName);
897            }
898    
899            protected void moveAttachmentsFromOldThread(
900                            MBMessage message, String oldAttachmentsDir)
901                    throws PortalException, SystemException {
902    
903                    if (!message.getAttachments()) {
904                            return;
905                    }
906    
907                    long companyId = message.getCompanyId();
908                    long repositoryId = CompanyConstants.SYSTEM;
909                    String newAttachmentsDir = message.getAttachmentsDir();
910    
911                    try {
912                            DLStoreUtil.addDirectory(
913                                    companyId, repositoryId, newAttachmentsDir);
914                    }
915                    catch (DuplicateDirectoryException dde) {
916                    }
917    
918                    String[] fileNames = DLStoreUtil.getFileNames(
919                            companyId, repositoryId, oldAttachmentsDir);
920    
921                    for (String fileName : fileNames) {
922                            moveAttachmentFromOldThread(companyId, fileName, newAttachmentsDir);
923                    }
924    
925                    try {
926                            DLStoreUtil.deleteDirectory(
927                                    companyId, repositoryId, oldAttachmentsDir);
928                    }
929                    catch (NoSuchDirectoryException nsde) {
930                    }
931            }
932    
933            protected int moveChildrenMessages(
934                            MBMessage parentMessage, MBCategory category, long oldThreadId)
935                    throws PortalException, SystemException {
936    
937                    int messagesMoved = 0;
938    
939                    List<MBMessage> messages = mbMessagePersistence.findByT_P(
940                            oldThreadId, parentMessage.getMessageId());
941    
942                    for (MBMessage message : messages) {
943                            String oldAttachmentsDir = message.getAttachmentsDir();
944    
945                            message.setCategoryId(parentMessage.getCategoryId());
946                            message.setThreadId(parentMessage.getThreadId());
947                            message.setRootMessageId(parentMessage.getRootMessageId());
948                            message.setAttachmentsDir(null);
949    
950                            mbMessagePersistence.update(message);
951    
952                            moveAttachmentsFromOldThread(message, oldAttachmentsDir);
953    
954                            if (!message.isDiscussion()) {
955                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
956                                            MBMessage.class);
957    
958                                    indexer.reindex(message);
959                            }
960    
961                            messagesMoved++;
962    
963                            messagesMoved += moveChildrenMessages(
964                                    message, category, oldThreadId);
965                    }
966    
967                    return messagesMoved;
968            }
969    
970            protected void moveThreadMessagesToTrash(MBThread thread)
971                    throws PortalException, SystemException {
972    
973                    List<MBMessage> messages = mbMessageLocalService.getThreadMessages(
974                            thread.getThreadId(), WorkflowConstants.STATUS_ANY);
975    
976                    for (MBMessage message : messages) {
977    
978                            // Asset
979    
980                            if (message.getStatus() == WorkflowConstants.STATUS_APPROVED) {
981                                    assetEntryLocalService.updateVisible(
982                                            MBMessage.class.getName(), message.getMessageId(), false);
983                            }
984    
985                            // Social
986    
987                            socialActivityCounterLocalService.disableActivityCounters(
988                                    MBMessage.class.getName(), message.getMessageId());
989    
990                            // Index
991    
992                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
993                                    MBMessage.class);
994    
995                            if (!message.isDiscussion()) {
996                                    indexer.delete(message);
997                            }
998    
999                            // Workflow
1000    
1001                            if (message.getStatus() == WorkflowConstants.STATUS_PENDING) {
1002                                    message.setStatus(WorkflowConstants.STATUS_DRAFT);
1003    
1004                                    mbMessagePersistence.update(message);
1005    
1006                                    WorkflowInstanceLink workflowInstanceLink =
1007                                            workflowInstanceLinkLocalService.getWorkflowInstanceLink(
1008                                                    message.getCompanyId(), message.getGroupId(),
1009                                                    MBMessage.class.getName(), message.getMessageId());
1010    
1011                                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
1012                                            workflowInstanceLink.getWorkflowInstanceLinkId());
1013                            }
1014                    }
1015            }
1016    
1017            protected void restoreThreadMessagesFromTrash(MBThread thread)
1018                    throws PortalException, SystemException {
1019    
1020                    List<MBMessage> messages = mbMessageLocalService.getThreadMessages(
1021                            thread.getThreadId(), WorkflowConstants.STATUS_ANY);
1022    
1023                    for (MBMessage message : messages) {
1024    
1025                            // Asset
1026    
1027                            if (message.getStatus() == WorkflowConstants.STATUS_APPROVED) {
1028                                    assetEntryLocalService.updateVisible(
1029                                            MBMessage.class.getName(), message.getMessageId(), true);
1030                            }
1031    
1032                            // Social
1033    
1034                            socialActivityCounterLocalService.disableActivityCounters(
1035                                    MBMessage.class.getName(), message.getMessageId());
1036    
1037                            // Index
1038    
1039                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1040                                    MBMessage.class);
1041    
1042                            if (!message.isDiscussion()) {
1043                                    indexer.reindex(message);
1044                            }
1045                    }
1046            }
1047    
1048            private static Log _log = LogFactoryUtil.getLog(
1049                    MBThreadLocalServiceImpl.class);
1050    
1051    }