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