1
22
23 package com.liferay.portlet.blogs.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.ArrayUtil;
30 import com.liferay.portal.kernel.util.ContentTypes;
31 import com.liferay.portal.kernel.util.GetterUtil;
32 import com.liferay.portal.kernel.util.OrderByComparator;
33 import com.liferay.portal.kernel.util.StringMaker;
34 import com.liferay.portal.kernel.util.Validator;
35 import com.liferay.portal.lucene.LuceneFields;
36 import com.liferay.portal.lucene.LuceneUtil;
37 import com.liferay.portal.model.Group;
38 import com.liferay.portal.model.User;
39 import com.liferay.portal.model.impl.ResourceImpl;
40 import com.liferay.portal.service.ResourceLocalServiceUtil;
41 import com.liferay.portal.service.persistence.GroupUtil;
42 import com.liferay.portal.service.persistence.UserUtil;
43 import com.liferay.portal.theme.ThemeDisplay;
44 import com.liferay.portal.util.PortalUtil;
45 import com.liferay.portlet.blogs.EntryContentException;
46 import com.liferay.portlet.blogs.EntryDisplayDateException;
47 import com.liferay.portlet.blogs.EntryTitleException;
48 import com.liferay.portlet.blogs.NoSuchCategoryException;
49 import com.liferay.portlet.blogs.model.BlogsCategory;
50 import com.liferay.portlet.blogs.model.BlogsEntry;
51 import com.liferay.portlet.blogs.model.BlogsStatsUser;
52 import com.liferay.portlet.blogs.model.impl.BlogsCategoryImpl;
53 import com.liferay.portlet.blogs.service.BlogsStatsUserLocalServiceUtil;
54 import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
55 import com.liferay.portlet.blogs.service.persistence.BlogsCategoryUtil;
56 import com.liferay.portlet.blogs.service.persistence.BlogsEntryFinder;
57 import com.liferay.portlet.blogs.service.persistence.BlogsEntryUtil;
58 import com.liferay.portlet.blogs.service.persistence.BlogsStatsUserUtil;
59 import com.liferay.portlet.blogs.util.Indexer;
60 import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
61 import com.liferay.portlet.ratings.service.RatingsStatsLocalServiceUtil;
62 import com.liferay.portlet.tags.service.TagsAssetLocalServiceUtil;
63 import com.liferay.util.Http;
64 import com.liferay.util.HttpUtil;
65 import com.liferay.util.lucene.HitsImpl;
66
67 import java.io.IOException;
68
69 import java.util.Date;
70 import java.util.Iterator;
71 import java.util.List;
72
73 import org.apache.commons.logging.Log;
74 import org.apache.commons.logging.LogFactory;
75 import org.apache.lucene.document.Document;
76 import org.apache.lucene.index.IndexWriter;
77 import org.apache.lucene.index.Term;
78 import org.apache.lucene.search.BooleanClause;
79 import org.apache.lucene.search.BooleanQuery;
80 import org.apache.lucene.search.Searcher;
81 import org.apache.lucene.search.TermQuery;
82
83
91 public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
92
93 public BlogsEntry addEntry(
94 long userId, long plid, long categoryId, String title,
95 String content, int displayDateMonth, int displayDateDay,
96 int displayDateYear, int displayDateHour, int displayDateMinute,
97 ThemeDisplay themeDisplay, String[] tagsEntries,
98 boolean addCommunityPermissions, boolean addGuestPermissions)
99 throws PortalException, SystemException {
100
101 return addEntry(
102 userId, plid, categoryId, title, content, displayDateMonth,
103 displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
104 themeDisplay, tagsEntries, Boolean.valueOf(addCommunityPermissions),
105 Boolean.valueOf(addGuestPermissions), null, null);
106 }
107
108 public BlogsEntry addEntry(
109 long userId, long plid, long categoryId, String title,
110 String content, int displayDateMonth, int displayDateDay,
111 int displayDateYear, int displayDateHour, int displayDateMinute,
112 ThemeDisplay themeDisplay, String[] tagsEntries,
113 String[] communityPermissions, String[] guestPermissions)
114 throws PortalException, SystemException {
115
116 return addEntry(
117 userId, plid, categoryId, title, content, displayDateMonth,
118 displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
119 themeDisplay, tagsEntries, null, null, communityPermissions,
120 guestPermissions);
121 }
122
123 public BlogsEntry addEntry(
124 long userId, long plid, long categoryId, String title,
125 String content, int displayDateMonth, int displayDateDay,
126 int displayDateYear, int displayDateHour, int displayDateMinute,
127 ThemeDisplay themeDisplay, String[] tagsEntries,
128 Boolean addCommunityPermissions, Boolean addGuestPermissions,
129 String[] communityPermissions, String[] guestPermissions)
130 throws PortalException, SystemException {
131
132
134 User user = UserUtil.findByPrimaryKey(userId);
135 long groupId = PortalUtil.getPortletGroupId(plid);
136 categoryId = getCategoryId(user.getCompanyId(), categoryId);
137 Date now = new Date();
138
139 Date displayDate = PortalUtil.getDate(
140 displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
141 displayDateMinute, user.getTimeZone(),
142 new EntryDisplayDateException());
143
144 validate(title, content);
145
146 long entryId = CounterLocalServiceUtil.increment();
147
148 BlogsEntry entry = BlogsEntryUtil.create(entryId);
149
150 entry.setGroupId(groupId);
151 entry.setCompanyId(user.getCompanyId());
152 entry.setUserId(user.getUserId());
153 entry.setUserName(user.getFullName());
154 entry.setCreateDate(now);
155 entry.setModifiedDate(now);
156 entry.setCategoryId(categoryId);
157 entry.setTitle(title);
158 entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
159 entry.setContent(content);
160 entry.setDisplayDate(displayDate);
161
162 BlogsEntryUtil.update(entry);
163
164
166 if ((addCommunityPermissions != null) &&
167 (addGuestPermissions != null)) {
168
169 addEntryResources(
170 entry, addCommunityPermissions.booleanValue(),
171 addGuestPermissions.booleanValue());
172 }
173 else {
174 addEntryResources(entry, communityPermissions, guestPermissions);
175 }
176
177
179 BlogsStatsUserLocalServiceUtil.updateStatsUser(
180 entry.getGroupId(), userId, now);
181
182
184 updateTagsAsset(userId, entry, tagsEntries);
185
186
188 try {
189 Indexer.addEntry(
190 entry.getCompanyId(), entry.getGroupId(), userId, categoryId,
191 entryId, title, content);
192 }
193 catch (IOException ioe) {
194 _log.error("Indexing " + entryId, ioe);
195 }
196
197
199 pingGoogle(entry, themeDisplay);
200
201 return entry;
202 }
203
204 public void addEntryResources(
205 long entryId, boolean addCommunityPermissions,
206 boolean addGuestPermissions)
207 throws PortalException, SystemException {
208
209 BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
210
211 addEntryResources(entry, addCommunityPermissions, addGuestPermissions);
212 }
213
214 public void addEntryResources(
215 BlogsEntry entry, boolean addCommunityPermissions,
216 boolean addGuestPermissions)
217 throws PortalException, SystemException {
218
219 ResourceLocalServiceUtil.addResources(
220 entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
221 BlogsEntry.class.getName(), entry.getEntryId(), false,
222 addCommunityPermissions, addGuestPermissions);
223 }
224
225 public void addEntryResources(
226 long entryId, String[] communityPermissions,
227 String[] guestPermissions)
228 throws PortalException, SystemException {
229
230 BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
231
232 addEntryResources(entry, communityPermissions, guestPermissions);
233 }
234
235 public void addEntryResources(
236 BlogsEntry entry, String[] communityPermissions,
237 String[] guestPermissions)
238 throws PortalException, SystemException {
239
240 ResourceLocalServiceUtil.addModelResources(
241 entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
242 BlogsEntry.class.getName(), entry.getEntryId(),
243 communityPermissions, guestPermissions);
244 }
245
246 public void deleteEntries(long groupId)
247 throws PortalException, SystemException {
248
249 Iterator itr = BlogsEntryUtil.findByGroupId(groupId).iterator();
250
251 while (itr.hasNext()) {
252 BlogsEntry entry = (BlogsEntry)itr.next();
253
254 deleteEntry(entry);
255 }
256 }
257
258 public void deleteEntry(long entryId)
259 throws PortalException, SystemException {
260
261 BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
262
263 deleteEntry(entry);
264 }
265
266 public void deleteEntry(BlogsEntry entry)
267 throws PortalException, SystemException {
268
269
271 try {
272 Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId());
273 }
274 catch (IOException ioe) {
275 _log.error("Deleting index " + entry.getEntryId(), ioe);
276 }
277
278
280 TagsAssetLocalServiceUtil.deleteAsset(
281 BlogsEntry.class.getName(), entry.getEntryId());
282
283
285 RatingsStatsLocalServiceUtil.deleteStats(
286 BlogsEntry.class.getName(), entry.getEntryId());
287
288
290 MBMessageLocalServiceUtil.deleteDiscussionMessages(
291 BlogsEntry.class.getName(), entry.getEntryId());
292
293
295 ResourceLocalServiceUtil.deleteResource(
296 entry.getCompanyId(), BlogsEntry.class.getName(),
297 ResourceImpl.SCOPE_INDIVIDUAL, entry.getEntryId());
298
299
301 BlogsEntryUtil.remove(entry.getEntryId());
302 }
303
304 public int getCategoriesEntriesCount(List categoryIds)
305 throws SystemException {
306
307 return BlogsEntryFinder.countByCategoryIds(categoryIds);
308 }
309
310 public List getCompanyEntries(long companyId, int begin, int end)
311 throws SystemException {
312
313 return BlogsEntryUtil.findByCompanyId(companyId, begin, end);
314 }
315
316 public List getCompanyEntries(
317 long companyId, int begin, int end, OrderByComparator obc)
318 throws SystemException {
319
320 return BlogsEntryUtil.findByCompanyId(companyId, begin, end, obc);
321 }
322
323 public int getCompanyEntriesCount(long companyId) throws SystemException {
324 return BlogsEntryUtil.countByCompanyId(companyId);
325 }
326
327 public List getEntries(long categoryId, int begin, int end)
328 throws SystemException {
329
330 return BlogsEntryUtil.findByCategoryId(categoryId, begin, end);
331 }
332
333 public int getEntriesCount(long categoryId) throws SystemException {
334 return BlogsEntryUtil.countByCategoryId(categoryId);
335 }
336
337 public BlogsEntry getEntry(long entryId)
338 throws PortalException, SystemException {
339
340 return BlogsEntryUtil.findByPrimaryKey(entryId);
341 }
342
343 public BlogsEntry getEntry(long groupId, String urlTitle)
344 throws PortalException, SystemException {
345
346 return BlogsEntryUtil.findByG_UT(groupId, urlTitle);
347 }
348
349 public List getGroupEntries(long groupId, int begin, int end)
350 throws SystemException {
351
352 return BlogsEntryUtil.findByGroupId(groupId, begin, end);
353 }
354
355 public List getGroupEntries(
356 long groupId, int begin, int end, OrderByComparator obc)
357 throws SystemException {
358
359 return BlogsEntryUtil.findByGroupId(groupId, begin, end, obc);
360 }
361
362 public int getGroupEntriesCount(long groupId) throws SystemException {
363 return BlogsEntryUtil.countByGroupId(groupId);
364 }
365
366 public List getGroupUserEntries(
367 long groupId, long userId, int begin, int end)
368 throws SystemException {
369
370 return BlogsEntryUtil.findByG_U(groupId, userId, begin, end);
371 }
372
373 public int getGroupUserEntriesCount(long groupId, long userId)
374 throws SystemException {
375
376 return BlogsEntryUtil.countByG_U(groupId, userId);
377 }
378
379 public List getNoAssetEntries() throws SystemException {
380 return BlogsEntryFinder.findByNoAssets();
381 }
382
383 public List getOrganizationEntries(long organizationId, int begin, int end)
384 throws SystemException {
385
386 return BlogsEntryFinder.findByOrganizationId(
387 organizationId, begin, end);
388 }
389
390 public int getOrganizationEntriesCount(long organizationId)
391 throws SystemException {
392
393 return BlogsEntryFinder.countByOrganizationId(
394 organizationId);
395 }
396
397 public String getUrlTitle(long entryId, String title) {
398 String urlTitle = String.valueOf(entryId);
399
400 title = title.trim().toLowerCase();
401
402 if (Validator.isNull(title) || Validator.isNumber(title) ||
403 title.equals("rss")) {
404
405 return urlTitle;
406 }
407
408 char[] urlTitleCharArray = title.toCharArray();
409
410 for (int i = 0; i < urlTitleCharArray.length; i++) {
411 char oldChar = urlTitleCharArray[i];
412
413 char newChar = oldChar;
414
415 if ((oldChar == '_') || (Validator.isChar(oldChar)) ||
416 (Validator.isDigit(oldChar))) {
417
418 }
419 else if (ArrayUtil.contains(_URL_TITLE_REPLACE_CHARS, oldChar)) {
420 newChar = '_';
421 }
422 else {
423 return urlTitle;
424 }
425
426 if (oldChar != newChar) {
427 urlTitleCharArray[i] = newChar;
428 }
429 }
430
431 urlTitle = new String(urlTitleCharArray);
432
433 return urlTitle;
434 }
435
436 public void reIndex(String[] ids) throws SystemException {
437 long companyId = GetterUtil.getLong(ids[0]);
438
439 IndexWriter writer = null;
440
441 try {
442 writer = LuceneUtil.getWriter(companyId);
443
444 Iterator itr = BlogsEntryUtil.findByCompanyId(companyId).iterator();
445
446 while (itr.hasNext()) {
447 BlogsEntry entry = (BlogsEntry)itr.next();
448
449 long groupId = entry.getGroupId();
450 long userId = entry.getUserId();
451 long categoryId = entry.getCategoryId();
452 long entryId = entry.getEntryId();
453 String title = entry.getTitle();
454 String content = entry.getContent();
455
456 try {
457 Document doc = Indexer.getAddEntryDocument(
458 companyId, groupId, userId, categoryId, entryId, title,
459 content);
460
461 writer.addDocument(doc);
462 }
463 catch (Exception e1) {
464 _log.error("Reindexing " + entryId, e1);
465 }
466 }
467 }
468 catch (SystemException se) {
469 throw se;
470 }
471 catch (Exception e2) {
472 throw new SystemException(e2);
473 }
474 finally {
475 try {
476 if (writer != null) {
477 LuceneUtil.write(companyId);
478 }
479 }
480 catch (Exception e) {
481 _log.error(e);
482 }
483 }
484 }
485
486 public Hits search(
487 long companyId, long groupId, long userId, long[] categoryIds,
488 String keywords)
489 throws SystemException {
490
491 Searcher searcher = null;
492
493 try {
494 HitsImpl hits = new HitsImpl();
495
496 if (Validator.isNull(keywords)) {
497 return hits;
498 }
499
500 BooleanQuery contextQuery = new BooleanQuery();
501
502 LuceneUtil.addRequiredTerm(
503 contextQuery, LuceneFields.PORTLET_ID, Indexer.PORTLET_ID);
504
505 if (groupId > 0) {
506 LuceneUtil.addRequiredTerm(
507 contextQuery, LuceneFields.GROUP_ID, groupId);
508 }
509
510 if (userId > 0) {
511 LuceneUtil.addRequiredTerm(
512 contextQuery, LuceneFields.USER_ID, userId);
513 }
514
515 if ((categoryIds != null) && (categoryIds.length > 0)) {
516 BooleanQuery categoryIdsQuery = new BooleanQuery();
517
518 for (int i = 0; i < categoryIds.length; i++) {
519 Term term = new Term(
520 "categoryId", String.valueOf(categoryIds[i]));
521 TermQuery termQuery = new TermQuery(term);
522
523 categoryIdsQuery.add(termQuery, BooleanClause.Occur.SHOULD);
524 }
525
526 contextQuery.add(categoryIdsQuery, BooleanClause.Occur.MUST);
527 }
528
529 BooleanQuery searchQuery = new BooleanQuery();
530
531 LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT, keywords);
532
533 BooleanQuery fullQuery = new BooleanQuery();
534
535 fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
536 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
537
538 searcher = LuceneUtil.getSearcher(companyId);
539
540 hits.recordHits(searcher.search(fullQuery), searcher);
541
542 return hits;
543 }
544 catch (Exception e) {
545 return LuceneUtil.closeSearcher(searcher, keywords, e);
546 }
547 }
548
549 public BlogsEntry updateEntry(
550 long userId, long entryId, long categoryId, String title,
551 String content, int displayDateMonth, int displayDateDay,
552 int displayDateYear, int displayDateHour, int displayDateMinute,
553 ThemeDisplay themeDisplay, String[] tagsEntries)
554 throws PortalException, SystemException {
555
556
558 User user = UserUtil.findByPrimaryKey(userId);
559 categoryId = getCategoryId(user.getCompanyId(), categoryId);
560 Date now = new Date();
561
562 Date displayDate = PortalUtil.getDate(
563 displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
564 displayDateMinute, user.getTimeZone(),
565 new EntryDisplayDateException());
566
567 validate(title, content);
568
569 BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
570
571 entry.setModifiedDate(now);
572 entry.setCategoryId(categoryId);
573 entry.setTitle(title);
574 entry.setUrlTitle(
575 getUniqueUrlTitle(entryId, entry.getGroupId(), title));
576 entry.setContent(content);
577 entry.setDisplayDate(displayDate);
578
579 BlogsEntryUtil.update(entry);
580
581
583 BlogsStatsUser statsUser = BlogsStatsUserUtil.fetchByG_U(
584 entry.getGroupId(), entry.getUserId());
585
586 if (statsUser != null) {
587 statsUser.setLastPostDate(now);
588
589 BlogsStatsUserUtil.update(statsUser);
590 }
591
592
594 updateTagsAsset(userId, entry, tagsEntries);
595
596
598 try {
599 Indexer.updateEntry(
600 entry.getCompanyId(), entry.getGroupId(), userId, categoryId,
601 entryId, title, content);
602 }
603 catch (IOException ioe) {
604 _log.error("Indexing " + entryId, ioe);
605 }
606
607
609 pingGoogle(entry, themeDisplay);
610
611 return entry;
612 }
613
614 public void updateTagsAsset(
615 long userId, BlogsEntry entry, String[] tagsEntries)
616 throws PortalException, SystemException {
617
618 TagsAssetLocalServiceUtil.updateAsset(
619 userId, BlogsEntry.class.getName(), entry.getEntryId(), tagsEntries,
620 null, null, null, null, ContentTypes.TEXT_HTML, entry.getTitle(),
621 entry.getTitle(), entry.getTitle(), null, 0, 0);
622 }
623
624 protected long getCategoryId(long companyId, long categoryId)
625 throws PortalException, SystemException {
626
627 if (categoryId != BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
628
629
631 try {
632 BlogsCategory category =
633 BlogsCategoryUtil.findByPrimaryKey(categoryId);
634
635 if (companyId != category.getCompanyId()) {
636 categoryId = BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
637 }
638 }
639 catch (NoSuchCategoryException nsfe) {
640 categoryId = BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
641 }
642 }
643
644 return categoryId;
645 }
646
647 protected String getUniqueUrlTitle(
648 long entryId, long groupId, String title)
649 throws SystemException {
650
651 String urlTitle = getUrlTitle(entryId, title);
652
653 String newUrlTitle = new String(urlTitle);
654
655 for (int i = 1;; i++) {
656 BlogsEntry entry = BlogsEntryUtil.fetchByG_UT(groupId, newUrlTitle);
657
658 if ((entry == null) || (entry.getEntryId() == entryId)) {
659 break;
660 }
661 else {
662 newUrlTitle = urlTitle + "_" + i;
663 }
664 }
665
666 return newUrlTitle;
667 }
668
669 protected void pingGoogle(BlogsEntry entry, ThemeDisplay themeDisplay)
670 throws PortalException, SystemException {
671
672 if (themeDisplay == null) {
673 return;
674 }
675
676 Group group = GroupUtil.findByPrimaryKey(entry.getGroupId());
677
678 String portalURL = PortalUtil.getPortalURL(themeDisplay);
679
680 if ((portalURL.indexOf("://localhost") != -1) ||
681 (portalURL.indexOf("://127.0.0.1") != -1)) {
682
683 return;
684 }
685
686 String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
687
688 StringMaker sm = new StringMaker();
689
690 String name = group.getDescriptiveName();
691 String url = portalURL + layoutURL + "/blogs";
693 String changesURL = portalURL + layoutURL + "/blogs/rss";
694
695 sm.append("http://blogsearch.google.com/ping?name=");
696 sm.append(HttpUtil.encodeURL(name));
697 sm.append("&url=");
698 sm.append(HttpUtil.encodeURL(url));
699 sm.append("&changesURL=");
700 sm.append(HttpUtil.encodeURL(changesURL));
701
702 String location = sm.toString();
703
704 if (_log.isInfoEnabled()) {
705 _log.info("Pinging Google at " + location);
706 }
707
708 try {
709 String response = Http.URLtoString(sm.toString());
710
711 if (_log.isInfoEnabled()) {
712 _log.info("Google ping response: " + response);
713 }
714 }
715 catch (IOException ioe) {
716 _log.error("Unable to ping Google at " + location, ioe);
717 }
718 }
719
720 protected void validate(String title, String content)
721 throws PortalException {
722
723 if (Validator.isNull(title)) {
724 throw new EntryTitleException();
725 }
726 else if (Validator.isNull(content)) {
727 throw new EntryContentException();
728 }
729 }
730
731 private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
732 ' ', '.', '-', ',', '/', '\\', '\'', '\"'
733 };
734
735 private static Log _log =
736 LogFactory.getLog(BlogsEntryLocalServiceImpl.class);
737
738 }