1   /**
2    * Copyright (c) 2000-2007 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.counter.service.CounterLocalServiceUtil;
26  import com.liferay.portal.PortalException;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.kernel.search.Hits;
29  import com.liferay.portal.kernel.util.ArrayUtil;
30  import com.liferay.portal.kernel.util.ContentTypes;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.OrderByComparator;
33  import com.liferay.portal.kernel.util.StringMaker;
34  import com.liferay.portal.kernel.util.Validator;
35  import com.liferay.portal.lucene.LuceneFields;
36  import com.liferay.portal.lucene.LuceneUtil;
37  import com.liferay.portal.model.Group;
38  import com.liferay.portal.model.User;
39  import com.liferay.portal.model.impl.ResourceImpl;
40  import com.liferay.portal.service.ResourceLocalServiceUtil;
41  import com.liferay.portal.service.persistence.GroupUtil;
42  import com.liferay.portal.service.persistence.UserUtil;
43  import com.liferay.portal.theme.ThemeDisplay;
44  import com.liferay.portal.util.PortalUtil;
45  import com.liferay.portlet.blogs.EntryContentException;
46  import com.liferay.portlet.blogs.EntryDisplayDateException;
47  import com.liferay.portlet.blogs.EntryTitleException;
48  import com.liferay.portlet.blogs.NoSuchCategoryException;
49  import com.liferay.portlet.blogs.model.BlogsCategory;
50  import com.liferay.portlet.blogs.model.BlogsEntry;
51  import com.liferay.portlet.blogs.model.BlogsStatsUser;
52  import com.liferay.portlet.blogs.model.impl.BlogsCategoryImpl;
53  import com.liferay.portlet.blogs.service.BlogsStatsUserLocalServiceUtil;
54  import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
55  import com.liferay.portlet.blogs.service.persistence.BlogsCategoryUtil;
56  import com.liferay.portlet.blogs.service.persistence.BlogsEntryFinder;
57  import com.liferay.portlet.blogs.service.persistence.BlogsEntryUtil;
58  import com.liferay.portlet.blogs.service.persistence.BlogsStatsUserUtil;
59  import com.liferay.portlet.blogs.util.Indexer;
60  import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
61  import com.liferay.portlet.ratings.service.RatingsStatsLocalServiceUtil;
62  import com.liferay.portlet.tags.service.TagsAssetLocalServiceUtil;
63  import com.liferay.util.Http;
64  import com.liferay.util.HttpUtil;
65  import com.liferay.util.lucene.HitsImpl;
66  
67  import java.io.IOException;
68  
69  import java.util.Date;
70  import java.util.Iterator;
71  import java.util.List;
72  
73  import org.apache.commons.logging.Log;
74  import org.apache.commons.logging.LogFactory;
75  import org.apache.lucene.document.Document;
76  import org.apache.lucene.index.IndexWriter;
77  import org.apache.lucene.index.Term;
78  import org.apache.lucene.search.BooleanClause;
79  import org.apache.lucene.search.BooleanQuery;
80  import org.apache.lucene.search.Searcher;
81  import org.apache.lucene.search.TermQuery;
82  
83  /**
84   * <a href="BlogsEntryLocalServiceImpl.java.html"><b><i>View Source</i></b>
85   * </a>
86   *
87   * @author Brian Wing Shun Chan
88   * @author Wilson S. Man
89   *
90   */
91  public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
92  
93      public BlogsEntry addEntry(
94              long userId, long plid, long categoryId, String title,
95              String content, int displayDateMonth, int displayDateDay,
96              int displayDateYear, int displayDateHour, int displayDateMinute,
97              ThemeDisplay themeDisplay, String[] tagsEntries,
98              boolean addCommunityPermissions, boolean addGuestPermissions)
99          throws PortalException, SystemException {
100 
101         return addEntry(
102             userId, plid, categoryId, title, content, displayDateMonth,
103             displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
104             themeDisplay, tagsEntries, Boolean.valueOf(addCommunityPermissions),
105             Boolean.valueOf(addGuestPermissions), null, null);
106     }
107 
108     public BlogsEntry addEntry(
109             long userId, long plid, long categoryId, String title,
110             String content, int displayDateMonth, int displayDateDay,
111             int displayDateYear, int displayDateHour, int displayDateMinute,
112             ThemeDisplay themeDisplay, String[] tagsEntries,
113             String[] communityPermissions, String[] guestPermissions)
114         throws PortalException, SystemException {
115 
116         return addEntry(
117             userId, plid, categoryId, title, content, displayDateMonth,
118             displayDateDay, displayDateYear, displayDateHour, displayDateMinute,
119             themeDisplay, tagsEntries, null, null, communityPermissions,
120             guestPermissions);
121     }
122 
123     public BlogsEntry addEntry(
124             long userId, long plid, long categoryId, String title,
125             String content, int displayDateMonth, int displayDateDay,
126             int displayDateYear, int displayDateHour, int displayDateMinute,
127             ThemeDisplay themeDisplay, String[] tagsEntries,
128             Boolean addCommunityPermissions, Boolean addGuestPermissions,
129             String[] communityPermissions, String[] guestPermissions)
130         throws PortalException, SystemException {
131 
132         // Entry
133 
134         User user = UserUtil.findByPrimaryKey(userId);
135         long groupId = PortalUtil.getPortletGroupId(plid);
136         categoryId = getCategoryId(user.getCompanyId(), categoryId);
137         Date now = new Date();
138 
139         Date displayDate = PortalUtil.getDate(
140             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
141             displayDateMinute, user.getTimeZone(),
142             new EntryDisplayDateException());
143 
144         validate(title, content);
145 
146         long entryId = CounterLocalServiceUtil.increment();
147 
148         BlogsEntry entry = BlogsEntryUtil.create(entryId);
149 
150         entry.setGroupId(groupId);
151         entry.setCompanyId(user.getCompanyId());
152         entry.setUserId(user.getUserId());
153         entry.setUserName(user.getFullName());
154         entry.setCreateDate(now);
155         entry.setModifiedDate(now);
156         entry.setCategoryId(categoryId);
157         entry.setTitle(title);
158         entry.setUrlTitle(getUniqueUrlTitle(entryId, groupId, title));
159         entry.setContent(content);
160         entry.setDisplayDate(displayDate);
161 
162         BlogsEntryUtil.update(entry);
163 
164         // Resources
165 
166         if ((addCommunityPermissions != null) &&
167             (addGuestPermissions != null)) {
168 
169             addEntryResources(
170                 entry, addCommunityPermissions.booleanValue(),
171                 addGuestPermissions.booleanValue());
172         }
173         else {
174             addEntryResources(entry, communityPermissions, guestPermissions);
175         }
176 
177         // Statistics
178 
179         BlogsStatsUserLocalServiceUtil.updateStatsUser(
180             entry.getGroupId(), userId, now);
181 
182         // Tags
183 
184         updateTagsAsset(userId, entry, tagsEntries);
185 
186         // Lucene
187 
188         try {
189             Indexer.addEntry(
190                 entry.getCompanyId(), entry.getGroupId(), userId, categoryId,
191                 entryId, title, content);
192         }
193         catch (IOException ioe) {
194             _log.error("Indexing " + entryId, ioe);
195         }
196 
197         // Google
198 
199         pingGoogle(entry, themeDisplay);
200 
201         return entry;
202     }
203 
204     public void addEntryResources(
205             long entryId, boolean addCommunityPermissions,
206             boolean addGuestPermissions)
207         throws PortalException, SystemException {
208 
209         BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
210 
211         addEntryResources(entry, addCommunityPermissions, addGuestPermissions);
212     }
213 
214     public void addEntryResources(
215             BlogsEntry entry, boolean addCommunityPermissions,
216             boolean addGuestPermissions)
217         throws PortalException, SystemException {
218 
219         ResourceLocalServiceUtil.addResources(
220             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
221             BlogsEntry.class.getName(), entry.getEntryId(), false,
222             addCommunityPermissions, addGuestPermissions);
223     }
224 
225     public void addEntryResources(
226             long entryId, String[] communityPermissions,
227             String[] guestPermissions)
228         throws PortalException, SystemException {
229 
230         BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
231 
232         addEntryResources(entry, communityPermissions, guestPermissions);
233     }
234 
235     public void addEntryResources(
236             BlogsEntry entry, String[] communityPermissions,
237             String[] guestPermissions)
238         throws PortalException, SystemException {
239 
240         ResourceLocalServiceUtil.addModelResources(
241             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
242             BlogsEntry.class.getName(), entry.getEntryId(),
243             communityPermissions, guestPermissions);
244     }
245 
246     public void deleteEntries(long groupId)
247         throws PortalException, SystemException {
248 
249         Iterator itr = BlogsEntryUtil.findByGroupId(groupId).iterator();
250 
251         while (itr.hasNext()) {
252             BlogsEntry entry = (BlogsEntry)itr.next();
253 
254             deleteEntry(entry);
255         }
256     }
257 
258     public void deleteEntry(long entryId)
259         throws PortalException, SystemException {
260 
261         BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
262 
263         deleteEntry(entry);
264     }
265 
266     public void deleteEntry(BlogsEntry entry)
267         throws PortalException, SystemException {
268 
269         // Lucene
270 
271         try {
272             Indexer.deleteEntry(entry.getCompanyId(), entry.getEntryId());
273         }
274         catch (IOException ioe) {
275             _log.error("Deleting index " + entry.getEntryId(), ioe);
276         }
277 
278         // Tags
279 
280         TagsAssetLocalServiceUtil.deleteAsset(
281             BlogsEntry.class.getName(), entry.getEntryId());
282 
283         // Ratings
284 
285         RatingsStatsLocalServiceUtil.deleteStats(
286             BlogsEntry.class.getName(), entry.getEntryId());
287 
288         // Message boards
289 
290         MBMessageLocalServiceUtil.deleteDiscussionMessages(
291             BlogsEntry.class.getName(), entry.getEntryId());
292 
293         // Resources
294 
295         ResourceLocalServiceUtil.deleteResource(
296             entry.getCompanyId(), BlogsEntry.class.getName(),
297             ResourceImpl.SCOPE_INDIVIDUAL, entry.getEntryId());
298 
299         // Entry
300 
301         BlogsEntryUtil.remove(entry.getEntryId());
302     }
303 
304     public int getCategoriesEntriesCount(List categoryIds)
305         throws SystemException {
306 
307         return BlogsEntryFinder.countByCategoryIds(categoryIds);
308     }
309 
310     public List getCompanyEntries(long companyId, int begin, int end)
311         throws SystemException {
312 
313         return BlogsEntryUtil.findByCompanyId(companyId, begin, end);
314     }
315 
316     public List getCompanyEntries(
317             long companyId, int begin, int end, OrderByComparator obc)
318         throws SystemException {
319 
320         return BlogsEntryUtil.findByCompanyId(companyId, begin, end, obc);
321     }
322 
323     public int getCompanyEntriesCount(long companyId) throws SystemException {
324         return BlogsEntryUtil.countByCompanyId(companyId);
325     }
326 
327     public List getEntries(long categoryId, int begin, int end)
328         throws SystemException {
329 
330         return BlogsEntryUtil.findByCategoryId(categoryId, begin, end);
331     }
332 
333     public int getEntriesCount(long categoryId) throws SystemException {
334         return BlogsEntryUtil.countByCategoryId(categoryId);
335     }
336 
337     public BlogsEntry getEntry(long entryId)
338         throws PortalException, SystemException {
339 
340         return BlogsEntryUtil.findByPrimaryKey(entryId);
341     }
342 
343     public BlogsEntry getEntry(long groupId, String urlTitle)
344         throws PortalException, SystemException {
345 
346         return BlogsEntryUtil.findByG_UT(groupId, urlTitle);
347     }
348 
349     public List getGroupEntries(long groupId, int begin, int end)
350         throws SystemException {
351 
352         return BlogsEntryUtil.findByGroupId(groupId, begin, end);
353     }
354 
355     public List getGroupEntries(
356             long groupId, int begin, int end, OrderByComparator obc)
357         throws SystemException {
358 
359         return BlogsEntryUtil.findByGroupId(groupId, begin, end, obc);
360     }
361 
362     public int getGroupEntriesCount(long groupId) throws SystemException {
363         return BlogsEntryUtil.countByGroupId(groupId);
364     }
365 
366     public List getGroupUserEntries(
367             long groupId, long userId, int begin, int end)
368         throws SystemException {
369 
370         return BlogsEntryUtil.findByG_U(groupId, userId, begin, end);
371     }
372 
373     public int getGroupUserEntriesCount(long groupId, long userId)
374         throws SystemException {
375 
376         return BlogsEntryUtil.countByG_U(groupId, userId);
377     }
378 
379     public List getNoAssetEntries() throws SystemException {
380         return BlogsEntryFinder.findByNoAssets();
381     }
382 
383     public List getOrganizationEntries(long organizationId, int begin, int end)
384         throws SystemException {
385 
386         return BlogsEntryFinder.findByOrganizationId(
387             organizationId, begin, end);
388     }
389 
390     public int getOrganizationEntriesCount(long organizationId)
391         throws SystemException {
392 
393         return BlogsEntryFinder.countByOrganizationId(
394             organizationId);
395     }
396 
397     public String getUrlTitle(long entryId, String title) {
398         String urlTitle = String.valueOf(entryId);
399 
400         title = title.trim().toLowerCase();
401 
402         if (Validator.isNull(title) || Validator.isNumber(title) ||
403             title.equals("rss")) {
404 
405             return urlTitle;
406         }
407 
408         char[] urlTitleCharArray = title.toCharArray();
409 
410         for (int i = 0; i < urlTitleCharArray.length; i++) {
411             char oldChar = urlTitleCharArray[i];
412 
413             char newChar = oldChar;
414 
415             if ((oldChar == '_') || (Validator.isChar(oldChar)) ||
416                 (Validator.isDigit(oldChar))) {
417 
418             }
419             else if (ArrayUtil.contains(_URL_TITLE_REPLACE_CHARS, oldChar)) {
420                 newChar = '_';
421             }
422             else {
423                 return urlTitle;
424             }
425 
426             if (oldChar != newChar) {
427                 urlTitleCharArray[i] = newChar;
428             }
429         }
430 
431         urlTitle = new String(urlTitleCharArray);
432 
433         return urlTitle;
434     }
435 
436     public void reIndex(String[] ids) throws SystemException {
437         long companyId = GetterUtil.getLong(ids[0]);
438 
439         IndexWriter writer = null;
440 
441         try {
442             writer = LuceneUtil.getWriter(companyId);
443 
444             Iterator itr = BlogsEntryUtil.findByCompanyId(companyId).iterator();
445 
446             while (itr.hasNext()) {
447                 BlogsEntry entry = (BlogsEntry)itr.next();
448 
449                 long groupId = entry.getGroupId();
450                 long userId = entry.getUserId();
451                 long categoryId = entry.getCategoryId();
452                 long entryId = entry.getEntryId();
453                 String title = entry.getTitle();
454                 String content = entry.getContent();
455 
456                 try {
457                     Document doc = Indexer.getAddEntryDocument(
458                         companyId, groupId, userId, categoryId, entryId, title,
459                         content);
460 
461                     writer.addDocument(doc);
462                 }
463                 catch (Exception e1) {
464                     _log.error("Reindexing " + entryId, e1);
465                 }
466             }
467         }
468         catch (SystemException se) {
469             throw se;
470         }
471         catch (Exception e2) {
472             throw new SystemException(e2);
473         }
474         finally {
475             try {
476                 if (writer != null) {
477                     LuceneUtil.write(companyId);
478                 }
479             }
480             catch (Exception e) {
481                 _log.error(e);
482             }
483         }
484     }
485 
486     public Hits search(
487             long companyId, long groupId, long userId, long[] categoryIds,
488             String keywords)
489         throws SystemException {
490 
491         Searcher searcher = null;
492 
493         try {
494             HitsImpl hits = new HitsImpl();
495 
496             if (Validator.isNull(keywords)) {
497                 return hits;
498             }
499 
500             BooleanQuery contextQuery = new BooleanQuery();
501 
502             LuceneUtil.addRequiredTerm(
503                 contextQuery, LuceneFields.PORTLET_ID, Indexer.PORTLET_ID);
504 
505             if (groupId > 0) {
506                 LuceneUtil.addRequiredTerm(
507                     contextQuery, LuceneFields.GROUP_ID, groupId);
508             }
509 
510             if (userId > 0) {
511                 LuceneUtil.addRequiredTerm(
512                     contextQuery, LuceneFields.USER_ID, userId);
513             }
514 
515             if ((categoryIds != null) && (categoryIds.length > 0)) {
516                 BooleanQuery categoryIdsQuery = new BooleanQuery();
517 
518                 for (int i = 0; i < categoryIds.length; i++) {
519                     Term term = new Term(
520                         "categoryId", String.valueOf(categoryIds[i]));
521                     TermQuery termQuery = new TermQuery(term);
522 
523                     categoryIdsQuery.add(termQuery, BooleanClause.Occur.SHOULD);
524                 }
525 
526                 contextQuery.add(categoryIdsQuery, BooleanClause.Occur.MUST);
527             }
528 
529             BooleanQuery searchQuery = new BooleanQuery();
530 
531             LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT, keywords);
532 
533             BooleanQuery fullQuery = new BooleanQuery();
534 
535             fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
536             fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
537 
538             searcher = LuceneUtil.getSearcher(companyId);
539 
540             hits.recordHits(searcher.search(fullQuery), searcher);
541 
542             return hits;
543         }
544         catch (Exception e) {
545             return LuceneUtil.closeSearcher(searcher, keywords, e);
546         }
547     }
548 
549     public BlogsEntry updateEntry(
550             long userId, long entryId, long categoryId, String title,
551             String content, int displayDateMonth, int displayDateDay,
552             int displayDateYear, int displayDateHour, int displayDateMinute,
553             ThemeDisplay themeDisplay, String[] tagsEntries)
554         throws PortalException, SystemException {
555 
556         // Entry
557 
558         User user = UserUtil.findByPrimaryKey(userId);
559         categoryId = getCategoryId(user.getCompanyId(), categoryId);
560         Date now = new Date();
561 
562         Date displayDate = PortalUtil.getDate(
563             displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
564             displayDateMinute, user.getTimeZone(),
565             new EntryDisplayDateException());
566 
567         validate(title, content);
568 
569         BlogsEntry entry = BlogsEntryUtil.findByPrimaryKey(entryId);
570 
571         entry.setModifiedDate(now);
572         entry.setCategoryId(categoryId);
573         entry.setTitle(title);
574         entry.setUrlTitle(
575             getUniqueUrlTitle(entryId, entry.getGroupId(), title));
576         entry.setContent(content);
577         entry.setDisplayDate(displayDate);
578 
579         BlogsEntryUtil.update(entry);
580 
581         // Statistics
582 
583         BlogsStatsUser statsUser = BlogsStatsUserUtil.fetchByG_U(
584             entry.getGroupId(), entry.getUserId());
585 
586         if (statsUser != null) {
587             statsUser.setLastPostDate(now);
588 
589             BlogsStatsUserUtil.update(statsUser);
590         }
591 
592         // Tags
593 
594         updateTagsAsset(userId, entry, tagsEntries);
595 
596         // Lucene
597 
598         try {
599             Indexer.updateEntry(
600                 entry.getCompanyId(), entry.getGroupId(), userId, categoryId,
601                 entryId, title, content);
602         }
603         catch (IOException ioe) {
604             _log.error("Indexing " + entryId, ioe);
605         }
606 
607         // Google
608 
609         pingGoogle(entry, themeDisplay);
610 
611         return entry;
612     }
613 
614     public void updateTagsAsset(
615             long userId, BlogsEntry entry, String[] tagsEntries)
616         throws PortalException, SystemException {
617 
618         TagsAssetLocalServiceUtil.updateAsset(
619             userId, BlogsEntry.class.getName(), entry.getEntryId(), tagsEntries,
620             null, null, null, null, ContentTypes.TEXT_HTML, entry.getTitle(),
621             entry.getTitle(), entry.getTitle(), null, 0, 0);
622     }
623 
624     protected long getCategoryId(long companyId, long categoryId)
625         throws PortalException, SystemException {
626 
627         if (categoryId != BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID) {
628 
629             // Ensure category exists and belongs to the proper company
630 
631             try {
632                 BlogsCategory category =
633                     BlogsCategoryUtil.findByPrimaryKey(categoryId);
634 
635                 if (companyId != category.getCompanyId()) {
636                     categoryId = BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
637                 }
638             }
639             catch (NoSuchCategoryException nsfe) {
640                 categoryId = BlogsCategoryImpl.DEFAULT_PARENT_CATEGORY_ID;
641             }
642         }
643 
644         return categoryId;
645     }
646 
647     protected String getUniqueUrlTitle(
648             long entryId, long groupId, String title)
649         throws SystemException {
650 
651         String urlTitle = getUrlTitle(entryId, title);
652 
653         String newUrlTitle = new String(urlTitle);
654 
655         for (int i = 1;; i++) {
656             BlogsEntry entry = BlogsEntryUtil.fetchByG_UT(groupId, newUrlTitle);
657 
658             if ((entry == null) || (entry.getEntryId() == entryId)) {
659                 break;
660             }
661             else {
662                 newUrlTitle = urlTitle + "_" + i;
663             }
664         }
665 
666         return newUrlTitle;
667     }
668 
669     protected void pingGoogle(BlogsEntry entry, ThemeDisplay themeDisplay)
670         throws PortalException, SystemException {
671 
672         if (themeDisplay == null) {
673             return;
674         }
675 
676         Group group = GroupUtil.findByPrimaryKey(entry.getGroupId());
677 
678         String portalURL = PortalUtil.getPortalURL(themeDisplay);
679 
680         if ((portalURL.indexOf("://localhost") != -1) ||
681             (portalURL.indexOf("://127.0.0.1") != -1)) {
682 
683             return;
684         }
685 
686         String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
687 
688         StringMaker sm = new StringMaker();
689 
690         String name = group.getDescriptiveName();
691         //String url = portalURL + layoutURL + "/blogs/" + entry.getUrlTitle();
692         String url = portalURL + layoutURL + "/blogs";
693         String changesURL = portalURL + layoutURL + "/blogs/rss";
694 
695         sm.append("http://blogsearch.google.com/ping?name=");
696         sm.append(HttpUtil.encodeURL(name));
697         sm.append("&url=");
698         sm.append(HttpUtil.encodeURL(url));
699         sm.append("&changesURL=");
700         sm.append(HttpUtil.encodeURL(changesURL));
701 
702         String location = sm.toString();
703 
704         if (_log.isInfoEnabled()) {
705             _log.info("Pinging Google at " + location);
706         }
707 
708         try {
709             String response = Http.URLtoString(sm.toString());
710 
711             if (_log.isInfoEnabled()) {
712                 _log.info("Google ping response: " + response);
713             }
714         }
715         catch (IOException ioe) {
716             _log.error("Unable to ping Google at " + location, ioe);
717         }
718     }
719 
720     protected void validate(String title, String content)
721         throws PortalException {
722 
723         if (Validator.isNull(title)) {
724             throw new EntryTitleException();
725         }
726         else if (Validator.isNull(content)) {
727             throw new EntryContentException();
728         }
729     }
730 
731     private static final char[] _URL_TITLE_REPLACE_CHARS = new char[] {
732         ' ',  '.',  '-',  ',',  '/',  '\\',  '\'',  '\"'
733     };
734 
735     private static Log _log =
736         LogFactory.getLog(BlogsEntryLocalServiceImpl.class);
737 
738 }