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, long parentCategoryId)
250         throws SystemException {
251 
252         return mbCategoryPersistence.findByG_P(groupId, parentCategoryId);
253     }
254 
255     public List<MBCategory> getCategories(
256             long groupId, long parentCategoryId, int start, int end)
257         throws SystemException {
258 
259         return mbCategoryPersistence.findByG_P(
260             groupId, parentCategoryId, start, end);
261     }
262 
263     public int getCategoriesCount(long groupId) throws SystemException {
264         return mbCategoryPersistence.countByGroupId(groupId);
265     }
266 
267     public int getCategoriesCount(long groupId, long parentCategoryId)
268         throws SystemException {
269 
270         return mbCategoryPersistence.countByG_P(groupId, parentCategoryId);
271     }
272 
273     public MBCategory getCategory(long categoryId)
274         throws PortalException, SystemException {
275 
276         return mbCategoryPersistence.findByPrimaryKey(categoryId);
277     }
278 
279     public void getSubcategoryIds(
280             List<Long> categoryIds, long groupId, long categoryId)
281         throws SystemException {
282 
283         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
284             groupId, categoryId);
285 
286         for (MBCategory category : categories) {
287             categoryIds.add(category.getCategoryId());
288 
289             getSubcategoryIds(
290                 categoryIds, category.getGroupId(), category.getCategoryId());
291         }
292     }
293 
294     public List<MBCategory> getSubscribedCategories(
295             long groupId, long userId, int start, int end)
296         throws SystemException {
297 
298         return mbCategoryFinder.findByS_G_U(groupId, userId, start, end);
299     }
300 
301     public int getSubscribedCategoriesCount(long groupId, long userId)
302         throws SystemException {
303 
304         return mbCategoryFinder.countByS_G_U(groupId, userId);
305     }
306 
307     public MBCategory getSystemCategory() throws SystemException {
308         long categoryId = CompanyConstants.SYSTEM;
309 
310         MBCategory category = mbCategoryPersistence.fetchByPrimaryKey(
311             categoryId);
312 
313         if (category == null) {
314             category = mbCategoryPersistence.create(categoryId);
315 
316             category.setCompanyId(CompanyConstants.SYSTEM);
317             category.setUserId(CompanyConstants.SYSTEM);
318 
319             mbCategoryPersistence.update(category, false);
320         }
321 
322         return category;
323     }
324 
325     public void reIndex(String[] ids) throws SystemException {
326         if (SearchEngineUtil.isIndexReadOnly()) {
327             return;
328         }
329 
330         long companyId = GetterUtil.getLong(ids[0]);
331 
332         try {
333             List<MBCategory> categories = mbCategoryPersistence.findByCompanyId(
334                 companyId);
335 
336             for (MBCategory category : categories) {
337                 long categoryId = category.getCategoryId();
338 
339                 List<MBMessage> messages =
340                     mbMessagePersistence.findByCategoryId(categoryId);
341 
342                 for (MBMessage message : messages) {
343                     long groupId = category.getGroupId();
344                     long userId = message.getUserId();
345                     String userName = message.getUserName();
346                     long threadId = message.getThreadId();
347                     long messageId = message.getMessageId();
348                     String title = message.getSubject();
349                     String content = message.getBody();
350                     Date modifiedDate = message.getModifiedDate();
351 
352                     String[] tagsEntries = tagsEntryLocalService.getEntryNames(
353                         MBMessage.class.getName(), messageId);
354 
355                     try {
356                         Indexer.updateMessage(
357                             companyId, groupId, userId, userName, categoryId,
358                             threadId, messageId, title, content, modifiedDate,
359                             tagsEntries);
360                     }
361                     catch (SearchException se) {
362                         _log.error("Reindexing " + messageId, se);
363                     }
364                 }
365             }
366         }
367         catch (SystemException se) {
368             throw se;
369         }
370         catch (Exception e) {
371             throw new SystemException(e);
372         }
373     }
374 
375     public Hits search(
376             long companyId, long groupId, long[] categoryIds, long threadId,
377             String keywords, int start, int end)
378         throws SystemException {
379 
380         try {
381             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
382 
383             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
384 
385             if (groupId > 0) {
386                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
387             }
388 
389             if ((categoryIds != null) && (categoryIds.length > 0)) {
390                 BooleanQuery categoryIdsQuery =
391                     BooleanQueryFactoryUtil.create();
392 
393                 for (long categoryId : categoryIds) {
394                     TermQuery termQuery = TermQueryFactoryUtil.create(
395                         "categoryId", categoryId);
396 
397                     categoryIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
398                 }
399 
400                 contextQuery.add(categoryIdsQuery, BooleanClauseOccur.MUST);
401             }
402 
403             if (threadId > 0) {
404                 contextQuery.addTerm("threadId", threadId);
405             }
406 
407             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
408 
409             if (Validator.isNotNull(keywords)) {
410                 searchQuery.addTerm(Field.USER_NAME, keywords);
411                 searchQuery.addTerm(Field.TITLE, keywords);
412                 searchQuery.addTerm(Field.CONTENT, keywords);
413                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
414             }
415 
416             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
417 
418             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
419 
420             if (searchQuery.clauses().size() > 0) {
421                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
422             }
423 
424             return SearchEngineUtil.search(companyId, fullQuery, start, end);
425         }
426         catch (Exception e) {
427             throw new SystemException(e);
428         }
429     }
430 
431     public MBCategory updateCategory(
432             long categoryId, long parentCategoryId, String name,
433             String description, boolean mergeWithParentCategory)
434         throws PortalException, SystemException {
435 
436         // Category
437 
438         MBCategory category = mbCategoryPersistence.findByPrimaryKey(
439             categoryId);
440 
441         parentCategoryId = getParentCategoryId(category, parentCategoryId);
442 
443         validate(name);
444 
445         category.setModifiedDate(new Date());
446         category.setParentCategoryId(parentCategoryId);
447         category.setName(name);
448         category.setDescription(description);
449 
450         mbCategoryPersistence.update(category, false);
451 
452         // Merge categories
453 
454         if (mergeWithParentCategory &&
455             (categoryId != parentCategoryId) &&
456             (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID)) {
457 
458             mergeCategories(category, parentCategoryId);
459         }
460 
461         return category;
462     }
463 
464     protected long getParentCategoryId(long groupId, long parentCategoryId)
465         throws SystemException {
466 
467         if (parentCategoryId != MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
468             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
469                 parentCategoryId);
470 
471             if ((parentCategory == null) ||
472                 (groupId != parentCategory.getGroupId())) {
473 
474                 parentCategoryId = MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
475             }
476         }
477 
478         return parentCategoryId;
479     }
480 
481     protected long getParentCategoryId(
482             MBCategory category, long parentCategoryId)
483         throws SystemException {
484 
485         if (parentCategoryId == MBCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
486             return parentCategoryId;
487         }
488 
489         if (category.getCategoryId() == parentCategoryId) {
490             return category.getParentCategoryId();
491         }
492         else {
493             MBCategory parentCategory = mbCategoryPersistence.fetchByPrimaryKey(
494                 parentCategoryId);
495 
496             if ((parentCategory == null) ||
497                 (category.getGroupId() != parentCategory.getGroupId())) {
498 
499                 return category.getParentCategoryId();
500             }
501 
502             List<Long> subcategoryIds = new ArrayList<Long>();
503 
504             getSubcategoryIds(
505                 subcategoryIds, category.getGroupId(),
506                 category.getCategoryId());
507 
508             if (subcategoryIds.contains(parentCategoryId)) {
509                 return category.getParentCategoryId();
510             }
511 
512             return parentCategoryId;
513         }
514     }
515 
516     protected void mergeCategories(MBCategory fromCategory, long toCategoryId)
517         throws PortalException, SystemException {
518 
519         List<MBCategory> categories = mbCategoryPersistence.findByG_P(
520             fromCategory.getGroupId(), fromCategory.getCategoryId());
521 
522         for (MBCategory category : categories) {
523             mergeCategories(category, toCategoryId);
524         }
525 
526         List<MBThread> threads = mbThreadPersistence.findByCategoryId(
527             fromCategory.getCategoryId());
528 
529         for (MBThread thread : threads) {
530 
531             // Thread
532 
533             thread.setCategoryId(toCategoryId);
534 
535             mbThreadPersistence.update(thread, false);
536 
537             List<MBMessage> messages = mbMessagePersistence.findByThreadId(
538                 thread.getThreadId());
539 
540             for (MBMessage message : messages) {
541 
542                 // Message
543 
544                 message.setCategoryId(toCategoryId);
545 
546                 mbMessagePersistence.update(message, false);
547 
548                 // Indexer
549 
550                 try {
551                     if (!fromCategory.isDiscussion()) {
552                         String[] tagsEntries =
553                             tagsEntryLocalService.getEntryNames(
554                                 MBMessage.class.getName(),
555                                 message.getMessageId());
556 
557                         Indexer.updateMessage(
558                             message.getCompanyId(), fromCategory.getGroupId(),
559                             message.getUserId(), message.getUserName(),
560                             toCategoryId, message.getThreadId(),
561                             message.getMessageId(), message.getSubject(),
562                             message.getBody(), message.getModifiedDate(),
563                             tagsEntries);
564                     }
565                 }
566                 catch (SearchException se) {
567                     _log.error("Indexing " + message.getMessageId(), se);
568                 }
569             }
570         }
571 
572         deleteCategory(fromCategory);
573     }
574 
575     public void subscribeCategory(long userId, long categoryId)
576         throws PortalException, SystemException {
577 
578         subscriptionLocalService.addSubscription(
579             userId, MBCategory.class.getName(), categoryId);
580     }
581 
582     public void unsubscribeCategory(long userId, long categoryId)
583         throws PortalException, SystemException {
584 
585         subscriptionLocalService.deleteSubscription(
586             userId, MBCategory.class.getName(), categoryId);
587     }
588 
589     protected void validate(String name) throws PortalException {
590         if (Validator.isNull(name)) {
591             throw new CategoryNameException();
592         }
593     }
594 
595     private static Log _log =
596         LogFactoryUtil.getLog(MBCategoryLocalServiceImpl.class);
597 
598 }