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