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