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