1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.blogs.service.impl;
16  
17  import com.liferay.portal.NoSuchUserException;
18  import com.liferay.portal.PortalException;
19  import com.liferay.portal.SystemException;
20  import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.messaging.DestinationNames;
24  import com.liferay.portal.kernel.messaging.Message;
25  import com.liferay.portal.kernel.messaging.MessageBusUtil;
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.util.ContentTypes;
34  import com.liferay.portal.kernel.util.GetterUtil;
35  import com.liferay.portal.kernel.util.HtmlUtil;
36  import com.liferay.portal.kernel.util.Http;
37  import com.liferay.portal.kernel.util.HttpUtil;
38  import com.liferay.portal.kernel.util.LocaleUtil;
39  import com.liferay.portal.kernel.util.OrderByComparator;
40  import com.liferay.portal.kernel.util.SetUtil;
41  import com.liferay.portal.kernel.util.StringBundler;
42  import com.liferay.portal.kernel.util.StringPool;
43  import com.liferay.portal.kernel.util.StringUtil;
44  import com.liferay.portal.kernel.util.Validator;
45  import com.liferay.portal.model.Company;
46  import com.liferay.portal.model.Group;
47  import com.liferay.portal.model.ResourceConstants;
48  import com.liferay.portal.model.User;
49  import com.liferay.portal.service.ServiceContext;
50  import com.liferay.portal.service.ServiceContextUtil;
51  import com.liferay.portal.util.Portal;
52  import com.liferay.portal.util.PortalUtil;
53  import com.liferay.portal.util.PortletKeys;
54  import com.liferay.portal.util.PropsValues;
55  import com.liferay.portlet.blogs.EntryContentException;
56  import com.liferay.portlet.blogs.EntryDisplayDateException;
57  import com.liferay.portlet.blogs.EntryTitleException;
58  import com.liferay.portlet.blogs.model.BlogsEntry;
59  import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
60  import com.liferay.portlet.blogs.social.BlogsActivityKeys;
61  import com.liferay.portlet.blogs.util.BlogsUtil;
62  import com.liferay.portlet.blogs.util.Indexer;
63  import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
64  import com.liferay.portlet.expando.model.ExpandoBridge;
65  
66  import java.io.IOException;
67  
68  import java.util.Date;
69  import java.util.HashMap;
70  import java.util.HashSet;
71  import java.util.List;
72  import java.util.Map;
73  import java.util.Set;
74  
75  import javax.portlet.PortletPreferences;
76  
77  import javax.xml.stream.XMLInputFactory;
78  import javax.xml.stream.XMLStreamReader;
79  
80  /**
81   * <a href="BlogsEntryLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
82   *
83   * @author Brian Wing Shun Chan
84   * @author Wilson S. Man
85   * @author Raymond Augé
86   * @author Thiago Moreira
87   */
88  public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
89  
90      public BlogsEntry addEntry(
91              long userId, String title, String content, int displayDateMonth,
92              int displayDateDay, int displayDateYear, int displayDateHour,
93              int displayDateMinute, boolean draft, boolean allowTrackbacks,
94              String[] trackbacks, ServiceContext serviceContext)
95          throws PortalException, SystemException {
96  
97          return addEntry(
98              null, userId, title, content, displayDateMonth, displayDateDay,
99              displayDateYear, displayDateHour, displayDateMinute, draft,
100             allowTrackbacks, trackbacks, serviceContext);
101     }
102 
103     public BlogsEntry addEntry(
104             String uuid, long userId, String title, String content,
105             int displayDateMonth, int displayDateDay, int displayDateYear,
106             int displayDateHour, int displayDateMinute, boolean draft,
107             boolean allowTrackbacks, String[] trackbacks,
108             ServiceContext serviceContext)
109         throws PortalException, SystemException {
110 
111         // Entry
112 
113         User user = userPersistence.findByPrimaryKey(userId);
114         long groupId = serviceContext.getScopeGroupId();
115 
116         Date displayDate = PortalUtil.getDate(
117             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
118             displayDateMinute, user.getTimeZone(),
119             new EntryDisplayDateException());
120 
121         Date now = new Date();
122 
123         validate(title, content);
124 
125         long entryId = counterLocalService.increment();
126 
127         BlogsEntry entry = blogsEntryPersistence.create(entryId);
128 
129         entry.setUuid(uuid);
130         entry.setGroupId(groupId);
131         entry.setCompanyId(user.getCompanyId());
132         entry.setUserId(user.getUserId());
133         entry.setUserName(user.getFullName());
134         entry.setCreateDate(serviceContext.getCreateDate(now));
135         entry.setModifiedDate(serviceContext.getModifiedDate(now));
136         entry.setTitle(title);
137         entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
138         entry.setContent(content);
139         entry.setDisplayDate(displayDate);
140         entry.setDraft(draft);
141         entry.setAllowTrackbacks(allowTrackbacks);
142         entry.setExpandoBridgeAttributes(serviceContext);
143 
144         blogsEntryPersistence.update(entry, false);
145 
146         // Resources
147 
148         if (serviceContext.getAddCommunityPermissions() ||
149             serviceContext.getAddGuestPermissions()) {
150 
151             addEntryResources(
152                 entry, serviceContext.getAddCommunityPermissions(),
153                 serviceContext.getAddGuestPermissions());
154         }
155         else {
156             addEntryResources(
157                 entry, serviceContext.getCommunityPermissions(),
158                 serviceContext.getGuestPermissions());
159         }
160 
161         // Statistics
162 
163         if (!draft) {
164             blogsStatsUserLocalService.updateStatsUser(groupId, userId, now);
165         }
166 
167         // Message boards
168 
169         if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
170             mbMessageLocalService.addDiscussionMessage(
171                 userId, entry.getUserName(), BlogsEntry.class.getName(),
172                 entryId);
173         }
174 
175         // Social
176 
177         if (!draft) {
178             socialActivityLocalService.addUniqueActivity(
179                 userId, groupId, BlogsEntry.class.getName(), entryId,
180                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
181         }
182 
183         // Tags
184 
185         updateTagsAsset(userId, entry, serviceContext.getTagsEntries());
186 
187         // Indexer
188 
189         reIndex(entry);
190 
191         // Subscriptions
192 
193         notifySubscribers(entry, serviceContext);
194 
195         // Ping
196 
197         pingGoogle(entry, serviceContext);
198         pingTrackbacks(entry, trackbacks, false, serviceContext);
199 
200         return entry;
201     }
202 
203     public void addEntryResources(
204             long entryId, boolean addCommunityPermissions,
205             boolean addGuestPermissions)
206         throws PortalException, SystemException {
207 
208         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
209 
210         addEntryResources(entry, addCommunityPermissions, addGuestPermissions);
211     }
212 
213     public void addEntryResources(
214             BlogsEntry entry, boolean addCommunityPermissions,
215             boolean addGuestPermissions)
216         throws PortalException, SystemException {
217 
218         resourceLocalService.addResources(
219             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
220             BlogsEntry.class.getName(), entry.getEntryId(), false,
221             addCommunityPermissions, addGuestPermissions);
222     }
223 
224     public void addEntryResources(
225             long entryId, String[] communityPermissions,
226             String[] guestPermissions)
227         throws PortalException, SystemException {
228 
229         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
230 
231         addEntryResources(entry, communityPermissions, guestPermissions);
232     }
233 
234     public void addEntryResources(
235             BlogsEntry entry, String[] communityPermissions,
236             String[] guestPermissions)
237         throws PortalException, SystemException {
238 
239         resourceLocalService.addModelResources(
240             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
241             BlogsEntry.class.getName(), entry.getEntryId(),
242             communityPermissions, guestPermissions);
243     }
244 
245     public void deleteEntries(long groupId)
246         throws PortalException, SystemException {
247 
248         for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
249             deleteEntry(entry);
250         }
251     }
252 
253     public void deleteEntry(long entryId)
254         throws PortalException, SystemException {
255 
256         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
257 
258         deleteEntry(entry);
259     }
260 
261     public void deleteEntry(BlogsEntry entry)
262         throws PortalException, SystemException {
263 
264         // Entry
265 
266         blogsEntryPersistence.remove(entry);
267 
268         // Resources
269 
270         resourceLocalService.deleteResource(
271             entry.getCompanyId(), BlogsEntry.class.getName(),
272             ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
273 
274         // Statistics
275 
276         blogsStatsUserLocalService.updateStatsUser(
277             entry.getGroupId(), entry.getUserId());
278 
279         // Expando
280 
281         expandoValueLocalService.deleteValues(
282             BlogsEntry.class.getName(), entry.getEntryId());
283 
284         // Message boards
285 
286         mbMessageLocalService.deleteDiscussionMessages(
287             BlogsEntry.class.getName(), entry.getEntryId());
288 
289         // Ratings
290 
291         ratingsStatsLocalService.deleteStats(
292             BlogsEntry.class.getName(), entry.getEntryId());
293 
294         // Social
295 
296         socialActivityLocalService.deleteActivities(
297             BlogsEntry.class.getName(), entry.getEntryId());
298 
299         // Tags
300 
301         tagsAssetLocalService.deleteAsset(
302             BlogsEntry.class.getName(), entry.getEntryId());
303 
304         // Indexer
305 
306         try {
307             Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId());
308         }
309         catch (SearchException se) {
310             _log.error("Deleting index " + entry.getEntryId(), se);
311         }
312     }
313 
314     public List<BlogsEntry> getCompanyEntries(
315             long companyId, int start, int end)
316         throws SystemException {
317 
318         return blogsEntryPersistence.findByCompanyId(companyId, start, end);
319     }
320 
321     public List<BlogsEntry> getCompanyEntries(
322             long companyId, int start, int end, OrderByComparator obc)
323         throws SystemException {
324 
325         return blogsEntryPersistence.findByCompanyId(
326             companyId, start, end, obc);
327     }
328 
329     public List<BlogsEntry> getCompanyEntries(
330             long companyId, boolean draft, int start, int end)
331         throws SystemException {
332 
333         return blogsEntryPersistence.findByC_D_D(
334             companyId, new Date(), draft, start, end);
335     }
336 
337     public List<BlogsEntry> getCompanyEntries(
338             long companyId, boolean draft, int start, int end,
339             OrderByComparator obc)
340         throws SystemException {
341 
342         return blogsEntryPersistence.findByC_D_D(
343             companyId, new Date(), draft, start, end, obc);
344     }
345 
346     public int getCompanyEntriesCount(long companyId) throws SystemException {
347         return blogsEntryPersistence.countByCompanyId(companyId);
348     }
349 
350     public int getCompanyEntriesCount(long companyId, boolean draft)
351         throws SystemException {
352 
353         return blogsEntryPersistence.countByC_D_D(companyId, new Date(), draft);
354     }
355 
356     public BlogsEntry[] getEntriesPrevAndNext(long entryId)
357         throws PortalException, SystemException {
358 
359         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
360 
361         return blogsEntryPersistence.findByGroupId_PrevAndNext(
362             entry.getEntryId(), entry.getGroupId(),
363             new EntryDisplayDateComparator(true));
364     }
365 
366     public BlogsEntry getEntry(long entryId)
367         throws PortalException, SystemException {
368 
369         return blogsEntryPersistence.findByPrimaryKey(entryId);
370     }
371 
372     public BlogsEntry getEntry(long groupId, String urlTitle)
373         throws PortalException, SystemException {
374 
375         return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
376     }
377 
378     public List<BlogsEntry> getGroupEntries(long groupId, int start, int end)
379         throws SystemException {
380 
381         return blogsEntryPersistence.findByGroupId(groupId, start, end);
382     }
383 
384     public List<BlogsEntry> getGroupEntries(
385             long groupId, int start, int end, OrderByComparator obc)
386         throws SystemException {
387 
388         return blogsEntryPersistence.findByGroupId(groupId, start, end, obc);
389     }
390 
391     public List<BlogsEntry> getGroupEntries(
392             long groupId, boolean draft, int start, int end)
393         throws SystemException {
394 
395         return blogsEntryPersistence.findByG_D_D(
396             groupId, new Date(), draft, start, end);
397     }
398 
399     public List<BlogsEntry> getGroupEntries(
400             long groupId, boolean draft, int start, int end,
401             OrderByComparator obc)
402         throws SystemException {
403 
404         return blogsEntryPersistence.findByG_D_D(
405             groupId, new Date(), draft, start, end, obc);
406     }
407 
408     public int getGroupEntriesCount(long groupId) throws SystemException {
409         return blogsEntryPersistence.countByGroupId(groupId);
410     }
411 
412     public int getGroupEntriesCount(long groupId, boolean draft)
413         throws SystemException {
414 
415         return blogsEntryPersistence.countByG_D_D(groupId, new Date(), draft);
416     }
417 
418     public List<BlogsEntry> getGroupsEntries(
419             long companyId, long groupId, int start, int end)
420         throws SystemException {
421 
422         return blogsEntryFinder.findByGroupIds(
423             companyId, groupId, start, end);
424     }
425 
426     public List<BlogsEntry> getGroupUserEntries(
427             long groupId, long userId, int start, int end)
428         throws SystemException {
429 
430         return blogsEntryPersistence.findByG_U(groupId, userId, start, end);
431     }
432 
433     public List<BlogsEntry> getGroupUserEntries(
434             long groupId, long userId, int start, int end,
435             OrderByComparator obc)
436         throws SystemException {
437 
438         return blogsEntryPersistence.findByG_U(
439             groupId, userId, start, end, obc);
440     }
441 
442     public List<BlogsEntry> getGroupUserEntries(
443             long groupId, long userId, boolean draft, int start, int end)
444         throws SystemException {
445 
446         return blogsEntryPersistence.findByG_U_D_D(
447             groupId, userId, new Date(), draft, start, end);
448     }
449 
450     public List<BlogsEntry> getGroupUserEntries(
451             long groupId, long userId, boolean draft, int start, int end,
452             OrderByComparator obc)
453         throws SystemException {
454 
455         return blogsEntryPersistence.findByG_U_D_D(
456             groupId, userId, new Date(), draft, start, end, obc);
457     }
458 
459     public int getGroupUserEntriesCount(long groupId, long userId)
460         throws SystemException {
461 
462         return blogsEntryPersistence.countByG_U(groupId, userId);
463     }
464 
465     public int getGroupUserEntriesCount(
466             long groupId, long userId, boolean draft)
467         throws SystemException {
468 
469         return blogsEntryPersistence.countByG_U_D_D(
470             groupId, userId, new Date(), draft);
471     }
472 
473     public List<BlogsEntry> getNoAssetEntries() throws SystemException {
474         return blogsEntryFinder.findByNoAssets();
475     }
476 
477     public List<BlogsEntry> getOrganizationEntries(
478             long organizationId, boolean draft, int start, int end)
479         throws SystemException {
480 
481         return blogsEntryFinder.findByOrganizationId(
482             organizationId, new Date(), draft, start, end);
483     }
484 
485     public int getOrganizationEntriesCount(long organizationId, boolean draft)
486         throws SystemException {
487 
488         return blogsEntryFinder.countByOrganizationId(
489             organizationId, new Date(), draft);
490     }
491 
492     /**
493      * @deprecated {@link BlogsUtil#getUrlTitle(long, String)}
494      */
495     public String getUrlTitle(long entryId, String title) {
496         return BlogsUtil.getUrlTitle(entryId, title);
497     }
498 
499     public void reIndex(long entryId) throws SystemException {
500         if (SearchEngineUtil.isIndexReadOnly()) {
501             return;
502         }
503 
504         BlogsEntry entry = blogsEntryPersistence.fetchByPrimaryKey(entryId);
505 
506         if (entry == null) {
507             return;
508         }
509 
510         reIndex(entry);
511     }
512 
513     public void reIndex(BlogsEntry entry) throws SystemException {
514         if (entry.isDraft()) {
515             return;
516         }
517 
518         long companyId = entry.getCompanyId();
519         long groupId = entry.getGroupId();
520         long userId = entry.getUserId();
521         String userName = entry.getUserName();
522         long entryId = entry.getEntryId();
523         String title = entry.getTitle();
524         String content = entry.getContent();
525         Date displayDate = entry.getDisplayDate();
526 
527         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
528             BlogsEntry.class.getName(), entryId);
529 
530         ExpandoBridge expandoBridge = entry.getExpandoBridge();
531 
532         try {
533             Indexer.updateEntry(
534                 companyId, groupId, userId, userName, entryId, title, content,
535                 displayDate, tagsEntries, expandoBridge);
536         }
537         catch (SearchException se) {
538             _log.error("Reindexing " + entryId, se);
539         }
540     }
541 
542     public void reIndex(String[] ids) throws SystemException {
543         if (SearchEngineUtil.isIndexReadOnly()) {
544             return;
545         }
546 
547         long companyId = GetterUtil.getLong(ids[0]);
548 
549         try {
550             reIndexEntries(companyId);
551         }
552         catch (SystemException se) {
553             throw se;
554         }
555         catch (Exception e) {
556             throw new SystemException(e);
557         }
558     }
559 
560     public Hits search(
561             long companyId, long groupId, long userId, long ownerUserId,
562             String keywords, int start, int end)
563         throws SystemException {
564 
565         try {
566             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
567 
568             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
569 
570             if (groupId > 0) {
571                 Group group = groupLocalService.getGroup(groupId);
572 
573                 if (group.isLayout()) {
574                     contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
575 
576                     groupId = group.getParentGroupId();
577                 }
578 
579                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
580             }
581 
582             if (ownerUserId > 0) {
583                 contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
584             }
585 
586             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
587 
588             if (Validator.isNotNull(keywords)) {
589                 searchQuery.addTerm(Field.USER_NAME, keywords);
590                 searchQuery.addTerm(Field.TITLE, keywords);
591                 searchQuery.addTerm(Field.CONTENT, keywords);
592                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords, true);
593             }
594 
595             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
596 
597             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
598 
599             if (searchQuery.clauses().size() > 0) {
600                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
601             }
602 
603             return SearchEngineUtil.search(
604                 companyId, groupId, userId, BlogsEntry.class.getName(),
605                 fullQuery, start, end);
606         }
607         catch (Exception e) {
608             throw new SystemException(e);
609         }
610     }
611 
612     public BlogsEntry updateEntry(
613             long userId, long entryId, String title, String content,
614             int displayDateMonth, int displayDateDay, int displayDateYear,
615             int displayDateHour, int displayDateMinute, boolean draft,
616             boolean allowTrackbacks, String[] trackbacks,
617             ServiceContext serviceContext)
618         throws PortalException, SystemException {
619 
620         // Entry
621 
622         User user = userPersistence.findByPrimaryKey(userId);
623 
624         Date displayDate = PortalUtil.getDate(
625             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
626             displayDateMinute, user.getTimeZone(),
627             new EntryDisplayDateException());
628 
629         validate(title, content);
630 
631         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
632 
633         String oldUrlTitle = entry.getUrlTitle();
634 
635         entry.setModifiedDate(serviceContext.getModifiedDate(null));
636         entry.setTitle(title);
637         entry.setUrlTitle(
638             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
639         entry.setContent(content);
640         entry.setDisplayDate(displayDate);
641         entry.setDraft(draft);
642         entry.setAllowTrackbacks(allowTrackbacks);
643         entry.setExpandoBridgeAttributes(serviceContext);
644 
645         blogsEntryPersistence.update(entry, false);
646 
647         // Resources
648 
649         if ((serviceContext.getCommunityPermissions() != null) ||
650             (serviceContext.getGuestPermissions() != null)) {
651 
652             updateEntryResources(
653                 entry, serviceContext.getCommunityPermissions(),
654                 serviceContext.getGuestPermissions());
655         }
656 
657         // Statistics
658 
659         if (!draft) {
660             blogsStatsUserLocalService.updateStatsUser(
661                 entry.getGroupId(), entry.getUserId(), displayDate);
662         }
663 
664         // Social
665 
666         if (!draft) {
667             socialActivityLocalService.addUniqueActivity(
668                 userId, entry.getGroupId(), BlogsEntry.class.getName(), entryId,
669                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
670         }
671 
672         // Tags
673 
674         updateTagsAsset(userId, entry, serviceContext.getTagsEntries());
675 
676         // Indexer
677 
678         if (!draft) {
679             reIndex(entry);
680         }
681         else {
682             try {
683                 Indexer.deleteEntry(entry.getCompanyId(), entryId);
684             }
685             catch (SearchException se) {
686                 _log.error("Deleting index " + entry.getEntryId(), se);
687             }
688         }
689 
690         // Subscriptions
691 
692         notifySubscribers(entry, serviceContext);
693 
694         // Ping
695 
696         pingGoogle(entry, serviceContext);
697 
698         boolean pingOldTrackbacks = false;
699 
700         if (!oldUrlTitle.equals(entry.getUrlTitle())) {
701             pingOldTrackbacks = true;
702         }
703 
704         pingTrackbacks(entry, trackbacks, pingOldTrackbacks, serviceContext);
705 
706         return entry;
707     }
708 
709     public void updateEntryResources(
710             BlogsEntry entry, String[] communityPermissions,
711             String[] guestPermissions)
712         throws PortalException, SystemException {
713 
714         resourceLocalService.updateResources(
715             entry.getCompanyId(), entry.getGroupId(),
716             BlogsEntry.class.getName(), entry.getEntryId(),
717             communityPermissions, guestPermissions);
718     }
719 
720     public void updateTagsAsset(
721             long userId, BlogsEntry entry, String[] tagsEntries)
722         throws PortalException, SystemException {
723 
724         tagsAssetLocalService.updateAsset(
725             userId, entry.getGroupId(), BlogsEntry.class.getName(),
726             entry.getEntryId(), null, tagsEntries, !entry.isDraft(), null, null,
727             entry.getDisplayDate(), null, ContentTypes.TEXT_HTML,
728             entry.getTitle(), null, null, null, 0, 0, null, false);
729     }
730 
731     protected String getUniqueUrlTitle(
732             long entryId, long groupId, String title)
733         throws SystemException {
734 
735         String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
736 
737         String newUrlTitle = urlTitle;
738 
739         for (int i = 1;; i++) {
740             BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
741                 groupId, newUrlTitle);
742 
743             if ((entry == null) || (entry.getEntryId() == entryId)) {
744                 break;
745             }
746             else {
747                 newUrlTitle = urlTitle + StringPool.DASH + i;
748             }
749         }
750 
751         return newUrlTitle;
752     }
753 
754     protected void notifySubscribers(
755             BlogsEntry entry, ServiceContext serviceContext)
756         throws PortalException, SystemException {
757 
758         if (entry.isDraft()) {
759             return;
760         }
761 
762         String layoutFullURL = PortalUtil.getLayoutFullURL(
763             serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
764 
765         if (Validator.isNull(layoutFullURL)) {
766             return;
767         }
768 
769         PortletPreferences preferences =
770             ServiceContextUtil.getPortletPreferences(serviceContext);
771 
772         if (preferences == null) {
773             long ownerId = entry.getGroupId();
774             int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
775             long plid = PortletKeys.PREFS_PLID_SHARED;
776             String portletId = PortletKeys.BLOGS;
777             String defaultPreferences = null;
778 
779             preferences = portletPreferencesLocalService.getPreferences(
780                 entry.getCompanyId(), ownerId, ownerType, plid, portletId,
781                 defaultPreferences);
782         }
783 
784         if (serviceContext.isCommandAdd() &&
785             BlogsUtil.getEmailEntryAddedEnabled(preferences)) {
786         }
787         else if (serviceContext.isCommandUpdate() &&
788                  BlogsUtil.getEmailEntryUpdatedEnabled(preferences)) {
789         }
790         else {
791             return;
792         }
793 
794         Company company = companyPersistence.findByPrimaryKey(
795             entry.getCompanyId());
796 
797         Group group = groupPersistence.findByPrimaryKey(
798             serviceContext.getScopeGroupId());
799 
800         String emailAddress = StringPool.BLANK;
801         String fullName = entry.getUserName();
802 
803         try {
804             User user = userPersistence.findByPrimaryKey(entry.getUserId());
805 
806             emailAddress = user.getEmailAddress();
807             fullName = user.getFullName();
808         }
809         catch (NoSuchUserException nsue) {
810         }
811 
812         String portletName = PortalUtil.getPortletTitle(
813             PortletKeys.BLOGS, LocaleUtil.getDefault());
814 
815         String fromName = BlogsUtil.getEmailFromName(preferences);
816         String fromAddress = BlogsUtil.getEmailFromAddress(preferences);
817 
818         fromName = StringUtil.replace(
819             fromName,
820             new String[] {
821                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
822                 "[$BLOGS_ENTRY_USER_NAME$]",
823                 "[$COMPANY_ID$]",
824                 "[$COMPANY_MX$]",
825                 "[$COMPANY_NAME$]",
826                 "[$COMMUNITY_NAME$]",
827                 "[$PORTLET_NAME$]"
828             },
829             new String[] {
830                 emailAddress,
831                 fullName,
832                 String.valueOf(company.getCompanyId()),
833                 company.getMx(),
834                 company.getName(),
835                 group.getName(),
836                 portletName
837             });
838 
839         fromAddress = StringUtil.replace(
840             fromAddress,
841             new String[] {
842                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
843                 "[$BLOGS_ENTRY_USER_NAME$]",
844                 "[$COMPANY_ID$]",
845                 "[$COMPANY_MX$]",
846                 "[$COMPANY_NAME$]",
847                 "[$COMMUNITY_NAME$]",
848                 "[$PORTLET_NAME$]"
849             },
850             new String[] {
851                 emailAddress,
852                 fullName,
853                 String.valueOf(company.getCompanyId()),
854                 company.getMx(),
855                 company.getName(),
856                 group.getName(),
857                 portletName
858             });
859 
860         String entryURL =
861             layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
862                 StringPool.SLASH + entry.getEntryId();
863 
864         String subject = null;
865         String body = null;
866 
867         if (serviceContext.isCommandUpdate()) {
868             subject = BlogsUtil.getEmailEntryUpdatedSubject(preferences);
869             body = BlogsUtil.getEmailEntryUpdatedBody(preferences);
870         }
871         else {
872             subject = BlogsUtil.getEmailEntryAddedSubject(preferences);
873             body = BlogsUtil.getEmailEntryAddedBody(preferences);
874         }
875 
876         subject = StringUtil.replace(
877             subject,
878             new String[] {
879                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
880                 "[$BLOGS_ENTRY_USER_NAME$]",
881                 "[$BLOGS_ENTRY_URL$]",
882                 "[$COMPANY_ID$]",
883                 "[$COMPANY_MX$]",
884                 "[$COMPANY_NAME$]",
885                 "[$COMMUNITY_NAME$]",
886                 "[$FROM_ADDRESS$]",
887                 "[$FROM_NAME$]",
888                 "[$PORTAL_URL$]",
889                 "[$PORTLET_NAME$]"
890             },
891             new String[] {
892                 emailAddress,
893                 fullName,
894                 entryURL,
895                 String.valueOf(company.getCompanyId()),
896                 company.getMx(),
897                 company.getName(),
898                 group.getName(),
899                 fromAddress,
900                 fromName,
901                 company.getVirtualHost(),
902                 portletName
903             });
904 
905         body = StringUtil.replace(
906             body,
907             new String[] {
908                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
909                 "[$BLOGS_ENTRY_USER_NAME$]",
910                 "[$BLOGS_ENTRY_URL$]",
911                 "[$COMPANY_ID$]",
912                 "[$COMPANY_MX$]",
913                 "[$COMPANY_NAME$]",
914                 "[$COMMUNITY_NAME$]",
915                 "[$FROM_ADDRESS$]",
916                 "[$FROM_NAME$]",
917                 "[$PORTAL_URL$]",
918                 "[$PORTLET_NAME$]"
919             },
920             new String[] {
921                 emailAddress,
922                 fullName,
923                 entryURL,
924                 String.valueOf(company.getCompanyId()),
925                 company.getMx(),
926                 company.getName(),
927                 group.getName(),
928                 fromAddress,
929                 fromName,
930                 company.getVirtualHost(),
931                 portletName
932             });
933 
934         Message message = new Message();
935 
936         message.put("companyId", entry.getCompanyId());
937         message.put("userId", entry.getUserId());
938         message.put("groupId", entry.getGroupId());
939         message.put("entryId", entry.getEntryId());
940         message.put("fromName", fromName);
941         message.put("fromAddress", fromAddress);
942         message.put("subject", subject);
943         message.put("body", body);
944         message.put("replyToAddress", fromAddress);
945         message.put(
946             "mailId", BlogsUtil.getMailId(company.getMx(), entry.getEntryId()));
947         message.put("htmlFormat", Boolean.TRUE);
948 
949         MessageBusUtil.sendMessage(DestinationNames.BLOGS, message);
950     }
951 
952     protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
953         throws PortalException, SystemException {
954 
955         if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
956             return;
957         }
958 
959         String layoutFullURL = PortalUtil.getLayoutFullURL(
960             serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
961 
962         if (Validator.isNull(layoutFullURL)) {
963             return;
964         }
965 
966         if (layoutFullURL.contains("://localhost")) {
967             if (_log.isDebugEnabled()) {
968                 _log.debug(
969                     "Not pinging Google because of localhost URL " +
970                         layoutFullURL);
971             }
972 
973             return;
974         }
975 
976         Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
977 
978         StringBundler sb = new StringBundler(6);
979 
980         String name = group.getDescriptiveName();
981         String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
982         String changesURL =
983             layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
984 
985         sb.append("http://blogsearch.google.com/ping?name=");
986         sb.append(HttpUtil.encodeURL(name));
987         sb.append("&url=");
988         sb.append(HttpUtil.encodeURL(url));
989         sb.append("&changesURL=");
990         sb.append(HttpUtil.encodeURL(changesURL));
991 
992         String location = sb.toString();
993 
994         if (_log.isInfoEnabled()) {
995             _log.info("Pinging Google at " + location);
996         }
997 
998         try {
999             String response = HttpUtil.URLtoString(sb.toString());
1000
1001            if (_log.isInfoEnabled()) {
1002                _log.info("Google ping response: " + response);
1003            }
1004        }
1005        catch (IOException ioe) {
1006            _log.error("Unable to ping Google at " + location, ioe);
1007        }
1008    }
1009
1010    protected boolean pingTrackback(String trackback, Map<String, String> parts)
1011        throws Exception {
1012
1013        if (_log.isDebugEnabled()) {
1014            _log.debug("Pinging trackback " + trackback);
1015        }
1016
1017        Http.Options options = new Http.Options();
1018
1019        options.setLocation(trackback);
1020        options.setParts(parts);
1021        options.setPost(true);
1022
1023        String xml = HttpUtil.URLtoString(options);
1024
1025        if (_log.isDebugEnabled()) {
1026            _log.debug(xml);
1027        }
1028
1029        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
1030
1031        XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(
1032            new UnsyncStringReader(xml));
1033
1034        String error = xml;
1035
1036        try {
1037            xmlStreamReader.nextTag();
1038            xmlStreamReader.nextTag();
1039
1040            String name = xmlStreamReader.getLocalName();
1041
1042            if (name.equals("error")) {
1043                int status = GetterUtil.getInteger(
1044                    xmlStreamReader.getElementText(), 1);
1045
1046                if (status == 0) {
1047                    return true;
1048                }
1049
1050                xmlStreamReader.nextTag();
1051
1052                name = xmlStreamReader.getLocalName();
1053
1054                if (name.equals("message")) {
1055                    error = xmlStreamReader.getElementText();
1056                }
1057            }
1058        }
1059        finally {
1060            if (xmlStreamReader != null) {
1061                try {
1062                    xmlStreamReader.close();
1063                }
1064                catch (Exception e) {
1065                }
1066            }
1067        }
1068
1069        _log.error(
1070            "Error while pinging trackback at " + trackback + ": " + error);
1071
1072        return false;
1073    }
1074
1075    protected void pingTrackbacks(
1076            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
1077            ServiceContext serviceContext)
1078        throws SystemException {
1079
1080        if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
1081            !entry.isAllowTrackbacks() || !entry.isApproved()) {
1082
1083            return;
1084        }
1085
1086        String layoutFullURL = serviceContext.getLayoutFullURL();
1087
1088        if (Validator.isNull(layoutFullURL)) {
1089            return;
1090        }
1091
1092        Map<String, String> parts = new HashMap<String, String>();
1093
1094        String excerpt = StringUtil.shorten(
1095            HtmlUtil.extractText(entry.getContent()),
1096            PropsValues.BLOGS_TRACKBACK_EXCERPT_LENGTH);
1097        String url =
1098            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1099                entry.getUrlTitle();
1100
1101        parts.put("title", entry.getTitle());
1102        parts.put("excerpt", excerpt);
1103        parts.put("url", url);
1104        parts.put("blog_name", entry.getUserName());
1105
1106        Set<String> trackbacksSet = null;
1107
1108        if (Validator.isNotNull(trackbacks)) {
1109            trackbacksSet = SetUtil.fromArray(trackbacks);
1110        }
1111        else {
1112            trackbacksSet = new HashSet<String>();
1113        }
1114
1115        if (pingOldTrackbacks) {
1116            trackbacksSet.addAll(
1117                SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
1118
1119            entry.setTrackbacks(StringPool.BLANK);
1120
1121            blogsEntryPersistence.update(entry, false);
1122        }
1123
1124        Set<String> oldTrackbacks = SetUtil.fromArray(
1125            StringUtil.split(entry.getTrackbacks()));
1126
1127        Set<String> validTrackbacks = new HashSet<String>();
1128
1129        for (String trackback : trackbacksSet) {
1130            if (oldTrackbacks.contains(trackback)) {
1131                continue;
1132            }
1133
1134            try {
1135                if (pingTrackback(trackback, parts)) {
1136                    validTrackbacks.add(trackback);
1137                }
1138            }
1139            catch (Exception e) {
1140                _log.error("Error while pinging trackback at " + trackback, e);
1141            }
1142        }
1143
1144        if (!validTrackbacks.isEmpty()) {
1145            String newTrackbacks = StringUtil.merge(validTrackbacks);
1146
1147            if (Validator.isNotNull(entry.getTrackbacks())) {
1148                newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
1149            }
1150
1151            entry.setTrackbacks(newTrackbacks);
1152
1153            blogsEntryPersistence.update(entry, false);
1154        }
1155    }
1156
1157    protected void reIndexEntries(long companyId) throws SystemException {
1158        int count = blogsEntryPersistence.countByCompanyId(companyId);
1159
1160        int pages = count / Indexer.DEFAULT_INTERVAL;
1161
1162        for (int i = 0; i <= pages; i++) {
1163            int start = (i * Indexer.DEFAULT_INTERVAL);
1164            int end = start + Indexer.DEFAULT_INTERVAL;
1165
1166            reIndexEntries(companyId, start, end);
1167        }
1168    }
1169
1170    protected void reIndexEntries(long companyId, int start, int end)
1171        throws SystemException {
1172
1173        List<BlogsEntry> entries = blogsEntryPersistence.findByCompanyId(
1174            companyId, start, end);
1175
1176        for (BlogsEntry entry : entries) {
1177            reIndex(entry);
1178        }
1179    }
1180
1181    protected void validate(String title, String content)
1182        throws PortalException {
1183
1184        if (Validator.isNull(title)) {
1185            throw new EntryTitleException();
1186        }
1187        else if (Validator.isNull(content)) {
1188            throw new EntryContentException();
1189        }
1190    }
1191
1192    private static Log _log = LogFactoryUtil.getLog(
1193        BlogsEntryLocalServiceImpl.class);
1194
1195}