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