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