1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portlet.messageboards.service.impl;
21  
22  import com.liferay.portal.PortalException;
23  import com.liferay.portal.SystemException;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.search.BooleanClauseOccur;
27  import com.liferay.portal.kernel.search.BooleanQuery;
28  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
29  import com.liferay.portal.kernel.search.Field;
30  import com.liferay.portal.kernel.search.Hits;
31  import com.liferay.portal.kernel.search.SearchEngineUtil;
32  import com.liferay.portal.kernel.search.SearchException;
33  import com.liferay.portal.kernel.search.TermQuery;
34  import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
35  import com.liferay.portal.kernel.util.GetterUtil;
36  import com.liferay.portal.kernel.util.Validator;
37  import com.liferay.portal.model.CompanyConstants;
38  import com.liferay.portal.model.ResourceConstants;
39  import com.liferay.portal.model.User;
40  import com.liferay.portal.util.PortalUtil;
41  import com.liferay.portlet.messageboards.CategoryNameException;
42  import com.liferay.portlet.messageboards.model.MBCategory;
43  import com.liferay.portlet.messageboards.model.MBMessage;
44  import com.liferay.portlet.messageboards.model.MBThread;
45  import com.liferay.portlet.messageboards.model.impl.MBCategoryImpl;
46  import com.liferay.portlet.messageboards.service.base.MBCategoryLocalServiceBaseImpl;
47  import com.liferay.portlet.messageboards.util.Indexer;
48  
49  import java.util.ArrayList;
50  import java.util.Date;
51  import java.util.List;
52  
53  /**
54   * <a href="MBCategoryLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
55   *
56   * @author Brian Wing Shun Chan
57   *
58   */
59  public class MBCategoryLocalServiceImpl extends MBCategoryLocalServiceBaseImpl {
60  
61      public MBCategory addCategory(
62              long userId, long plid, long parentCategoryId, String name,
63              String description, boolean addCommunityPermissions,
64              boolean addGuestPermissions)
65          throws PortalException, SystemException {
66  
67          return addCategory(
68              null, userId, plid, parentCategoryId, name, description,
69              Boolean.valueOf(addCommunityPermissions),
70              Boolean.valueOf(addGuestPermissions), null, null);
71      }
72  
73      public MBCategory addCategory(
74              String uuid, long userId, long plid, long parentCategoryId,
75              String name, String description, boolean addCommunityPermissions,
76              boolean addGuestPermissions)
77          throws PortalException, SystemException {
78  
79          return addCategory(
80              uuid, userId, plid, parentCategoryId, name, description,
81              Boolean.valueOf(addCommunityPermissions),
82              Boolean.valueOf(addGuestPermissions), null, null);
83      }
84  
85      public MBCategory addCategory(
86              long userId, long plid, long parentCategoryId, String name,
87              String description, String[] communityPermissions,
88              String[] guestPermissions)
89          throws PortalException, SystemException {
90  
91          return addCategory(
92              null, userId, plid, parentCategoryId, name, description, null, null,
93              communityPermissions, guestPermissions);
94      }
95  
96      public MBCategory addCategory(
97              String uuid, long userId, long plid, long parentCategoryId,
98              String name, String description, Boolean addCommunityPermissions,
99              Boolean addGuestPermissions, String[] communityPermissions,
100             String[] guestPermissions)
101         throws PortalException, SystemException {
102 
103         // Category
104 
105         User user = userPersistence.findByPrimaryKey(userId);
106         long groupId = PortalUtil.getScopeGroupId(plid);
107         parentCategoryId = getParentCategoryId(groupId, parentCategoryId);
108         Date now = new Date();
109 
110         validate(name);
111 
112         long categoryId = counterLocalService.increment();
113 
114         MBCategory category = mbCategoryPersistence.create(categoryId);
115 
116         category.setUuid(uuid);
117         category.setGroupId(groupId);
118         category.setCompanyId(user.getCompanyId());
119         category.setUserId(user.getUserId());
120         category.setUserName(user.getFullName());
121         category.setCreateDate(now);
122         category.setModifiedDate(now);
123         category.setParentCategoryId(parentCategoryId);
124         category.setName(name);
125         category.setDescription(description);
126 
127         mbCategoryPersistence.update(category, false);
128 
129         // Resources
130 
131         if ((addCommunityPermissions != null) &&
132             (addGuestPermissions != null)) {
133 
134             addCategoryResources(
135                 category, addCommunityPermissions.booleanValue(),
136                 addGuestPermissions.booleanValue());
137         }
138         else {
139             addCategoryResources(
140                 category, communityPermissions, guestPermissions);
141         }
142 
143         return category;
144     }
145 
146     public void addCategoryResources(
147             long categoryId, boolean addCommunityPermissions,
148             boolean addGuestPermissions)
149         throws PortalException, SystemException {
150 
151         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
152             categoryId);
153 
154         addCategoryResources(
155             category, addCommunityPermissions, addGuestPermissions);
156     }
157 
158     public void addCategoryResources(
159             MBCategory category, boolean addCommunityPermissions,
160             boolean addGuestPermissions)
161         throws PortalException, SystemException {
162 
163         resourceLocalService.addResources(
164             category.getCompanyId(), category.getGroupId(),
165             category.getUserId(), MBCategory.class.getName(),
166             category.getCategoryId(), false, addCommunityPermissions,
167             addGuestPermissions);
168     }
169 
170     public void addCategoryResources(
171             long categoryId, String[] communityPermissions,
172             String[] guestPermissions)
173         throws PortalException, SystemException {
174 
175         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
176             categoryId);
177 
178         addCategoryResources(category, communityPermissions, guestPermissions);
179     }
180 
181     public void addCategoryResources(
182             MBCategory category, String[] communityPermissions,
183             String[] guestPermissions)
184         throws PortalException, SystemException {
185 
186         resourceLocalService.addModelResources(
187             category.getCompanyId(), category.getGroupId(),
188             category.getUserId(), MBCategory.class.getName(),
189             category.getCategoryId(), communityPermissions, guestPermissions);
190     }
191 
192     public void deleteCategories(long groupId)
193         throws PortalException, SystemException {
194 
195         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
196             groupId, MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID);
197 
198         for (MBCategory category : categories) {
199             deleteCategory(category);
200         }
201     }
202 
203     public void deleteCategory(long categoryId)
204         throws PortalException, SystemException {
205 
206         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
207             categoryId);
208 
209         deleteCategory(category);
210     }
211 
212     public void deleteCategory(MBCategory category)
213         throws PortalException, SystemException {
214 
215         // Categories
216 
217         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
218             category.getGroupId(), category.getCategoryId());
219 
220         for (MBCategory curCategory : categories) {
221             deleteCategory(curCategory);
222         }
223 
224         // Indexer
225 
226         try {
227             Indexer.deleteMessages(
228                 category.getCompanyId(), category.getCategoryId());
229         }
230         catch (SearchException se) {
231             _log.error("Deleting index " + category.getCategoryId(), se);
232         }
233 
234         // Threads
235 
236         mbThreadLocalService.deleteThreads(category.getCategoryId());
237 
238         // Resources
239 
240         resourceLocalService.deleteResource(
241             category.getCompanyId(), MBCategory.class.getName(),
242             ResourceConstants.SCOPE_INDIVIDUAL, category.getCategoryId());
243 
244         // Category
245 
246         mbCategoryPersistence.remove(category);
247     }
248 
249     public List<MBCategory> getCategories(long groupId) throws SystemException {
250         return mbCategoryPersistence.findByGroupId(groupId);
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             reIndexCategories(companyId);
338         }
339         catch (SystemException se) {
340             throw se;
341         }
342         catch (Exception e) {
343             throw new SystemException(e);
344         }
345     }
346 
347     public Hits search(
348             long companyId, long groupId, long[] categoryIds, long threadId,
349             String keywords, int start, int end)
350         throws SystemException {
351 
352         try {
353             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
354 
355             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
356 
357             if (groupId > 0) {
358                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
359             }
360 
361             if ((categoryIds != null) && (categoryIds.length > 0)) {
362                 BooleanQuery categoryIdsQuery =
363                     BooleanQueryFactoryUtil.create();
364 
365                 for (long categoryId : categoryIds) {
366                     TermQuery termQuery = TermQueryFactoryUtil.create(
367                         "categoryId", categoryId);
368 
369                     categoryIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
370                 }
371 
372                 contextQuery.add(categoryIdsQuery, BooleanClauseOccur.MUST);
373             }
374 
375             if (threadId > 0) {
376                 contextQuery.addTerm("threadId", threadId);
377             }
378 
379             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
380 
381             if (Validator.isNotNull(keywords)) {
382                 searchQuery.addTerm(Field.USER_NAME, keywords);
383                 searchQuery.addTerm(Field.TITLE, keywords);
384                 searchQuery.addTerm(Field.CONTENT, keywords);
385                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
386             }
387 
388             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
389 
390             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
391 
392             if (searchQuery.clauses().size() > 0) {
393                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
394             }
395 
396             return SearchEngineUtil.search(companyId, fullQuery, start, end);
397         }
398         catch (Exception e) {
399             throw new SystemException(e);
400         }
401     }
402 
403     public MBCategory updateCategory(
404             long categoryId, long parentCategoryId, String name,
405             String description, boolean mergeWithParentCategory)
406         throws PortalException, SystemException {
407 
408         // Category
409 
410         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
411             categoryId);
412 
413         parentCategoryId = getParentCategoryId(category, parentCategoryId);
414 
415         validate(name);
416 
417         category.setModifiedDate(new Date());
418         category.setParentCategoryId(parentCategoryId);
419         category.setName(name);
420         category.setDescription(description);
421 
422         mbCategoryPersistence.update(category, false);
423 
424         // Merge categories
425 
426         if (mergeWithParentCategory &&
427             (categoryId != parentCategoryId) &&
428             (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID)) {
429 
430             mergeCategories(category, parentCategoryId);
431         }
432 
433         return category;
434     }
435 
436     protected long getParentCategoryId(long groupId, long parentCategoryId)
437         throws SystemException {
438 
439         if (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
440             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
441                 parentCategoryId);
442 
443             if ((parentCategory == null) ||
444                 (groupId != parentCategory.getGroupId())) {
445 
446                 parentCategoryId = MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
447             }
448         }
449 
450         return parentCategoryId;
451     }
452 
453     protected long getParentCategoryId(
454             MBCategory category, long parentCategoryId)
455         throws SystemException {
456 
457         if (parentCategoryId == MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
458             return parentCategoryId;
459         }
460 
461         if (category.getCategoryId() == parentCategoryId) {
462             return category.getParentCategoryId();
463         }
464         else {
465             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
466                 parentCategoryId);
467 
468             if ((parentCategory == null) ||
469                 (category.getGroupId() != parentCategory.getGroupId())) {
470 
471                 return category.getParentCategoryId();
472             }
473 
474             List<Long> subcategoryIds = new ArrayList<Long>();
475 
476             getSubcategoryIds(
477                 subcategoryIds, category.getGroupId(),
478                 category.getCategoryId());
479 
480             if (subcategoryIds.contains(parentCategoryId)) {
481                 return category.getParentCategoryId();
482             }
483 
484             return parentCategoryId;
485         }
486     }
487 
488     protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
489         throws PortalException, SystemException {
490 
491         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
492             fromCategory.getGroupId(), fromCategory.getCategoryId());
493 
494         for (MBCategory category : categories) {
495             mergeCategories(category, toCategoryId);
496         }
497 
498         List<MBThread> threads = mbThreadPersistence.findByCategoryId(
499             fromCategory.getCategoryId());
500 
501         for (MBThread thread : threads) {
502 
503             // Thread
504 
505             thread.setCategoryId(toCategoryId);
506 
507             mbThreadPersistence.update(thread, false);
508 
509             List<MBMessage> messages = mbMessagePersistence.findByThreadId(
510                 thread.getThreadId());
511 
512             for (MBMessage message : messages) {
513 
514                 // Message
515 
516                 message.setCategoryId(toCategoryId);
517 
518                 mbMessagePersistence.update(message, false);
519 
520                 // Indexer
521 
522                 mbMessageLocalService.reIndex(message);
523             }
524         }
525 
526         deleteCategory(fromCategory);
527     }
528 
529     public void subscribeCategory(long userId, long categoryId)
530         throws PortalException, SystemException {
531 
532         subscriptionLocalService.addSubscription(
533             userId, MBCategory.class.getName(), categoryId);
534     }
535 
536     public void unsubscribeCategory(long userId, long categoryId)
537         throws PortalException, SystemException {
538 
539         subscriptionLocalService.deleteSubscription(
540             userId, MBCategory.class.getName(), categoryId);
541     }
542 
543     protected void reIndexCategories(long companyId) throws SystemException {
544         int categoryCount = mbCategoryPersistence.countByCompanyId(companyId);
545 
546         int categoryPages = categoryCount / Indexer.DEFAULT_INTERVAL;
547 
548         for (int i = 0; i <= categoryPages; i++) {
549             int categoryStart = (i * Indexer.DEFAULT_INTERVAL);
550             int categoryEnd = categoryStart + Indexer.DEFAULT_INTERVAL;
551 
552             reIndexCategories(companyId, categoryStart, categoryEnd);
553         }
554     }
555 
556     protected void reIndexCategories(
557             long companyId, int categoryStart, int categoryEnd)
558         throws SystemException {
559 
560         List<MBCategory> categories = mbCategoryPersistence.findByCompanyId(
561             companyId, categoryStart, categoryEnd);
562 
563         for (MBCategory category : categories) {
564             long categoryId = category.getCategoryId();
565 
566             int messageCount = mbMessagePersistence.countByCategoryId(
567                 categoryId);
568 
569             int messagePages = messageCount / Indexer.DEFAULT_INTERVAL;
570 
571             for (int i = 0; i <= messagePages; i++) {
572                 int messageStart = (i * Indexer.DEFAULT_INTERVAL);
573                 int messageEnd = messageStart + Indexer.DEFAULT_INTERVAL;
574 
575                 reIndexMessages(categoryId, messageStart, messageEnd);
576             }
577         }
578     }
579 
580     protected void reIndexMessages(
581             long categoryId, int messageStart, int messageEnd)
582         throws SystemException {
583 
584         List<MBMessage> messages = mbMessagePersistence.findByCategoryId(
585             categoryId, messageStart, messageEnd);
586 
587         for (MBMessage message : messages) {
588             mbMessageLocalService.reIndex(message);
589         }
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         LogFactoryUtil.getLog(MBCategoryLocalServiceImpl.class);
600 
601 }