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.Document;
28  import com.liferay.portal.kernel.search.Field;
29  import com.liferay.portal.kernel.search.Hits;
30  import com.liferay.portal.kernel.search.SearchEngineUtil;
31  import com.liferay.portal.kernel.search.SearchException;
32  import com.liferay.portal.kernel.util.ArrayUtil;
33  import com.liferay.portal.kernel.util.CharPool;
34  import com.liferay.portal.kernel.util.ContentTypes;
35  import com.liferay.portal.kernel.util.GetterUtil;
36  import com.liferay.portal.kernel.util.HtmlUtil;
37  import com.liferay.portal.kernel.util.HttpUtil;
38  import com.liferay.portal.kernel.util.OrderByComparator;
39  import com.liferay.portal.kernel.util.StringPool;
40  import com.liferay.portal.kernel.util.StringUtil;
41  import com.liferay.portal.kernel.util.Validator;
42  import com.liferay.portal.model.Group;
43  import com.liferay.portal.model.ResourceConstants;
44  import com.liferay.portal.model.User;
45  import com.liferay.portal.search.lucene.LuceneUtil;
46  import com.liferay.portal.theme.ThemeDisplay;
47  import com.liferay.portal.util.PortalUtil;
48  import com.liferay.portal.util.PropsValues;
49  import com.liferay.portlet.blogs.EntryContentException;
50  import com.liferay.portlet.blogs.EntryDisplayDateException;
51  import com.liferay.portlet.blogs.EntryTitleException;
52  import com.liferay.portlet.blogs.model.BlogsEntry;
53  import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
54  import com.liferay.portlet.blogs.social.BlogsActivityKeys;
55  import com.liferay.portlet.blogs.util.Indexer;
56  import com.liferay.util.Normalizer;
57  import com.liferay.util.SetUtil;
58  
59  import java.io.IOException;
60  import java.io.StringReader;
61  
62  import java.util.Date;
63  import java.util.HashMap;
64  import java.util.HashSet;
65  import java.util.List;
66  import java.util.Map;
67  import java.util.Set;
68  
69  import javax.xml.stream.XMLInputFactory;
70  import javax.xml.stream.XMLStreamReader;
71  
72  import org.apache.commons.logging.Log;
73  import org.apache.commons.logging.LogFactory;
74  import org.apache.lucene.search.BooleanClause;
75  import org.apache.lucene.search.BooleanQuery;
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.getPortletGroupId(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.getEntryId());
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 getEntry(long entryId)
383         throws PortalException, SystemException {
384 
385         return blogsEntryPersistence.findByPrimaryKey(entryId);
386     }
387 
388     public BlogsEntry getEntry(long groupId, String urlTitle)
389         throws PortalException, SystemException {
390 
391         return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
392     }
393 
394     public List<BlogsEntry> getGroupEntries(long groupId, int start, int end)
395         throws SystemException {
396 
397         return blogsEntryPersistence.findByGroupId(groupId, start, end);
398     }
399 
400     public List<BlogsEntry> getGroupEntries(
401             long groupId, int start, int end, OrderByComparator obc)
402         throws SystemException {
403 
404         return blogsEntryPersistence.findByGroupId(groupId, start, end, obc);
405     }
406 
407     public List<BlogsEntry> getGroupEntries(
408             long groupId, boolean draft, int start, int end)
409         throws SystemException {
410 
411         return blogsEntryPersistence.findByG_D(groupId, draft, start, end);
412     }
413 
414     public List<BlogsEntry> getGroupEntries(
415             long groupId, boolean draft, int start, int end,
416             OrderByComparator obc)
417         throws SystemException {
418 
419         return blogsEntryPersistence.findByG_D(groupId, draft, start, end, obc);
420     }
421 
422     public int getGroupEntriesCount(long groupId) throws SystemException {
423         return blogsEntryPersistence.countByGroupId(groupId);
424     }
425 
426     public int getGroupEntriesCount(long groupId, boolean draft)
427         throws SystemException {
428 
429         return blogsEntryPersistence.countByG_D(groupId, draft);
430     }
431 
432     public List<BlogsEntry> getGroupUserEntries(
433             long groupId, long userId, int start, int end)
434         throws SystemException {
435 
436         return blogsEntryPersistence.findByG_U(groupId, userId, start, end);
437     }
438 
439     public List<BlogsEntry> getGroupUserEntries(
440             long groupId, long userId, int start, int end,
441             OrderByComparator obc)
442         throws SystemException {
443 
444         return blogsEntryPersistence.findByG_U(
445             groupId, userId, start, end, obc);
446     }
447 
448     public List<BlogsEntry> getGroupUserEntries(
449             long groupId, long userId, boolean draft, int start, int end)
450         throws SystemException {
451 
452         return blogsEntryPersistence.findByG_U_D(
453             groupId, userId, draft, start, end);
454     }
455 
456     public List<BlogsEntry> getGroupUserEntries(
457             long groupId, long userId, boolean draft, int start, int end,
458             OrderByComparator obc)
459         throws SystemException {
460 
461         return blogsEntryPersistence.findByG_U_D(
462             groupId, userId, draft, start, end, obc);
463     }
464 
465     public int getGroupUserEntriesCount(long groupId, long userId)
466         throws SystemException {
467 
468         return blogsEntryPersistence.countByG_U(groupId, userId);
469     }
470 
471     public int getGroupUserEntriesCount(
472             long groupId, long userId, boolean draft)
473         throws SystemException {
474 
475         return blogsEntryPersistence.countByG_U_D(groupId, userId, draft);
476     }
477 
478     public List<BlogsEntry> getNoAssetEntries() throws SystemException {
479         return blogsEntryFinder.findByNoAssets();
480     }
481 
482     public List<BlogsEntry> getOrganizationEntries(
483             long organizationId, boolean draft, int start, int end)
484         throws SystemException {
485 
486         return blogsEntryFinder.findByOrganizationId(
487             organizationId, draft, start, end);
488     }
489 
490     public int getOrganizationEntriesCount(long organizationId, boolean draft)
491         throws SystemException {
492 
493         return blogsEntryFinder.countByOrganizationId(
494             organizationId, draft);
495     }
496 
497     public String getUrlTitle(long entryId, String title) {
498         String urlTitle = String.valueOf(entryId);
499 
500         title = title.trim().toLowerCase();
501 
502         if (Validator.isNull(title) || Validator.isNumber(title) ||
503             title.equals("rss")) {
504 
505             return urlTitle;
506         }
507 
508         title = Normalizer.normalizeToAscii(title);
509 
510         char[] urlTitleCharArray = title.toCharArray();
511 
512         for (int i = 0; i < urlTitleCharArray.length; i++) {
513             char oldChar = urlTitleCharArray[i];
514 
515             char newChar = oldChar;
516 
517             if ((oldChar == CharPool.DASH) ||
518                 (Validator.isChar(oldChar)) || (Validator.isDigit(oldChar))) {
519 
520             }
521             else if (ArrayUtil.contains(_URL_TITLE_REPLACE_CHARS, oldChar)) {
522                 newChar = CharPool.DASH;
523             }
524             else {
525                 return urlTitle;
526             }
527 
528             if (oldChar != newChar) {
529                 urlTitleCharArray[i] = newChar;
530             }
531         }
532 
533         urlTitle = new String(urlTitleCharArray);
534 
535         return urlTitle;
536     }
537 
538     public void reIndex(String[] ids) throws SystemException {
539         if (SearchEngineUtil.isIndexReadOnly()) {
540             return;
541         }
542 
543         long companyId = GetterUtil.getLong(ids[0]);
544 
545         try {
546             for (BlogsEntry entry :
547                     blogsEntryPersistence.findByCompanyId(companyId)) {
548 
549                 long groupId = entry.getGroupId();
550                 long userId = entry.getUserId();
551                 long entryId = entry.getEntryId();
552                 String title = entry.getTitle();
553                 String content = entry.getContent();
554 
555                 String[] tagsEntries = tagsEntryLocalService.getEntryNames(
556                     BlogsEntry.class.getName(), entryId);
557 
558                 try {
559                     Document doc = Indexer.getEntryDocument(
560                         companyId, groupId, userId, entryId, title, content,
561                         tagsEntries);
562 
563                     SearchEngineUtil.addDocument(companyId, doc);
564                 }
565                 catch (Exception e1) {
566                     _log.error("Reindexing " + entryId, e1);
567                 }
568             }
569         }
570         catch (SystemException se) {
571             throw se;
572         }
573         catch (Exception e2) {
574             throw new SystemException(e2);
575         }
576     }
577 
578     public Hits search(
579             long companyId, long groupId, long userId, String keywords,
580             int start, int end)
581         throws SystemException {
582 
583         try {
584             BooleanQuery contextQuery = new BooleanQuery();
585 
586             LuceneUtil.addRequiredTerm(
587                 contextQuery, Field.PORTLET_ID, Indexer.PORTLET_ID);
588 
589             if (groupId > 0) {
590                 LuceneUtil.addRequiredTerm(
591                     contextQuery, Field.GROUP_ID, groupId);
592             }
593 
594             if (userId > 0) {
595                 LuceneUtil.addRequiredTerm(
596                     contextQuery, Field.USER_ID, userId);
597             }
598 
599             BooleanQuery searchQuery = new BooleanQuery();
600 
601             if (Validator.isNotNull(keywords)) {
602                 LuceneUtil.addTerm(searchQuery, Field.TITLE, keywords);
603                 LuceneUtil.addTerm(searchQuery, Field.CONTENT, keywords);
604                 LuceneUtil.addTerm(searchQuery, Field.TAGS_ENTRIES, keywords);
605             }
606 
607             BooleanQuery fullQuery = new BooleanQuery();
608 
609             fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
610 
611             if (searchQuery.clauses().size() > 0) {
612                 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
613             }
614 
615             return SearchEngineUtil.search(
616                 companyId, fullQuery.toString(), start, end);
617         }
618         catch (Exception e) {
619             throw new SystemException(e);
620         }
621     }
622 
623     public BlogsEntry updateEntry(
624             long userId, long entryId, String title, String content,
625             int displayDateMonth, int displayDateDay, int displayDateYear,
626             int displayDateHour, int displayDateMinute, boolean draft,
627             boolean allowTrackbacks, String[] trackbacks, String[] tagsEntries,
628             ThemeDisplay themeDisplay)
629         throws PortalException, SystemException {
630 
631         // Entry
632 
633         User user = userPersistence.findByPrimaryKey(userId);
634 
635         Date displayDate = PortalUtil.getDate(
636             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
637             displayDateMinute, user.getTimeZone(),
638             new EntryDisplayDateException());
639 
640         validate(title, content);
641 
642         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
643 
644         String oldUrlTitle = entry.getUrlTitle();
645         boolean oldDraft = entry.isDraft();
646 
647         entry.setModifiedDate(new Date());
648         entry.setTitle(title);
649         entry.setUrlTitle(
650             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
651         entry.setContent(content);
652         entry.setDisplayDate(displayDate);
653         entry.setDraft(draft);
654         entry.setAllowTrackbacks(allowTrackbacks);
655 
656         blogsEntryPersistence.update(entry, false);
657 
658         // Statistics
659 
660         if (!draft) {
661             blogsStatsUserLocalService.updateStatsUser(
662                 entry.getGroupId(), entry.getUserId(), displayDate);
663         }
664 
665         // Social
666 
667         if (oldDraft && !draft) {
668             socialActivityLocalService.addActivity(
669                 userId, entry.getGroupId(), BlogsEntry.class.getName(), entryId,
670                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
671         }
672 
673         // Tags
674 
675         updateTagsAsset(userId, entry, tagsEntries);
676 
677         // Lucene
678 
679         try {
680             if (!draft) {
681                 Indexer.updateEntry(
682                     entry.getCompanyId(), entry.getGroupId(), userId, entryId,
683                     title, content, tagsEntries);
684             }
685         }
686         catch (SearchException se) {
687             _log.error("Indexing " + entryId, se);
688         }
689 
690         // Ping
691 
692         if (!draft) {
693             pingGoogle(entry, themeDisplay);
694 
695             String urlTitle = entry.getUrlTitle();
696 
697             if (!oldDraft && !oldUrlTitle.equals(urlTitle)) {
698                 pingTrackbacks(entry, trackbacks, true, themeDisplay);
699             }
700             else {
701                 pingTrackbacks(entry, trackbacks, false, themeDisplay);
702             }
703         }
704 
705         return entry;
706     }
707 
708     public void updateTagsAsset(
709             long userId, BlogsEntry entry, String[] tagsEntries)
710         throws PortalException, SystemException {
711 
712         tagsAssetLocalService.updateAsset(
713             userId, entry.getGroupId(), BlogsEntry.class.getName(),
714             entry.getEntryId(), tagsEntries, null, null, null, null,
715             ContentTypes.TEXT_HTML, entry.getTitle(), null, null, null, 0, 0,
716             null, false);
717     }
718 
719     protected String getUniqueUrlTitle(
720             long entryId, long groupId, String title)
721         throws SystemException {
722 
723         String urlTitle = getUrlTitle(entryId, title);
724 
725         String newUrlTitle = new String(urlTitle);
726 
727         for (int i = 1;; i++) {
728             BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
729                 groupId, newUrlTitle);
730 
731             if ((entry == null) || (entry.getEntryId() == entryId)) {
732                 break;
733             }
734             else {
735                 newUrlTitle = urlTitle + StringPool.DASH + i;
736             }
737         }
738 
739         return newUrlTitle;
740     }
741 
742     protected void pingGoogle(BlogsEntry entry, ThemeDisplay themeDisplay)
743         throws PortalException, SystemException {
744 
745         if (themeDisplay == null) {
746             return;
747         }
748 
749         Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
750 
751         String portalURL = PortalUtil.getPortalURL(themeDisplay);
752 
753         if ((portalURL.indexOf("://localhost") != -1) ||
754             (portalURL.indexOf("://127.0.0.1") != -1)) {
755 
756             return;
757         }
758 
759         String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
760 
761         StringBuilder sb = new StringBuilder();
762 
763         String name = group.getDescriptiveName();
764         String url = portalURL + layoutURL + "/-/blogs";
765         String changesURL = portalURL + layoutURL + "/-/blogs/rss";
766 
767         sb.append("http://blogsearch.google.com/ping?name=");
768         sb.append(HttpUtil.encodeURL(name));
769         sb.append("&url=");
770         sb.append(HttpUtil.encodeURL(url));
771         sb.append("&changesURL=");
772         sb.append(HttpUtil.encodeURL(changesURL));
773 
774         String location = sb.toString();
775 
776         if (_log.isInfoEnabled()) {
777             _log.info("Pinging Google at " + location);
778         }
779 
780         try {
781             String response = HttpUtil.URLtoString(sb.toString());
782 
783             if (_log.isInfoEnabled()) {
784                 _log.info("Google ping response: " + response);
785             }
786         }
787         catch (IOException ioe) {
788             _log.error("Unable to ping Google at " + location, ioe);
789         }
790     }
791 
792     protected boolean pingTrackback(String trackback, Map<String, String> parts)
793         throws Exception {
794 
795         if (_log.isDebugEnabled()) {
796             _log.debug("Pinging trackback " + trackback);
797         }
798 
799         String xml = HttpUtil.URLtoString(trackback, null, parts, true);
800 
801         if (_log.isDebugEnabled()) {
802             _log.debug(xml);
803         }
804 
805         XMLInputFactory inputFactory = XMLInputFactory.newInstance();
806 
807         XMLStreamReader reader = inputFactory.createXMLStreamReader(
808             new StringReader(xml));
809 
810         String error = xml;
811 
812         try {
813             reader.nextTag();
814             reader.nextTag();
815 
816             String name = reader.getLocalName();
817 
818             if (name.equals("error")) {
819                 int status = GetterUtil.getInteger(reader.getElementText(), 1);
820 
821                 if (status == 0) {
822                     return true;
823                 }
824 
825                 reader.nextTag();
826 
827                 name = reader.getLocalName();
828 
829                 if (name.equals("message")) {
830                     error = reader.getElementText();
831                 }
832             }
833         }
834         finally {
835             if (reader != null) {
836                 try {
837                     reader.close();
838                 }
839                 catch (Exception e) {
840                 }
841             }
842         }
843 
844         _log.error(
845             "Error while pinging trackback at " + trackback + ": " + error);
846 
847         return false;
848     }
849 
850     protected void pingTrackbacks(
851             BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
852             ThemeDisplay themeDisplay)
853         throws SystemException {
854 
855         if (themeDisplay == null) {
856             return;
857         }
858 
859         Map<String, String> parts = new HashMap<String, String>();
860 
861         String excerpt = StringUtil.shorten(
862             HtmlUtil.extractText(entry.getContent()),
863             PropsValues.BLOGS_TRACKBACK_EXCERPT_LENGTH);
864         String url =
865             themeDisplay.getPortalURL() + PortalUtil.getLayoutURL(themeDisplay)
866                 + "/-/blogs/" + entry.getUrlTitle();
867 
868         parts.put("title", entry.getTitle());
869         parts.put("excerpt", excerpt);
870         parts.put("url", url);
871         parts.put("blog_name", entry.getUserName());
872 
873         Set<String> trackbacksSet = null;
874 
875         if (Validator.isNotNull(trackbacks)) {
876             trackbacksSet = SetUtil.fromArray(trackbacks);
877         }
878         else {
879             trackbacksSet = new HashSet<String>();
880         }
881 
882         if (pingOldTrackbacks) {
883             trackbacksSet.addAll(
884                 SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
885 
886             entry.setTrackbacks(StringPool.BLANK);
887 
888             blogsEntryPersistence.update(entry, false);
889         }
890 
891         Set<String> oldTrackbacks = SetUtil.fromArray(
892             StringUtil.split(entry.getTrackbacks()));
893 
894         Set<String> validTrackbacks = new HashSet<String>();
895 
896         for (String trackback : trackbacksSet) {
897             if (oldTrackbacks.contains(trackback)) {
898                 continue;
899             }
900 
901             try {
902                 if (pingTrackback(trackback, parts)) {
903                     validTrackbacks.add(trackback);
904                 }
905             }
906             catch (Exception e) {
907                 _log.error("Error while pinging trackback at " + trackback, e);
908             }
909         }
910 
911         if (!validTrackbacks.isEmpty()) {
912             String newTrackbacks = StringUtil.merge(validTrackbacks);
913 
914             if (Validator.isNotNull(entry.getTrackbacks())) {
915                 newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
916             }
917 
918             entry.setTrackbacks(newTrackbacks);
919 
920             blogsEntryPersistence.update(entry, false);
921         }
922     }
923 
924     protected void validate(String title, String content)
925         throws PortalException {
926 
927         if (Validator.isNull(title)) {
928             throw new EntryTitleException();
929         }
930         else if (Validator.isNull(content)) {
931             throw new EntryContentException();
932         }
933     }
934 
935     private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
936         ' ', '.', ',', '/', '\\', '\'', '\"'
937     };
938 
939     private static Log _log =
940         LogFactory.getLog(BlogsEntryLocalServiceImpl.class);
941 
942 }