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