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