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