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