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