1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions 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.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.search.BooleanClauseOccur;
30  import com.liferay.portal.kernel.search.BooleanQuery;
31  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
32  import com.liferay.portal.kernel.search.Field;
33  import com.liferay.portal.kernel.search.Hits;
34  import com.liferay.portal.kernel.search.SearchEngineUtil;
35  import com.liferay.portal.kernel.search.SearchException;
36  import com.liferay.portal.kernel.util.ContentTypes;
37  import com.liferay.portal.kernel.util.GetterUtil;
38  import com.liferay.portal.kernel.util.HtmlUtil;
39  import com.liferay.portal.kernel.util.HttpUtil;
40  import com.liferay.portal.kernel.util.OrderByComparator;
41  import com.liferay.portal.kernel.util.SetUtil;
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.Group;
46  import com.liferay.portal.model.ResourceConstants;
47  import com.liferay.portal.model.User;
48  import com.liferay.portal.service.ServiceContext;
49  import com.liferay.portal.util.FriendlyURLNormalizer;
50  import com.liferay.portal.util.Portal;
51  import com.liferay.portal.util.PortalUtil;
52  import com.liferay.portal.util.PropsValues;
53  import com.liferay.portlet.blogs.EntryContentException;
54  import com.liferay.portlet.blogs.EntryDisplayDateException;
55  import com.liferay.portlet.blogs.EntryTitleException;
56  import com.liferay.portlet.blogs.model.BlogsEntry;
57  import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
58  import com.liferay.portlet.blogs.social.BlogsActivityKeys;
59  import com.liferay.portlet.blogs.util.Indexer;
60  import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
61  import com.liferay.portlet.expando.model.ExpandoBridge;
62  
63  import java.io.IOException;
64  import java.io.StringReader;
65  
66  import java.util.Date;
67  import java.util.HashMap;
68  import java.util.HashSet;
69  import java.util.List;
70  import java.util.Map;
71  import java.util.Set;
72  
73  import javax.xml.stream.XMLInputFactory;
74  import javax.xml.stream.XMLStreamReader;
75  
76  /**
77   * <a href="BlogsEntryLocalServiceImpl.java.html"><b><i>View Source</i></b>
78   * </a>
79   *
80   * @author Brian Wing Shun Chan
81   * @author Wilson S. Man
82   * @author Raymond Augé
83   *
84   */
85  public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
86  
87      public BlogsEntry addEntry(
88              long userId, String title, String content, int displayDateMonth,
89              int displayDateDay, int displayDateYear, int displayDateHour,
90              int displayDateMinute, boolean draft, boolean allowTrackbacks,
91              String[] trackbacks, ServiceContext serviceContext)
92          throws PortalException, SystemException {
93  
94          return addEntry(
95              null, userId, title, content, displayDateMonth, displayDateDay,
96              displayDateYear, displayDateHour, displayDateMinute, draft,
97              allowTrackbacks, trackbacks, serviceContext);
98      }
99  
100     public BlogsEntry addEntry(
101             String uuid, long userId, String title, String content,
102             int displayDateMonth, int displayDateDay, int displayDateYear,
103             int displayDateHour, int displayDateMinute, boolean draft,
104             boolean allowTrackbacks, String[] trackbacks,
105             ServiceContext serviceContext)
106         throws PortalException, SystemException {
107 
108         // Entry
109 
110         User user = userPersistence.findByPrimaryKey(userId);
111         long groupId = serviceContext.getScopeGroupId();
112 
113         Date displayDate = PortalUtil.getDate(
114             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
115             displayDateMinute, user.getTimeZone(),
116             new EntryDisplayDateException());
117 
118         Date now = new Date();
119 
120         validate(title, content);
121 
122         long entryId = counterLocalService.increment();
123 
124         BlogsEntry entry = blogsEntryPersistence.create(entryId);
125 
126         entry.setUuid(uuid);
127         entry.setGroupId(groupId);
128         entry.setCompanyId(user.getCompanyId());
129         entry.setUserId(user.getUserId());
130         entry.setUserName(user.getFullName());
131         entry.setCreateDate(now);
132         entry.setModifiedDate(now);
133         entry.setTitle(title);
134         entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
135         entry.setContent(content);
136         entry.setDisplayDate(displayDate);
137         entry.setDraft(draft);
138         entry.setAllowTrackbacks(allowTrackbacks);
139 
140         blogsEntryPersistence.update(entry, false);
141 
142         // Resources
143 
144         if (serviceContext.getAddCommunityPermissions() ||
145             serviceContext.getAddGuestPermissions()) {
146 
147             addEntryResources(
148                 entry, serviceContext.getAddCommunityPermissions(),
149                 serviceContext.getAddGuestPermissions());
150         }
151         else {
152             addEntryResources(
153                 entry, serviceContext.getCommunityPermissions(),
154                 serviceContext.getGuestPermissions());
155         }
156 
157         // Expando
158 
159         ExpandoBridge expandoBridge = entry.getExpandoBridge();
160 
161         expandoBridge.setAttributes(serviceContext);
162 
163         // Statistics
164 
165         if (!draft) {
166             blogsStatsUserLocalService.updateStatsUser(groupId, userId, now);
167         }
168 
169         // Message boards
170 
171         if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
172             mbMessageLocalService.addDiscussionMessage(
173                 userId, entry.getUserName(), BlogsEntry.class.getName(),
174                 entryId);
175         }
176 
177         // Social
178 
179         if (!draft) {
180             socialActivityLocalService.addActivity(
181                 userId, groupId, BlogsEntry.class.getName(), entryId,
182                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
183         }
184 
185         // Tags
186 
187         updateTagsAsset(userId, entry, serviceContext.getTagsEntries());
188 
189         // Indexer
190 
191         reIndex(entry);
192 
193         // Ping
194 
195         if (!draft) {
196             pingGoogle(entry, serviceContext);
197 
198             if (allowTrackbacks) {
199                 pingTrackbacks(entry, trackbacks, false, serviceContext);
200             }
201         }
202 
203         return entry;
204     }
205 
206     public void addEntryResources(
207             long entryId, boolean addCommunityPermissions,
208             boolean addGuestPermissions)
209         throws PortalException, SystemException {
210 
211         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
212 
213         addEntryResources(entry, addCommunityPermissions, addGuestPermissions);
214     }
215 
216     public void addEntryResources(
217             BlogsEntry entry, boolean addCommunityPermissions,
218             boolean addGuestPermissions)
219         throws PortalException, SystemException {
220 
221         resourceLocalService.addResources(
222             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
223             BlogsEntry.class.getName(), entry.getEntryId(), false,
224             addCommunityPermissions, addGuestPermissions);
225     }
226 
227     public void addEntryResources(
228             long entryId, String[] communityPermissions,
229             String[] guestPermissions)
230         throws PortalException, SystemException {
231 
232         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
233 
234         addEntryResources(entry, communityPermissions, guestPermissions);
235     }
236 
237     public void addEntryResources(
238             BlogsEntry entry, String[] communityPermissions,
239             String[] guestPermissions)
240         throws PortalException, SystemException {
241 
242         resourceLocalService.addModelResources(
243             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
244             BlogsEntry.class.getName(), entry.getEntryId(),
245             communityPermissions, guestPermissions);
246     }
247 
248     public void deleteEntries(long groupId)
249         throws PortalException, SystemException {
250 
251         for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
252             deleteEntry(entry);
253         }
254     }
255 
256     public void deleteEntry(long entryId)
257         throws PortalException, SystemException {
258 
259         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
260 
261         deleteEntry(entry);
262     }
263 
264     public void deleteEntry(BlogsEntry entry)
265         throws PortalException, SystemException {
266 
267         // Indexer
268 
269         try {
270             Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId());
271         }
272         catch (SearchException se) {
273             _log.error("Deleting index " + entry.getEntryId(), se);
274         }
275 
276         // Tags
277 
278         tagsAssetLocalService.deleteAsset(
279             BlogsEntry.class.getName(), entry.getEntryId());
280 
281         // Social
282 
283         socialActivityLocalService.deleteActivities(
284             BlogsEntry.class.getName(), entry.getEntryId());
285 
286         // Ratings
287 
288         ratingsStatsLocalService.deleteStats(
289             BlogsEntry.class.getName(), entry.getEntryId());
290 
291         // Message boards
292 
293         mbMessageLocalService.deleteDiscussionMessages(
294             BlogsEntry.class.getName(), entry.getEntryId());
295 
296         // Statistics
297 
298         blogsStatsUserLocalService.updateStatsUser(
299             entry.getGroupId(), entry.getUserId());
300 
301         // Expando
302 
303         expandoValueLocalService.deleteValues(
304             BlogsEntry.class.getName(), entry.getEntryId());
305 
306         // Resources
307 
308         resourceLocalService.deleteResource(
309             entry.getCompanyId(), BlogsEntry.class.getName(),
310             ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
311 
312         // Entry
313 
314         blogsEntryPersistence.remove(entry);
315     }
316 
317     public List<BlogsEntry> getCompanyEntries(
318             long companyId, int start, int end)
319         throws SystemException {
320 
321         return blogsEntryPersistence.findByCompanyId(companyId, start, end);
322     }
323 
324     public List<BlogsEntry> getCompanyEntries(
325             long companyId, int start, int end, OrderByComparator obc)
326         throws SystemException {
327 
328         return blogsEntryPersistence.findByCompanyId(
329             companyId, start, end, obc);
330     }
331 
332     public List<BlogsEntry> getCompanyEntries(
333             long companyId, boolean draft, int start, int end)
334         throws SystemException {
335 
336         return blogsEntryPersistence.findByC_D_D(
337             companyId, new Date(), draft, start, end);
338     }
339 
340     public List<BlogsEntry> getCompanyEntries(
341             long companyId, boolean draft, int start, int end,
342             OrderByComparator obc)
343         throws SystemException {
344 
345         return blogsEntryPersistence.findByC_D_D(
346             companyId, new Date(), draft, start, end, obc);
347     }
348 
349     public int getCompanyEntriesCount(long companyId) throws SystemException {
350         return blogsEntryPersistence.countByCompanyId(companyId);
351     }
352 
353     public int getCompanyEntriesCount(long companyId, boolean draft)
354         throws SystemException {
355 
356         return blogsEntryPersistence.countByC_D_D(companyId, new Date(), draft);
357     }
358 
359     public BlogsEntry[] getEntriesPrevAndNext(long entryId)
360         throws PortalException, SystemException {
361 
362         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
363 
364         return blogsEntryPersistence.findByGroupId_PrevAndNext(
365             entry.getEntryId(), entry.getGroupId(),
366             new EntryDisplayDateComparator(true));
367     }
368 
369     public BlogsEntry getEntry(long entryId)
370         throws PortalException, SystemException {
371 
372         return blogsEntryPersistence.findByPrimaryKey(entryId);
373     }
374 
375     public BlogsEntry getEntry(long groupId, String urlTitle)
376         throws PortalException, SystemException {
377 
378         return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
379     }
380 
381     public List<BlogsEntry> getGroupEntries(long groupId, int start, int end)
382         throws SystemException {
383 
384         return blogsEntryPersistence.findByGroupId(groupId, start, end);
385     }
386 
387     public List<BlogsEntry> getGroupEntries(
388             long groupId, int start, int end, OrderByComparator obc)
389         throws SystemException {
390 
391         return blogsEntryPersistence.findByGroupId(groupId, start, end, obc);
392     }
393 
394     public List<BlogsEntry> getGroupEntries(
395             long groupId, boolean draft, int start, int end)
396         throws SystemException {
397 
398         return blogsEntryPersistence.findByG_D_D(
399             groupId, new Date(), draft, start, end);
400     }
401 
402     public List<BlogsEntry> getGroupEntries(
403             long groupId, boolean draft, int start, int end,
404             OrderByComparator obc)
405         throws SystemException {
406 
407         return blogsEntryPersistence.findByG_D_D(
408             groupId, new Date(), draft, start, end, obc);
409     }
410 
411     public int getGroupEntriesCount(long groupId) throws SystemException {
412         return blogsEntryPersistence.countByGroupId(groupId);
413     }
414 
415     public int getGroupEntriesCount(long groupId, boolean draft)
416         throws SystemException {
417 
418         return blogsEntryPersistence.countByG_D_D(groupId, new Date(), draft);
419     }
420 
421     public List<BlogsEntry> getGroupUserEntries(
422             long groupId, long userId, int start, int end)
423         throws SystemException {
424 
425         return blogsEntryPersistence.findByG_U(groupId, userId, start, end);
426     }
427 
428     public List<BlogsEntry> getGroupUserEntries(
429             long groupId, long userId, int start, int end,
430             OrderByComparator obc)
431         throws SystemException {
432 
433         return blogsEntryPersistence.findByG_U(
434             groupId, userId, start, end, obc);
435     }
436 
437     public List<BlogsEntry> getGroupUserEntries(
438             long groupId, long userId, boolean draft, int start, int end)
439         throws SystemException {
440 
441         return blogsEntryPersistence.findByG_U_D_D(
442             groupId, userId, new Date(), draft, start, end);
443     }
444 
445     public List<BlogsEntry> getGroupUserEntries(
446             long groupId, long userId, boolean draft, int start, int end,
447             OrderByComparator obc)
448         throws SystemException {
449 
450         return blogsEntryPersistence.findByG_U_D_D(
451             groupId, userId, new Date(), draft, start, end, obc);
452     }
453 
454     public int getGroupUserEntriesCount(long groupId, long userId)
455         throws SystemException {
456 
457         return blogsEntryPersistence.countByG_U(groupId, userId);
458     }
459 
460     public int getGroupUserEntriesCount(
461             long groupId, long userId, boolean draft)
462         throws SystemException {
463 
464         return blogsEntryPersistence.countByG_U_D_D(
465             groupId, userId, new Date(), draft);
466     }
467 
468     public List<BlogsEntry> getNoAssetEntries() throws SystemException {
469         return blogsEntryFinder.findByNoAssets();
470     }
471 
472     public List<BlogsEntry> getOrganizationEntries(
473             long organizationId, boolean draft, int start, int end)
474         throws SystemException {
475 
476         return blogsEntryFinder.findByOrganizationId(
477             organizationId, new Date(), draft, start, end);
478     }
479 
480     public int getOrganizationEntriesCount(long organizationId, boolean draft)
481         throws SystemException {
482 
483         return blogsEntryFinder.countByOrganizationId(
484             organizationId, new Date(), draft);
485     }
486 
487     public String getUrlTitle(long entryId, String title) {
488         title = title.trim().toLowerCase();
489 
490         if (Validator.isNull(title) || Validator.isNumber(title) ||
491             title.equals("rss")) {
492 
493             return String.valueOf(entryId);
494         }
495         else {
496             return FriendlyURLNormalizer.normalize(
497                 title, _URL_TITLE_REPLACE_CHARS);
498         }
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                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
574             }
575 
576             if (ownerUserId > 0) {
577                 contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
578             }
579 
580             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
581 
582             if (Validator.isNotNull(keywords)) {
583                 searchQuery.addTerm(Field.USER_NAME, keywords);
584                 searchQuery.addTerm(Field.TITLE, keywords);
585                 searchQuery.addTerm(Field.CONTENT, keywords);
586                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
587             }
588 
589             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
590 
591             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
592 
593             if (searchQuery.clauses().size() > 0) {
594                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
595             }
596 
597             return SearchEngineUtil.search(
598                 companyId, groupId, userId, BlogsEntry.class.getName(),
599                 fullQuery, start, end);
600         }
601         catch (Exception e) {
602             throw new SystemException(e);
603         }
604     }
605 
606     public BlogsEntry updateEntry(
607             long userId, long entryId, String title, String content,
608             int displayDateMonth, int displayDateDay, int displayDateYear,
609             int displayDateHour, int displayDateMinute, boolean draft,
610             boolean allowTrackbacks, String[] trackbacks,
611             ServiceContext serviceContext)
612         throws PortalException, SystemException {
613 
614         // Entry
615 
616         User user = userPersistence.findByPrimaryKey(userId);
617 
618         Date displayDate = PortalUtil.getDate(
619             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
620             displayDateMinute, user.getTimeZone(),
621             new EntryDisplayDateException());
622 
623         validate(title, content);
624 
625         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
626 
627         String oldUrlTitle = entry.getUrlTitle();
628         boolean oldDraft = entry.isDraft();
629 
630         entry.setModifiedDate(new Date());
631         entry.setTitle(title);
632         entry.setUrlTitle(
633             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
634         entry.setContent(content);
635         entry.setDisplayDate(displayDate);
636         entry.setDraft(draft);
637         entry.setAllowTrackbacks(allowTrackbacks);
638 
639         blogsEntryPersistence.update(entry, false);
640 
641         // Resources
642 
643         if ((serviceContext.getCommunityPermissions() != null) ||
644             (serviceContext.getGuestPermissions() != null)) {
645 
646             updateEntryResources(
647                 entry, serviceContext.getCommunityPermissions(),
648                 serviceContext.getGuestPermissions());
649         }
650 
651         // Statistics
652 
653         if (!draft) {
654             blogsStatsUserLocalService.updateStatsUser(
655                 entry.getGroupId(), entry.getUserId(), displayDate);
656         }
657 
658         // Expando
659 
660         ExpandoBridge expandoBridge = entry.getExpandoBridge();
661 
662         expandoBridge.setAttributes(serviceContext);
663 
664         // Social
665 
666         if (oldDraft && !draft) {
667             socialActivityLocalService.addActivity(
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         reIndex(entry);
679 
680         // Ping
681 
682         if (!draft) {
683             pingGoogle(entry, serviceContext);
684 
685             if (allowTrackbacks) {
686                 String urlTitle = entry.getUrlTitle();
687 
688                 if (!oldDraft && !oldUrlTitle.equals(urlTitle)) {
689                     pingTrackbacks(entry, trackbacks, true, serviceContext);
690                 }
691                 else {
692                     pingTrackbacks(entry, trackbacks, false, serviceContext);
693                 }
694             }
695         }
696 
697         return entry;
698     }
699 
700     public void updateEntryResources(
701             BlogsEntry entry, String[] communityPermissions,
702             String[] guestPermissions)
703         throws PortalException, SystemException {
704 
705         resourceLocalService.updateResources(
706             entry.getCompanyId(), entry.getGroupId(),
707             BlogsEntry.class.getName(), entry.getEntryId(),
708             communityPermissions, guestPermissions);
709     }
710 
711     public void updateTagsAsset(
712             long userId, BlogsEntry entry, String[] tagsEntries)
713         throws PortalException, SystemException {
714 
715         tagsAssetLocalService.updateAsset(
716             userId, entry.getGroupId(), BlogsEntry.class.getName(),
717             entry.getEntryId(), null, tagsEntries, !entry.isDraft(), null, null,
718             entry.getDisplayDate(), null, ContentTypes.TEXT_HTML,
719             entry.getTitle(), null, null, null, 0, 0, null, false);
720     }
721 
722     protected String getUniqueUrlTitle(
723             long entryId, long groupId, String title)
724         throws SystemException {
725 
726         String urlTitle = getUrlTitle(entryId, title);
727 
728         String newUrlTitle = urlTitle;
729 
730         for (int i = 1;; i++) {
731             BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
732                 groupId, newUrlTitle);
733 
734             if ((entry == null) || (entry.getEntryId() == entryId)) {
735                 break;
736             }
737             else {
738                 newUrlTitle = urlTitle + StringPool.DASH + i;
739             }
740         }
741 
742         return newUrlTitle;
743     }
744 
745     protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
746         throws PortalException, SystemException {
747 
748         if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED) {
749             return;
750         }
751 
752         String portalURL = serviceContext.getPortalURL();
753         String layoutURL = serviceContext.getLayoutURL();
754 
755         if (Validator.isNull(portalURL) || Validator.isNull(layoutURL) ||
756             (portalURL.indexOf("://localhost") != -1) ||
757             (portalURL.indexOf("://127.0.0.1") != -1)) {
758 
759             return;
760         }
761 
762         Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
763 
764         StringBuilder sb = new StringBuilder();
765 
766         String name = group.getDescriptiveName();
767         String url =
768             portalURL + layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
769         String changesURL =
770             portalURL + layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
771 
772         sb.append("http://blogsearch.google.com/ping?name=");
773         sb.append(HttpUtil.encodeURL(name));
774         sb.append("&url=");
775         sb.append(HttpUtil.encodeURL(url));
776         sb.append("&changesURL=");
777         sb.append(HttpUtil.encodeURL(changesURL));
778 
779         String location = sb.toString();
780 
781         if (_log.isInfoEnabled()) {
782             _log.info("Pinging Google at " + location);
783         }
784 
785         try {
786             String response = HttpUtil.URLtoString(sb.toString());
787 
788             if (_log.isInfoEnabled()) {
789                 _log.info("Google ping response: " + response);
790             }
791         }
792         catch (IOException ioe) {
793             _log.error("Unable to ping Google at " + location, ioe);
794         }
795     }
796 
797     protected boolean pingTrackback(String trackback, Map<String, String> parts)
798         throws Exception {
799 
800         if (_log.isDebugEnabled()) {
801             _log.debug("Pinging trackback " + trackback);
802         }
803 
804         String xml = HttpUtil.URLtoString(trackback, null, null, parts, true);
805 
806         if (_log.isDebugEnabled()) {
807             _log.debug(xml);
808         }
809 
810         XMLInputFactory inputFactory = XMLInputFactory.newInstance();
811 
812         XMLStreamReader reader = inputFactory.createXMLStreamReader(
813             new StringReader(xml));
814 
815         String error = xml;
816 
817         try {
818             reader.nextTag();
819             reader.nextTag();
820 
821             String name = reader.getLocalName();
822 
823             if (name.equals("error")) {
824                 int status = GetterUtil.getInteger(reader.getElementText(), 1);
825 
826                 if (status == 0) {
827                     return true;
828                 }
829 
830                 reader.nextTag();
831 
832                 name = reader.getLocalName();
833 
834                 if (name.equals("message")) {
835                     error = reader.getElementText();
836                 }
837             }
838         }
839         finally {
840             if (reader != null) {
841                 try {
842                     reader.close();
843                 }
844                 catch (Exception e) {
845                 }
846             }
847         }
848 
849         _log.error(
850             "Error while pinging trackback at " + trackback + ": " + error);
851 
852         return false;
853     }
854 
855     protected void pingTrackbacks(
856             BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
857             ServiceContext serviceContext)
858         throws SystemException {
859 
860         if (!PropsValues.BLOGS_TRACKBACK_ENABLED) {
861             return;
862         }
863 
864         String portalURL = serviceContext.getPortalURL();
865         String layoutURL = serviceContext.getLayoutURL();
866 
867         if (Validator.isNull(portalURL) || Validator.isNull(layoutURL)) {
868             return;
869         }
870 
871         Map<String, String> parts = new HashMap<String, String>();
872 
873         String excerpt = StringUtil.shorten(
874             HtmlUtil.extractText(entry.getContent()),
875             PropsValues.BLOGS_TRACKBACK_EXCERPT_LENGTH);
876         String url =
877             portalURL + layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
878                 entry.getUrlTitle();
879 
880         parts.put("title", entry.getTitle());
881         parts.put("excerpt", excerpt);
882         parts.put("url", url);
883         parts.put("blog_name", entry.getUserName());
884 
885         Set<String> trackbacksSet = null;
886 
887         if (Validator.isNotNull(trackbacks)) {
888             trackbacksSet = SetUtil.fromArray(trackbacks);
889         }
890         else {
891             trackbacksSet = new HashSet<String>();
892         }
893 
894         if (pingOldTrackbacks) {
895             trackbacksSet.addAll(
896                 SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
897 
898             entry.setTrackbacks(StringPool.BLANK);
899 
900             blogsEntryPersistence.update(entry, false);
901         }
902 
903         Set<String> oldTrackbacks = SetUtil.fromArray(
904             StringUtil.split(entry.getTrackbacks()));
905 
906         Set<String> validTrackbacks = new HashSet<String>();
907 
908         for (String trackback : trackbacksSet) {
909             if (oldTrackbacks.contains(trackback)) {
910                 continue;
911             }
912 
913             try {
914                 if (pingTrackback(trackback, parts)) {
915                     validTrackbacks.add(trackback);
916                 }
917             }
918             catch (Exception e) {
919                 _log.error("Error while pinging trackback at " + trackback, e);
920             }
921         }
922 
923         if (!validTrackbacks.isEmpty()) {
924             String newTrackbacks = StringUtil.merge(validTrackbacks);
925 
926             if (Validator.isNotNull(entry.getTrackbacks())) {
927                 newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
928             }
929 
930             entry.setTrackbacks(newTrackbacks);
931 
932             blogsEntryPersistence.update(entry, false);
933         }
934     }
935 
936     protected void reIndexEntries(long companyId) throws SystemException {
937         int count = blogsEntryPersistence.countByCompanyId(companyId);
938 
939         int pages = count / Indexer.DEFAULT_INTERVAL;
940 
941         for (int i = 0; i <= pages; i++) {
942             int start = (i * Indexer.DEFAULT_INTERVAL);
943             int end = start + Indexer.DEFAULT_INTERVAL;
944 
945             reIndexEntries(companyId, start, end);
946         }
947     }
948 
949     protected void reIndexEntries(long companyId, int start, int end)
950         throws SystemException {
951 
952         List<BlogsEntry> entries = blogsEntryPersistence.findByCompanyId(
953             companyId, start, end);
954 
955         for (BlogsEntry entry : entries) {
956             reIndex(entry);
957         }
958     }
959 
960     protected void validate(String title, String content)
961         throws PortalException {
962 
963         if (Validator.isNull(title)) {
964             throw new EntryTitleException();
965         }
966         else if (Validator.isNull(content)) {
967             throw new EntryContentException();
968         }
969     }
970 
971     private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
972         '.', '/'
973     };
974 
975     private static Log _log =
976         LogFactoryUtil.getLog(BlogsEntryLocalServiceImpl.class);
977 
978 }