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