001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.blogs.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.json.JSONFactoryUtil;
021    import com.liferay.portal.kernel.json.JSONObject;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.search.Indexable;
025    import com.liferay.portal.kernel.search.IndexableType;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.Constants;
030    import com.liferay.portal.kernel.util.ContentTypes;
031    import com.liferay.portal.kernel.util.FileUtil;
032    import com.liferay.portal.kernel.util.HtmlUtil;
033    import com.liferay.portal.kernel.util.HttpUtil;
034    import com.liferay.portal.kernel.util.OrderByComparator;
035    import com.liferay.portal.kernel.util.ParamUtil;
036    import com.liferay.portal.kernel.util.PropsKeys;
037    import com.liferay.portal.kernel.util.SetUtil;
038    import com.liferay.portal.kernel.util.StringBundler;
039    import com.liferay.portal.kernel.util.StringPool;
040    import com.liferay.portal.kernel.util.StringUtil;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.util.WebKeys;
043    import com.liferay.portal.kernel.workflow.WorkflowConstants;
044    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
045    import com.liferay.portal.model.Group;
046    import com.liferay.portal.model.ResourceConstants;
047    import com.liferay.portal.model.User;
048    import com.liferay.portal.service.ServiceContext;
049    import com.liferay.portal.service.ServiceContextUtil;
050    import com.liferay.portal.theme.ThemeDisplay;
051    import com.liferay.portal.util.Portal;
052    import com.liferay.portal.util.PortalUtil;
053    import com.liferay.portal.util.PortletKeys;
054    import com.liferay.portal.util.PrefsPropsUtil;
055    import com.liferay.portal.util.PropsValues;
056    import com.liferay.portal.util.SubscriptionSender;
057    import com.liferay.portlet.asset.model.AssetEntry;
058    import com.liferay.portlet.asset.model.AssetLinkConstants;
059    import com.liferay.portlet.blogs.EntryContentException;
060    import com.liferay.portlet.blogs.EntryDisplayDateException;
061    import com.liferay.portlet.blogs.EntrySmallImageNameException;
062    import com.liferay.portlet.blogs.EntrySmallImageSizeException;
063    import com.liferay.portlet.blogs.EntryTitleException;
064    import com.liferay.portlet.blogs.model.BlogsEntry;
065    import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
066    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
067    import com.liferay.portlet.blogs.util.BlogsUtil;
068    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
069    import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
070    import com.liferay.portlet.social.model.SocialActivityConstants;
071    import com.liferay.portlet.trash.model.TrashEntry;
072    
073    import java.io.IOException;
074    import java.io.InputStream;
075    
076    import java.util.Date;
077    import java.util.HashMap;
078    import java.util.HashSet;
079    import java.util.List;
080    import java.util.Locale;
081    import java.util.Map;
082    import java.util.Set;
083    
084    import javax.portlet.PortletPreferences;
085    
086    import javax.servlet.http.HttpServletRequest;
087    
088    import net.htmlparser.jericho.Source;
089    import net.htmlparser.jericho.StartTag;
090    
091    /**
092     * Provides the local service for accessing, adding, checking, deleting,
093     * subscription handling of, trash handling of, and updating blog entries.
094     *
095     * @author Brian Wing Shun Chan
096     * @author Wilson S. Man
097     * @author Raymond Aug??
098     * @author Thiago Moreira
099     * @author Juan Fern??ndez
100     * @author Zsolt Berentey
101     */
102    public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
103    
104            @Indexable(type = IndexableType.REINDEX)
105            @Override
106            public BlogsEntry addEntry(
107                            long userId, String title, String description, String content,
108                            int displayDateMonth, int displayDateDay, int displayDateYear,
109                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
110                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
111                            String smallImageURL, String smallImageFileName,
112                            InputStream smallImageInputStream, ServiceContext serviceContext)
113                    throws PortalException, SystemException {
114    
115                    // Entry
116    
117                    User user = userPersistence.findByPrimaryKey(userId);
118                    long groupId = serviceContext.getScopeGroupId();
119    
120                    Date displayDate = PortalUtil.getDate(
121                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
122                            displayDateMinute, user.getTimeZone(),
123                            EntryDisplayDateException.class);
124    
125                    byte[] smallImageBytes = null;
126    
127                    try {
128                            if ((smallImageInputStream != null) && smallImage) {
129                                    smallImageBytes = FileUtil.getBytes(smallImageInputStream);
130                            }
131                    }
132                    catch (IOException ioe) {
133                    }
134    
135                    Date now = new Date();
136    
137                    validate(
138                            title, content, smallImage, smallImageURL, smallImageFileName,
139                            smallImageBytes);
140    
141                    long entryId = counterLocalService.increment();
142    
143                    BlogsEntry entry = blogsEntryPersistence.create(entryId);
144    
145                    entry.setUuid(serviceContext.getUuid());
146                    entry.setGroupId(groupId);
147                    entry.setCompanyId(user.getCompanyId());
148                    entry.setUserId(user.getUserId());
149                    entry.setUserName(user.getFullName());
150                    entry.setCreateDate(serviceContext.getCreateDate(now));
151                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
152                    entry.setTitle(title);
153                    entry.setUrlTitle(
154                            getUniqueUrlTitle(entryId, title, null, serviceContext));
155                    entry.setDescription(description);
156                    entry.setContent(content);
157                    entry.setDisplayDate(displayDate);
158                    entry.setAllowPingbacks(allowPingbacks);
159                    entry.setAllowTrackbacks(allowTrackbacks);
160                    entry.setSmallImage(smallImage);
161                    entry.setSmallImageId(counterLocalService.increment());
162                    entry.setSmallImageURL(smallImageURL);
163                    entry.setStatus(WorkflowConstants.STATUS_DRAFT);
164                    entry.setStatusByUserId(userId);
165                    entry.setStatusDate(serviceContext.getModifiedDate(now));
166                    entry.setExpandoBridgeAttributes(serviceContext);
167    
168                    blogsEntryPersistence.update(entry);
169    
170                    // Resources
171    
172                    if (serviceContext.isAddGroupPermissions() ||
173                            serviceContext.isAddGuestPermissions()) {
174    
175                            addEntryResources(
176                                    entry, serviceContext.isAddGroupPermissions(),
177                                    serviceContext.isAddGuestPermissions());
178                    }
179                    else {
180                            addEntryResources(
181                                    entry, serviceContext.getGroupPermissions(),
182                                    serviceContext.getGuestPermissions());
183                    }
184    
185                    // Small image
186    
187                    saveImages(smallImage, entry.getSmallImageId(), smallImageBytes);
188    
189                    // Asset
190    
191                    updateAsset(
192                            userId, entry, serviceContext.getAssetCategoryIds(),
193                            serviceContext.getAssetTagNames(),
194                            serviceContext.getAssetLinkEntryIds());
195    
196                    // Message boards
197    
198                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
199                            mbMessageLocalService.addDiscussionMessage(
200                                    userId, entry.getUserName(), groupId,
201                                    BlogsEntry.class.getName(), entryId,
202                                    WorkflowConstants.ACTION_PUBLISH);
203                    }
204    
205                    // Workflow
206    
207                    if (ArrayUtil.isNotEmpty(trackbacks)) {
208                            serviceContext.setAttribute("trackbacks", trackbacks);
209                    }
210                    else {
211                            serviceContext.setAttribute("trackbacks", null);
212                    }
213    
214                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
215                            user.getCompanyId(), groupId, userId, BlogsEntry.class.getName(),
216                            entry.getEntryId(), entry, serviceContext);
217    
218                    return getEntry(entry.getEntryId());
219            }
220    
221            @Override
222            public void addEntryResources(
223                            BlogsEntry entry, boolean addGroupPermissions,
224                            boolean addGuestPermissions)
225                    throws PortalException, SystemException {
226    
227                    resourceLocalService.addResources(
228                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
229                            BlogsEntry.class.getName(), entry.getEntryId(), false,
230                            addGroupPermissions, addGuestPermissions);
231            }
232    
233            @Override
234            public void addEntryResources(
235                            BlogsEntry entry, String[] groupPermissions,
236                            String[] guestPermissions)
237                    throws PortalException, SystemException {
238    
239                    resourceLocalService.addModelResources(
240                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
241                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
242                            guestPermissions);
243            }
244    
245            @Override
246            public void addEntryResources(
247                            long entryId, boolean addGroupPermissions,
248                            boolean addGuestPermissions)
249                    throws PortalException, SystemException {
250    
251                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
252    
253                    addEntryResources(entry, addGroupPermissions, addGuestPermissions);
254            }
255    
256            @Override
257            public void addEntryResources(
258                            long entryId, String[] groupPermissions, String[] guestPermissions)
259                    throws PortalException, SystemException {
260    
261                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
262    
263                    addEntryResources(entry, groupPermissions, guestPermissions);
264            }
265    
266            @Override
267            public void checkEntries() throws PortalException, SystemException {
268                    Date now = new Date();
269    
270                    int count = blogsEntryPersistence.countByLtD_S(
271                            now, WorkflowConstants.STATUS_SCHEDULED);
272    
273                    if (count == 0) {
274                            return;
275                    }
276    
277                    List<BlogsEntry> entries = blogsEntryPersistence.findByLtD_S(
278                            now, WorkflowConstants.STATUS_SCHEDULED);
279    
280                    for (BlogsEntry entry : entries) {
281                            ServiceContext serviceContext = new ServiceContext();
282    
283                            String[] trackbacks = StringUtil.split(entry.getTrackbacks());
284    
285                            serviceContext.setAttribute("trackbacks", trackbacks);
286    
287                            serviceContext.setCommand(Constants.UPDATE);
288    
289                            String layoutFullURL = PortalUtil.getLayoutFullURL(
290                                    entry.getGroupId(), PortletKeys.BLOGS);
291    
292                            serviceContext.setLayoutFullURL(layoutFullURL);
293    
294                            serviceContext.setScopeGroupId(entry.getGroupId());
295    
296                            blogsEntryLocalService.updateStatus(
297                                    entry.getStatusByUserId(), entry.getEntryId(),
298                                    WorkflowConstants.STATUS_APPROVED, serviceContext);
299                    }
300            }
301    
302            @Override
303            public void deleteEntries(long groupId)
304                    throws PortalException, SystemException {
305    
306                    for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
307                            blogsEntryLocalService.deleteEntry(entry);
308                    }
309            }
310    
311            @Override
312            public void deleteEntry(BlogsEntry entry)
313                    throws PortalException, SystemException {
314    
315                    // Entry
316    
317                    blogsEntryPersistence.remove(entry);
318    
319                    // Resources
320    
321                    resourceLocalService.deleteResource(
322                            entry.getCompanyId(), BlogsEntry.class.getName(),
323                            ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
324    
325                    // Image
326    
327                    imageLocalService.deleteImage(entry.getSmallImageId());
328    
329                    // Subscriptions
330    
331                    subscriptionLocalService.deleteSubscriptions(
332                            entry.getCompanyId(), BlogsEntry.class.getName(),
333                            entry.getEntryId());
334    
335                    // Statistics
336    
337                    blogsStatsUserLocalService.updateStatsUser(
338                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
339    
340                    // Asset
341    
342                    assetEntryLocalService.deleteEntry(
343                            BlogsEntry.class.getName(), entry.getEntryId());
344    
345                    // Expando
346    
347                    expandoRowLocalService.deleteRows(entry.getEntryId());
348    
349                    // Message boards
350    
351                    mbMessageLocalService.deleteDiscussionMessages(
352                            BlogsEntry.class.getName(), entry.getEntryId());
353    
354                    // Ratings
355    
356                    ratingsStatsLocalService.deleteStats(
357                            BlogsEntry.class.getName(), entry.getEntryId());
358    
359                    // Trash
360    
361                    trashEntryLocalService.deleteEntry(
362                            BlogsEntry.class.getName(), entry.getEntryId());
363    
364                    // Indexer
365    
366                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
367                            BlogsEntry.class);
368    
369                    indexer.delete(entry);
370    
371                    // Workflow
372    
373                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
374                            entry.getCompanyId(), entry.getGroupId(),
375                            BlogsEntry.class.getName(), entry.getEntryId());
376            }
377    
378            @Override
379            public void deleteEntry(long entryId)
380                    throws PortalException, SystemException {
381    
382                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
383    
384                    blogsEntryLocalService.deleteEntry(entry);
385            }
386    
387            /**
388             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
389             *             Date, QueryDefinition)}
390             */
391            @Override
392            public List<BlogsEntry> getCompanyEntries(
393                            long companyId, Date displayDate, int status, int start, int end)
394                    throws SystemException {
395    
396                    QueryDefinition queryDefinition = new QueryDefinition(
397                            status, start, end, null);
398    
399                    return getCompanyEntries(companyId, displayDate, queryDefinition);
400            }
401    
402            /**
403             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
404             *             Date, QueryDefinition)}
405             */
406            @Override
407            public List<BlogsEntry> getCompanyEntries(
408                            long companyId, Date displayDate, int status, int start, int end,
409                            OrderByComparator obc)
410                    throws SystemException {
411    
412                    QueryDefinition queryDefinition = new QueryDefinition(
413                            status, start, end, obc);
414    
415                    return getCompanyEntries(companyId, displayDate, queryDefinition);
416            }
417    
418            @Override
419            public List<BlogsEntry> getCompanyEntries(
420                            long companyId, Date displayDate, QueryDefinition queryDefinition)
421                    throws SystemException {
422    
423                    if (queryDefinition.isExcludeStatus()) {
424                            return blogsEntryPersistence.findByC_LtD_NotS(
425                                    companyId, displayDate, queryDefinition.getStatus(),
426                                    queryDefinition.getStart(), queryDefinition.getEnd(),
427                                    queryDefinition.getOrderByComparator());
428                    }
429                    else {
430                            return blogsEntryPersistence.findByC_LtD_S(
431                                    companyId, displayDate, queryDefinition.getStatus(),
432                                    queryDefinition.getStart(), queryDefinition.getEnd(),
433                                    queryDefinition.getOrderByComparator());
434                    }
435            }
436    
437            /**
438             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntriesCount(long,
439             *             Date, QueryDefinition)}
440             */
441            @Override
442            public int getCompanyEntriesCount(
443                            long companyId, Date displayDate, int status)
444                    throws SystemException {
445    
446                    QueryDefinition queryDefinition = new QueryDefinition(status);
447    
448                    return getCompanyEntriesCount(companyId, displayDate, queryDefinition);
449            }
450    
451            @Override
452            public int getCompanyEntriesCount(
453                            long companyId, Date displayDate, QueryDefinition queryDefinition)
454                    throws SystemException {
455    
456                    if (queryDefinition.isExcludeStatus()) {
457                            return blogsEntryPersistence.countByC_LtD_NotS(
458                                    companyId, displayDate, queryDefinition.getStatus());
459                    }
460                    else {
461                            return blogsEntryPersistence.countByC_LtD_S(
462                                    companyId, displayDate, queryDefinition.getStatus());
463                    }
464            }
465    
466            @Override
467            public BlogsEntry[] getEntriesPrevAndNext(long entryId)
468                    throws PortalException, SystemException {
469    
470                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
471    
472                    return blogsEntryPersistence.findByG_S_PrevAndNext(
473                            entry.getEntryId(), entry.getGroupId(),
474                            WorkflowConstants.STATUS_APPROVED,
475                            new EntryDisplayDateComparator(true));
476            }
477    
478            @Override
479            public BlogsEntry getEntry(long entryId)
480                    throws PortalException, SystemException {
481    
482                    return blogsEntryPersistence.findByPrimaryKey(entryId);
483            }
484    
485            @Override
486            public BlogsEntry getEntry(long groupId, String urlTitle)
487                    throws PortalException, SystemException {
488    
489                    return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
490            }
491    
492            /**
493             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
494             *             QueryDefinition)}
495             */
496            @Override
497            public List<BlogsEntry> getGroupEntries(
498                            long groupId, Date displayDate, int status, int start, int end)
499                    throws SystemException {
500    
501                    QueryDefinition queryDefinition = new QueryDefinition(
502                            status, start, end, null);
503    
504                    return getGroupEntries(groupId, displayDate, queryDefinition);
505            }
506    
507            /**
508             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
509             *             QueryDefinition)}
510             */
511            @Override
512            public List<BlogsEntry> getGroupEntries(
513                            long groupId, Date displayDate, int status, int start, int end,
514                            OrderByComparator obc)
515                    throws SystemException {
516    
517                    QueryDefinition queryDefinition = new QueryDefinition(
518                            status, start, end, obc);
519    
520                    return getGroupEntries(groupId, displayDate, queryDefinition);
521            }
522    
523            @Override
524            public List<BlogsEntry> getGroupEntries(
525                            long groupId, Date displayDate, QueryDefinition queryDefinition)
526                    throws SystemException {
527    
528                    if (queryDefinition.isExcludeStatus()) {
529                            return blogsEntryPersistence.findByG_LtD_NotS(
530                                    groupId, displayDate, queryDefinition.getStatus(),
531                                    queryDefinition.getStart(), queryDefinition.getEnd(),
532                                    queryDefinition.getOrderByComparator());
533                    }
534                    else {
535                            return blogsEntryPersistence.findByG_LtD_S(
536                                    groupId, displayDate, queryDefinition.getStatus(),
537                                    queryDefinition.getStart(), queryDefinition.getEnd(),
538                                    queryDefinition.getOrderByComparator());
539                    }
540            }
541    
542            /**
543             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
544             *             QueryDefinition)}
545             */
546            @Override
547            public List<BlogsEntry> getGroupEntries(
548                            long groupId, int status, int start, int end)
549                    throws SystemException {
550    
551                    QueryDefinition queryDefinition = new QueryDefinition(
552                            status, start, end, null);
553    
554                    return getGroupEntries(groupId, queryDefinition);
555            }
556    
557            /**
558             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
559             *             QueryDefinition)}
560             */
561            @Override
562            public List<BlogsEntry> getGroupEntries(
563                            long groupId, int status, int start, int end, OrderByComparator obc)
564                    throws SystemException {
565    
566                    QueryDefinition queryDefinition = new QueryDefinition(
567                            status, start, end, obc);
568    
569                    return getGroupEntries(groupId, queryDefinition);
570            }
571    
572            @Override
573            public List<BlogsEntry> getGroupEntries(
574                            long groupId, QueryDefinition queryDefinition)
575                    throws SystemException {
576    
577                    if (queryDefinition.isExcludeStatus()) {
578                            return blogsEntryPersistence.findByG_NotS(
579                                    groupId, queryDefinition.getStatus(),
580                                    queryDefinition.getStart(), queryDefinition.getEnd(),
581                                    queryDefinition.getOrderByComparator());
582                    }
583                    else {
584                            return blogsEntryPersistence.findByG_S(
585                                    groupId, queryDefinition.getStatus(),
586                                    queryDefinition.getStart(), queryDefinition.getEnd(),
587                                    queryDefinition.getOrderByComparator());
588                    }
589            }
590    
591            /**
592             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
593             *             Date, QueryDefinition)}
594             */
595            @Override
596            public int getGroupEntriesCount(long groupId, Date displayDate, int status)
597                    throws SystemException {
598    
599                    QueryDefinition queryDefinition = new QueryDefinition(status);
600    
601                    return getGroupEntriesCount(groupId, displayDate, queryDefinition);
602            }
603    
604            @Override
605            public int getGroupEntriesCount(
606                            long groupId, Date displayDate, QueryDefinition queryDefinition)
607                    throws SystemException {
608    
609                    if (queryDefinition.isExcludeStatus()) {
610                            return blogsEntryPersistence.countByG_LtD_NotS(
611                                    groupId, displayDate, queryDefinition.getStatus());
612                    }
613                    else {
614                            return blogsEntryPersistence.countByG_LtD_S(
615                                    groupId, displayDate, queryDefinition.getStatus());
616                    }
617            }
618    
619            /**
620             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
621             *             QueryDefinition)}
622             */
623            @Override
624            public int getGroupEntriesCount(long groupId, int status)
625                    throws SystemException {
626    
627                    QueryDefinition queryDefinition = new QueryDefinition(status);
628    
629                    return getGroupEntriesCount(groupId, queryDefinition);
630            }
631    
632            @Override
633            public int getGroupEntriesCount(
634                            long groupId, QueryDefinition queryDefinition)
635                    throws SystemException {
636    
637                    if (queryDefinition.isExcludeStatus()) {
638                            return blogsEntryPersistence.countByG_NotS(
639                                    groupId, queryDefinition.getStatus());
640                    }
641                    else {
642                            return blogsEntryPersistence.countByG_S(
643                                    groupId, queryDefinition.getStatus());
644                    }
645            }
646    
647            /**
648             * @deprecated As of 6.2.0, replaced by {@link #getGroupsEntries(long, long,
649             *             Date, QueryDefinition)}
650             */
651            @Override
652            public List<BlogsEntry> getGroupsEntries(
653                            long companyId, long groupId, Date displayDate, int status,
654                            int start, int end)
655                    throws SystemException {
656    
657                    QueryDefinition queryDefinition = new QueryDefinition(
658                            status, start, end, null);
659    
660                    return getGroupsEntries(
661                            companyId, groupId, displayDate, queryDefinition);
662            }
663    
664            @Override
665            public List<BlogsEntry> getGroupsEntries(
666                            long companyId, long groupId, Date displayDate,
667                            QueryDefinition queryDefinition)
668                    throws SystemException {
669    
670                    return blogsEntryFinder.findByGroupIds(
671                            companyId, groupId, displayDate, queryDefinition);
672            }
673    
674            /**
675             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
676             *             long, Date, QueryDefinition)}
677             */
678            @Override
679            public List<BlogsEntry> getGroupUserEntries(
680                            long groupId, long userId, Date displayDate, int status, int start,
681                            int end)
682                    throws SystemException {
683    
684                    QueryDefinition queryDefinition = new QueryDefinition(
685                            status, start, end, null);
686    
687                    return getGroupUserEntries(
688                            groupId, userId, displayDate, queryDefinition);
689            }
690    
691            /**
692             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
693             *             long, Date, QueryDefinition)}
694             */
695            @Override
696            public List<BlogsEntry> getGroupUserEntries(
697                            long groupId, long userId, Date displayDate, int status, int start,
698                            int end, OrderByComparator obc)
699                    throws SystemException {
700    
701                    QueryDefinition queryDefinition = new QueryDefinition(
702                            status, start, end, obc);
703    
704                    return getGroupUserEntries(
705                            groupId, userId, displayDate, queryDefinition);
706            }
707    
708            @Override
709            public List<BlogsEntry> getGroupUserEntries(
710                            long groupId, long userId, Date displayDate,
711                            QueryDefinition queryDefinition)
712                    throws SystemException {
713    
714                    if (queryDefinition.isExcludeStatus()) {
715                            return blogsEntryPersistence.findByG_U_NotS(
716                                    groupId, userId, queryDefinition.getStatus(),
717                                    queryDefinition.getStart(), queryDefinition.getEnd(),
718                                    queryDefinition.getOrderByComparator());
719                    }
720                    else {
721                            return blogsEntryPersistence.findByG_U_S(
722                                    groupId, userId, queryDefinition.getStatus(),
723                                    queryDefinition.getStart(), queryDefinition.getEnd(),
724                                    queryDefinition.getOrderByComparator());
725                    }
726            }
727    
728            /**
729             * @deprecated As of 6.2.0, replaced by {@link
730             *             #getGroupUserEntriesCount(long, long, Date, QueryDefinition)}
731             */
732            @Override
733            public int getGroupUserEntriesCount(
734                            long groupId, long userId, Date displayDate, int status)
735                    throws SystemException {
736    
737                    QueryDefinition queryDefinition = new QueryDefinition(status);
738    
739                    return getGroupUserEntriesCount(
740                            groupId, userId, displayDate, queryDefinition);
741            }
742    
743            @Override
744            public int getGroupUserEntriesCount(
745                            long groupId, long userId, Date displayDate,
746                            QueryDefinition queryDefinition)
747                    throws SystemException {
748    
749                    if (queryDefinition.isExcludeStatus()) {
750                            return blogsEntryPersistence.countByG_U_LtD_NotS(
751                                    groupId, userId, displayDate, queryDefinition.getStatus());
752                    }
753                    else {
754                            return blogsEntryPersistence.countByG_U_LtD_S(
755                                    groupId, userId, displayDate, queryDefinition.getStatus());
756                    }
757            }
758    
759            @Override
760            public List<BlogsEntry> getNoAssetEntries() throws SystemException {
761                    return blogsEntryFinder.findByNoAssets();
762            }
763    
764            /**
765             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
766             *             Date, QueryDefinition)}
767             */
768            @Override
769            public List<BlogsEntry> getOrganizationEntries(
770                            long organizationId, Date displayDate, int status, int start,
771                            int end)
772                    throws SystemException {
773    
774                    QueryDefinition queryDefinition = new QueryDefinition(
775                            status, start, end, null);
776    
777                    return getOrganizationEntries(
778                            organizationId, displayDate, queryDefinition);
779            }
780    
781            /**
782             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
783             *             Date, QueryDefinition)}
784             */
785            @Override
786            public List<BlogsEntry> getOrganizationEntries(
787                            long organizationId, Date displayDate, int status, int start,
788                            int end, OrderByComparator obc)
789                    throws SystemException {
790    
791                    QueryDefinition queryDefinition = new QueryDefinition(
792                            status, start, end, obc);
793    
794                    return getOrganizationEntries(
795                            organizationId, displayDate, queryDefinition);
796            }
797    
798            @Override
799            public List<BlogsEntry> getOrganizationEntries(
800                            long organizationId, Date displayDate,
801                            QueryDefinition queryDefinition)
802                    throws SystemException {
803    
804                    return blogsEntryFinder.findByOrganizationId(
805                            organizationId, displayDate, queryDefinition);
806            }
807    
808            /**
809             * @deprecated As of 6.2.0, replaced by {@link
810             *             #getOrganizationEntriesCount(long, Date, QueryDefinition)}
811             */
812            @Override
813            public int getOrganizationEntriesCount(
814                            long organizationId, Date displayDate, int status)
815                    throws SystemException {
816    
817                    QueryDefinition queryDefinition = new QueryDefinition(status);
818    
819                    return getOrganizationEntriesCount(
820                            organizationId, displayDate, queryDefinition);
821            }
822    
823            @Override
824            public int getOrganizationEntriesCount(
825                            long organizationId, Date displayDate,
826                            QueryDefinition queryDefinition)
827                    throws SystemException {
828    
829                    return blogsEntryFinder.countByOrganizationId(
830                            organizationId, displayDate, queryDefinition);
831            }
832    
833            @Override
834            public void moveEntriesToTrash(long groupId, long userId)
835                    throws PortalException, SystemException {
836    
837                    List<BlogsEntry> entries = blogsEntryPersistence.findByGroupId(groupId);
838    
839                    for (BlogsEntry entry : entries) {
840                            blogsEntryLocalService.moveEntryToTrash(userId, entry);
841                    }
842            }
843    
844            /**
845             * Moves the blogs entry to the recycle bin. Social activity counters for
846             * this entry get disabled.
847             *
848             * @param  userId the primary key of the user moving the blogs entry
849             * @param  entry the blogs entry to be moved
850             * @return the moved blogs entry
851             * @throws PortalException if a user with the primary key could not be found
852             *         or if the blogs entry owner's social activity counter could not
853             *         be updated
854             * @throws SystemException if a system exception occurred
855             */
856            @Indexable(type = IndexableType.REINDEX)
857            @Override
858            public BlogsEntry moveEntryToTrash(long userId, BlogsEntry entry)
859                    throws PortalException, SystemException {
860    
861                    // Entry
862    
863                    int oldStatus = entry.getStatus();
864    
865                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
866                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
867    
868                            blogsEntryPersistence.update(entry);
869                    }
870    
871                    entry = blogsEntryLocalService.updateStatus(
872                            userId, entry.getEntryId(), WorkflowConstants.STATUS_IN_TRASH,
873                            new ServiceContext());
874    
875                    // Social
876    
877                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
878    
879                    extraDataJSONObject.put("title", entry.getTitle());
880    
881                    socialActivityLocalService.addActivity(
882                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
883                            entry.getEntryId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
884                            extraDataJSONObject.toString(), 0);
885    
886                    // Workflow
887    
888                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
889                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
890                                    entry.getCompanyId(), entry.getGroupId(),
891                                    BlogsEntry.class.getName(), entry.getEntryId());
892                    }
893    
894                    return entry;
895            }
896    
897            /**
898             * Moves the blogs entry with the ID to the recycle bin.
899             *
900             * @param  userId the primary key of the user moving the blogs entry
901             * @param  entryId the primary key of the blogs entry to be moved
902             * @return the moved blogs entry
903             * @throws PortalException if a user or blogs entry with the primary key
904             *         could not be found or if the blogs entry owner's social activity
905             *         counter could not be updated
906             * @throws SystemException if a system exception occurred
907             */
908            @Override
909            public BlogsEntry moveEntryToTrash(long userId, long entryId)
910                    throws PortalException, SystemException {
911    
912                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
913    
914                    return blogsEntryLocalService.moveEntryToTrash(userId, entry);
915            }
916    
917            /**
918             * Restores the blogs entry with the ID from the recycle bin. Social
919             * activity counters for this entry get activated.
920             *
921             * @param  userId the primary key of the user restoring the blogs entry
922             * @param  entryId the primary key of the blogs entry to be restored
923             * @throws PortalException if a user or blogs entry with the primary key
924             *         could not be found or if the blogs entry owner's social activity
925             *         counter could not be updated
926             * @throws SystemException if a system exception occurred
927             */
928            @Override
929            public void restoreEntryFromTrash(long userId, long entryId)
930                    throws PortalException, SystemException {
931    
932                    // Entry
933    
934                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
935                            BlogsEntry.class.getName(), entryId);
936    
937                    BlogsEntry entry = blogsEntryLocalService.updateStatus(
938                            userId, entryId, trashEntry.getStatus(), new ServiceContext());
939    
940                    // Social
941    
942                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
943    
944                    extraDataJSONObject.put("title", entry.getTitle());
945    
946                    socialActivityLocalService.addActivity(
947                            userId, trashEntry.getGroupId(), BlogsEntry.class.getName(),
948                            entryId, SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
949                            extraDataJSONObject.toString(), 0);
950    
951                    // Indexer
952    
953                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
954                            BlogsEntry.class);
955    
956                    indexer.reindex(entry);
957            }
958    
959            @Override
960            public void subscribe(long userId, long groupId)
961                    throws PortalException, SystemException {
962    
963                    subscriptionLocalService.addSubscription(
964                            userId, groupId, BlogsEntry.class.getName(), groupId);
965            }
966    
967            @Override
968            public void unsubscribe(long userId, long groupId)
969                    throws PortalException, SystemException {
970    
971                    subscriptionLocalService.deleteSubscription(
972                            userId, BlogsEntry.class.getName(), groupId);
973            }
974    
975            @Override
976            public void updateAsset(
977                            long userId, BlogsEntry entry, long[] assetCategoryIds,
978                            String[] assetTagNames, long[] assetLinkEntryIds)
979                    throws PortalException, SystemException {
980    
981                    boolean visible = false;
982    
983                    if (entry.isApproved()) {
984                            visible = true;
985                    }
986    
987                    String summary = HtmlUtil.extractText(
988                            StringUtil.shorten(entry.getContent(), 500));
989    
990                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
991                            userId, entry.getGroupId(), entry.getCreateDate(),
992                            entry.getModifiedDate(), BlogsEntry.class.getName(),
993                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
994                            assetTagNames, visible, null, null, null, ContentTypes.TEXT_HTML,
995                            entry.getTitle(), entry.getDescription(), summary, null, null, 0, 0,
996                            null, false);
997    
998                    assetLinkLocalService.updateLinks(
999                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
1000                            AssetLinkConstants.TYPE_RELATED);
1001            }
1002    
1003            @Indexable(type = IndexableType.REINDEX)
1004            @Override
1005            public BlogsEntry updateEntry(
1006                            long userId, long entryId, String title, String description,
1007                            String content, int displayDateMonth, int displayDateDay,
1008                            int displayDateYear, int displayDateHour, int displayDateMinute,
1009                            boolean allowPingbacks, boolean allowTrackbacks,
1010                            String[] trackbacks, boolean smallImage, String smallImageURL,
1011                            String smallImageFileName, InputStream smallImageInputStream,
1012                            ServiceContext serviceContext)
1013                    throws PortalException, SystemException {
1014    
1015                    // Entry
1016    
1017                    User user = userPersistence.findByPrimaryKey(userId);
1018    
1019                    Date displayDate = PortalUtil.getDate(
1020                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1021                            displayDateMinute, user.getTimeZone(),
1022                            EntryDisplayDateException.class);
1023    
1024                    byte[] smallImageBytes = null;
1025    
1026                    try {
1027                            if ((smallImageInputStream != null) && smallImage) {
1028                                    smallImageBytes = FileUtil.getBytes(smallImageInputStream);
1029                            }
1030                    }
1031                    catch (IOException ioe) {
1032                    }
1033    
1034                    validate(
1035                            title, content, smallImage, smallImageURL, smallImageFileName,
1036                            smallImageBytes);
1037    
1038                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1039    
1040                    String oldUrlTitle = entry.getUrlTitle();
1041    
1042                    entry.setModifiedDate(serviceContext.getModifiedDate(null));
1043                    entry.setTitle(title);
1044                    entry.setUrlTitle(
1045                            getUniqueUrlTitle(entryId, title, oldUrlTitle, serviceContext));
1046                    entry.setDescription(description);
1047                    entry.setContent(content);
1048                    entry.setDisplayDate(displayDate);
1049                    entry.setAllowPingbacks(allowPingbacks);
1050                    entry.setAllowTrackbacks(allowTrackbacks);
1051                    entry.setSmallImage(smallImage);
1052    
1053                    if (entry.getSmallImageId() == 0) {
1054                            entry.setSmallImageId(counterLocalService.increment());
1055                    }
1056    
1057                    entry.setSmallImageURL(smallImageURL);
1058    
1059                    if (entry.isPending() || entry.isDraft()) {
1060                    }
1061                    else {
1062                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
1063                    }
1064    
1065                    entry.setExpandoBridgeAttributes(serviceContext);
1066    
1067                    blogsEntryPersistence.update(entry);
1068    
1069                    // Small image
1070    
1071                    saveImages(smallImage, entry.getSmallImageId(), smallImageBytes);
1072    
1073                    // Asset
1074    
1075                    updateAsset(
1076                            userId, entry, serviceContext.getAssetCategoryIds(),
1077                            serviceContext.getAssetTagNames(),
1078                            serviceContext.getAssetLinkEntryIds());
1079    
1080                    // Workflow
1081    
1082                    boolean pingOldTrackbacks = false;
1083    
1084                    if (!oldUrlTitle.equals(entry.getUrlTitle())) {
1085                            pingOldTrackbacks = true;
1086                    }
1087    
1088                    serviceContext.setAttribute(
1089                            "pingOldTrackbacks", String.valueOf(pingOldTrackbacks));
1090    
1091                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1092                            serviceContext.setAttribute("trackbacks", trackbacks);
1093                    }
1094                    else {
1095                            serviceContext.setAttribute("trackbacks", null);
1096                    }
1097    
1098                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
1099                            user.getCompanyId(), entry.getGroupId(), userId,
1100                            BlogsEntry.class.getName(), entry.getEntryId(), entry,
1101                            serviceContext);
1102    
1103                    return getEntry(entry.getEntryId());
1104            }
1105    
1106            @Override
1107            public void updateEntryResources(
1108                            BlogsEntry entry, String[] groupPermissions,
1109                            String[] guestPermissions)
1110                    throws PortalException, SystemException {
1111    
1112                    resourceLocalService.updateResources(
1113                            entry.getCompanyId(), entry.getGroupId(),
1114                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
1115                            guestPermissions);
1116            }
1117    
1118            @Indexable(type = IndexableType.REINDEX)
1119            @Override
1120            public BlogsEntry updateStatus(
1121                            long userId, long entryId, int status,
1122                            ServiceContext serviceContext)
1123                    throws PortalException, SystemException {
1124    
1125                    // Entry
1126    
1127                    User user = userPersistence.findByPrimaryKey(userId);
1128                    Date now = new Date();
1129    
1130                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1131    
1132                    int oldStatus = entry.getStatus();
1133    
1134                    if ((status == WorkflowConstants.STATUS_APPROVED) &&
1135                            now.before(entry.getDisplayDate())) {
1136    
1137                            status = WorkflowConstants.STATUS_SCHEDULED;
1138                    }
1139    
1140                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
1141                    entry.setStatus(status);
1142                    entry.setStatusByUserId(user.getUserId());
1143                    entry.setStatusByUserName(user.getFullName());
1144                    entry.setStatusDate(serviceContext.getModifiedDate(now));
1145    
1146                    blogsEntryPersistence.update(entry);
1147    
1148                    // Statistics
1149    
1150                    blogsStatsUserLocalService.updateStatsUser(
1151                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
1152    
1153                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
1154                            BlogsEntry.class.getName(), entryId);
1155    
1156                    if ((assetEntry == null) || (assetEntry.getPublishDate() == null)) {
1157                            serviceContext.setCommand(Constants.ADD);
1158                    }
1159    
1160                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1161    
1162                    extraDataJSONObject.put("title", entry.getTitle());
1163    
1164                    if (status == WorkflowConstants.STATUS_APPROVED) {
1165    
1166                            // Asset
1167    
1168                            assetEntryLocalService.updateEntry(
1169                                    BlogsEntry.class.getName(), entryId, entry.getDisplayDate(),
1170                                    true);
1171    
1172                            // Social
1173    
1174                            if ((oldStatus != WorkflowConstants.STATUS_IN_TRASH) &&
1175                                    (oldStatus != WorkflowConstants.STATUS_SCHEDULED)) {
1176    
1177                                    if (serviceContext.isCommandUpdate()) {
1178                                            socialActivityLocalService.addActivity(
1179                                                    user.getUserId(), entry.getGroupId(),
1180                                                    BlogsEntry.class.getName(), entryId,
1181                                                    BlogsActivityKeys.UPDATE_ENTRY,
1182                                                    extraDataJSONObject.toString(), 0);
1183                                    }
1184                                    else {
1185                                            socialActivityLocalService.addUniqueActivity(
1186                                                    user.getUserId(), entry.getGroupId(),
1187                                                    BlogsEntry.class.getName(), entryId,
1188                                                    BlogsActivityKeys.ADD_ENTRY,
1189                                                    extraDataJSONObject.toString(), 0);
1190                                    }
1191                            }
1192    
1193                            // Trash
1194    
1195                            if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1196                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1197                                            mbMessageLocalService.restoreDiscussionFromTrash(
1198                                                    BlogsEntry.class.getName(), entryId);
1199                                    }
1200    
1201                                    trashEntryLocalService.deleteEntry(
1202                                            BlogsEntry.class.getName(), entryId);
1203                            }
1204    
1205                            if (oldStatus != WorkflowConstants.STATUS_IN_TRASH) {
1206    
1207                                    // Subscriptions
1208    
1209                                    notifySubscribers(entry, serviceContext);
1210    
1211                                    // Ping
1212    
1213                                    String[] trackbacks = (String[])serviceContext.getAttribute(
1214                                            "trackbacks");
1215                                    Boolean pingOldTrackbacks = ParamUtil.getBoolean(
1216                                            serviceContext, "pingOldTrackbacks");
1217    
1218                                    pingGoogle(entry, serviceContext);
1219                                    pingPingback(entry, serviceContext);
1220                                    pingTrackbacks(
1221                                            entry, trackbacks, pingOldTrackbacks, serviceContext);
1222                            }
1223                    }
1224                    else {
1225    
1226                            // Asset
1227    
1228                            assetEntryLocalService.updateVisible(
1229                                    BlogsEntry.class.getName(), entryId, false);
1230    
1231                            // Social
1232    
1233                            if ((status == WorkflowConstants.STATUS_SCHEDULED) &&
1234                                    (oldStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1235    
1236                                    if (serviceContext.isCommandUpdate()) {
1237                                            socialActivityLocalService.addActivity(
1238                                                    user.getUserId(), entry.getGroupId(),
1239                                                    BlogsEntry.class.getName(), entryId,
1240                                                    BlogsActivityKeys.UPDATE_ENTRY,
1241                                                    extraDataJSONObject.toString(), 0);
1242                                    }
1243                                    else {
1244                                            socialActivityLocalService.addUniqueActivity(
1245                                                    user.getUserId(), entry.getGroupId(),
1246                                                    BlogsEntry.class.getName(), entryId,
1247                                                    BlogsActivityKeys.ADD_ENTRY,
1248                                                    extraDataJSONObject.toString(), 0);
1249                                    }
1250                            }
1251    
1252                            // Trash
1253    
1254                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
1255                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1256                                            mbMessageLocalService.moveDiscussionToTrash(
1257                                                    BlogsEntry.class.getName(), entryId);
1258                                    }
1259    
1260                                    trashEntryLocalService.addTrashEntry(
1261                                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
1262                                            entry.getEntryId(), entry.getUuid(), null, oldStatus, null,
1263                                            null);
1264                            }
1265                            else if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1266                                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1267                                            mbMessageLocalService.restoreDiscussionFromTrash(
1268                                                    BlogsEntry.class.getName(), entryId);
1269                                    }
1270    
1271                                    trashEntryLocalService.deleteEntry(
1272                                            BlogsEntry.class.getName(), entryId);
1273                            }
1274                    }
1275    
1276                    return entry;
1277            }
1278    
1279            protected String getUniqueUrlTitle(long entryId, long groupId, String title)
1280                    throws SystemException {
1281    
1282                    String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
1283    
1284                    for (int i = 1;; i++) {
1285                            BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
1286                                    groupId, urlTitle);
1287    
1288                            if ((entry == null) || (entryId == entry.getEntryId())) {
1289                                    break;
1290                            }
1291                            else {
1292                                    String suffix = StringPool.DASH + i;
1293    
1294                                    String prefix = urlTitle;
1295    
1296                                    if (urlTitle.length() > suffix.length()) {
1297                                            prefix = urlTitle.substring(
1298                                                    0, urlTitle.length() - suffix.length());
1299                                    }
1300    
1301                                    urlTitle = prefix + suffix;
1302                            }
1303                    }
1304    
1305                    return urlTitle;
1306            }
1307    
1308            protected String getUniqueUrlTitle(
1309                            long entryId, String title, String oldUrlTitle,
1310                            ServiceContext serviceContext)
1311                    throws SystemException {
1312    
1313                    String serviceContextUrlTitle = ParamUtil.getString(
1314                            serviceContext, "urlTitle");
1315    
1316                    String urlTitle = null;
1317    
1318                    if (Validator.isNotNull(serviceContextUrlTitle)) {
1319                            urlTitle = BlogsUtil.getUrlTitle(entryId, serviceContextUrlTitle);
1320                    }
1321                    else if (Validator.isNotNull(oldUrlTitle)) {
1322                            return oldUrlTitle;
1323                    }
1324                    else {
1325                            urlTitle = getUniqueUrlTitle(
1326                                    entryId, serviceContext.getScopeGroupId(), title);
1327                    }
1328    
1329                    BlogsEntry urlTitleEntry = blogsEntryPersistence.fetchByG_UT(
1330                            serviceContext.getScopeGroupId(), urlTitle);
1331    
1332                    if ((urlTitleEntry != null) &&
1333                            (urlTitleEntry.getEntryId() != entryId)) {
1334    
1335                            urlTitle = getUniqueUrlTitle(
1336                                    entryId, serviceContext.getScopeGroupId(), urlTitle);
1337                    }
1338    
1339                    return urlTitle;
1340            }
1341    
1342            protected void notifySubscribers(
1343                            BlogsEntry entry, ServiceContext serviceContext)
1344                    throws SystemException {
1345    
1346                    if (!entry.isApproved()) {
1347                            return;
1348                    }
1349    
1350                    String layoutFullURL = serviceContext.getLayoutFullURL();
1351    
1352                    if (Validator.isNull(layoutFullURL)) {
1353                            return;
1354                    }
1355    
1356                    PortletPreferences preferences =
1357                            ServiceContextUtil.getPortletPreferences(serviceContext);
1358    
1359                    if (preferences == null) {
1360                            long ownerId = entry.getGroupId();
1361                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1362                            long plid = PortletKeys.PREFS_PLID_SHARED;
1363                            String portletId = PortletKeys.BLOGS;
1364                            String defaultPreferences = null;
1365    
1366                            preferences = portletPreferencesLocalService.getPreferences(
1367                                    entry.getCompanyId(), ownerId, ownerType, plid, portletId,
1368                                    defaultPreferences);
1369                    }
1370    
1371                    if (serviceContext.isCommandAdd() &&
1372                            BlogsUtil.getEmailEntryAddedEnabled(preferences)) {
1373                    }
1374                    else if (serviceContext.isCommandUpdate() &&
1375                                     BlogsUtil.getEmailEntryUpdatedEnabled(preferences)) {
1376                    }
1377                    else {
1378                            return;
1379                    }
1380    
1381                    String entryURL =
1382                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
1383                                    StringPool.SLASH + entry.getEntryId();
1384    
1385                    String fromName = BlogsUtil.getEmailFromName(
1386                            preferences, entry.getCompanyId());
1387                    String fromAddress = BlogsUtil.getEmailFromAddress(
1388                            preferences, entry.getCompanyId());
1389    
1390                    Map<Locale, String> localizedSubjectMap = null;
1391                    Map<Locale, String> localizedBodyMap = null;
1392    
1393                    if (serviceContext.isCommandUpdate()) {
1394                            localizedSubjectMap = BlogsUtil.getEmailEntryUpdatedSubjectMap(
1395                                    preferences);
1396                            localizedBodyMap = BlogsUtil.getEmailEntryUpdatedBodyMap(
1397                                    preferences);
1398                    }
1399                    else {
1400                            localizedSubjectMap = BlogsUtil.getEmailEntryAddedSubjectMap(
1401                                    preferences);
1402                            localizedBodyMap = BlogsUtil.getEmailEntryAddedBodyMap(preferences);
1403                    }
1404    
1405                    SubscriptionSender subscriptionSender = new SubscriptionSender();
1406    
1407                    subscriptionSender.setCompanyId(entry.getCompanyId());
1408                    subscriptionSender.setContextAttributes(
1409                            "[$BLOGS_ENTRY_STATUS_BY_USER_NAME$]", entry.getStatusByUserName(),
1410                            "[$BLOGS_ENTRY_URL$]", entryURL);
1411                    subscriptionSender.setContextUserPrefix("BLOGS_ENTRY");
1412                    subscriptionSender.setFrom(fromAddress, fromName);
1413                    subscriptionSender.setHtmlFormat(true);
1414                    subscriptionSender.setLocalizedBodyMap(localizedBodyMap);
1415                    subscriptionSender.setLocalizedSubjectMap(localizedSubjectMap);
1416                    subscriptionSender.setMailId("blogs_entry", entry.getEntryId());
1417                    subscriptionSender.setPortletId(PortletKeys.BLOGS);
1418                    subscriptionSender.setReplyToAddress(fromAddress);
1419                    subscriptionSender.setScopeGroupId(entry.getGroupId());
1420                    subscriptionSender.setServiceContext(serviceContext);
1421                    subscriptionSender.setUserId(entry.getUserId());
1422    
1423                    subscriptionSender.addPersistedSubscribers(
1424                            BlogsEntry.class.getName(), entry.getGroupId());
1425    
1426                    subscriptionSender.addPersistedSubscribers(
1427                            BlogsEntry.class.getName(), entry.getEntryId());
1428    
1429                    subscriptionSender.flushNotificationsAsync();
1430            }
1431    
1432            protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
1433                    throws PortalException, SystemException {
1434    
1435                    if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
1436                            return;
1437                    }
1438    
1439                    String layoutFullURL = PortalUtil.getLayoutFullURL(
1440                            serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
1441    
1442                    if (Validator.isNull(layoutFullURL)) {
1443                            return;
1444                    }
1445    
1446                    if (layoutFullURL.contains("://localhost")) {
1447                            if (_log.isDebugEnabled()) {
1448                                    _log.debug(
1449                                            "Not pinging Google because of localhost URL " +
1450                                                    layoutFullURL);
1451                            }
1452    
1453                            return;
1454                    }
1455    
1456                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1457    
1458                    StringBundler sb = new StringBundler(6);
1459    
1460                    String name = group.getDescriptiveName();
1461                    String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
1462                    String changesURL =
1463                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
1464    
1465                    sb.append("http://blogsearch.google.com/ping?name=");
1466                    sb.append(HttpUtil.encodeURL(name));
1467                    sb.append("&url=");
1468                    sb.append(HttpUtil.encodeURL(url));
1469                    sb.append("&changesURL=");
1470                    sb.append(HttpUtil.encodeURL(changesURL));
1471    
1472                    String location = sb.toString();
1473    
1474                    if (_log.isInfoEnabled()) {
1475                            _log.info("Pinging Google at " + location);
1476                    }
1477    
1478                    try {
1479                            String response = HttpUtil.URLtoString(sb.toString());
1480    
1481                            if (_log.isInfoEnabled()) {
1482                                    _log.info("Google ping response: " + response);
1483                            }
1484                    }
1485                    catch (IOException ioe) {
1486                            _log.error("Unable to ping Google at " + location, ioe);
1487                    }
1488            }
1489    
1490            protected void pingPingback(BlogsEntry entry, ServiceContext serviceContext)
1491                    throws PortalException, SystemException {
1492    
1493                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
1494                            !entry.isAllowPingbacks() || !entry.isApproved()) {
1495    
1496                            return;
1497                    }
1498    
1499                    HttpServletRequest request = serviceContext.getRequest();
1500    
1501                    if (request == null) {
1502                            return;
1503                    }
1504    
1505                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1506                            WebKeys.THEME_DISPLAY);
1507    
1508                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1509    
1510                    if (Validator.isNull(layoutFullURL)) {
1511                            return;
1512                    }
1513    
1514                    String sourceUri =
1515                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1516                                    entry.getUrlTitle();
1517    
1518                    Source source = new Source(entry.getContent());
1519    
1520                    List<StartTag> tags = source.getAllStartTags("a");
1521    
1522                    for (StartTag tag : tags) {
1523                            String targetUri = tag.getAttributeValue("href");
1524    
1525                            if (Validator.isNotNull(targetUri)) {
1526                                    try {
1527                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
1528                                    }
1529                                    catch (Exception e) {
1530                                            _log.error("Error while sending pingback " + targetUri, e);
1531                                    }
1532                            }
1533                    }
1534            }
1535    
1536            protected void pingTrackbacks(
1537                            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
1538                            ServiceContext serviceContext)
1539                    throws PortalException, SystemException {
1540    
1541                    if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
1542                            !entry.isAllowTrackbacks() || !entry.isApproved()) {
1543    
1544                            return;
1545                    }
1546    
1547                    HttpServletRequest request = serviceContext.getRequest();
1548    
1549                    if (request == null) {
1550                            return;
1551                    }
1552    
1553                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1554                            WebKeys.THEME_DISPLAY);
1555    
1556                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1557    
1558                    if (Validator.isNull(layoutFullURL)) {
1559                            return;
1560                    }
1561    
1562                    Map<String, String> parts = new HashMap<String, String>();
1563    
1564                    String excerpt = StringUtil.shorten(
1565                            HtmlUtil.extractText(entry.getContent()),
1566                            PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
1567                    String url =
1568                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1569                                    entry.getUrlTitle();
1570    
1571                    parts.put("title", entry.getTitle());
1572                    parts.put("excerpt", excerpt);
1573                    parts.put("url", url);
1574                    parts.put("blog_name", entry.getUserName());
1575    
1576                    Set<String> trackbacksSet = null;
1577    
1578                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1579                            trackbacksSet = SetUtil.fromArray(trackbacks);
1580                    }
1581                    else {
1582                            trackbacksSet = new HashSet<String>();
1583                    }
1584    
1585                    if (pingOldTrackbacks) {
1586                            trackbacksSet.addAll(
1587                                    SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
1588    
1589                            entry.setTrackbacks(StringPool.BLANK);
1590    
1591                            blogsEntryPersistence.update(entry);
1592                    }
1593    
1594                    Set<String> oldTrackbacks = SetUtil.fromArray(
1595                            StringUtil.split(entry.getTrackbacks()));
1596    
1597                    Set<String> validTrackbacks = new HashSet<String>();
1598    
1599                    for (String trackback : trackbacksSet) {
1600                            if (oldTrackbacks.contains(trackback)) {
1601                                    continue;
1602                            }
1603    
1604                            try {
1605                                    if (LinkbackProducerUtil.sendTrackback(trackback, parts)) {
1606                                            validTrackbacks.add(trackback);
1607                                    }
1608                            }
1609                            catch (Exception e) {
1610                                    _log.error("Error while sending trackback at " + trackback, e);
1611                            }
1612                    }
1613    
1614                    if (!validTrackbacks.isEmpty()) {
1615                            String newTrackbacks = StringUtil.merge(validTrackbacks);
1616    
1617                            if (Validator.isNotNull(entry.getTrackbacks())) {
1618                                    newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
1619                            }
1620    
1621                            entry.setTrackbacks(newTrackbacks);
1622    
1623                            blogsEntryPersistence.update(entry);
1624                    }
1625            }
1626    
1627            protected void saveImages(
1628                            boolean smallImage, long smallImageId, byte[] smallImageBytes)
1629                    throws PortalException, SystemException {
1630    
1631                    if (smallImage) {
1632                            if (smallImageBytes != null) {
1633                                    imageLocalService.updateImage(smallImageId, smallImageBytes);
1634                            }
1635                    }
1636                    else {
1637                            imageLocalService.deleteImage(smallImageId);
1638                    }
1639            }
1640    
1641            protected void validate(
1642                            String title, String content, boolean smallImage,
1643                            String smallImageURL, String smallImageFileName,
1644                            byte[] smallImageBytes)
1645                    throws PortalException, SystemException {
1646    
1647                    if (Validator.isNull(title)) {
1648                            throw new EntryTitleException();
1649                    }
1650                    else if (Validator.isNull(content)) {
1651                            throw new EntryContentException();
1652                    }
1653    
1654                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
1655                            PropsKeys.BLOGS_IMAGE_EXTENSIONS, StringPool.COMMA);
1656    
1657                    if (smallImage && Validator.isNull(smallImageURL) &&
1658                            (smallImageBytes != null)) {
1659    
1660                            if (smallImageFileName != null) {
1661                                    boolean validSmallImageExtension = false;
1662    
1663                                    for (String _imageExtension : imageExtensions) {
1664                                            if (StringPool.STAR.equals(_imageExtension) ||
1665                                                    StringUtil.endsWith(
1666                                                            smallImageFileName, _imageExtension)) {
1667    
1668                                                    validSmallImageExtension = true;
1669    
1670                                                    break;
1671                                            }
1672                                    }
1673    
1674                                    if (!validSmallImageExtension) {
1675                                            throw new EntrySmallImageNameException(smallImageFileName);
1676                                    }
1677                            }
1678    
1679                            long smallImageMaxSize = PrefsPropsUtil.getLong(
1680                                    PropsKeys.BLOGS_IMAGE_SMALL_MAX_SIZE);
1681    
1682                            if ((smallImageMaxSize > 0) &&
1683                                    (smallImageBytes.length > smallImageMaxSize)) {
1684    
1685                                    throw new EntrySmallImageSizeException();
1686                            }
1687                    }
1688            }
1689    
1690            private static Log _log = LogFactoryUtil.getLog(
1691                    BlogsEntryLocalServiceImpl.class);
1692    
1693    }