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.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 = BooleanQueryFactoryUtil.create();
585 
586             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
587 
588             if (groupId > 0) {
589                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
590             }
591 
592             if (userId > 0) {
593                 contextQuery.addRequiredTerm(Field.USER_ID, userId);
594             }
595 
596             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
597 
598             if (Validator.isNotNull(keywords)) {
599                 searchQuery.addTerm(Field.TITLE, keywords);
600                 searchQuery.addTerm(Field.CONTENT, keywords);
601                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
602             }
603 
604             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
605 
606             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
607 
608             if (searchQuery.clauses().size() > 0) {
609                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
610             }
611 
612             return SearchEngineUtil.search(companyId, fullQuery, start, end);
613         }
614         catch (Exception e) {
615             throw new SystemException(e);
616         }
617     }
618 
619     public BlogsEntry updateEntry(
620             long userId, long entryId, String title, String content,
621             int displayDateMonth, int displayDateDay, int displayDateYear,
622             int displayDateHour, int displayDateMinute, boolean draft,
623             boolean allowTrackbacks, String[] trackbacks, String[] tagsEntries,
624             ThemeDisplay themeDisplay)
625         throws PortalException, SystemException {
626 
627         // Entry
628 
629         User user = userPersistence.findByPrimaryKey(userId);
630 
631         Date displayDate = PortalUtil.getDate(
632             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
633             displayDateMinute, user.getTimeZone(),
634             new EntryDisplayDateException());
635 
636         validate(title, content);
637 
638         BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
639 
640         String oldUrlTitle = entry.getUrlTitle();
641         boolean oldDraft = entry.isDraft();
642 
643         entry.setModifiedDate(new Date());
644         entry.setTitle(title);
645         entry.setUrlTitle(
646             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
647         entry.setContent(content);
648         entry.setDisplayDate(displayDate);
649         entry.setDraft(draft);
650         entry.setAllowTrackbacks(allowTrackbacks);
651 
652         blogsEntryPersistence.update(entry, false);
653 
654         // Statistics
655 
656         if (!draft) {
657             blogsStatsUserLocalService.updateStatsUser(
658                 entry.getGroupId(), entry.getUserId(), displayDate);
659         }
660 
661         // Social
662 
663         if (oldDraft && !draft) {
664             socialActivityLocalService.addActivity(
665                 userId, entry.getGroupId(), BlogsEntry.class.getName(), entryId,
666                 BlogsActivityKeys.ADD_ENTRY, StringPool.BLANK, 0);
667         }
668 
669         // Tags
670 
671         updateTagsAsset(userId, entry, tagsEntries);
672 
673         // Lucene
674 
675         try {
676             if (!draft) {
677                 Indexer.updateEntry(
678                     entry.getCompanyId(), entry.getGroupId(), userId, entryId,
679                     title, content, tagsEntries);
680             }
681         }
682         catch (SearchException se) {
683             _log.error("Indexing " + entryId, se);
684         }
685 
686         // Ping
687 
688         if (!draft) {
689             pingGoogle(entry, themeDisplay);
690 
691             String urlTitle = entry.getUrlTitle();
692 
693             if (!oldDraft && !oldUrlTitle.equals(urlTitle)) {
694                 pingTrackbacks(entry, trackbacks, true, themeDisplay);
695             }
696             else {
697                 pingTrackbacks(entry, trackbacks, false, themeDisplay);
698             }
699         }
700 
701         return entry;
702     }
703 
704     public void updateTagsAsset(
705             long userId, BlogsEntry entry, String[] tagsEntries)
706         throws PortalException, SystemException {
707 
708         tagsAssetLocalService.updateAsset(
709             userId, entry.getGroupId(), BlogsEntry.class.getName(),
710             entry.getEntryId(), tagsEntries, null, null, null, null,
711             ContentTypes.TEXT_HTML, entry.getTitle(), null, null, null, 0, 0,
712             null, false);
713     }
714 
715     protected String getUniqueUrlTitle(
716             long entryId, long groupId, String title)
717         throws SystemException {
718 
719         String urlTitle = getUrlTitle(entryId, title);
720 
721         String newUrlTitle = new String(urlTitle);
722 
723         for (int i = 1;; i++) {
724             BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
725                 groupId, newUrlTitle);
726 
727             if ((entry == null) || (entry.getEntryId() == entryId)) {
728                 break;
729             }
730             else {
731                 newUrlTitle = urlTitle + StringPool.DASH + i;
732             }
733         }
734 
735         return newUrlTitle;
736     }
737 
738     protected void pingGoogle(BlogsEntry entry, ThemeDisplay themeDisplay)
739         throws PortalException, SystemException {
740 
741         if (themeDisplay == null) {
742             return;
743         }
744 
745         Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
746 
747         String portalURL = PortalUtil.getPortalURL(themeDisplay);
748 
749         if ((portalURL.indexOf("://localhost") != -1) ||
750             (portalURL.indexOf("://127.0.0.1") != -1)) {
751 
752             return;
753         }
754 
755         String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
756 
757         StringBuilder sb = new StringBuilder();
758 
759         String name = group.getDescriptiveName();
760         String url = portalURL + layoutURL + "/-/blogs";
761         String changesURL = portalURL + layoutURL + "/-/blogs/rss";
762 
763         sb.append("http://blogsearch.google.com/ping?name=");
764         sb.append(HttpUtil.encodeURL(name));
765         sb.append("&url=");
766         sb.append(HttpUtil.encodeURL(url));
767         sb.append("&changesURL=");
768         sb.append(HttpUtil.encodeURL(changesURL));
769 
770         String location = sb.toString();
771 
772         if (_log.isInfoEnabled()) {
773             _log.info("Pinging Google at " + location);
774         }
775 
776         try {
777             String response = HttpUtil.URLtoString(sb.toString());
778 
779             if (_log.isInfoEnabled()) {
780                 _log.info("Google ping response: " + response);
781             }
782         }
783         catch (IOException ioe) {
784             _log.error("Unable to ping Google at " + location, ioe);
785         }
786     }
787 
788     protected boolean pingTrackback(String trackback, Map<String, String> parts)
789         throws Exception {
790 
791         if (_log.isDebugEnabled()) {
792             _log.debug("Pinging trackback " + trackback);
793         }
794 
795         String xml = HttpUtil.URLtoString(trackback, null, parts, true);
796 
797         if (_log.isDebugEnabled()) {
798             _log.debug(xml);
799         }
800 
801         XMLInputFactory inputFactory = XMLInputFactory.newInstance();
802 
803         XMLStreamReader reader = inputFactory.createXMLStreamReader(
804             new StringReader(xml));
805 
806         String error = xml;
807 
808         try {
809             reader.nextTag();
810             reader.nextTag();
811 
812             String name = reader.getLocalName();
813 
814             if (name.equals("error")) {
815                 int status = GetterUtil.getInteger(reader.getElementText(), 1);
816 
817                 if (status == 0) {
818                     return true;
819                 }
820 
821                 reader.nextTag();
822 
823                 name = reader.getLocalName();
824 
825                 if (name.equals("message")) {
826                     error = reader.getElementText();
827                 }
828             }
829         }
830         finally {
831             if (reader != null) {
832                 try {
833                     reader.close();
834                 }
835                 catch (Exception e) {
836                 }
837             }
838         }
839 
840         _log.error(
841             "Error while pinging trackback at " + trackback + ": " + error);
842 
843         return false;
844     }
845 
846     protected void pingTrackbacks(
847             BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
848             ThemeDisplay themeDisplay)
849         throws SystemException {
850 
851         if (themeDisplay == null) {
852             return;
853         }
854 
855         Map<String, String> parts = new HashMap<String, String>();
856 
857         String excerpt = StringUtil.shorten(
858             HtmlUtil.extractText(entry.getContent()),
859             PropsValues.BLOGS_TRACKBACK_EXCERPT_LENGTH);
860         String url =
861             themeDisplay.getPortalURL() + PortalUtil.getLayoutURL(themeDisplay)
862                 + "/-/blogs/" + entry.getUrlTitle();
863 
864         parts.put("title", entry.getTitle());
865         parts.put("excerpt", excerpt);
866         parts.put("url", url);
867         parts.put("blog_name", entry.getUserName());
868 
869         Set<String> trackbacksSet = null;
870 
871         if (Validator.isNotNull(trackbacks)) {
872             trackbacksSet = SetUtil.fromArray(trackbacks);
873         }
874         else {
875             trackbacksSet = new HashSet<String>();
876         }
877 
878         if (pingOldTrackbacks) {
879             trackbacksSet.addAll(
880                 SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
881 
882             entry.setTrackbacks(StringPool.BLANK);
883 
884             blogsEntryPersistence.update(entry, false);
885         }
886 
887         Set<String> oldTrackbacks = SetUtil.fromArray(
888             StringUtil.split(entry.getTrackbacks()));
889 
890         Set<String> validTrackbacks = new HashSet<String>();
891 
892         for (String trackback : trackbacksSet) {
893             if (oldTrackbacks.contains(trackback)) {
894                 continue;
895             }
896 
897             try {
898                 if (pingTrackback(trackback, parts)) {
899                     validTrackbacks.add(trackback);
900                 }
901             }
902             catch (Exception e) {
903                 _log.error("Error while pinging trackback at " + trackback, e);
904             }
905         }
906 
907         if (!validTrackbacks.isEmpty()) {
908             String newTrackbacks = StringUtil.merge(validTrackbacks);
909 
910             if (Validator.isNotNull(entry.getTrackbacks())) {
911                 newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
912             }
913 
914             entry.setTrackbacks(newTrackbacks);
915 
916             blogsEntryPersistence.update(entry, false);
917         }
918     }
919 
920     protected void validate(String title, String content)
921         throws PortalException {
922 
923         if (Validator.isNull(title)) {
924             throw new EntryTitleException();
925         }
926         else if (Validator.isNull(content)) {
927             throw new EntryContentException();
928         }
929     }
930 
931     private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
932         ' ', '.', ',', '/', '\\', '\'', '\"'
933     };
934 
935     private static Log _log =
936         LogFactory.getLog(BlogsEntryLocalServiceImpl.class);
937 
938 }