1   /**
2    * Copyright (c) 2000-2010 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   *
12   *
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(
186             userId, entry, serviceContext.getTagsCategories(),
187             serviceContext.getTagsEntries());
188 
189         // Indexer
190 
191         reIndex(entry);
192 
193         // Subscriptions
194 
195         notifySubscribers(entry, serviceContext);
196 
197         // Ping
198 
199         pingGoogle(entry, serviceContext);
200         pingTrackbacks(entry, trackbacks, false, serviceContext);
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 = blogsEntryPersistence.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         resourceLocalService.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 = blogsEntryPersistence.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         resourceLocalService.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         for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
251             deleteEntry(entry);
252         }
253     }
254 
255     public void deleteEntry(long entryId)
256         throws PortalException, SystemException {
257 
258         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
259 
260         deleteEntry(entry);
261     }
262 
263     public void deleteEntry(BlogsEntry entry)
264         throws PortalException, SystemException {
265 
266         // Entry
267 
268         blogsEntryPersistence.remove(entry);
269 
270         // Resources
271 
272         resourceLocalService.deleteResource(
273             entry.getCompanyId(), BlogsEntry.class.getName(),
274             ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
275 
276         // Statistics
277 
278         blogsStatsUserLocalService.updateStatsUser(
279             entry.getGroupId(), entry.getUserId());
280 
281         // Expando
282 
283         expandoValueLocalService.deleteValues(
284             BlogsEntry.class.getName(), entry.getEntryId());
285 
286         // Message boards
287 
288         mbMessageLocalService.deleteDiscussionMessages(
289             BlogsEntry.class.getName(), entry.getEntryId());
290 
291         // Ratings
292 
293         ratingsStatsLocalService.deleteStats(
294             BlogsEntry.class.getName(), entry.getEntryId());
295 
296         // Social
297 
298         socialActivityLocalService.deleteActivities(
299             BlogsEntry.class.getName(), entry.getEntryId());
300 
301         // Tags
302 
303         tagsAssetLocalService.deleteAsset(
304             BlogsEntry.class.getName(), entry.getEntryId());
305 
306         // Indexer
307 
308         try {
309             Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId());
310         }
311         catch (SearchException se) {
312             _log.error("Deleting index " + entry.getEntryId(), se);
313         }
314     }
315 
316     public List<BlogsEntry> getCompanyEntries(
317             long companyId, int start, int end)
318         throws SystemException {
319 
320         return blogsEntryPersistence.findByCompanyId(companyId, start, end);
321     }
322 
323     public List<BlogsEntry> getCompanyEntries(
324             long companyId, int start, int end, OrderByComparator obc)
325         throws SystemException {
326 
327         return blogsEntryPersistence.findByCompanyId(
328             companyId, start, end, obc);
329     }
330 
331     public List<BlogsEntry> getCompanyEntries(
332             long companyId, boolean draft, int start, int end)
333         throws SystemException {
334 
335         return blogsEntryPersistence.findByC_D_D(
336             companyId, new Date(), draft, start, end);
337     }
338 
339     public List<BlogsEntry> getCompanyEntries(
340             long companyId, boolean draft, int start, int end,
341             OrderByComparator obc)
342         throws SystemException {
343 
344         return blogsEntryPersistence.findByC_D_D(
345             companyId, new Date(), draft, start, end, obc);
346     }
347 
348     public int getCompanyEntriesCount(long companyId) throws SystemException {
349         return blogsEntryPersistence.countByCompanyId(companyId);
350     }
351 
352     public int getCompanyEntriesCount(long companyId, boolean draft)
353         throws SystemException {
354 
355         return blogsEntryPersistence.countByC_D_D(companyId, new Date(), draft);
356     }
357 
358     public BlogsEntry[] getEntriesPrevAndNext(long entryId)
359         throws PortalException, SystemException {
360 
361         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
362 
363         return blogsEntryPersistence.findByGroupId_PrevAndNext(
364             entry.getEntryId(), entry.getGroupId(),
365             new EntryDisplayDateComparator(true));
366     }
367 
368     public BlogsEntry getEntry(long entryId)
369         throws PortalException, SystemException {
370 
371         return blogsEntryPersistence.findByPrimaryKey(entryId);
372     }
373 
374     public BlogsEntry getEntry(long groupId, String urlTitle)
375         throws PortalException, SystemException {
376 
377         return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
378     }
379 
380     public List<BlogsEntry> getGroupEntries(long groupId, int start, int end)
381         throws SystemException {
382 
383         return blogsEntryPersistence.findByGroupId(groupId, start, end);
384     }
385 
386     public List<BlogsEntry> getGroupEntries(
387             long groupId, int start, int end, OrderByComparator obc)
388         throws SystemException {
389 
390         return blogsEntryPersistence.findByGroupId(groupId, start, end, obc);
391     }
392 
393     public List<BlogsEntry> getGroupEntries(
394             long groupId, boolean draft, int start, int end)
395         throws SystemException {
396 
397         return blogsEntryPersistence.findByG_D_D(
398             groupId, new Date(), draft, start, end);
399     }
400 
401     public List<BlogsEntry> getGroupEntries(
402             long groupId, boolean draft, int start, int end,
403             OrderByComparator obc)
404         throws SystemException {
405 
406         return blogsEntryPersistence.findByG_D_D(
407             groupId, new Date(), draft, start, end, obc);
408     }
409 
410     public int getGroupEntriesCount(long groupId) throws SystemException {
411         return blogsEntryPersistence.countByGroupId(groupId);
412     }
413 
414     public int getGroupEntriesCount(long groupId, boolean draft)
415         throws SystemException {
416 
417         return blogsEntryPersistence.countByG_D_D(groupId, new Date(), draft);
418     }
419 
420     public List<BlogsEntry> getGroupsEntries(
421             long companyId, long groupId, int start, int end)
422         throws SystemException {
423 
424         return blogsEntryFinder.findByGroupIds(
425             companyId, groupId, start, end);
426     }
427 
428     public List<BlogsEntry> getGroupUserEntries(
429             long groupId, long userId, int start, int end)
430         throws SystemException {
431 
432         return blogsEntryPersistence.findByG_U(groupId, userId, start, end);
433     }
434 
435     public List<BlogsEntry> getGroupUserEntries(
436             long groupId, long userId, int start, int end,
437             OrderByComparator obc)
438         throws SystemException {
439 
440         return blogsEntryPersistence.findByG_U(
441             groupId, userId, start, end, obc);
442     }
443 
444     public List<BlogsEntry> getGroupUserEntries(
445             long groupId, long userId, boolean draft, int start, int end)
446         throws SystemException {
447 
448         return blogsEntryPersistence.findByG_U_D_D(
449             groupId, userId, new Date(), draft, start, end);
450     }
451 
452     public List<BlogsEntry> getGroupUserEntries(
453             long groupId, long userId, boolean draft, int start, int end,
454             OrderByComparator obc)
455         throws SystemException {
456 
457         return blogsEntryPersistence.findByG_U_D_D(
458             groupId, userId, new Date(), draft, start, end, obc);
459     }
460 
461     public int getGroupUserEntriesCount(long groupId, long userId)
462         throws SystemException {
463 
464         return blogsEntryPersistence.countByG_U(groupId, userId);
465     }
466 
467     public int getGroupUserEntriesCount(
468             long groupId, long userId, boolean draft)
469         throws SystemException {
470 
471         return blogsEntryPersistence.countByG_U_D_D(
472             groupId, userId, new Date(), draft);
473     }
474 
475     public List<BlogsEntry> getNoAssetEntries() throws SystemException {
476         return blogsEntryFinder.findByNoAssets();
477     }
478 
479     public List<BlogsEntry> getOrganizationEntries(
480             long organizationId, boolean draft, int start, int end)
481         throws SystemException {
482 
483         return blogsEntryFinder.findByOrganizationId(
484             organizationId, new Date(), draft, start, end);
485     }
486 
487     public int getOrganizationEntriesCount(long organizationId, boolean draft)
488         throws SystemException {
489 
490         return blogsEntryFinder.countByOrganizationId(
491             organizationId, new Date(), draft);
492     }
493 
494     /**
495      * @deprecated {@link BlogsUtil#getUrlTitle(long, String)}
496      */
497     public String getUrlTitle(long entryId, String title) {
498         return BlogsUtil.getUrlTitle(entryId, title);
499     }
500 
501     public void reIndex(long entryId) throws SystemException {
502         if (SearchEngineUtil.isIndexReadOnly()) {
503             return;
504         }
505 
506         BlogsEntry entry = blogsEntryPersistence.fetchByPrimaryKey(entryId);
507 
508         if (entry == null) {
509             return;
510         }
511 
512         reIndex(entry);
513     }
514 
515     public void reIndex(BlogsEntry entry) throws SystemException {
516         if (entry.isDraft()) {
517             return;
518         }
519 
520         long companyId = entry.getCompanyId();
521         long groupId = entry.getGroupId();
522         long userId = entry.getUserId();
523         String userName = entry.getUserName();
524         long entryId = entry.getEntryId();
525         String title = entry.getTitle();
526         String content = entry.getContent();
527         Date displayDate = entry.getDisplayDate();
528 
529         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
530             BlogsEntry.class.getName(), entryId);
531 
532         ExpandoBridge expandoBridge = entry.getExpandoBridge();
533 
534         try {
535             Indexer.updateEntry(
536                 companyId, groupId, userId, userName, entryId, title, content,
537                 displayDate, tagsEntries, expandoBridge);
538         }
539         catch (SearchException se) {
540             _log.error("Reindexing " + entryId, se);
541         }
542     }
543 
544     public void reIndex(String[] ids) throws SystemException {
545         if (SearchEngineUtil.isIndexReadOnly()) {
546             return;
547         }
548 
549         long companyId = GetterUtil.getLong(ids[0]);
550 
551         try {
552             reIndexEntries(companyId);
553         }
554         catch (SystemException se) {
555             throw se;
556         }
557         catch (Exception e) {
558             throw new SystemException(e);
559         }
560     }
561 
562     public Hits search(
563             long companyId, long groupId, long userId, long ownerUserId,
564             String keywords, int start, int end)
565         throws SystemException {
566 
567         try {
568             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
569 
570             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
571 
572             if (groupId > 0) {
573                 Group group = groupLocalService.getGroup(groupId);
574 
575                 contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
576 
577                 if (group.isLayout()) {
578                     groupId = group.getParentGroupId();
579                 }
580 
581                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
582             }
583 
584             if (ownerUserId > 0) {
585                 contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
586             }
587 
588             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
589 
590             searchQuery.addTerms(_KEYWORDS_FIELDS, keywords);
591 
592             searchQuery.addExactTerm(Field.TAGS_ENTRIES, keywords);
593 
594             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
595 
596             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
597 
598             if (searchQuery.clauses().size() > 0) {
599                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
600             }
601 
602             return SearchEngineUtil.search(
603                 companyId, groupId, userId, BlogsEntry.class.getName(),
604                 fullQuery, start, end);
605         }
606         catch (Exception e) {
607             throw new SystemException(e);
608         }
609     }
610 
611     public BlogsEntry updateEntry(
612             long userId, long entryId, String title, String content,
613             int displayDateMonth, int displayDateDay, int displayDateYear,
614             int displayDateHour, int displayDateMinute, boolean draft,
615             boolean allowTrackbacks, String[] trackbacks,
616             ServiceContext serviceContext)
617         throws PortalException, SystemException {
618 
619         // Entry
620 
621         User user = userPersistence.findByPrimaryKey(userId);
622 
623         Date displayDate = PortalUtil.getDate(
624             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
625             displayDateMinute, user.getTimeZone(),
626             new EntryDisplayDateException());
627 
628         validate(title, content);
629 
630         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
631 
632         String oldUrlTitle = entry.getUrlTitle();
633 
634         entry.setModifiedDate(serviceContext.getModifiedDate(null));
635         entry.setTitle(title);
636         entry.setUrlTitle(
637             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
638         entry.setContent(content);
639         entry.setDisplayDate(displayDate);
640         entry.setDraft(draft);
641         entry.setAllowTrackbacks(allowTrackbacks);
642         entry.setExpandoBridgeAttributes(serviceContext);
643 
644         blogsEntryPersistence.update(entry, false);
645 
646         // Resources
647 
648         if ((serviceContext.getCommunityPermissions() != null) ||
649             (serviceContext.getGuestPermissions() != null)) {
650 
651             updateEntryResources(
652                 entry, serviceContext.getCommunityPermissions(),
653                 serviceContext.getGuestPermissions());
654         }
655 
656         // Statistics
657 
658         if (!draft) {
659             blogsStatsUserLocalService.updateStatsUser(
660                 entry.getGroupId(), entry.getUserId(), displayDate);
661         }
662 
663         // Social
664 
665         if (!draft) {
666             socialActivityLocalService.addUniqueActivity(
667                 userId, entry.getGroupId(), BlogsEntry.class.getName(), entryId,
668                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
669         }
670 
671         // Tags
672 
673         updateTagsAsset(
674             userId, entry, serviceContext.getTagsCategories(),
675             serviceContext.getTagsEntries());
676 
677         // Indexer
678 
679         if (!draft) {
680             reIndex(entry);
681         }
682         else {
683             try {
684                 Indexer.deleteEntry(entry.getCompanyId(), entryId);
685             }
686             catch (SearchException se) {
687                 _log.error("Deleting index " + entry.getEntryId(), se);
688             }
689         }
690 
691         // Subscriptions
692 
693         notifySubscribers(entry, serviceContext);
694 
695         // Ping
696 
697         pingGoogle(entry, serviceContext);
698 
699         boolean pingOldTrackbacks = false;
700 
701         if (!oldUrlTitle.equals(entry.getUrlTitle())) {
702             pingOldTrackbacks = true;
703         }
704 
705         pingTrackbacks(entry, trackbacks, pingOldTrackbacks, serviceContext);
706 
707         return entry;
708     }
709 
710     public void updateEntryResources(
711             BlogsEntry entry, String[] communityPermissions,
712             String[] guestPermissions)
713         throws PortalException, SystemException {
714 
715         resourceLocalService.updateResources(
716             entry.getCompanyId(), entry.getGroupId(),
717             BlogsEntry.class.getName(), entry.getEntryId(),
718             communityPermissions, guestPermissions);
719     }
720 
721     public void updateTagsAsset(
722             long userId, BlogsEntry entry, String[] tagsCategories,
723             String[] tagsEntries)
724         throws PortalException, SystemException {
725 
726         tagsAssetLocalService.updateAsset(
727             userId, entry.getGroupId(), BlogsEntry.class.getName(),
728             entry.getEntryId(), tagsCategories, tagsEntries, !entry.isDraft(),
729             null, null, entry.getDisplayDate(), null, ContentTypes.TEXT_HTML,
730             entry.getTitle(), null, null, null, 0, 0, null, false);
731     }
732 
733     protected String getUniqueUrlTitle(
734             long entryId, long groupId, String title)
735         throws SystemException {
736 
737         String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
738 
739         String newUrlTitle = urlTitle;
740 
741         for (int i = 1;; i++) {
742             BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
743                 groupId, newUrlTitle);
744 
745             if ((entry == null) || (entry.getEntryId() == entryId)) {
746                 break;
747             }
748             else {
749                 newUrlTitle = urlTitle + StringPool.DASH + i;
750             }
751         }
752 
753         return newUrlTitle;
754     }
755 
756     protected void notifySubscribers(
757             BlogsEntry entry, ServiceContext serviceContext)
758         throws PortalException, SystemException {
759 
760         if (entry.isDraft()) {
761             return;
762         }
763 
764         String layoutFullURL = PortalUtil.getLayoutFullURL(
765             serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
766 
767         if (Validator.isNull(layoutFullURL)) {
768             return;
769         }
770 
771         PortletPreferences preferences =
772             ServiceContextUtil.getPortletPreferences(serviceContext);
773 
774         if (preferences == null) {
775             long ownerId = entry.getGroupId();
776             int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
777             long plid = PortletKeys.PREFS_PLID_SHARED;
778             String portletId = PortletKeys.BLOGS;
779             String defaultPreferences = null;
780 
781             preferences = portletPreferencesLocalService.getPreferences(
782                 entry.getCompanyId(), ownerId, ownerType, plid, portletId,
783                 defaultPreferences);
784         }
785 
786         if (serviceContext.isCommandAdd() &&
787             BlogsUtil.getEmailEntryAddedEnabled(preferences)) {
788         }
789         else if (serviceContext.isCommandUpdate() &&
790                  BlogsUtil.getEmailEntryUpdatedEnabled(preferences)) {
791         }
792         else {
793             return;
794         }
795 
796         Company company = companyPersistence.findByPrimaryKey(
797             entry.getCompanyId());
798 
799         Group group = groupPersistence.findByPrimaryKey(
800             serviceContext.getScopeGroupId());
801 
802         String emailAddress = StringPool.BLANK;
803         String fullName = entry.getUserName();
804 
805         try {
806             User user = userPersistence.findByPrimaryKey(entry.getUserId());
807 
808             emailAddress = user.getEmailAddress();
809             fullName = user.getFullName();
810         }
811         catch (NoSuchUserException nsue) {
812         }
813 
814         String portletName = PortalUtil.getPortletTitle(
815             PortletKeys.BLOGS, LocaleUtil.getDefault());
816 
817         String fromName = BlogsUtil.getEmailFromName(preferences);
818         String fromAddress = BlogsUtil.getEmailFromAddress(preferences);
819 
820         fromName = StringUtil.replace(
821             fromName,
822             new String[] {
823                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
824                 "[$BLOGS_ENTRY_USER_NAME$]",
825                 "[$COMPANY_ID$]",
826                 "[$COMPANY_MX$]",
827                 "[$COMPANY_NAME$]",
828                 "[$COMMUNITY_NAME$]",
829                 "[$PORTLET_NAME$]"
830             },
831             new String[] {
832                 emailAddress,
833                 fullName,
834                 String.valueOf(company.getCompanyId()),
835                 company.getMx(),
836                 company.getName(),
837                 group.getName(),
838                 portletName
839             });
840 
841         fromAddress = StringUtil.replace(
842             fromAddress,
843             new String[] {
844                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
845                 "[$BLOGS_ENTRY_USER_NAME$]",
846                 "[$COMPANY_ID$]",
847                 "[$COMPANY_MX$]",
848                 "[$COMPANY_NAME$]",
849                 "[$COMMUNITY_NAME$]",
850                 "[$PORTLET_NAME$]"
851             },
852             new String[] {
853                 emailAddress,
854                 fullName,
855                 String.valueOf(company.getCompanyId()),
856                 company.getMx(),
857                 company.getName(),
858                 group.getName(),
859                 portletName
860             });
861 
862         String entryURL =
863             layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
864                 StringPool.SLASH + entry.getEntryId();
865 
866         String subject = null;
867         String body = null;
868 
869         if (serviceContext.isCommandUpdate()) {
870             subject = BlogsUtil.getEmailEntryUpdatedSubject(preferences);
871             body = BlogsUtil.getEmailEntryUpdatedBody(preferences);
872         }
873         else {
874             subject = BlogsUtil.getEmailEntryAddedSubject(preferences);
875             body = BlogsUtil.getEmailEntryAddedBody(preferences);
876         }
877 
878         subject = StringUtil.replace(
879             subject,
880             new String[] {
881                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
882                 "[$BLOGS_ENTRY_USER_NAME$]",
883                 "[$BLOGS_ENTRY_URL$]",
884                 "[$COMPANY_ID$]",
885                 "[$COMPANY_MX$]",
886                 "[$COMPANY_NAME$]",
887                 "[$COMMUNITY_NAME$]",
888                 "[$FROM_ADDRESS$]",
889                 "[$FROM_NAME$]",
890                 "[$PORTAL_URL$]",
891                 "[$PORTLET_NAME$]"
892             },
893             new String[] {
894                 emailAddress,
895                 fullName,
896                 entryURL,
897                 String.valueOf(company.getCompanyId()),
898                 company.getMx(),
899                 company.getName(),
900                 group.getName(),
901                 fromAddress,
902                 fromName,
903                 company.getVirtualHost(),
904                 portletName
905             });
906 
907         body = StringUtil.replace(
908             body,
909             new String[] {
910                 "[$BLOGS_ENTRY_USER_ADDRESS$]",
911                 "[$BLOGS_ENTRY_USER_NAME$]",
912                 "[$BLOGS_ENTRY_URL$]",
913                 "[$COMPANY_ID$]",
914                 "[$COMPANY_MX$]",
915                 "[$COMPANY_NAME$]",
916                 "[$COMMUNITY_NAME$]",
917                 "[$FROM_ADDRESS$]",
918                 "[$FROM_NAME$]",
919                 "[$PORTAL_URL$]",
920                 "[$PORTLET_NAME$]"
921             },
922             new String[] {
923                 emailAddress,
924                 fullName,
925                 entryURL,
926                 String.valueOf(company.getCompanyId()),
927                 company.getMx(),
928                 company.getName(),
929                 group.getName(),
930                 fromAddress,
931                 fromName,
932                 company.getVirtualHost(),
933                 portletName
934             });
935 
936         Message message = new Message();
937 
938         message.put("companyId", entry.getCompanyId());
939         message.put("userId", entry.getUserId());
940         message.put("groupId", entry.getGroupId());
941         message.put("entryId", entry.getEntryId());
942         message.put("fromName", fromName);
943         message.put("fromAddress", fromAddress);
944         message.put("subject", subject);
945         message.put("body", body);
946         message.put("replyToAddress", fromAddress);
947         message.put(
948             "mailId", BlogsUtil.getMailId(company.getMx(), entry.getEntryId()));
949         message.put("htmlFormat", Boolean.TRUE);
950 
951         MessageBusUtil.sendMessage(DestinationNames.BLOGS, message);
952     }
953 
954     protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
955         throws PortalException, SystemException {
956 
957         if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
958             return;
959         }
960 
961         String layoutFullURL = PortalUtil.getLayoutFullURL(
962             serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
963 
964         if (Validator.isNull(layoutFullURL)) {
965             return;
966         }
967 
968         if (layoutFullURL.contains("://localhost")) {
969             if (_log.isDebugEnabled()) {
970                 _log.debug(
971                     "Not pinging Google because of localhost URL " +
972                         layoutFullURL);
973             }
974 
975             return;
976         }
977 
978         Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
979 
980         StringBundler sb = new StringBundler(6);
981 
982         String name = group.getDescriptiveName();
983         String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
984         String changesURL =
985             layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
986 
987         sb.append("http://blogsearch.google.com/ping?name=");
988         sb.append(HttpUtil.encodeURL(name));
989         sb.append("&url=");
990         sb.append(HttpUtil.encodeURL(url));
991         sb.append("&changesURL=");
992         sb.append(HttpUtil.encodeURL(changesURL));
993 
994         String location = sb.toString();
995 
996         if (_log.isInfoEnabled()) {
997             _log.info("Pinging Google at " + location);
998         }
999 
1000        try {
1001            String response = HttpUtil.URLtoString(sb.toString());
1002
1003            if (_log.isInfoEnabled()) {
1004                _log.info("Google ping response: " + response);
1005            }
1006        }
1007        catch (IOException ioe) {
1008            _log.error("Unable to ping Google at " + location, ioe);
1009        }
1010    }
1011
1012    protected boolean pingTrackback(String trackback, Map<String, String> parts)
1013        throws Exception {
1014
1015        if (_log.isDebugEnabled()) {
1016            _log.debug("Pinging trackback " + trackback);
1017        }
1018
1019        Http.Options options = new Http.Options();
1020
1021        options.setLocation(trackback);
1022        options.setParts(parts);
1023        options.setPost(true);
1024
1025        String xml = HttpUtil.URLtoString(options);
1026
1027        if (_log.isDebugEnabled()) {
1028            _log.debug(xml);
1029        }
1030
1031        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
1032
1033        XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(
1034            new UnsyncStringReader(xml));
1035
1036        String error = xml;
1037
1038        try {
1039            xmlStreamReader.nextTag();
1040            xmlStreamReader.nextTag();
1041
1042            String name = xmlStreamReader.getLocalName();
1043
1044            if (name.equals("error")) {
1045                int status = GetterUtil.getInteger(
1046                    xmlStreamReader.getElementText(), 1);
1047
1048                if (status == 0) {
1049                    return true;
1050                }
1051
1052                xmlStreamReader.nextTag();
1053
1054                name = xmlStreamReader.getLocalName();
1055
1056                if (name.equals("message")) {
1057                    error = xmlStreamReader.getElementText();
1058                }
1059            }
1060        }
1061        finally {
1062            if (xmlStreamReader != null) {
1063                try {
1064                    xmlStreamReader.close();
1065                }
1066                catch (Exception e) {
1067                }
1068            }
1069        }
1070
1071        _log.error(
1072            "Error while pinging trackback at " + trackback + ": " + error);
1073
1074        return false;
1075    }
1076
1077    protected void pingTrackbacks(
1078            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
1079            ServiceContext serviceContext)
1080        throws SystemException {
1081
1082        if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
1083            !entry.isAllowTrackbacks() || !entry.isApproved()) {
1084
1085            return;
1086        }
1087
1088        String layoutFullURL = serviceContext.getLayoutFullURL();
1089
1090        if (Validator.isNull(layoutFullURL)) {
1091            return;
1092        }
1093
1094        Map<String, String> parts = new HashMap<String, String>();
1095
1096        String excerpt = StringUtil.shorten(
1097            HtmlUtil.extractText(entry.getContent()),
1098            PropsValues.BLOGS_TRACKBACK_EXCERPT_LENGTH);
1099        String url =
1100            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1101                entry.getUrlTitle();
1102
1103        parts.put("title", entry.getTitle());
1104        parts.put("excerpt", excerpt);
1105        parts.put("url", url);
1106        parts.put("blog_name", entry.getUserName());
1107
1108        Set<String> trackbacksSet = null;
1109
1110        if (Validator.isNotNull(trackbacks)) {
1111            trackbacksSet = SetUtil.fromArray(trackbacks);
1112        }
1113        else {
1114            trackbacksSet = new HashSet<String>();
1115        }
1116
1117        if (pingOldTrackbacks) {
1118            trackbacksSet.addAll(
1119                SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
1120
1121            entry.setTrackbacks(StringPool.BLANK);
1122
1123            blogsEntryPersistence.update(entry, false);
1124        }
1125
1126        Set<String> oldTrackbacks = SetUtil.fromArray(
1127            StringUtil.split(entry.getTrackbacks()));
1128
1129        Set<String> validTrackbacks = new HashSet<String>();
1130
1131        for (String trackback : trackbacksSet) {
1132            if (oldTrackbacks.contains(trackback)) {
1133                continue;
1134            }
1135
1136            try {
1137                if (pingTrackback(trackback, parts)) {
1138                    validTrackbacks.add(trackback);
1139                }
1140            }
1141            catch (Exception e) {
1142                _log.error("Error while pinging trackback at " + trackback, e);
1143            }
1144        }
1145
1146        if (!validTrackbacks.isEmpty()) {
1147            String newTrackbacks = StringUtil.merge(validTrackbacks);
1148
1149            if (Validator.isNotNull(entry.getTrackbacks())) {
1150                newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
1151            }
1152
1153            entry.setTrackbacks(newTrackbacks);
1154
1155            blogsEntryPersistence.update(entry, false);
1156        }
1157    }
1158
1159    protected void reIndexEntries(long companyId) throws SystemException {
1160        int count = blogsEntryPersistence.countByCompanyId(companyId);
1161
1162        int pages = count / Indexer.DEFAULT_INTERVAL;
1163
1164        for (int i = 0; i <= pages; i++) {
1165            int start = (i * Indexer.DEFAULT_INTERVAL);
1166            int end = start + Indexer.DEFAULT_INTERVAL;
1167
1168            reIndexEntries(companyId, start, end);
1169        }
1170    }
1171
1172    protected void reIndexEntries(long companyId, int start, int end)
1173        throws SystemException {
1174
1175        List<BlogsEntry> entries = blogsEntryPersistence.findByCompanyId(
1176            companyId, start, end);
1177
1178        for (BlogsEntry entry : entries) {
1179            reIndex(entry);
1180        }
1181    }
1182
1183    protected void validate(String title, String content)
1184        throws PortalException {
1185
1186        if (Validator.isNull(title)) {
1187            throw new EntryTitleException();
1188        }
1189        else if (Validator.isNull(content)) {
1190            throw new EntryContentException();
1191        }
1192    }
1193
1194    private static final String[] _KEYWORDS_FIELDS = {
1195        Field.CONTENT, Field.TITLE, Field.USER_NAME
1196    };
1197
1198    private static Log _log = LogFactoryUtil.getLog(
1199        BlogsEntryLocalServiceImpl.class);
1200
1201}