1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.messageboards.service.impl;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.search.BooleanClauseOccur;
28  import com.liferay.portal.kernel.search.BooleanQuery;
29  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
30  import com.liferay.portal.kernel.search.Field;
31  import com.liferay.portal.kernel.search.Hits;
32  import com.liferay.portal.kernel.search.SearchEngineUtil;
33  import com.liferay.portal.kernel.search.SearchException;
34  import com.liferay.portal.kernel.search.TermQuery;
35  import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
36  import com.liferay.portal.kernel.util.GetterUtil;
37  import com.liferay.portal.kernel.util.Validator;
38  import com.liferay.portal.model.CompanyConstants;
39  import com.liferay.portal.model.ResourceConstants;
40  import com.liferay.portal.model.User;
41  import com.liferay.portal.util.PortalUtil;
42  import com.liferay.portlet.messageboards.CategoryNameException;
43  import com.liferay.portlet.messageboards.model.MBCategory;
44  import com.liferay.portlet.messageboards.model.MBMessage;
45  import com.liferay.portlet.messageboards.model.MBThread;
46  import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
47  import com.liferay.portlet.messageboards.service.base.MBCategoryLocalServiceBaseImpl;
48  import com.liferay.portlet.messageboards.util.Indexer;
49  
50  import java.util.ArrayList;
51  import java.util.Date;
52  import java.util.List;
53  
54  import org.apache.commons.logging.Log;
55  import org.apache.commons.logging.LogFactory;
56  
57  /**
58   * <a href="MBCategoryLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
59   *
60   * @author Brian Wing Shun Chan
61   *
62   */
63  public class MBCategoryLocalServiceImpl extends MBCategoryLocalServiceBaseImpl {
64  
65      public MBCategory addCategory(
66              long userId, long plid, long parentCategoryId, String name,
67              String description, boolean addCommunityPermissions,
68              boolean addGuestPermissions)
69          throws PortalException, SystemException {
70  
71          return addCategory(
72              null, userId, plid, parentCategoryId, name, description,
73              Boolean.valueOf(addCommunityPermissions),
74              Boolean.valueOf(addGuestPermissions), null, null);
75      }
76  
77      public MBCategory addCategory(
78              String uuid, long userId, long plid, long parentCategoryId,
79              String name, String description, boolean addCommunityPermissions,
80              boolean addGuestPermissions)
81          throws PortalException, SystemException {
82  
83          return addCategory(
84              uuid, userId, plid, parentCategoryId, name, description,
85              Boolean.valueOf(addCommunityPermissions),
86              Boolean.valueOf(addGuestPermissions), null, null);
87      }
88  
89      public MBCategory addCategory(
90              long userId, long plid, long parentCategoryId, String name,
91              String description, String[] communityPermissions,
92              String[] guestPermissions)
93          throws PortalException, SystemException {
94  
95          return addCategory(
96              null, userId, plid, parentCategoryId, name, description, null, null,
97              communityPermissions, guestPermissions);
98      }
99  
100     public MBCategory addCategory(
101             String uuid, long userId, long plid, long parentCategoryId,
102             String name, String description, Boolean addCommunityPermissions,
103             Boolean addGuestPermissions, String[] communityPermissions,
104             String[] guestPermissions)
105         throws PortalException, SystemException {
106 
107         // Category
108 
109         User user = userPersistence.findByPrimaryKey(userId);
110         long groupId = PortalUtil.getScopeGroupId(plid);
111         parentCategoryId = getParentCategoryId(groupId, parentCategoryId);
112         Date now = new Date();
113 
114         validate(name);
115 
116         long categoryId = counterLocalService.increment();
117 
118         MBCategory category = mbCategoryPersistence.create(categoryId);
119 
120         category.setUuid(uuid);
121         category.setGroupId(groupId);
122         category.setCompanyId(user.getCompanyId());
123         category.setUserId(user.getUserId());
124         category.setUserName(user.getFullName());
125         category.setCreateDate(now);
126         category.setModifiedDate(now);
127         category.setParentCategoryId(parentCategoryId);
128         category.setName(name);
129         category.setDescription(description);
130 
131         mbCategoryPersistence.update(category, false);
132 
133         // Resources
134 
135         if ((addCommunityPermissions != null) &&
136             (addGuestPermissions != null)) {
137 
138             addCategoryResources(
139                 category, addCommunityPermissions.booleanValue(),
140                 addGuestPermissions.booleanValue());
141         }
142         else {
143             addCategoryResources(
144                 category, communityPermissions, guestPermissions);
145         }
146 
147         return category;
148     }
149 
150     public void addCategoryResources(
151             long categoryId, boolean addCommunityPermissions,
152             boolean addGuestPermissions)
153         throws PortalException, SystemException {
154 
155         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
156             categoryId);
157 
158         addCategoryResources(
159             category, addCommunityPermissions, addGuestPermissions);
160     }
161 
162     public void addCategoryResources(
163             MBCategory category, boolean addCommunityPermissions,
164             boolean addGuestPermissions)
165         throws PortalException, SystemException {
166 
167         resourceLocalService.addResources(
168             category.getCompanyId(), category.getGroupId(),
169             category.getUserId(), MBCategory.class.getName(),
170             category.getCategoryId(), false, addCommunityPermissions,
171             addGuestPermissions);
172     }
173 
174     public void addCategoryResources(
175             long categoryId, String[] communityPermissions,
176             String[] guestPermissions)
177         throws PortalException, SystemException {
178 
179         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
180             categoryId);
181 
182         addCategoryResources(category, communityPermissions, guestPermissions);
183     }
184 
185     public void addCategoryResources(
186             MBCategory category, String[] communityPermissions,
187             String[] guestPermissions)
188         throws PortalException, SystemException {
189 
190         resourceLocalService.addModelResources(
191             category.getCompanyId(), category.getGroupId(),
192             category.getUserId(), MBCategory.class.getName(),
193             category.getCategoryId(), communityPermissions, guestPermissions);
194     }
195 
196     public void deleteCategories(long groupId)
197         throws PortalException, SystemException {
198 
199         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
200             groupId, MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID);
201 
202         for (MBCategory category : categories) {
203             deleteCategory(category);
204         }
205     }
206 
207     public void deleteCategory(long categoryId)
208         throws PortalException, SystemException {
209 
210         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
211             categoryId);
212 
213         deleteCategory(category);
214     }
215 
216     public void deleteCategory(MBCategory category)
217         throws PortalException, SystemException {
218 
219         // Categories
220 
221         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
222             category.getGroupId(), category.getCategoryId());
223 
224         for (MBCategory curCategory : categories) {
225             deleteCategory(curCategory);
226         }
227 
228         // Indexer
229 
230         try {
231             Indexer.deleteMessages(
232                 category.getCompanyId(), category.getCategoryId());
233         }
234         catch (SearchException se) {
235             _log.error("Deleting index " + category.getCategoryId(), se);
236         }
237 
238         // Threads
239 
240         mbThreadLocalService.deleteThreads(category.getCategoryId());
241 
242         // Resources
243 
244         resourceLocalService.deleteResource(
245             category.getCompanyId(), MBCategory.class.getName(),
246             ResourceConstants.SCOPE_INDIVIDUAL, category.getCategoryId());
247 
248         // Category
249 
250         mbCategoryPersistence.remove(category);
251     }
252 
253     public List<MBCategory> getCategories(long groupId, long parentCategoryId)
254         throws SystemException {
255 
256         return mbCategoryPersistence.findByG_P(groupId, parentCategoryId);
257     }
258 
259     public List<MBCategory> getCategories(
260             long groupId, long parentCategoryId, int start, int end)
261         throws SystemException {
262 
263         return mbCategoryPersistence.findByG_P(
264             groupId, parentCategoryId, start, end);
265     }
266 
267     public int getCategoriesCount(long groupId) throws SystemException {
268         return mbCategoryPersistence.countByGroupId(groupId);
269     }
270 
271     public int getCategoriesCount(long groupId, long parentCategoryId)
272         throws SystemException {
273 
274         return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
275     }
276 
277     public MBCategory getCategory(long categoryId)
278         throws PortalException, SystemException {
279 
280         return mbCategoryPersistence.findByPrimaryKey(categoryId);
281     }
282 
283     public void getSubcategoryIds(
284             List<Long> categoryIds, long groupId, long categoryId)
285         throws SystemException {
286 
287         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
288             groupId, categoryId);
289 
290         for (MBCategory category : categories) {
291             categoryIds.add(category.getCategoryId());
292 
293             getSubcategoryIds(
294                 categoryIds, category.getGroupId(), category.getCategoryId());
295         }
296     }
297 
298     public List<MBCategory> getSubscribedCategories(
299             long groupId, long userId, int start, int end)
300         throws SystemException {
301 
302         return mbCategoryFinder.findByS_G_U(groupId, userId, start, end);
303     }
304 
305     public int getSubscribedCategoriesCount(long groupId, long userId)
306         throws SystemException {
307 
308         return mbCategoryFinder.countByS_G_U(groupId, userId);
309     }
310 
311     public MBCategory getSystemCategory() throws SystemException {
312         long categoryId = CompanyConstants.SYSTEM;
313 
314         MBCategory category = mbCategoryPersistence.fetchByPrimaryKey(
315             categoryId);
316 
317         if (category == null) {
318             category = mbCategoryPersistence.create(categoryId);
319 
320             category.setCompanyId(CompanyConstants.SYSTEM);
321             category.setUserId(CompanyConstants.SYSTEM);
322 
323             mbCategoryPersistence.update(category, false);
324         }
325 
326         return category;
327     }
328 
329     public void reIndex(String[] ids) throws SystemException {
330         if (SearchEngineUtil.isIndexReadOnly()) {
331             return;
332         }
333 
334         long companyId = GetterUtil.getLong(ids[0]);
335 
336         try {
337             List<MBCategory> categories = mbCategoryPersistence.findByCompanyId(
338                 companyId);
339 
340             for (MBCategory category : categories) {
341                 long categoryId = category.getCategoryId();
342 
343                 List<MBMessage> messages =
344                     mbMessagePersistence.findByCategoryId(categoryId);
345 
346                 for (MBMessage message : messages) {
347                     long groupId = category.getGroupId();
348                     long userId = message.getUserId();
349                     String userName = message.getUserName();
350                     long threadId = message.getThreadId();
351                     long messageId = message.getMessageId();
352                     String title = message.getSubject();
353                     String content = message.getBody();
354 
355                     String[] tagsEntries = tagsEntryLocalService.getEntryNames(
356                         MBMessage.class.getName(), messageId);
357 
358                     try {
359                         Indexer.updateMessage(
360                             companyId, groupId, userId, userName, categoryId,
361                             threadId, messageId, title, content, tagsEntries);
362                     }
363                     catch (SearchException se) {
364                         _log.error("Reindexing " + messageId, se);
365                     }
366                 }
367             }
368         }
369         catch (SystemException se) {
370             throw se;
371         }
372         catch (Exception e) {
373             throw new SystemException(e);
374         }
375     }
376 
377     public Hits search(
378             long companyId, long groupId, long[] categoryIds, long threadId,
379             String keywords, int start, int end)
380         throws SystemException {
381 
382         try {
383             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
384 
385             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
386 
387             if (groupId > 0) {
388                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
389             }
390 
391             if ((categoryIds != null) && (categoryIds.length > 0)) {
392                 BooleanQuery categoryIdsQuery =
393                     BooleanQueryFactoryUtil.create();
394 
395                 for (long categoryId : categoryIds) {
396                     TermQuery termQuery = TermQueryFactoryUtil.create(
397                         "categoryId", categoryId);
398 
399                     categoryIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
400                 }
401 
402                 contextQuery.add(categoryIdsQuery, BooleanClauseOccur.MUST);
403             }
404 
405             if (threadId > 0) {
406                 contextQuery.addTerm("threadId", threadId);
407             }
408 
409             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
410 
411             if (Validator.isNotNull(keywords)) {
412                 searchQuery.addTerm(Field.USER_NAME, keywords);
413                 searchQuery.addTerm(Field.TITLE, keywords);
414                 searchQuery.addTerm(Field.CONTENT, keywords);
415                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
416             }
417 
418             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
419 
420             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
421 
422             if (searchQuery.clauses().size() > 0) {
423                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
424             }
425 
426             return SearchEngineUtil.search(companyId, fullQuery, start, end);
427         }
428         catch (Exception e) {
429             throw new SystemException(e);
430         }
431     }
432 
433     public MBCategory updateCategory(
434             long categoryId, long parentCategoryId, String name,
435             String description, boolean mergeWithParentCategory)
436         throws PortalException, SystemException {
437 
438         // Category
439 
440         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
441             categoryId);
442 
443         parentCategoryId = getParentCategoryId(category, parentCategoryId);
444 
445         validate(name);
446 
447         category.setModifiedDate(new Date());
448         category.setParentCategoryId(parentCategoryId);
449         category.setName(name);
450         category.setDescription(description);
451 
452         mbCategoryPersistence.update(category, false);
453 
454         // Merge categories
455 
456         if (mergeWithParentCategory &&
457             (categoryId != parentCategoryId) &&
458             (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID)) {
459 
460             mergeCategories(category, parentCategoryId);
461         }
462 
463         return category;
464     }
465 
466     protected long getParentCategoryId(long groupId, long parentCategoryId)
467         throws SystemException {
468 
469         if (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
470             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
471                 parentCategoryId);
472 
473             if ((parentCategory == null) ||
474                 (groupId != parentCategory.getGroupId())) {
475 
476                 parentCategoryId = MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
477             }
478         }
479 
480         return parentCategoryId;
481     }
482 
483     protected long getParentCategoryId(
484             MBCategory category, long parentCategoryId)
485         throws SystemException {
486 
487         if (parentCategoryId == MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
488             return parentCategoryId;
489         }
490 
491         if (category.getCategoryId() == parentCategoryId) {
492             return category.getParentCategoryId();
493         }
494         else {
495             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
496                 parentCategoryId);
497 
498             if ((parentCategory == null) ||
499                 (category.getGroupId() != parentCategory.getGroupId())) {
500 
501                 return category.getParentCategoryId();
502             }
503 
504             List<Long> subcategoryIds = new ArrayList<Long>();
505 
506             getSubcategoryIds(
507                 subcategoryIds, category.getGroupId(),
508                 category.getCategoryId());
509 
510             if (subcategoryIds.contains(parentCategoryId)) {
511                 return category.getParentCategoryId();
512             }
513 
514             return parentCategoryId;
515         }
516     }
517 
518     protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
519         throws PortalException, SystemException {
520 
521         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
522             fromCategory.getGroupId(), fromCategory.getCategoryId());
523 
524         for (MBCategory category : categories) {
525             mergeCategories(category, toCategoryId);
526         }
527 
528         List<MBThread> threads = mbThreadPersistence.findByCategoryId(
529             fromCategory.getCategoryId());
530 
531         for (MBThread thread : threads) {
532 
533             // Thread
534 
535             thread.setCategoryId(toCategoryId);
536 
537             mbThreadPersistence.update(thread, false);
538 
539             List<MBMessage> messages = mbMessagePersistence.findByThreadId(
540                 thread.getThreadId());
541 
542             for (MBMessage message : messages) {
543 
544                 // Message
545 
546                 message.setCategoryId(toCategoryId);
547 
548                 mbMessagePersistence.update(message, false);
549 
550                 // Indexer
551 
552                 try {
553                     if (!fromCategory.isDiscussion()) {
554                         String[] tagsEntries =
555                             tagsEntryLocalService.getEntryNames(
556                                 MBMessage.class.getName(),
557                                 message.getMessageId());
558 
559                         Indexer.updateMessage(
560                             message.getCompanyId(), fromCategory.getGroupId(),
561                             message.getUserId(), message.getUserName(),
562                             toCategoryId, message.getThreadId(),
563                             message.getMessageId(), message.getSubject(),
564                             message.getBody(), tagsEntries);
565                     }
566                 }
567                 catch (SearchException se) {
568                     _log.error("Indexing " + message.getMessageId(), se);
569                 }
570             }
571         }
572 
573         deleteCategory(fromCategory);
574     }
575 
576     public void subscribeCategory(long userId, long categoryId)
577         throws PortalException, SystemException {
578 
579         subscriptionLocalService.addSubscription(
580             userId, MBCategory.class.getName(), categoryId);
581     }
582 
583     public void unsubscribeCategory(long userId, long categoryId)
584         throws PortalException, SystemException {
585 
586         subscriptionLocalService.deleteSubscription(
587             userId, MBCategory.class.getName(), categoryId);
588     }
589 
590     protected void validate(String name) throws PortalException {
591         if (Validator.isNull(name)) {
592             throw new CategoryNameException();
593         }
594     }
595 
596     private static Log _log =
597         LogFactory.getLog(MBCategoryLocalServiceImpl.class);
598 
599 }