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