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