001    /**
002     * Copyright (c) 2000-present 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.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.search.Indexer;
021    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
022    import com.liferay.portal.kernel.systemevent.SystemEvent;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.kernel.workflow.WorkflowConstants;
025    import com.liferay.portal.model.ResourceConstants;
026    import com.liferay.portal.model.SystemEventConstants;
027    import com.liferay.portal.model.User;
028    import com.liferay.portal.service.ServiceContext;
029    import com.liferay.portlet.messageboards.CategoryNameException;
030    import com.liferay.portlet.messageboards.NoSuchMailingListException;
031    import com.liferay.portlet.messageboards.model.MBCategory;
032    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
033    import com.liferay.portlet.messageboards.model.MBMailingList;
034    import com.liferay.portlet.messageboards.model.MBMessage;
035    import com.liferay.portlet.messageboards.model.MBThread;
036    import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
037    import com.liferay.portlet.messageboards.service.base.MBCategoryLocalServiceBaseImpl;
038    import com.liferay.portlet.trash.model.TrashEntry;
039    import com.liferay.portlet.trash.model.TrashVersion;
040    
041    import java.util.ArrayList;
042    import java.util.Date;
043    import java.util.List;
044    
045    /**
046     * @author Brian Wing Shun Chan
047     * @author Wesley Gong
048     */
049    public class MBCategoryLocalServiceImpl extends MBCategoryLocalServiceBaseImpl {
050    
051            @Override
052            public MBCategory addCategory(
053                            long userId, long parentCategoryId, String name, String description,
054                            ServiceContext serviceContext)
055                    throws PortalException {
056    
057                    return addCategory(
058                            userId, parentCategoryId, name, description,
059                            MBCategoryConstants.DEFAULT_DISPLAY_STYLE, null, null, null, 0,
060                            false, null, null, 0, null, false, null, 0, false, null, null,
061                            false, false, serviceContext);
062            }
063    
064            @Override
065            public MBCategory addCategory(
066                            long userId, long parentCategoryId, String name, String description,
067                            String displayStyle, String emailAddress, String inProtocol,
068                            String inServerName, int inServerPort, boolean inUseSSL,
069                            String inUserName, String inPassword, int inReadInterval,
070                            String outEmailAddress, boolean outCustom, String outServerName,
071                            int outServerPort, boolean outUseSSL, String outUserName,
072                            String outPassword, boolean allowAnonymous,
073                            boolean mailingListActive, ServiceContext serviceContext)
074                    throws PortalException {
075    
076                    // Category
077    
078                    User user = userPersistence.findByPrimaryKey(userId);
079                    long groupId = serviceContext.getScopeGroupId();
080                    parentCategoryId = getParentCategoryId(groupId, parentCategoryId);
081                    Date now = new Date();
082    
083                    validate(name);
084    
085                    long categoryId = counterLocalService.increment();
086    
087                    MBCategory category = mbCategoryPersistence.create(categoryId);
088    
089                    category.setUuid(serviceContext.getUuid());
090                    category.setGroupId(groupId);
091                    category.setCompanyId(user.getCompanyId());
092                    category.setUserId(user.getUserId());
093                    category.setUserName(user.getFullName());
094                    category.setCreateDate(serviceContext.getCreateDate(now));
095                    category.setModifiedDate(serviceContext.getModifiedDate(now));
096                    category.setParentCategoryId(parentCategoryId);
097                    category.setName(name);
098                    category.setDescription(description);
099                    category.setDisplayStyle(displayStyle);
100                    category.setExpandoBridgeAttributes(serviceContext);
101    
102                    mbCategoryPersistence.update(category);
103    
104                    // Resources
105    
106                    if (serviceContext.isAddGroupPermissions() ||
107                            serviceContext.isAddGuestPermissions()) {
108    
109                            addCategoryResources(
110                                    category, serviceContext.isAddGroupPermissions(),
111                                    serviceContext.isAddGuestPermissions());
112                    }
113                    else {
114                            addCategoryResources(
115                                    category, serviceContext.getGroupPermissions(),
116                                    serviceContext.getGuestPermissions());
117                    }
118    
119                    // Mailing list
120    
121                    mbMailingListLocalService.addMailingList(
122                            userId, groupId, category.getCategoryId(), emailAddress, inProtocol,
123                            inServerName, inServerPort, inUseSSL, inUserName, inPassword,
124                            inReadInterval, outEmailAddress, outCustom, outServerName,
125                            outServerPort, outUseSSL, outUserName, outPassword, allowAnonymous,
126                            mailingListActive, serviceContext);
127    
128                    return category;
129            }
130    
131            @Override
132            public void addCategoryResources(
133                            long categoryId, boolean addGroupPermissions,
134                            boolean addGuestPermissions)
135                    throws PortalException {
136    
137                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
138                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
139    
140                            return;
141                    }
142    
143                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
144                            categoryId);
145    
146                    addCategoryResources(
147                            category, addGroupPermissions, addGuestPermissions);
148            }
149    
150            @Override
151            public void addCategoryResources(
152                            long categoryId, String[] groupPermissions,
153                            String[] guestPermissions)
154                    throws PortalException {
155    
156                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
157                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
158    
159                            return;
160                    }
161    
162                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
163                            categoryId);
164    
165                    addCategoryResources(category, groupPermissions, guestPermissions);
166            }
167    
168            @Override
169            public void addCategoryResources(
170                            MBCategory category, boolean addGroupPermissions,
171                            boolean addGuestPermissions)
172                    throws PortalException {
173    
174                    resourceLocalService.addResources(
175                            category.getCompanyId(), category.getGroupId(),
176                            category.getUserId(), MBCategory.class.getName(),
177                            category.getCategoryId(), false, addGroupPermissions,
178                            addGuestPermissions);
179            }
180    
181            @Override
182            public void addCategoryResources(
183                            MBCategory category, String[] groupPermissions,
184                            String[] guestPermissions)
185                    throws PortalException {
186    
187                    resourceLocalService.addModelResources(
188                            category.getCompanyId(), category.getGroupId(),
189                            category.getUserId(), MBCategory.class.getName(),
190                            category.getCategoryId(), groupPermissions, guestPermissions);
191            }
192    
193            @Override
194            public void deleteCategories(long groupId) throws PortalException {
195                    List<MBCategory> categories = mbCategoryPersistence.findByGroupId(
196                            groupId);
197    
198                    for (MBCategory category : categories) {
199                            mbCategoryLocalService.deleteCategory(category);
200                    }
201            }
202    
203            @Override
204            public void deleteCategory(long categoryId) throws PortalException {
205                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
206                            categoryId);
207    
208                    mbCategoryLocalService.deleteCategory(category);
209            }
210    
211            @Override
212            @SystemEvent(
213                    action = SystemEventConstants.ACTION_SKIP,
214                    type = SystemEventConstants.TYPE_DELETE)
215            public void deleteCategory(MBCategory category) throws PortalException {
216                    deleteCategory(category, true);
217            }
218    
219            @Override
220            @SystemEvent(
221                    action = SystemEventConstants.ACTION_SKIP,
222                    type = SystemEventConstants.TYPE_DELETE)
223            public void deleteCategory(
224                            MBCategory category, boolean includeTrashedEntries)
225                    throws PortalException {
226    
227                    // Categories
228    
229                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
230                            category.getGroupId(), category.getCategoryId());
231    
232                    for (MBCategory curCategory : categories) {
233                            if (includeTrashedEntries || !curCategory.isInTrashExplicitly()) {
234                                    deleteCategory(curCategory, includeTrashedEntries);
235                            }
236                    }
237    
238                    // Threads
239    
240                    mbThreadLocalService.deleteThreads(
241                            category.getGroupId(), category.getCategoryId(),
242                            includeTrashedEntries);
243    
244                    // Mailing list
245    
246                    try {
247                            mbMailingListLocalService.deleteCategoryMailingList(
248                                    category.getGroupId(), category.getCategoryId());
249                    }
250                    catch (NoSuchMailingListException nsmle) {
251                    }
252    
253                    // Subscriptions
254    
255                    subscriptionLocalService.deleteSubscriptions(
256                            category.getCompanyId(), MBCategory.class.getName(),
257                            category.getCategoryId());
258    
259                    // Expando
260    
261                    expandoRowLocalService.deleteRows(category.getCategoryId());
262    
263                    // Resources
264    
265                    resourceLocalService.deleteResource(
266                            category.getCompanyId(), MBCategory.class.getName(),
267                            ResourceConstants.SCOPE_INDIVIDUAL, category.getCategoryId());
268    
269                    // Trash
270    
271                    if (category.isInTrashExplicitly()) {
272                            trashEntryLocalService.deleteEntry(
273                                    MBCategory.class.getName(), category.getCategoryId());
274                    }
275                    else {
276                            trashVersionLocalService.deleteTrashVersion(
277                                    MBCategory.class.getName(), category.getCategoryId());
278                    }
279    
280                    // Category
281    
282                    mbCategoryPersistence.remove(category);
283            }
284    
285            @Override
286            public List<MBCategory> getCategories(long groupId) {
287                    return mbCategoryPersistence.findByGroupId(groupId);
288            }
289    
290            @Override
291            public List<MBCategory> getCategories(long groupId, int status) {
292                    return mbCategoryPersistence.findByG_S(groupId, status);
293            }
294    
295            @Override
296            public List<MBCategory> getCategories(
297                    long groupId, long parentCategoryId, int start, int end) {
298    
299                    return mbCategoryPersistence.findByG_P(
300                            groupId, parentCategoryId, start, end);
301            }
302    
303            @Override
304            public List<MBCategory> getCategories(
305                    long groupId, long parentCategoryId, int status, int start, int end) {
306    
307                    if (status == WorkflowConstants.STATUS_ANY) {
308                            return mbCategoryPersistence.findByG_P(
309                                    groupId, parentCategoryId, start, end);
310                    }
311    
312                    return mbCategoryPersistence.findByG_P_S(
313                            groupId, parentCategoryId, status, start, end);
314            }
315    
316            @Override
317            public List<MBCategory> getCategories(
318                    long groupId, long excludedCategoryId, long parentCategoryId,
319                    int status, int start, int end) {
320    
321                    if (status == WorkflowConstants.STATUS_ANY) {
322                            return mbCategoryPersistence.findByNotC_G_P(
323                                    excludedCategoryId, groupId, parentCategoryId, start, end);
324                    }
325    
326                    return mbCategoryPersistence.findByNotC_G_P_S(
327                            excludedCategoryId, groupId, parentCategoryId, status, start, end);
328            }
329    
330            @Override
331            public List<MBCategory> getCategories(
332                    long groupId, long[] parentCategoryIds, int start, int end) {
333    
334                    return mbCategoryPersistence.findByG_P(
335                            groupId, parentCategoryIds, start, end);
336            }
337    
338            @Override
339            public List<MBCategory> getCategories(
340                    long groupId, long[] parentCategoryIds, int status, int start,
341                    int end) {
342    
343                    if (status == WorkflowConstants.STATUS_ANY) {
344                            return mbCategoryPersistence.findByG_P(
345                                    groupId, parentCategoryIds, start, end);
346                    }
347    
348                    return mbCategoryPersistence.findByG_P_S(
349                            groupId, parentCategoryIds, status, start, end);
350            }
351    
352            @Override
353            public List<MBCategory> getCategories(
354                    long groupId, long[] excludedCategoryIds, long[] parentCategoryIds,
355                    int status, int start, int end) {
356    
357                    if (status == WorkflowConstants.STATUS_ANY) {
358                            return mbCategoryPersistence.findByNotC_G_P(
359                                    excludedCategoryIds, groupId, parentCategoryIds, start, end);
360                    }
361    
362                    return mbCategoryPersistence.findByNotC_G_P_S(
363                            excludedCategoryIds, groupId, parentCategoryIds, status, start,
364                            end);
365            }
366    
367            @Override
368            public List<Object> getCategoriesAndThreads(long groupId, long categoryId) {
369                    List<Object> categoriesAndThreads = new ArrayList<Object>();
370    
371                    List<MBCategory> categories = getCategories(
372                            groupId, categoryId, QueryUtil.ALL_POS, QueryUtil.ALL_POS);
373    
374                    categoriesAndThreads.addAll(categories);
375    
376                    List<MBThread> threads = mbThreadLocalService.getThreads(
377                            groupId, categoryId, WorkflowConstants.STATUS_ANY,
378                            QueryUtil.ALL_POS, QueryUtil.ALL_POS);
379    
380                    categoriesAndThreads.addAll(threads);
381    
382                    return categoriesAndThreads;
383            }
384    
385            @Override
386            public int getCategoriesCount(long groupId) {
387                    return mbCategoryPersistence.countByGroupId(groupId);
388            }
389    
390            @Override
391            public int getCategoriesCount(long groupId, int status) {
392                    return mbCategoryPersistence.countByG_S(groupId, status);
393            }
394    
395            @Override
396            public int getCategoriesCount(long groupId, long parentCategoryId) {
397                    return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
398            }
399    
400            @Override
401            public int getCategoriesCount(
402                    long groupId, long parentCategoryId, int status) {
403    
404                    if (status == WorkflowConstants.STATUS_ANY) {
405                            return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
406                    }
407    
408                    return mbCategoryPersistence.countByG_P_S(
409                            groupId, parentCategoryId, status);
410            }
411    
412            @Override
413            public int getCategoriesCount(
414                    long groupId, long excludedCategoryId, long parentCategoryId,
415                    int status) {
416    
417                    if (status == WorkflowConstants.STATUS_ANY) {
418                            return mbCategoryPersistence.countByNotC_G_P(
419                                    excludedCategoryId, groupId, parentCategoryId);
420                    }
421    
422                    return mbCategoryPersistence.countByNotC_G_P_S(
423                            excludedCategoryId, groupId, parentCategoryId, status);
424            }
425    
426            @Override
427            public int getCategoriesCount(long groupId, long[] parentCategoryIds) {
428                    return mbCategoryPersistence.countByG_P(groupId, parentCategoryIds);
429            }
430    
431            @Override
432            public int getCategoriesCount(
433                    long groupId, long[] parentCategoryIds, int status) {
434    
435                    if (status == WorkflowConstants.STATUS_ANY) {
436                            return mbCategoryPersistence.countByG_P(groupId, parentCategoryIds);
437                    }
438    
439                    return mbCategoryPersistence.countByG_P_S(
440                            groupId, parentCategoryIds, status);
441            }
442    
443            @Override
444            public int getCategoriesCount(
445                    long groupId, long[] excludedCategoryIds, long[] parentCategoryIds,
446                    int status) {
447    
448                    if (status == WorkflowConstants.STATUS_ANY) {
449                            return mbCategoryPersistence.countByNotC_G_P(
450                                    excludedCategoryIds, groupId, parentCategoryIds);
451                    }
452    
453                    return mbCategoryPersistence.countByNotC_G_P_S(
454                            excludedCategoryIds, groupId, parentCategoryIds, status);
455            }
456    
457            @Override
458            public MBCategory getCategory(long categoryId) throws PortalException {
459                    MBCategory category = null;
460    
461                    if ((categoryId != MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
462                            (categoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
463    
464                            category = mbCategoryPersistence.findByPrimaryKey(categoryId);
465                    }
466                    else {
467                            category = new MBCategoryImpl();
468    
469                            category.setCategoryId(categoryId);
470                            category.setParentCategoryId(categoryId);
471                    }
472    
473                    return category;
474            }
475    
476            @Override
477            public List<MBCategory> getCompanyCategories(
478                    long companyId, int start, int end) {
479    
480                    return mbCategoryPersistence.findByCompanyId(companyId, start, end);
481            }
482    
483            @Override
484            public int getCompanyCategoriesCount(long companyId) {
485                    return mbCategoryPersistence.countByCompanyId(companyId);
486            }
487    
488            @Override
489            public List<Long> getSubcategoryIds(
490                    List<Long> categoryIds, long groupId, long categoryId) {
491    
492                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
493                            groupId, categoryId);
494    
495                    for (MBCategory category : categories) {
496                            categoryIds.add(category.getCategoryId());
497    
498                            getSubcategoryIds(
499                                    categoryIds, category.getGroupId(), category.getCategoryId());
500                    }
501    
502                    return categoryIds;
503            }
504    
505            @Override
506            public List<MBCategory> getSubscribedCategories(
507                    long groupId, long userId, int start, int end) {
508    
509                    QueryDefinition<MBCategory> queryDefinition =
510                            new QueryDefinition<MBCategory>(
511                                    WorkflowConstants.STATUS_ANY, start, end, null);
512    
513                    return mbCategoryFinder.findByS_G_U_P(
514                            groupId, userId, null, queryDefinition);
515            }
516    
517            @Override
518            public int getSubscribedCategoriesCount(long groupId, long userId) {
519                    QueryDefinition<MBCategory> queryDefinition =
520                            new QueryDefinition<MBCategory>(WorkflowConstants.STATUS_ANY);
521    
522                    return mbCategoryFinder.countByS_G_U_P(
523                            groupId, userId, null, queryDefinition);
524            }
525    
526            @Override
527            public void moveCategoriesToTrash(long groupId, long userId)
528                    throws PortalException {
529    
530                    List<MBCategory> categories = mbCategoryPersistence.findByGroupId(
531                            groupId);
532    
533                    for (MBCategory category : categories) {
534                            moveCategoryToTrash(userId, category.getCategoryId());
535                    }
536            }
537    
538            @Override
539            public MBCategory moveCategory(
540                            long categoryId, long parentCategoryId,
541                            boolean mergeWithParentCategory)
542                    throws PortalException {
543    
544                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
545                            categoryId);
546    
547                    parentCategoryId = getParentCategoryId(category, parentCategoryId);
548    
549                    if (mergeWithParentCategory &&
550                            (categoryId != parentCategoryId) &&
551                            (parentCategoryId !=
552                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
553                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
554    
555                            mergeCategories(category, parentCategoryId);
556    
557                            return category;
558                    }
559    
560                    category.setParentCategoryId(parentCategoryId);
561    
562                    return mbCategoryPersistence.update(category);
563            }
564    
565            @Override
566            public MBCategory moveCategoryFromTrash(
567                            long userId, long categoryId, long newCategoryId)
568                    throws PortalException {
569    
570                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
571                            categoryId);
572    
573                    if (category.isInTrashExplicitly()) {
574                            restoreCategoryFromTrash(userId, categoryId);
575                    }
576                    else {
577    
578                            // Category
579    
580                            TrashVersion trashVersion = trashVersionLocalService.fetchVersion(
581                                    MBCategory.class.getName(), category.getCategoryId());
582    
583                            int status = WorkflowConstants.STATUS_APPROVED;
584    
585                            if (trashVersion != null) {
586                                    status = trashVersion.getStatus();
587                            }
588    
589                            updateStatus(userId, categoryId, status);
590    
591                            // Trash
592    
593                            if (trashVersion != null) {
594                                    trashVersionLocalService.deleteTrashVersion(trashVersion);
595                            }
596    
597                            // Categories and threads
598    
599                            User user = userPersistence.findByPrimaryKey(userId);
600    
601                            List<Object> categoriesAndThreads = getCategoriesAndThreads(
602                                    category.getGroupId(), categoryId);
603    
604                            restoreDependentsFromTrash(user, categoriesAndThreads);
605                    }
606    
607                    return moveCategory(categoryId, newCategoryId, false);
608            }
609    
610            @Override
611            public MBCategory moveCategoryToTrash(long userId, long categoryId)
612                    throws PortalException {
613    
614                    // Category
615    
616                    MBCategory category = updateStatus(
617                            userId, categoryId, WorkflowConstants.STATUS_IN_TRASH);
618    
619                    // Trash
620    
621                    TrashEntry trashEntry = trashEntryLocalService.addTrashEntry(
622                            userId, category.getGroupId(), MBCategory.class.getName(),
623                            categoryId, category.getUuid(), null,
624                            WorkflowConstants.STATUS_APPROVED, null, null);
625    
626                    // Categories and threads
627    
628                    User user = userPersistence.findByPrimaryKey(userId);
629    
630                    List<Object> categoriesAndThreads = getCategoriesAndThreads(
631                            category.getGroupId(), categoryId);
632    
633                    moveDependentsToTrash(
634                            user, categoriesAndThreads, trashEntry.getEntryId());
635    
636                    return category;
637            }
638    
639            @Override
640            public void restoreCategoryFromTrash(long userId, long categoryId)
641                    throws PortalException {
642    
643                    // Category
644    
645                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
646                            MBCategory.class.getName(), categoryId);
647    
648                    MBCategory category = updateStatus(
649                            userId, categoryId, WorkflowConstants.STATUS_APPROVED);
650    
651                    // Categories and threads
652    
653                    User user = userPersistence.findByPrimaryKey(userId);
654    
655                    List<Object> categoriesAndThreads = getCategoriesAndThreads(
656                            category.getGroupId(), categoryId);
657    
658                    restoreDependentsFromTrash(user, categoriesAndThreads);
659    
660                    // Trash
661    
662                    trashEntryLocalService.deleteEntry(trashEntry.getEntryId());
663            }
664    
665            @Override
666            public void subscribeCategory(long userId, long groupId, long categoryId)
667                    throws PortalException {
668    
669                    if (categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
670                            categoryId = groupId;
671                    }
672    
673                    subscriptionLocalService.addSubscription(
674                            userId, groupId, MBCategory.class.getName(), categoryId);
675            }
676    
677            @Override
678            public void unsubscribeCategory(long userId, long groupId, long categoryId)
679                    throws PortalException {
680    
681                    if (categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
682                            categoryId = groupId;
683                    }
684    
685                    subscriptionLocalService.deleteSubscription(
686                            userId, MBCategory.class.getName(), categoryId);
687            }
688    
689            @Override
690            public MBCategory updateCategory(
691                            long categoryId, long parentCategoryId, String name,
692                            String description, String displayStyle, String emailAddress,
693                            String inProtocol, String inServerName, int inServerPort,
694                            boolean inUseSSL, String inUserName, String inPassword,
695                            int inReadInterval, String outEmailAddress, boolean outCustom,
696                            String outServerName, int outServerPort, boolean outUseSSL,
697                            String outUserName, String outPassword, boolean allowAnonymous,
698                            boolean mailingListActive, boolean mergeWithParentCategory,
699                            ServiceContext serviceContext)
700                    throws PortalException {
701    
702                    // Merge categories
703    
704                    if ((categoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
705                            (categoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
706    
707                            return null;
708                    }
709    
710                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
711                            categoryId);
712    
713                    parentCategoryId = getParentCategoryId(category, parentCategoryId);
714    
715                    if (mergeWithParentCategory &&
716                            (categoryId != parentCategoryId) &&
717                            (parentCategoryId !=
718                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
719                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
720    
721                            mergeCategories(category, parentCategoryId);
722    
723                            return category;
724                    }
725    
726                    // Category
727    
728                    validate(name);
729    
730                    category.setModifiedDate(serviceContext.getModifiedDate(null));
731                    category.setParentCategoryId(parentCategoryId);
732                    category.setName(name);
733                    category.setDescription(description);
734    
735                    if (!displayStyle.equals(category.getDisplayStyle())) {
736                            category.setDisplayStyle(displayStyle);
737    
738                            updateChildCategoriesDisplayStyle(category, displayStyle);
739                    }
740    
741                    category.setExpandoBridgeAttributes(serviceContext);
742    
743                    mbCategoryPersistence.update(category);
744    
745                    // Mailing list
746    
747                    MBMailingList mailingList = mbMailingListPersistence.fetchByG_C(
748                            category.getGroupId(), category.getCategoryId());
749    
750                    if (mailingList != null) {
751                            mbMailingListLocalService.updateMailingList(
752                                    mailingList.getMailingListId(), emailAddress, inProtocol,
753                                    inServerName, inServerPort, inUseSSL, inUserName, inPassword,
754                                    inReadInterval, outEmailAddress, outCustom, outServerName,
755                                    outServerPort, outUseSSL, outUserName, outPassword,
756                                    allowAnonymous, mailingListActive, serviceContext);
757                    }
758                    else {
759                            mbMailingListLocalService.addMailingList(
760                                    category.getUserId(), category.getGroupId(),
761                                    category.getCategoryId(), emailAddress, inProtocol,
762                                    inServerName, inServerPort, inUseSSL, inUserName, inPassword,
763                                    inReadInterval, outEmailAddress, outCustom, outServerName,
764                                    outServerPort, outUseSSL, outUserName, outPassword,
765                                    allowAnonymous, mailingListActive, serviceContext);
766                    }
767    
768                    return category;
769            }
770    
771            @Override
772            public MBCategory updateStatus(long userId, long categoryId, int status)
773                    throws PortalException {
774    
775                    // Category
776    
777                    User user = userPersistence.findByPrimaryKey(userId);
778    
779                    MBCategory category = mbCategoryPersistence.findByPrimaryKey(
780                            categoryId);
781    
782                    category.setStatus(status);
783                    category.setStatusByUserId(user.getUserId());
784                    category.setStatusByUserName(user.getFullName());
785                    category.setStatusDate(new Date());
786    
787                    mbCategoryPersistence.update(category);
788    
789                    return category;
790            }
791    
792            protected long getParentCategoryId(long groupId, long parentCategoryId) {
793                    if ((parentCategoryId !=
794                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) &&
795                            (parentCategoryId != MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
796    
797                            MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
798                                    parentCategoryId);
799    
800                            if ((parentCategory == null) ||
801                                    (groupId != parentCategory.getGroupId())) {
802    
803                                    parentCategoryId =
804                                            MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
805                            }
806                    }
807    
808                    return parentCategoryId;
809            }
810    
811            protected long getParentCategoryId(
812                    MBCategory category, long parentCategoryId) {
813    
814                    if ((parentCategoryId ==
815                                    MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
816                            (parentCategoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
817    
818                            return parentCategoryId;
819                    }
820    
821                    if (category.getCategoryId() == parentCategoryId) {
822                            return category.getParentCategoryId();
823                    }
824    
825                    MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
826                            parentCategoryId);
827    
828                    if ((parentCategory == null) ||
829                            (category.getGroupId() != parentCategory.getGroupId())) {
830    
831                            return category.getParentCategoryId();
832                    }
833    
834                    List<Long> subcategoryIds = new ArrayList<Long>();
835    
836                    getSubcategoryIds(
837                            subcategoryIds, category.getGroupId(), category.getCategoryId());
838    
839                    if (subcategoryIds.contains(parentCategoryId)) {
840                            return category.getParentCategoryId();
841                    }
842    
843                    return parentCategoryId;
844            }
845    
846            protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
847                    throws PortalException {
848    
849                    if ((toCategoryId == MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) ||
850                            (toCategoryId == MBCategoryConstants.DISCUSSION_CATEGORY_ID)) {
851    
852                            return;
853                    }
854    
855                    List<MBCategory> categories = mbCategoryPersistence.findByG_P(
856                            fromCategory.getGroupId(), fromCategory.getCategoryId());
857    
858                    for (MBCategory category : categories) {
859                            mergeCategories(category, toCategoryId);
860                    }
861    
862                    List<MBThread> threads = mbThreadPersistence.findByG_C(
863                            fromCategory.getGroupId(), fromCategory.getCategoryId());
864    
865                    for (MBThread thread : threads) {
866    
867                            // Thread
868    
869                            thread.setCategoryId(toCategoryId);
870    
871                            mbThreadPersistence.update(thread);
872    
873                            List<MBMessage> messages = mbMessagePersistence.findByThreadId(
874                                    thread.getThreadId());
875    
876                            for (MBMessage message : messages) {
877    
878                                    // Message
879    
880                                    message.setCategoryId(toCategoryId);
881    
882                                    mbMessagePersistence.update(message);
883    
884                                    // Indexer
885    
886                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
887                                            MBMessage.class);
888    
889                                    indexer.reindex(message);
890                            }
891                    }
892    
893                    MBCategory toCategory = mbCategoryPersistence.findByPrimaryKey(
894                            toCategoryId);
895    
896                    toCategory.setThreadCount(
897                            fromCategory.getThreadCount() + toCategory.getThreadCount());
898                    toCategory.setMessageCount(
899                            fromCategory.getMessageCount() + toCategory.getMessageCount());
900    
901                    mbCategoryPersistence.update(toCategory);
902    
903                    mbCategoryLocalService.deleteCategory(fromCategory);
904            }
905    
906            protected void moveDependentsToTrash(
907                            User user, List<Object> categoriesAndThreads, long trashEntryId)
908                    throws PortalException {
909    
910                    for (Object object : categoriesAndThreads) {
911                            if (object instanceof MBThread) {
912    
913                                    // Thread
914    
915                                    MBThread thread = (MBThread)object;
916    
917                                    int oldStatus = thread.getStatus();
918    
919                                    if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
920                                            continue;
921                                    }
922    
923                                    thread.setStatus(WorkflowConstants.STATUS_IN_TRASH);
924    
925                                    mbThreadPersistence.update(thread);
926    
927                                    // Trash
928    
929                                    if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
930                                            trashVersionLocalService.addTrashVersion(
931                                                    trashEntryId, MBThread.class.getName(),
932                                                    thread.getThreadId(), oldStatus, null);
933                                    }
934    
935                                    // Threads
936    
937                                    mbThreadLocalService.moveDependentsToTrash(
938                                            user.getUserId(), thread.getThreadId(), trashEntryId);
939    
940                                    // Indexer
941    
942                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
943                                            MBThread.class);
944    
945                                    indexer.reindex(thread);
946                            }
947                            else if (object instanceof MBCategory) {
948    
949                                    // Category
950    
951                                    MBCategory category = (MBCategory)object;
952    
953                                    if (category.isInTrash()) {
954                                            continue;
955                                    }
956    
957                                    int oldStatus = category.getStatus();
958    
959                                    category.setStatus(WorkflowConstants.STATUS_IN_TRASH);
960    
961                                    mbCategoryPersistence.update(category);
962    
963                                    // Trash
964    
965                                    if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
966                                            trashVersionLocalService.addTrashVersion(
967                                                    trashEntryId, MBCategory.class.getName(),
968                                                    category.getCategoryId(), oldStatus, null);
969                                    }
970    
971                                    // Categories and threads
972    
973                                    moveDependentsToTrash(
974                                            user,
975                                            getCategoriesAndThreads(
976                                                    category.getGroupId(), category.getCategoryId()),
977                                            trashEntryId);
978                            }
979                    }
980            }
981    
982            protected void restoreDependentsFromTrash(
983                            User user, List<Object> categoriesAndThreads)
984                    throws PortalException {
985    
986                    for (Object object : categoriesAndThreads) {
987                            if (object instanceof MBThread) {
988    
989                                    // Thread
990    
991                                    MBThread thread = (MBThread)object;
992    
993                                    if (!thread.isInTrashImplicitly()) {
994                                            continue;
995                                    }
996    
997                                    TrashVersion trashVersion =
998                                            trashVersionLocalService.fetchVersion(
999                                                    MBThread.class.getName(), thread.getThreadId());
1000    
1001                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
1002    
1003                                    if (trashVersion != null) {
1004                                            oldStatus = trashVersion.getStatus();
1005                                    }
1006    
1007                                    thread.setStatus(oldStatus);
1008    
1009                                    mbThreadPersistence.update(thread);
1010    
1011                                    // Threads
1012    
1013                                    mbThreadLocalService.restoreDependentsFromTrash(
1014                                            user.getUserId(), thread.getThreadId());
1015    
1016                                    // Trash
1017    
1018                                    if (trashVersion != null) {
1019                                            trashVersionLocalService.deleteTrashVersion(trashVersion);
1020                                    }
1021    
1022                                    // Indexer
1023    
1024                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1025                                            MBThread.class);
1026    
1027                                    indexer.reindex(thread);
1028                            }
1029                            else if (object instanceof MBCategory) {
1030    
1031                                    // Category
1032    
1033                                    MBCategory category = (MBCategory)object;
1034    
1035                                    if (!category.isInTrashImplicitly()) {
1036                                            continue;
1037                                    }
1038    
1039                                    TrashVersion trashVersion =
1040                                            trashVersionLocalService.fetchVersion(
1041                                                    MBCategory.class.getName(), category.getCategoryId());
1042    
1043                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
1044    
1045                                    if (trashVersion != null) {
1046                                            oldStatus = trashVersion.getStatus();
1047                                    }
1048    
1049                                    category.setStatus(oldStatus);
1050    
1051                                    mbCategoryPersistence.update(category);
1052    
1053                                    // Categories and threads
1054    
1055                                    restoreDependentsFromTrash(
1056                                            user,
1057                                            getCategoriesAndThreads(
1058                                                    category.getGroupId(), category.getCategoryId()));
1059    
1060                                    // Trash
1061    
1062                                    if (trashVersion != null) {
1063                                            trashVersionLocalService.deleteTrashVersion(trashVersion);
1064                                    }
1065                            }
1066                    }
1067            }
1068    
1069            protected void updateChildCategoriesDisplayStyle(
1070                            MBCategory category, String displayStyle)
1071                    throws PortalException {
1072    
1073                    List<MBCategory> categories = getCategories(
1074                            category.getGroupId(), category.getCategoryId(), QueryUtil.ALL_POS,
1075                            QueryUtil.ALL_POS);
1076    
1077                    for (MBCategory curCategory : categories) {
1078                            updateChildCategoriesDisplayStyle(curCategory, displayStyle);
1079    
1080                            curCategory.setDisplayStyle(displayStyle);
1081    
1082                            mbCategoryPersistence.update(curCategory);
1083                    }
1084            }
1085    
1086            protected void validate(String name) throws PortalException {
1087                    if (Validator.isNull(name)) {
1088                            throw new CategoryNameException();
1089                    }
1090            }
1091    
1092    }