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.Document;
28  import com.liferay.portal.kernel.search.Field;
29  import com.liferay.portal.kernel.search.Hits;
30  import com.liferay.portal.kernel.search.SearchEngineUtil;
31  import com.liferay.portal.kernel.search.SearchException;
32  import com.liferay.portal.kernel.util.GetterUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.CompanyConstants;
35  import com.liferay.portal.model.ResourceConstants;
36  import com.liferay.portal.model.User;
37  import com.liferay.portal.search.lucene.LuceneUtil;
38  import com.liferay.portal.util.PortalUtil;
39  import com.liferay.portlet.messageboards.CategoryNameException;
40  import com.liferay.portlet.messageboards.model.MBCategory;
41  import com.liferay.portlet.messageboards.model.MBMessage;
42  import com.liferay.portlet.messageboards.model.MBThread;
43  import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
44  import com.liferay.portlet.messageboards.service.base.MBCategoryLocalServiceBaseImpl;
45  import com.liferay.portlet.messageboards.util.Indexer;
46  
47  import java.util.ArrayList;
48  import java.util.Date;
49  import java.util.List;
50  
51  import org.apache.commons.logging.Log;
52  import org.apache.commons.logging.LogFactory;
53  import org.apache.lucene.index.Term;
54  import org.apache.lucene.search.BooleanClause;
55  import org.apache.lucene.search.BooleanQuery;
56  import org.apache.lucene.search.TermQuery;
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 = new BooleanQuery();
386 
387             LuceneUtil.addRequiredTerm(
388                 contextQuery, Field.PORTLET_ID, Indexer.PORTLET_ID);
389 
390             if (groupId > 0) {
391                 LuceneUtil.addRequiredTerm(
392                     contextQuery, Field.GROUP_ID, groupId);
393             }
394 
395             if ((categoryIds != null) && (categoryIds.length > 0)) {
396                 BooleanQuery categoryIdsQuery = new BooleanQuery();
397 
398                 for (int i = 0; i < categoryIds.length; i++) {
399                     Term term = new Term(
400                         "categoryId", String.valueOf(categoryIds[i]));
401                     TermQuery termQuery = new TermQuery(term);
402 
403                     categoryIdsQuery.add(termQuery, BooleanClause.Occur.SHOULD);
404                 }
405 
406                 contextQuery.add(categoryIdsQuery, BooleanClause.Occur.MUST);
407             }
408 
409             if (threadId > 0) {
410                 LuceneUtil.addTerm(contextQuery, "threadId", threadId);
411             }
412 
413             BooleanQuery searchQuery = new BooleanQuery();
414 
415             if (Validator.isNotNull(keywords)) {
416                 LuceneUtil.addTerm(searchQuery, Field.USER_NAME, keywords);
417                 LuceneUtil.addTerm(searchQuery, Field.TITLE, keywords);
418                 LuceneUtil.addTerm(searchQuery, Field.CONTENT, keywords);
419                 LuceneUtil.addTerm(searchQuery, Field.TAGS_ENTRIES, keywords);
420             }
421 
422             BooleanQuery fullQuery = new BooleanQuery();
423 
424             fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
425 
426             if (searchQuery.clauses().size() > 0) {
427                 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
428             }
429 
430             return SearchEngineUtil.search(
431                 companyId, fullQuery.toString(), start, end);
432         }
433         catch (Exception e) {
434             throw new SystemException(e);
435         }
436     }
437 
438     public MBCategory updateCategory(
439             long categoryId, long parentCategoryId, String name,
440             String description, boolean mergeWithParentCategory)
441         throws PortalException, SystemException {
442 
443         // Category
444 
445         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
446             categoryId);
447 
448         parentCategoryId = getParentCategoryId(category, parentCategoryId);
449 
450         validate(name);
451 
452         category.setModifiedDate(new Date());
453         category.setParentCategoryId(parentCategoryId);
454         category.setName(name);
455         category.setDescription(description);
456 
457         mbCategoryPersistence.update(category, false);
458 
459         // Merge categories
460 
461         if (mergeWithParentCategory &&
462             (categoryId != parentCategoryId) &&
463             (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID)) {
464 
465             mergeCategories(category, parentCategoryId);
466         }
467 
468         return category;
469     }
470 
471     protected long getParentCategoryId(long groupId, long parentCategoryId)
472         throws SystemException {
473 
474         if (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
475             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
476                 parentCategoryId);
477 
478             if ((parentCategory == null) ||
479                 (groupId != parentCategory.getGroupId())) {
480 
481                 parentCategoryId = MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
482             }
483         }
484 
485         return parentCategoryId;
486     }
487 
488     protected long getParentCategoryId(
489             MBCategory category, long parentCategoryId)
490         throws SystemException {
491 
492         if (parentCategoryId == MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
493             return parentCategoryId;
494         }
495 
496         if (category.getCategoryId() == parentCategoryId) {
497             return category.getParentCategoryId();
498         }
499         else {
500             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
501                 parentCategoryId);
502 
503             if ((parentCategory == null) ||
504                 (category.getGroupId() != parentCategory.getGroupId())) {
505 
506                 return category.getParentCategoryId();
507             }
508 
509             List<Long> subcategoryIds = new ArrayList<Long>();
510 
511             getSubcategoryIds(
512                 subcategoryIds, category.getGroupId(),
513                 category.getCategoryId());
514 
515             if (subcategoryIds.contains(parentCategoryId)) {
516                 return category.getParentCategoryId();
517             }
518 
519             return parentCategoryId;
520         }
521     }
522 
523     protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
524         throws PortalException, SystemException {
525 
526         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
527             fromCategory.getGroupId(), fromCategory.getCategoryId());
528 
529         for (MBCategory category : categories) {
530             mergeCategories(category, toCategoryId);
531         }
532 
533         List<MBThread> threads = mbThreadPersistence.findByCategoryId(
534             fromCategory.getCategoryId());
535 
536         for (MBThread thread : threads) {
537 
538             // Thread
539 
540             thread.setCategoryId(toCategoryId);
541 
542             mbThreadPersistence.update(thread, false);
543 
544             List<MBMessage> messages = mbMessagePersistence.findByThreadId(
545                 thread.getThreadId());
546 
547             for (MBMessage message : messages) {
548 
549                 // Message
550 
551                 message.setCategoryId(toCategoryId);
552 
553                 mbMessagePersistence.update(message, false);
554 
555                 // Lucene
556 
557                 try {
558                     if (!fromCategory.isDiscussion()) {
559                         String[] tagsEntries =
560                             tagsEntryLocalService.getEntryNames(
561                                 MBMessage.class.getName(),
562                                 message.getMessageId());
563 
564                         Indexer.updateMessage(
565                             message.getCompanyId(), fromCategory.getGroupId(),
566                             message.getUserName(), toCategoryId,
567                             message.getThreadId(), message.getMessageId(),
568                             message.getSubject(), message.getBody(),
569                             tagsEntries);
570                     }
571                 }
572                 catch (SearchException se) {
573                     _log.error("Indexing " + message.getMessageId(), se);
574                 }
575             }
576         }
577 
578         mbCategoryPersistence.remove(fromCategory.getCategoryId());
579     }
580 
581     public void subscribeCategory(long userId, long categoryId)
582         throws PortalException, SystemException {
583 
584         subscriptionLocalService.addSubscription(
585             userId, MBCategory.class.getName(), categoryId);
586     }
587 
588     public void unsubscribeCategory(long userId, long categoryId)
589         throws PortalException, SystemException {
590 
591         subscriptionLocalService.deleteSubscription(
592             userId, MBCategory.class.getName(), categoryId);
593     }
594 
595     protected void validate(String name) throws PortalException {
596         if (Validator.isNull(name)) {
597             throw new CategoryNameException();
598         }
599     }
600 
601     private static Log _log =
602         LogFactory.getLog(MBCategoryLocalServiceImpl.class);
603 
604 }