001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.blogs.service.impl;
016    
017    import com.liferay.portal.kernel.bean.BeanReference;
018    import com.liferay.portal.kernel.comment.CommentManager;
019    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.notifications.UserNotificationDefinition;
026    import com.liferay.portal.kernel.repository.model.FileEntry;
027    import com.liferay.portal.kernel.repository.model.Folder;
028    import com.liferay.portal.kernel.search.Indexable;
029    import com.liferay.portal.kernel.search.IndexableType;
030    import com.liferay.portal.kernel.search.Indexer;
031    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
032    import com.liferay.portal.kernel.servlet.taglib.ui.ImageSelector;
033    import com.liferay.portal.kernel.settings.LocalizedValuesMap;
034    import com.liferay.portal.kernel.systemevent.SystemEvent;
035    import com.liferay.portal.kernel.util.ArrayUtil;
036    import com.liferay.portal.kernel.util.Constants;
037    import com.liferay.portal.kernel.util.ContentTypes;
038    import com.liferay.portal.kernel.util.FileUtil;
039    import com.liferay.portal.kernel.util.GetterUtil;
040    import com.liferay.portal.kernel.util.HtmlUtil;
041    import com.liferay.portal.kernel.util.HttpUtil;
042    import com.liferay.portal.kernel.util.MimeTypesUtil;
043    import com.liferay.portal.kernel.util.OrderByComparator;
044    import com.liferay.portal.kernel.util.ParamUtil;
045    import com.liferay.portal.kernel.util.PropsKeys;
046    import com.liferay.portal.kernel.util.SetUtil;
047    import com.liferay.portal.kernel.util.StringBundler;
048    import com.liferay.portal.kernel.util.StringPool;
049    import com.liferay.portal.kernel.util.StringUtil;
050    import com.liferay.portal.kernel.util.TempFileEntryUtil;
051    import com.liferay.portal.kernel.util.Time;
052    import com.liferay.portal.kernel.util.Validator;
053    import com.liferay.portal.kernel.util.WebKeys;
054    import com.liferay.portal.kernel.workflow.WorkflowConstants;
055    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
056    import com.liferay.portal.model.Group;
057    import com.liferay.portal.model.Repository;
058    import com.liferay.portal.model.ResourceConstants;
059    import com.liferay.portal.model.SystemEventConstants;
060    import com.liferay.portal.model.User;
061    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
062    import com.liferay.portal.service.ServiceContext;
063    import com.liferay.portal.theme.ThemeDisplay;
064    import com.liferay.portal.util.GroupSubscriptionCheckSubscriptionSender;
065    import com.liferay.portal.util.LayoutURLUtil;
066    import com.liferay.portal.util.Portal;
067    import com.liferay.portal.util.PortalUtil;
068    import com.liferay.portal.util.PortletKeys;
069    import com.liferay.portal.util.PrefsPropsUtil;
070    import com.liferay.portal.util.PropsValues;
071    import com.liferay.portal.util.SubscriptionSender;
072    import com.liferay.portlet.PortletURLFactoryUtil;
073    import com.liferay.portlet.asset.model.AssetEntry;
074    import com.liferay.portlet.asset.model.AssetLinkConstants;
075    import com.liferay.portlet.blogs.BlogsSettings;
076    import com.liferay.portlet.blogs.EntryContentException;
077    import com.liferay.portlet.blogs.EntryDisplayDateException;
078    import com.liferay.portlet.blogs.EntrySmallImageNameException;
079    import com.liferay.portlet.blogs.EntrySmallImageSizeException;
080    import com.liferay.portlet.blogs.EntryTitleException;
081    import com.liferay.portlet.blogs.model.BlogsEntry;
082    import com.liferay.portlet.blogs.service.base.BlogsEntryLocalServiceBaseImpl;
083    import com.liferay.portlet.blogs.service.permission.BlogsPermission;
084    import com.liferay.portlet.blogs.social.BlogsActivityKeys;
085    import com.liferay.portlet.blogs.util.BlogsUtil;
086    import com.liferay.portlet.blogs.util.LinkbackProducerUtil;
087    import com.liferay.portlet.blogs.util.comparator.EntryDisplayDateComparator;
088    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
089    import com.liferay.portlet.social.model.SocialActivityConstants;
090    import com.liferay.portlet.trash.model.TrashEntry;
091    
092    import java.io.File;
093    import java.io.IOException;
094    import java.io.InputStream;
095    import java.io.Serializable;
096    
097    import java.util.Date;
098    import java.util.HashMap;
099    import java.util.HashSet;
100    import java.util.List;
101    import java.util.Map;
102    import java.util.Set;
103    
104    import javax.portlet.PortletRequest;
105    import javax.portlet.PortletURL;
106    
107    import javax.servlet.http.HttpServletRequest;
108    
109    import net.htmlparser.jericho.Source;
110    import net.htmlparser.jericho.StartTag;
111    
112    /**
113     * Provides the local service for accessing, adding, checking, deleting,
114     * subscription handling of, trash handling of, and updating blog entries.
115     *
116     * @author Brian Wing Shun Chan
117     * @author Wilson S. Man
118     * @author Raymond Aug??
119     * @author Thiago Moreira
120     * @author Juan Fern??ndez
121     * @author Zsolt Berentey
122     */
123    public class BlogsEntryLocalServiceImpl extends BlogsEntryLocalServiceBaseImpl {
124    
125            @Override
126            public Folder addAttachmentsFolder(long userId, long groupId)
127                    throws PortalException {
128    
129                    ServiceContext serviceContext = new ServiceContext();
130    
131                    serviceContext.setAddGroupPermissions(true);
132                    serviceContext.setAddGuestPermissions(true);
133    
134                    Repository repository = PortletFileRepositoryUtil.addPortletRepository(
135                            groupId, PortletKeys.BLOGS, serviceContext);
136    
137                    Folder folder = PortletFileRepositoryUtil.addPortletFolder(
138                            userId, repository.getRepositoryId(),
139                            DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, PortletKeys.BLOGS,
140                            serviceContext);
141    
142                    return folder;
143            }
144    
145            /**
146             * @deprecated As of 7.0.0, replaced by {@link #addEntry(long, String,
147             *             String, String, String, int, int, int, int, int, boolean,
148             *             boolean, String[], boolean, String, String, InputStream,
149             *             ServiceContext)}
150             */
151            @Deprecated
152            @Override
153            public BlogsEntry addEntry(
154                            long userId, String title, String description, String content,
155                            int displayDateMonth, int displayDateDay, int displayDateYear,
156                            int displayDateHour, int displayDateMinute, boolean allowPingbacks,
157                            boolean allowTrackbacks, String[] trackbacks, boolean smallImage,
158                            String smallImageURL, String smallImageFileName,
159                            InputStream smallImageInputStream, ServiceContext serviceContext)
160                    throws PortalException {
161    
162                    ImageSelector coverImageImageSelector = null;
163                    ImageSelector smallImageImageSelector = null;
164    
165                    if (smallImage && Validator.isNotNull(smallImageFileName) &&
166                            (smallImageInputStream != null)) {
167    
168                            FileEntry tempFileEntry = TempFileEntryUtil.addTempFileEntry(
169                                    serviceContext.getScopeGroupId(), userId,
170                                    BlogsEntry.class.getName(), smallImageFileName,
171                                    smallImageInputStream,
172                                    MimeTypesUtil.getContentType(smallImageFileName));
173    
174                            smallImageImageSelector = new ImageSelector(
175                                    tempFileEntry.getFileEntryId(), smallImageURL, null);
176                    }
177    
178                    return addEntry(
179                            userId, title, StringPool.BLANK, description, content,
180                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
181                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
182                            coverImageImageSelector, smallImageImageSelector, serviceContext);
183            }
184    
185            @Indexable(type = IndexableType.REINDEX)
186            @Override
187            public BlogsEntry addEntry(
188                            long userId, String title, String subtitle, String description,
189                            String content, int displayDateMonth, int displayDateDay,
190                            int displayDateYear, int displayDateHour, int displayDateMinute,
191                            boolean allowPingbacks, boolean allowTrackbacks,
192                            String[] trackbacks, ImageSelector coverImageImageSelector,
193                            ImageSelector smallImageImageSelector,
194                            ServiceContext serviceContext)
195                    throws PortalException {
196    
197                    // Entry
198    
199                    User user = userPersistence.findByPrimaryKey(userId);
200                    long groupId = serviceContext.getScopeGroupId();
201                    Date displayDate = PortalUtil.getDate(
202                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
203                            displayDateMinute, user.getTimeZone(),
204                            EntryDisplayDateException.class);
205    
206                    long entryId = counterLocalService.increment();
207    
208                    long coverImageFileEntryId = 0;
209                    String coverImageURL = null;
210    
211                    if (coverImageImageSelector != null) {
212                            coverImageFileEntryId = coverImageImageSelector.getImageId();
213                            coverImageURL = coverImageImageSelector.getImageURL();
214                    }
215    
216                    if (coverImageFileEntryId != 0) {
217                            coverImageFileEntryId = addCoverImage(
218                                    userId, groupId, entryId, coverImageImageSelector);
219                    }
220    
221                    boolean smallImage = false;
222                    long smallImageFileEntryId = 0;
223                    String smallImageURL = null;
224    
225                    if (smallImageImageSelector != null) {
226                            smallImage = !smallImageImageSelector.isRemoveSmallImage();
227                            smallImageFileEntryId = smallImageImageSelector.getImageId();
228                            smallImageURL = smallImageImageSelector.getImageURL();
229                    }
230    
231                    if (smallImageFileEntryId != 0) {
232                            FileEntry tempFileEntry =
233                                    PortletFileRepositoryUtil.getPortletFileEntry(
234                                            smallImageFileEntryId);
235    
236                            smallImageFileEntryId = addSmallImageFileEntry(
237                                    userId, groupId, entryId, tempFileEntry.getMimeType(),
238                                    tempFileEntry.getTitle(), tempFileEntry.getContentStream());
239    
240                            PortletFileRepositoryUtil.deletePortletFileEntry(
241                                    tempFileEntry.getFileEntryId());
242                    }
243    
244                    Date now = new Date();
245    
246                    validate(title, content, smallImageFileEntryId);
247    
248                    BlogsEntry entry = blogsEntryPersistence.create(entryId);
249    
250                    entry.setUuid(serviceContext.getUuid());
251                    entry.setGroupId(groupId);
252                    entry.setCompanyId(user.getCompanyId());
253                    entry.setUserId(user.getUserId());
254                    entry.setUserName(user.getFullName());
255                    entry.setCreateDate(serviceContext.getCreateDate(now));
256                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
257                    entry.setTitle(title);
258                    entry.setSubtitle(subtitle);
259                    entry.setUrlTitle(
260                            getUniqueUrlTitle(entryId, title, null, serviceContext));
261                    entry.setDescription(description);
262                    entry.setContent(content);
263                    entry.setDisplayDate(displayDate);
264                    entry.setAllowPingbacks(allowPingbacks);
265                    entry.setAllowTrackbacks(allowTrackbacks);
266                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
267                    entry.setCoverImageURL(coverImageURL);
268                    entry.setSmallImage(smallImage);
269                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
270                    entry.setSmallImageURL(smallImageURL);
271                    entry.setStatus(WorkflowConstants.STATUS_DRAFT);
272                    entry.setStatusByUserId(userId);
273                    entry.setStatusDate(serviceContext.getModifiedDate(now));
274                    entry.setExpandoBridgeAttributes(serviceContext);
275    
276                    blogsEntryPersistence.update(entry);
277    
278                    // Resources
279    
280                    if (serviceContext.isAddGroupPermissions() ||
281                            serviceContext.isAddGuestPermissions()) {
282    
283                            addEntryResources(
284                                    entry, serviceContext.isAddGroupPermissions(),
285                                    serviceContext.isAddGuestPermissions());
286                    }
287                    else {
288                            addEntryResources(
289                                    entry, serviceContext.getGroupPermissions(),
290                                    serviceContext.getGuestPermissions());
291                    }
292    
293                    // Asset
294    
295                    updateAsset(
296                            userId, entry, serviceContext.getAssetCategoryIds(),
297                            serviceContext.getAssetTagNames(),
298                            serviceContext.getAssetLinkEntryIds());
299    
300                    // Comments
301    
302                    addDiscussion(entry, userId, groupId);
303    
304                    // Workflow
305    
306                    if (ArrayUtil.isNotEmpty(trackbacks)) {
307                            serviceContext.setAttribute("trackbacks", trackbacks);
308                    }
309                    else {
310                            serviceContext.setAttribute("trackbacks", null);
311                    }
312    
313                    return startWorkflowInstance(userId, entry, serviceContext);
314            }
315    
316            @Override
317            public void addEntryResources(
318                            BlogsEntry entry, boolean addGroupPermissions,
319                            boolean addGuestPermissions)
320                    throws PortalException {
321    
322                    resourceLocalService.addResources(
323                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
324                            BlogsEntry.class.getName(), entry.getEntryId(), false,
325                            addGroupPermissions, addGuestPermissions);
326            }
327    
328            @Override
329            public void addEntryResources(
330                            BlogsEntry entry, String[] groupPermissions,
331                            String[] guestPermissions)
332                    throws PortalException {
333    
334                    resourceLocalService.addModelResources(
335                            entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
336                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
337                            guestPermissions);
338            }
339    
340            @Override
341            public void addEntryResources(
342                            long entryId, boolean addGroupPermissions,
343                            boolean addGuestPermissions)
344                    throws PortalException {
345    
346                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
347    
348                    addEntryResources(entry, addGroupPermissions, addGuestPermissions);
349            }
350    
351            @Override
352            public void addEntryResources(
353                            long entryId, String[] groupPermissions, String[] guestPermissions)
354                    throws PortalException {
355    
356                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
357    
358                    addEntryResources(entry, groupPermissions, guestPermissions);
359            }
360    
361            @Override
362            public void checkEntries() throws PortalException {
363                    Date now = new Date();
364    
365                    int count = blogsEntryPersistence.countByLtD_S(
366                            now, WorkflowConstants.STATUS_SCHEDULED);
367    
368                    if (count == 0) {
369                            return;
370                    }
371    
372                    List<BlogsEntry> entries = blogsEntryPersistence.findByLtD_S(
373                            now, WorkflowConstants.STATUS_SCHEDULED);
374    
375                    for (BlogsEntry entry : entries) {
376                            ServiceContext serviceContext = new ServiceContext();
377    
378                            String[] trackbacks = StringUtil.split(entry.getTrackbacks());
379    
380                            serviceContext.setAttribute("trackbacks", trackbacks);
381    
382                            serviceContext.setCommand(Constants.UPDATE);
383    
384                            String layoutFullURL = PortalUtil.getLayoutFullURL(
385                                    entry.getGroupId(), PortletKeys.BLOGS);
386    
387                            serviceContext.setLayoutFullURL(layoutFullURL);
388    
389                            serviceContext.setScopeGroupId(entry.getGroupId());
390    
391                            blogsEntryLocalService.updateStatus(
392                                    entry.getStatusByUserId(), entry.getEntryId(),
393                                    WorkflowConstants.STATUS_APPROVED, serviceContext,
394                                    new HashMap<String, Serializable>());
395                    }
396            }
397    
398            @Override
399            public void deleteEntries(long groupId) throws PortalException {
400                    for (BlogsEntry entry : blogsEntryPersistence.findByGroupId(groupId)) {
401                            blogsEntryLocalService.deleteEntry(entry);
402                    }
403            }
404    
405            @Indexable(type = IndexableType.DELETE)
406            @Override
407            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
408            public BlogsEntry deleteEntry(BlogsEntry entry) throws PortalException {
409    
410                    // Entry
411    
412                    blogsEntryPersistence.remove(entry);
413    
414                    // Resources
415    
416                    resourceLocalService.deleteResource(
417                            entry.getCompanyId(), BlogsEntry.class.getName(),
418                            ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
419    
420                    // Image
421    
422                    imageLocalService.deleteImage(entry.getSmallImageId());
423    
424                    // Subscriptions
425    
426                    subscriptionLocalService.deleteSubscriptions(
427                            entry.getCompanyId(), BlogsEntry.class.getName(),
428                            entry.getEntryId());
429    
430                    // Statistics
431    
432                    blogsStatsUserLocalService.updateStatsUser(
433                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
434    
435                    // Asset
436    
437                    assetEntryLocalService.deleteEntry(
438                            BlogsEntry.class.getName(), entry.getEntryId());
439    
440                    // Comment
441    
442                    deleteDiscussion(entry);
443    
444                    // Expando
445    
446                    expandoRowLocalService.deleteRows(entry.getEntryId());
447    
448                    // Ratings
449    
450                    ratingsStatsLocalService.deleteStats(
451                            BlogsEntry.class.getName(), entry.getEntryId());
452    
453                    // Trash
454    
455                    trashEntryLocalService.deleteEntry(
456                            BlogsEntry.class.getName(), entry.getEntryId());
457    
458                    // Indexer
459    
460                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
461                            BlogsEntry.class);
462    
463                    indexer.delete(entry);
464    
465                    // Workflow
466    
467                    workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
468                            entry.getCompanyId(), entry.getGroupId(),
469                            BlogsEntry.class.getName(), entry.getEntryId());
470    
471                    return entry;
472            }
473    
474            @Override
475            public void deleteEntry(long entryId) throws PortalException {
476                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
477    
478                    blogsEntryLocalService.deleteEntry(entry);
479            }
480    
481            /**
482             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
483             *             Date, QueryDefinition)}
484             */
485            @Deprecated
486            @Override
487            public List<BlogsEntry> getCompanyEntries(
488                    long companyId, Date displayDate, int status, int start, int end) {
489    
490                    QueryDefinition<BlogsEntry> queryDefinition =
491                            new QueryDefinition<BlogsEntry>(status, start, end, null);
492    
493                    return getCompanyEntries(companyId, displayDate, queryDefinition);
494            }
495    
496            /**
497             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntries(long,
498             *             Date, QueryDefinition)}
499             */
500            @Deprecated
501            @Override
502            public List<BlogsEntry> getCompanyEntries(
503                    long companyId, Date displayDate, int status, int start, int end,
504                    OrderByComparator<BlogsEntry> obc) {
505    
506                    QueryDefinition<BlogsEntry> queryDefinition =
507                            new QueryDefinition<BlogsEntry>(status, start, end, obc);
508    
509                    return getCompanyEntries(companyId, displayDate, queryDefinition);
510            }
511    
512            @Override
513            public List<BlogsEntry> getCompanyEntries(
514                    long companyId, Date displayDate,
515                    QueryDefinition<BlogsEntry> queryDefinition) {
516    
517                    if (queryDefinition.isExcludeStatus()) {
518                            return blogsEntryPersistence.findByC_LtD_NotS(
519                                    companyId, displayDate, queryDefinition.getStatus(),
520                                    queryDefinition.getStart(), queryDefinition.getEnd(),
521                                    queryDefinition.getOrderByComparator());
522                    }
523                    else {
524                            return blogsEntryPersistence.findByC_LtD_S(
525                                    companyId, displayDate, queryDefinition.getStatus(),
526                                    queryDefinition.getStart(), queryDefinition.getEnd(),
527                                    queryDefinition.getOrderByComparator());
528                    }
529            }
530    
531            /**
532             * @deprecated As of 6.2.0, replaced by {@link #getCompanyEntriesCount(long,
533             *             Date, QueryDefinition)}
534             */
535            @Deprecated
536            @Override
537            public int getCompanyEntriesCount(
538                    long companyId, Date displayDate, int status) {
539    
540                    QueryDefinition<BlogsEntry> queryDefinition =
541                            new QueryDefinition<BlogsEntry>(status);
542    
543                    return getCompanyEntriesCount(companyId, displayDate, queryDefinition);
544            }
545    
546            @Override
547            public int getCompanyEntriesCount(
548                    long companyId, Date displayDate,
549                    QueryDefinition<BlogsEntry> queryDefinition) {
550    
551                    if (queryDefinition.isExcludeStatus()) {
552                            return blogsEntryPersistence.countByC_LtD_NotS(
553                                    companyId, displayDate, queryDefinition.getStatus());
554                    }
555                    else {
556                            return blogsEntryPersistence.countByC_LtD_S(
557                                    companyId, displayDate, queryDefinition.getStatus());
558                    }
559            }
560    
561            @Override
562            public BlogsEntry[] getEntriesPrevAndNext(long entryId)
563                    throws PortalException {
564    
565                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
566    
567                    return blogsEntryPersistence.findByG_S_PrevAndNext(
568                            entry.getEntryId(), entry.getGroupId(),
569                            WorkflowConstants.STATUS_APPROVED,
570                            new EntryDisplayDateComparator(true));
571            }
572    
573            @Override
574            public BlogsEntry getEntry(long entryId) throws PortalException {
575                    return blogsEntryPersistence.findByPrimaryKey(entryId);
576            }
577    
578            @Override
579            public BlogsEntry getEntry(long groupId, String urlTitle)
580                    throws PortalException {
581    
582                    return blogsEntryPersistence.findByG_UT(groupId, urlTitle);
583            }
584    
585            /**
586             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
587             *             QueryDefinition)}
588             */
589            @Deprecated
590            @Override
591            public List<BlogsEntry> getGroupEntries(
592                    long groupId, Date displayDate, int status, int start, int end) {
593    
594                    QueryDefinition<BlogsEntry> queryDefinition =
595                            new QueryDefinition<BlogsEntry>(status, start, end, null);
596    
597                    return getGroupEntries(groupId, displayDate, queryDefinition);
598            }
599    
600            /**
601             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long, Date,
602             *             QueryDefinition)}
603             */
604            @Deprecated
605            @Override
606            public List<BlogsEntry> getGroupEntries(
607                    long groupId, Date displayDate, int status, int start, int end,
608                    OrderByComparator<BlogsEntry> obc) {
609    
610                    QueryDefinition<BlogsEntry> queryDefinition =
611                            new QueryDefinition<BlogsEntry>(status, start, end, obc);
612    
613                    return getGroupEntries(groupId, displayDate, queryDefinition);
614            }
615    
616            @Override
617            public List<BlogsEntry> getGroupEntries(
618                    long groupId, Date displayDate,
619                    QueryDefinition<BlogsEntry> queryDefinition) {
620    
621                    if (queryDefinition.isExcludeStatus()) {
622                            return blogsEntryPersistence.findByG_LtD_NotS(
623                                    groupId, displayDate, queryDefinition.getStatus(),
624                                    queryDefinition.getStart(), queryDefinition.getEnd(),
625                                    queryDefinition.getOrderByComparator());
626                    }
627                    else {
628                            return blogsEntryPersistence.findByG_LtD_S(
629                                    groupId, displayDate, queryDefinition.getStatus(),
630                                    queryDefinition.getStart(), queryDefinition.getEnd(),
631                                    queryDefinition.getOrderByComparator());
632                    }
633            }
634    
635            /**
636             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
637             *             QueryDefinition)}
638             */
639            @Deprecated
640            @Override
641            public List<BlogsEntry> getGroupEntries(
642                    long groupId, int status, int start, int end) {
643    
644                    QueryDefinition<BlogsEntry> queryDefinition =
645                            new QueryDefinition<BlogsEntry>(status, start, end, null);
646    
647                    return getGroupEntries(groupId, queryDefinition);
648            }
649    
650            /**
651             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntries(long,
652             *             QueryDefinition)}
653             */
654            @Deprecated
655            @Override
656            public List<BlogsEntry> getGroupEntries(
657                    long groupId, int status, int start, int end,
658                    OrderByComparator<BlogsEntry> obc) {
659    
660                    QueryDefinition<BlogsEntry> queryDefinition =
661                            new QueryDefinition<BlogsEntry>(status, start, end, obc);
662    
663                    return getGroupEntries(groupId, queryDefinition);
664            }
665    
666            @Override
667            public List<BlogsEntry> getGroupEntries(
668                    long groupId, QueryDefinition<BlogsEntry> queryDefinition) {
669    
670                    if (queryDefinition.isExcludeStatus()) {
671                            return blogsEntryPersistence.findByG_NotS(
672                                    groupId, queryDefinition.getStatus(),
673                                    queryDefinition.getStart(), queryDefinition.getEnd(),
674                                    queryDefinition.getOrderByComparator());
675                    }
676                    else {
677                            return blogsEntryPersistence.findByG_S(
678                                    groupId, queryDefinition.getStatus(),
679                                    queryDefinition.getStart(), queryDefinition.getEnd(),
680                                    queryDefinition.getOrderByComparator());
681                    }
682            }
683    
684            /**
685             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
686             *             Date, QueryDefinition)}
687             */
688            @Deprecated
689            @Override
690            public int getGroupEntriesCount(
691                    long groupId, Date displayDate, int status) {
692    
693                    QueryDefinition<BlogsEntry> queryDefinition =
694                            new QueryDefinition<BlogsEntry>(status);
695    
696                    return getGroupEntriesCount(groupId, displayDate, queryDefinition);
697            }
698    
699            @Override
700            public int getGroupEntriesCount(
701                    long groupId, Date displayDate,
702                    QueryDefinition<BlogsEntry> queryDefinition) {
703    
704                    if (queryDefinition.isExcludeStatus()) {
705                            return blogsEntryPersistence.countByG_LtD_NotS(
706                                    groupId, displayDate, queryDefinition.getStatus());
707                    }
708                    else {
709                            return blogsEntryPersistence.countByG_LtD_S(
710                                    groupId, displayDate, queryDefinition.getStatus());
711                    }
712            }
713    
714            /**
715             * @deprecated As of 6.2.0, replaced by {@link #getGroupEntriesCount(long,
716             *             QueryDefinition)}
717             */
718            @Deprecated
719            @Override
720            public int getGroupEntriesCount(long groupId, int status) {
721                    QueryDefinition<BlogsEntry> queryDefinition =
722                            new QueryDefinition<BlogsEntry>(status);
723    
724                    return getGroupEntriesCount(groupId, queryDefinition);
725            }
726    
727            @Override
728            public int getGroupEntriesCount(
729                    long groupId, QueryDefinition<BlogsEntry> queryDefinition) {
730    
731                    if (queryDefinition.isExcludeStatus()) {
732                            return blogsEntryPersistence.countByG_NotS(
733                                    groupId, queryDefinition.getStatus());
734                    }
735                    else {
736                            return blogsEntryPersistence.countByG_S(
737                                    groupId, queryDefinition.getStatus());
738                    }
739            }
740    
741            /**
742             * @deprecated As of 6.2.0, replaced by {@link #getGroupsEntries(long, long,
743             *             Date, QueryDefinition)}
744             */
745            @Deprecated
746            @Override
747            public List<BlogsEntry> getGroupsEntries(
748                    long companyId, long groupId, Date displayDate, int status, int start,
749                    int end) {
750    
751                    QueryDefinition<BlogsEntry> queryDefinition =
752                            new QueryDefinition<BlogsEntry>(status, start, end, null);
753    
754                    return getGroupsEntries(
755                            companyId, groupId, displayDate, queryDefinition);
756            }
757    
758            @Override
759            public List<BlogsEntry> getGroupsEntries(
760                    long companyId, long groupId, Date displayDate,
761                    QueryDefinition<BlogsEntry> queryDefinition) {
762    
763                    return blogsEntryFinder.findByGroupIds(
764                            companyId, groupId, displayDate, queryDefinition);
765            }
766    
767            /**
768             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
769             *             long, Date, QueryDefinition)}
770             */
771            @Deprecated
772            @Override
773            public List<BlogsEntry> getGroupUserEntries(
774                    long groupId, long userId, Date displayDate, int status, int start,
775                    int end) {
776    
777                    QueryDefinition<BlogsEntry> queryDefinition =
778                            new QueryDefinition<BlogsEntry>(status, start, end, null);
779    
780                    return getGroupUserEntries(
781                            groupId, userId, displayDate, queryDefinition);
782            }
783    
784            /**
785             * @deprecated As of 6.2.0, replaced by {@link #getGroupUserEntries(long,
786             *             long, Date, QueryDefinition)}
787             */
788            @Deprecated
789            @Override
790            public List<BlogsEntry> getGroupUserEntries(
791                    long groupId, long userId, Date displayDate, int status, int start,
792                    int end, OrderByComparator<BlogsEntry> obc) {
793    
794                    QueryDefinition<BlogsEntry> queryDefinition =
795                            new QueryDefinition<BlogsEntry>(status, start, end, obc);
796    
797                    return getGroupUserEntries(
798                            groupId, userId, displayDate, queryDefinition);
799            }
800    
801            @Override
802            public List<BlogsEntry> getGroupUserEntries(
803                    long groupId, long userId, Date displayDate,
804                    QueryDefinition<BlogsEntry> queryDefinition) {
805    
806                    if (queryDefinition.isExcludeStatus()) {
807                            return blogsEntryPersistence.findByG_U_NotS(
808                                    groupId, userId, queryDefinition.getStatus(),
809                                    queryDefinition.getStart(), queryDefinition.getEnd(),
810                                    queryDefinition.getOrderByComparator());
811                    }
812                    else {
813                            return blogsEntryPersistence.findByG_U_S(
814                                    groupId, userId, queryDefinition.getStatus(),
815                                    queryDefinition.getStart(), queryDefinition.getEnd(),
816                                    queryDefinition.getOrderByComparator());
817                    }
818            }
819    
820            /**
821             * @deprecated As of 6.2.0, replaced by {@link
822             *             #getGroupUserEntriesCount(long, long, Date, QueryDefinition)}
823             */
824            @Deprecated
825            @Override
826            public int getGroupUserEntriesCount(
827                    long groupId, long userId, Date displayDate, int status) {
828    
829                    QueryDefinition<BlogsEntry> queryDefinition =
830                            new QueryDefinition<BlogsEntry>(status);
831    
832                    return getGroupUserEntriesCount(
833                            groupId, userId, displayDate, queryDefinition);
834            }
835    
836            @Override
837            public int getGroupUserEntriesCount(
838                    long groupId, long userId, Date displayDate,
839                    QueryDefinition<BlogsEntry> queryDefinition) {
840    
841                    if (queryDefinition.isExcludeStatus()) {
842                            return blogsEntryPersistence.countByG_U_LtD_NotS(
843                                    groupId, userId, displayDate, queryDefinition.getStatus());
844                    }
845                    else {
846                            return blogsEntryPersistence.countByG_U_LtD_S(
847                                    groupId, userId, displayDate, queryDefinition.getStatus());
848                    }
849            }
850    
851            @Override
852            public List<BlogsEntry> getNoAssetEntries() {
853                    return blogsEntryFinder.findByNoAssets();
854            }
855    
856            /**
857             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
858             *             Date, QueryDefinition)}
859             */
860            @Deprecated
861            @Override
862            public List<BlogsEntry> getOrganizationEntries(
863                    long organizationId, Date displayDate, int status, int start, int end) {
864    
865                    QueryDefinition<BlogsEntry> queryDefinition =
866                            new QueryDefinition<BlogsEntry>(status, start, end, null);
867    
868                    return getOrganizationEntries(
869                            organizationId, displayDate, queryDefinition);
870            }
871    
872            /**
873             * @deprecated As of 6.2.0, replaced by {@link #getOrganizationEntries(long,
874             *             Date, QueryDefinition)}
875             */
876            @Deprecated
877            @Override
878            public List<BlogsEntry> getOrganizationEntries(
879                    long organizationId, Date displayDate, int status, int start, int end,
880                    OrderByComparator<BlogsEntry> obc) {
881    
882                    QueryDefinition<BlogsEntry> queryDefinition =
883                            new QueryDefinition<BlogsEntry>(status, start, end, obc);
884    
885                    return getOrganizationEntries(
886                            organizationId, displayDate, queryDefinition);
887            }
888    
889            @Override
890            public List<BlogsEntry> getOrganizationEntries(
891                    long organizationId, Date displayDate,
892                    QueryDefinition<BlogsEntry> queryDefinition) {
893    
894                    return blogsEntryFinder.findByOrganizationId(
895                            organizationId, displayDate, queryDefinition);
896            }
897    
898            /**
899             * @deprecated As of 6.2.0, replaced by {@link
900             *             #getOrganizationEntriesCount(long, Date, QueryDefinition)}
901             */
902            @Deprecated
903            @Override
904            public int getOrganizationEntriesCount(
905                    long organizationId, Date displayDate, int status) {
906    
907                    QueryDefinition<BlogsEntry> queryDefinition =
908                            new QueryDefinition<BlogsEntry>(status);
909    
910                    return getOrganizationEntriesCount(
911                            organizationId, displayDate, queryDefinition);
912            }
913    
914            @Override
915            public int getOrganizationEntriesCount(
916                    long organizationId, Date displayDate,
917                    QueryDefinition<BlogsEntry> queryDefinition) {
918    
919                    return blogsEntryFinder.countByOrganizationId(
920                            organizationId, displayDate, queryDefinition);
921            }
922    
923            @Override
924            public void moveEntriesToTrash(long groupId, long userId)
925                    throws PortalException {
926    
927                    List<BlogsEntry> entries = blogsEntryPersistence.findByGroupId(groupId);
928    
929                    for (BlogsEntry entry : entries) {
930                            blogsEntryLocalService.moveEntryToTrash(userId, entry);
931                    }
932            }
933    
934            /**
935             * Moves the blogs entry to the recycle bin. Social activity counters for
936             * this entry get disabled.
937             *
938             * @param  userId the primary key of the user moving the blogs entry
939             * @param  entry the blogs entry to be moved
940             * @return the moved blogs entry
941             * @throws PortalException if a user with the primary key could not be found
942             *         or if the blogs entry owner's social activity counter could not
943             *         be updated
944             */
945            @Indexable(type = IndexableType.REINDEX)
946            @Override
947            public BlogsEntry moveEntryToTrash(long userId, BlogsEntry entry)
948                    throws PortalException {
949    
950                    // Entry
951    
952                    int oldStatus = entry.getStatus();
953    
954                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
955                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
956    
957                            blogsEntryPersistence.update(entry);
958                    }
959    
960                    entry = updateStatus(
961                            userId, entry.getEntryId(), WorkflowConstants.STATUS_IN_TRASH,
962                            new ServiceContext());
963    
964                    // Social
965    
966                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
967    
968                    extraDataJSONObject.put("title", entry.getTitle());
969    
970                    socialActivityLocalService.addActivity(
971                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
972                            entry.getEntryId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
973                            extraDataJSONObject.toString(), 0);
974    
975                    // Workflow
976    
977                    if (oldStatus == WorkflowConstants.STATUS_PENDING) {
978                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
979                                    entry.getCompanyId(), entry.getGroupId(),
980                                    BlogsEntry.class.getName(), entry.getEntryId());
981                    }
982    
983                    return entry;
984            }
985    
986            /**
987             * Moves the blogs entry with the ID to the recycle bin.
988             *
989             * @param  userId the primary key of the user moving the blogs entry
990             * @param  entryId the primary key of the blogs entry to be moved
991             * @return the moved blogs entry
992             * @throws PortalException if a user or blogs entry with the primary key
993             *         could not be found or if the blogs entry owner's social activity
994             *         counter could not be updated
995             */
996            @Override
997            public BlogsEntry moveEntryToTrash(long userId, long entryId)
998                    throws PortalException {
999    
1000                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1001    
1002                    return blogsEntryLocalService.moveEntryToTrash(userId, entry);
1003            }
1004    
1005            /**
1006             * Restores the blogs entry with the ID from the recycle bin. Social
1007             * activity counters for this entry get activated.
1008             *
1009             * @param  userId the primary key of the user restoring the blogs entry
1010             * @param  entryId the primary key of the blogs entry to be restored
1011             * @return the restored blogs entry from the recycle bin
1012             * @throws PortalException if a user or blogs entry with the primary key
1013             *         could not be found or if the blogs entry owner's social activity
1014             *         counter could not be updated
1015             */
1016            @Indexable(type = IndexableType.REINDEX)
1017            @Override
1018            public BlogsEntry restoreEntryFromTrash(long userId, long entryId)
1019                    throws PortalException {
1020    
1021                    // Entry
1022    
1023                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
1024                            BlogsEntry.class.getName(), entryId);
1025    
1026                    BlogsEntry entry = updateStatus(
1027                            userId, entryId, trashEntry.getStatus(), new ServiceContext());
1028    
1029                    // Social
1030    
1031                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1032    
1033                    extraDataJSONObject.put("title", entry.getTitle());
1034    
1035                    socialActivityLocalService.addActivity(
1036                            userId, trashEntry.getGroupId(), BlogsEntry.class.getName(),
1037                            entryId, SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
1038                            extraDataJSONObject.toString(), 0);
1039    
1040                    return entry;
1041            }
1042    
1043            @Override
1044            public void subscribe(long userId, long groupId) throws PortalException {
1045                    subscriptionLocalService.addSubscription(
1046                            userId, groupId, BlogsEntry.class.getName(), groupId);
1047            }
1048    
1049            @Override
1050            public void unsubscribe(long userId, long groupId) throws PortalException {
1051                    subscriptionLocalService.deleteSubscription(
1052                            userId, BlogsEntry.class.getName(), groupId);
1053            }
1054    
1055            @Override
1056            public void updateAsset(
1057                            long userId, BlogsEntry entry, long[] assetCategoryIds,
1058                            String[] assetTagNames, long[] assetLinkEntryIds)
1059                    throws PortalException {
1060    
1061                    boolean visible = false;
1062    
1063                    if (entry.isApproved()) {
1064                            visible = true;
1065                    }
1066    
1067                    String summary = HtmlUtil.extractText(
1068                            StringUtil.shorten(entry.getContent(), 500));
1069    
1070                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
1071                            userId, entry.getGroupId(), entry.getCreateDate(),
1072                            entry.getModifiedDate(), BlogsEntry.class.getName(),
1073                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
1074                            assetTagNames, visible, null, null, null, ContentTypes.TEXT_HTML,
1075                            entry.getTitle(), entry.getDescription(), summary, null, null, 0, 0,
1076                            null, false);
1077    
1078                    assetLinkLocalService.updateLinks(
1079                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
1080                            AssetLinkConstants.TYPE_RELATED);
1081            }
1082    
1083            /**
1084             * @deprecated As of 7.0.0, replaced by {@link #updateEntry(long, long,
1085             *             String, String, String, String, int, int, int, int, int,
1086             *             boolean, boolean, String[], boolean, String, long,
1087             *             ServiceContext)}
1088             */
1089            @Deprecated
1090            @Override
1091            public BlogsEntry updateEntry(
1092                            long userId, long entryId, String title, String description,
1093                            String content, int displayDateMonth, int displayDateDay,
1094                            int displayDateYear, int displayDateHour, int displayDateMinute,
1095                            boolean allowPingbacks, boolean allowTrackbacks,
1096                            String[] trackbacks, boolean smallImage, String smallImageURL,
1097                            String smallImageFileName, InputStream smallImageInputStream,
1098                            ServiceContext serviceContext)
1099                    throws PortalException {
1100    
1101                    ImageSelector coverImageImageSelector = null;
1102                    ImageSelector smallImageImageSelector = null;
1103    
1104                    if (smallImage) {
1105                            if (Validator.isNotNull(smallImageFileName) &&
1106                                    (smallImageInputStream != null)) {
1107    
1108                                    FileEntry tempFileEntry = TempFileEntryUtil.addTempFileEntry(
1109                                            serviceContext.getScopeGroupId(), userId,
1110                                            BlogsEntry.class.getName(), smallImageFileName,
1111                                            smallImageInputStream,
1112                                            MimeTypesUtil.getContentType(smallImageFileName));
1113    
1114                                    smallImageImageSelector = new ImageSelector(
1115                                            tempFileEntry.getFileEntryId(), smallImageURL, null);
1116                            }
1117                    }
1118                    else {
1119                            smallImageImageSelector = new ImageSelector(0);
1120                    }
1121    
1122                    return updateEntry(
1123                            userId, entryId, title, StringPool.BLANK, description, content,
1124                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1125                            displayDateMinute, allowPingbacks, allowTrackbacks, trackbacks,
1126                            coverImageImageSelector, smallImageImageSelector, serviceContext);
1127            }
1128    
1129            @Indexable(type = IndexableType.REINDEX)
1130            @Override
1131            public BlogsEntry updateEntry(
1132                            long userId, long entryId, String title, String subtitle,
1133                            String description, String content, int displayDateMonth,
1134                            int displayDateDay, int displayDateYear, int displayDateHour,
1135                            int displayDateMinute, boolean allowPingbacks,
1136                            boolean allowTrackbacks, String[] trackbacks,
1137                            ImageSelector coverImageImageSelector,
1138                            ImageSelector smallImageImageSelector,
1139                            ServiceContext serviceContext)
1140                    throws PortalException {
1141    
1142                    // Entry
1143    
1144                    User user = userPersistence.findByPrimaryKey(userId);
1145                    Date displayDate = PortalUtil.getDate(
1146                            displayDateMonth, displayDateDay, displayDateYear, displayDateHour,
1147                            displayDateMinute, user.getTimeZone(),
1148                            EntryDisplayDateException.class);
1149    
1150                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1151    
1152                    long coverImageFileEntryId = 0;
1153                    String coverImageURL = null;
1154    
1155                    if (coverImageImageSelector != null) {
1156                            coverImageFileEntryId = coverImageImageSelector.getImageId();
1157                            coverImageURL = coverImageImageSelector.getImageURL();
1158    
1159                            if (coverImageImageSelector.getImageId() == 0) {
1160                                    if (entry.getCoverImageFileEntryId() != 0) {
1161                                            PortletFileRepositoryUtil.deletePortletFileEntry(
1162                                                    entry.getCoverImageFileEntryId());
1163                                    }
1164                            }
1165                            else if (coverImageImageSelector.getImageId() !=
1166                                                    entry.getCoverImageFileEntryId()) {
1167    
1168                                    if (entry.getCoverImageFileEntryId() != 0) {
1169                                            PortletFileRepositoryUtil.deletePortletFileEntry(
1170                                                    entry.getCoverImageFileEntryId());
1171                                    }
1172    
1173                                    if (coverImageImageSelector.getImageId() != 0) {
1174                                            coverImageFileEntryId = addCoverImage(
1175                                                    userId, entry.getGroupId(), entryId,
1176                                                    coverImageImageSelector);
1177                                    }
1178                            }
1179                    }
1180    
1181                    boolean smallImage = entry.isSmallImage();
1182                    long smallImageFileEntryId = 0;
1183                    String smallImageURL = null;
1184    
1185                    if (smallImageImageSelector != null) {
1186                            smallImage = !smallImageImageSelector.isRemoveSmallImage();
1187                            smallImageFileEntryId = smallImageImageSelector.getImageId();
1188                            smallImageURL = smallImageImageSelector.getImageURL();
1189    
1190                            if (smallImageImageSelector.getImageId() == 0) {
1191                                    if (entry.getSmallImageFileEntryId() != 0) {
1192                                            PortletFileRepositoryUtil.deletePortletFileEntry(
1193                                                    entry.getSmallImageFileEntryId());
1194                                    }
1195                            }
1196                            else if (smallImageImageSelector.getImageId() !=
1197                                                    entry.getSmallImageFileEntryId()) {
1198    
1199                                    if (entry.getSmallImageFileEntryId() != 0) {
1200                                            PortletFileRepositoryUtil.deletePortletFileEntry(
1201                                                    entry.getSmallImageFileEntryId());
1202                                    }
1203    
1204                                    FileEntry tempFileEntry =
1205                                            PortletFileRepositoryUtil.getPortletFileEntry(
1206                                                    smallImageImageSelector.getImageId());
1207    
1208                                    smallImageFileEntryId = addSmallImageFileEntry(
1209                                            userId, entry.getGroupId(), entry.getEntryId(),
1210                                            tempFileEntry.getMimeType(), tempFileEntry.getTitle(),
1211                                            tempFileEntry.getContentStream());
1212    
1213                                    PortletFileRepositoryUtil.deletePortletFileEntry(
1214                                            tempFileEntry.getFileEntryId());
1215                            }
1216                    }
1217    
1218                    validate(title, content, smallImageFileEntryId);
1219    
1220                    String oldUrlTitle = entry.getUrlTitle();
1221    
1222                    entry.setModifiedDate(serviceContext.getModifiedDate(null));
1223                    entry.setTitle(title);
1224                    entry.setSubtitle(subtitle);
1225                    entry.setUrlTitle(
1226                            getUniqueUrlTitle(entryId, title, oldUrlTitle, serviceContext));
1227                    entry.setDescription(description);
1228                    entry.setContent(content);
1229                    entry.setDisplayDate(displayDate);
1230                    entry.setAllowPingbacks(allowPingbacks);
1231                    entry.setAllowTrackbacks(allowTrackbacks);
1232                    entry.setCoverImageFileEntryId(coverImageFileEntryId);
1233                    entry.setCoverImageURL(coverImageURL);
1234                    entry.setSmallImage(smallImage);
1235                    entry.setSmallImageFileEntryId(smallImageFileEntryId);
1236                    entry.setSmallImageURL(smallImageURL);
1237    
1238                    if (entry.isPending() || entry.isDraft()) {
1239                    }
1240                    else {
1241                            entry.setStatus(WorkflowConstants.STATUS_DRAFT);
1242                    }
1243    
1244                    entry.setExpandoBridgeAttributes(serviceContext);
1245    
1246                    blogsEntryPersistence.update(entry);
1247    
1248                    // Resources
1249    
1250                    if ((serviceContext.getGroupPermissions() != null) ||
1251                            (serviceContext.getGuestPermissions() != null)) {
1252    
1253                            updateEntryResources(
1254                                    entry, serviceContext.getGroupPermissions(),
1255                                    serviceContext.getGuestPermissions());
1256                    }
1257    
1258                    // Asset
1259    
1260                    updateAsset(
1261                            userId, entry, serviceContext.getAssetCategoryIds(),
1262                            serviceContext.getAssetTagNames(),
1263                            serviceContext.getAssetLinkEntryIds());
1264    
1265                    // Workflow
1266    
1267                    boolean pingOldTrackbacks = false;
1268    
1269                    if (!oldUrlTitle.equals(entry.getUrlTitle())) {
1270                            pingOldTrackbacks = true;
1271                    }
1272    
1273                    serviceContext.setAttribute(
1274                            "pingOldTrackbacks", String.valueOf(pingOldTrackbacks));
1275    
1276                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1277                            serviceContext.setAttribute("trackbacks", trackbacks);
1278                    }
1279                    else {
1280                            serviceContext.setAttribute("trackbacks", null);
1281                    }
1282    
1283                    return startWorkflowInstance(userId, entry, serviceContext);
1284            }
1285    
1286            @Override
1287            public void updateEntryResources(
1288                            BlogsEntry entry, String[] groupPermissions,
1289                            String[] guestPermissions)
1290                    throws PortalException {
1291    
1292                    resourceLocalService.updateResources(
1293                            entry.getCompanyId(), entry.getGroupId(),
1294                            BlogsEntry.class.getName(), entry.getEntryId(), groupPermissions,
1295                            guestPermissions);
1296            }
1297    
1298            /**
1299             * @deprecated As of 7.0.0, replaced by {@link #updateStatus(long, long,
1300             *             int, ServiceContext, Map)}
1301             */
1302            @Deprecated
1303            @Override
1304            public BlogsEntry updateStatus(
1305                            long userId, long entryId, int status,
1306                            ServiceContext serviceContext)
1307                    throws PortalException {
1308    
1309                    return updateStatus(
1310                            userId, entryId, status, serviceContext,
1311                            new HashMap<String, Serializable>());
1312            }
1313    
1314            @Indexable(type = IndexableType.REINDEX)
1315            @Override
1316            public BlogsEntry updateStatus(
1317                            long userId, long entryId, int status,
1318                            ServiceContext serviceContext,
1319                            Map<String, Serializable> workflowContext)
1320                    throws PortalException {
1321    
1322                    // Entry
1323    
1324                    User user = userPersistence.findByPrimaryKey(userId);
1325                    Date now = new Date();
1326    
1327                    BlogsEntry entry = blogsEntryPersistence.findByPrimaryKey(entryId);
1328    
1329                    int oldStatus = entry.getStatus();
1330    
1331                    if ((status == WorkflowConstants.STATUS_APPROVED) &&
1332                            now.before(entry.getDisplayDate())) {
1333    
1334                            status = WorkflowConstants.STATUS_SCHEDULED;
1335                    }
1336    
1337                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
1338                    entry.setStatus(status);
1339                    entry.setStatusByUserId(user.getUserId());
1340                    entry.setStatusByUserName(user.getFullName());
1341                    entry.setStatusDate(serviceContext.getModifiedDate(now));
1342    
1343                    blogsEntryPersistence.update(entry);
1344    
1345                    // Statistics
1346    
1347                    blogsStatsUserLocalService.updateStatsUser(
1348                            entry.getGroupId(), entry.getUserId(), entry.getDisplayDate());
1349    
1350                    AssetEntry assetEntry = assetEntryLocalService.fetchEntry(
1351                            BlogsEntry.class.getName(), entryId);
1352    
1353                    if ((assetEntry == null) || (assetEntry.getPublishDate() == null)) {
1354                            serviceContext.setCommand(Constants.ADD);
1355                    }
1356    
1357                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1358    
1359                    extraDataJSONObject.put("title", entry.getTitle());
1360    
1361                    if (status == WorkflowConstants.STATUS_APPROVED) {
1362    
1363                            // Asset
1364    
1365                            assetEntryLocalService.updateEntry(
1366                                    BlogsEntry.class.getName(), entryId, entry.getDisplayDate(),
1367                                    true);
1368    
1369                            // Social
1370    
1371                            if ((oldStatus != WorkflowConstants.STATUS_IN_TRASH) &&
1372                                    (oldStatus != WorkflowConstants.STATUS_SCHEDULED)) {
1373    
1374                                    if (serviceContext.isCommandUpdate()) {
1375                                            socialActivityLocalService.addActivity(
1376                                                    user.getUserId(), entry.getGroupId(),
1377                                                    BlogsEntry.class.getName(), entryId,
1378                                                    BlogsActivityKeys.UPDATE_ENTRY,
1379                                                    extraDataJSONObject.toString(), 0);
1380                                    }
1381                                    else {
1382                                            socialActivityLocalService.addUniqueActivity(
1383                                                    user.getUserId(), entry.getGroupId(),
1384                                                    BlogsEntry.class.getName(), entryId,
1385                                                    BlogsActivityKeys.ADD_ENTRY,
1386                                                    extraDataJSONObject.toString(), 0);
1387                                    }
1388                            }
1389    
1390                            // Trash
1391    
1392                            if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1393                                    trashEntryLocalService.deleteEntry(
1394                                            BlogsEntry.class.getName(), entryId);
1395                            }
1396    
1397                            if (oldStatus != WorkflowConstants.STATUS_IN_TRASH) {
1398    
1399                                    // Subscriptions
1400    
1401                                    notifySubscribers(entry, serviceContext, workflowContext);
1402    
1403                                    // Ping
1404    
1405                                    String[] trackbacks = (String[])serviceContext.getAttribute(
1406                                            "trackbacks");
1407                                    Boolean pingOldTrackbacks = ParamUtil.getBoolean(
1408                                            serviceContext, "pingOldTrackbacks");
1409    
1410                                    pingGoogle(entry, serviceContext);
1411                                    pingPingback(entry, serviceContext);
1412                                    pingTrackbacks(
1413                                            entry, trackbacks, pingOldTrackbacks, serviceContext);
1414                            }
1415                    }
1416                    else {
1417    
1418                            // Asset
1419    
1420                            assetEntryLocalService.updateVisible(
1421                                    BlogsEntry.class.getName(), entryId, false);
1422    
1423                            // Social
1424    
1425                            if ((status == WorkflowConstants.STATUS_SCHEDULED) &&
1426                                    (oldStatus != WorkflowConstants.STATUS_IN_TRASH)) {
1427    
1428                                    if (serviceContext.isCommandUpdate()) {
1429                                            socialActivityLocalService.addActivity(
1430                                                    user.getUserId(), entry.getGroupId(),
1431                                                    BlogsEntry.class.getName(), entryId,
1432                                                    BlogsActivityKeys.UPDATE_ENTRY,
1433                                                    extraDataJSONObject.toString(), 0);
1434                                    }
1435                                    else {
1436                                            socialActivityLocalService.addUniqueActivity(
1437                                                    user.getUserId(), entry.getGroupId(),
1438                                                    BlogsEntry.class.getName(), entryId,
1439                                                    BlogsActivityKeys.ADD_ENTRY,
1440                                                    extraDataJSONObject.toString(), 0);
1441                                    }
1442                            }
1443    
1444                            // Trash
1445    
1446                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
1447                                    trashEntryLocalService.addTrashEntry(
1448                                            userId, entry.getGroupId(), BlogsEntry.class.getName(),
1449                                            entry.getEntryId(), entry.getUuid(), null, oldStatus, null,
1450                                            null);
1451                            }
1452                            else if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
1453                                    trashEntryLocalService.deleteEntry(
1454                                            BlogsEntry.class.getName(), entryId);
1455                            }
1456                    }
1457    
1458                    return entry;
1459            }
1460    
1461            protected long addCoverImage(
1462                            long userId, long groupId, long entryId,
1463                            ImageSelector coverImageImageSelector)
1464                    throws PortalException {
1465    
1466                    long coverImageId = 0;
1467    
1468                    byte[] bytes = null;
1469    
1470                    try {
1471                            bytes = coverImageImageSelector.getCroppedImageBytes();
1472                    }
1473                    catch (IOException ioe) {
1474                            if (_log.isDebugEnabled()) {
1475                                    _log.debug(
1476                                            "Unable to get cropped image from image selector image " +
1477                                                    coverImageImageSelector.getImageId());
1478                            }
1479                    }
1480    
1481                    if (bytes == null) {
1482                            return coverImageId;
1483                    }
1484    
1485                    File file = null;
1486    
1487                    try {
1488                            file = FileUtil.createTempFile(bytes);
1489    
1490                            String title = coverImageImageSelector.getTitle();
1491                            String mimeType = coverImageImageSelector.getMimeType();
1492    
1493                            if (Validator.isNull(title)) {
1494                                    title =
1495                                            StringUtil.randomString() + "_tempCroppedImage_" + entryId;
1496                            }
1497    
1498                            ServiceContext serviceContext = new ServiceContext();
1499    
1500                            serviceContext.setAddGroupPermissions(true);
1501                            serviceContext.setAddGuestPermissions(true);
1502    
1503                            Folder folder = addAttachmentsFolder(userId, groupId);
1504    
1505                            FileEntry fileEntry = PortletFileRepositoryUtil.addPortletFileEntry(
1506                                    groupId, userId, BlogsEntry.class.getName(), entryId,
1507                                    PortletKeys.BLOGS, folder.getFolderId(), file, title, mimeType,
1508                                    false);
1509    
1510                            coverImageId = fileEntry.getFileEntryId();
1511    
1512                            PortletFileRepositoryUtil.deletePortletFileEntry(
1513                                    coverImageImageSelector.getImageId());
1514                    }
1515                    catch (IOException ioe) {
1516                            if (_log.isDebugEnabled()) {
1517                                    _log.debug(
1518                                            "Unable to get cropped image from image selector image " +
1519                                                    coverImageImageSelector.getImageId());
1520                            }
1521                    }
1522                    finally {
1523                            FileUtil.delete(file);
1524                    }
1525    
1526                    return coverImageId;
1527            }
1528    
1529            protected void addDiscussion(BlogsEntry entry, long userId, long groupId)
1530                    throws PortalException {
1531    
1532                    if (PropsValues.BLOGS_ENTRY_COMMENTS_ENABLED) {
1533                            commentManager.addDiscussion(
1534                                    userId, groupId, BlogsEntry.class.getName(), entry.getEntryId(),
1535                                    entry.getUserName());
1536                    }
1537            }
1538    
1539            protected long addSmallImageFileEntry(
1540                            long userId, long groupId, long entryId, String mimeType,
1541                            String title, InputStream is)
1542                    throws PortalException {
1543    
1544                    ServiceContext serviceContext = new ServiceContext();
1545    
1546                    serviceContext.setAddGroupPermissions(true);
1547                    serviceContext.setAddGuestPermissions(true);
1548    
1549                    Folder folder = addAttachmentsFolder(userId, groupId);
1550    
1551                    FileEntry fileEntry = PortletFileRepositoryUtil.addPortletFileEntry(
1552                            groupId, userId, BlogsEntry.class.getName(), entryId,
1553                            PortletKeys.BLOGS, folder.getFolderId(), is, title, mimeType,
1554                            false);
1555    
1556                    return fileEntry.getFileEntryId();
1557            }
1558    
1559            protected void deleteDiscussion(BlogsEntry entry) throws PortalException {
1560                    commentManager.deleteDiscussion(
1561                            BlogsEntry.class.getName(), entry.getEntryId());
1562            }
1563    
1564            protected String getEntryURL(
1565                            BlogsEntry entry, ServiceContext serviceContext)
1566                    throws PortalException {
1567    
1568                    HttpServletRequest request = serviceContext.getRequest();
1569    
1570                    if (request == null) {
1571                            return StringPool.BLANK;
1572                    }
1573    
1574                    String layoutURL = LayoutURLUtil.getLayoutURL(
1575                            entry.getGroupId(), PortletKeys.BLOGS, serviceContext);
1576    
1577                    if (Validator.isNotNull(layoutURL)) {
1578                            return layoutURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs" +
1579                                    StringPool.SLASH + entry.getEntryId();
1580                    }
1581    
1582                    long controlPanelPlid = PortalUtil.getControlPanelPlid(
1583                            serviceContext.getCompanyId());
1584    
1585                    PortletURL portletURL = PortletURLFactoryUtil.create(
1586                            request, PortletKeys.BLOGS_ADMIN, controlPanelPlid,
1587                            PortletRequest.RENDER_PHASE);
1588    
1589                    portletURL.setParameter("struts_action", "/blogs_admin/view_entry");
1590                    portletURL.setParameter("entryId", String.valueOf(entry.getEntryId()));
1591    
1592                    return portletURL.toString();
1593            }
1594    
1595            protected String getUniqueUrlTitle(
1596                    long entryId, long groupId, String title) {
1597    
1598                    String urlTitle = BlogsUtil.getUrlTitle(entryId, title);
1599    
1600                    for (int i = 1;; i++) {
1601                            BlogsEntry entry = blogsEntryPersistence.fetchByG_UT(
1602                                    groupId, urlTitle);
1603    
1604                            if ((entry == null) || (entryId == entry.getEntryId())) {
1605                                    break;
1606                            }
1607                            else {
1608                                    String suffix = StringPool.DASH + i;
1609    
1610                                    String prefix = urlTitle;
1611    
1612                                    if (urlTitle.length() > suffix.length()) {
1613                                            prefix = urlTitle.substring(
1614                                                    0, urlTitle.length() - suffix.length());
1615                                    }
1616    
1617                                    urlTitle = prefix + suffix;
1618                            }
1619                    }
1620    
1621                    return urlTitle;
1622            }
1623    
1624            protected String getUniqueUrlTitle(
1625                    long entryId, String title, String oldUrlTitle,
1626                    ServiceContext serviceContext) {
1627    
1628                    String serviceContextUrlTitle = ParamUtil.getString(
1629                            serviceContext, "urlTitle");
1630    
1631                    String urlTitle = null;
1632    
1633                    if (Validator.isNotNull(serviceContextUrlTitle)) {
1634                            urlTitle = BlogsUtil.getUrlTitle(entryId, serviceContextUrlTitle);
1635                    }
1636                    else if (Validator.isNotNull(oldUrlTitle)) {
1637                            return oldUrlTitle;
1638                    }
1639                    else {
1640                            urlTitle = getUniqueUrlTitle(
1641                                    entryId, serviceContext.getScopeGroupId(), title);
1642                    }
1643    
1644                    BlogsEntry urlTitleEntry = blogsEntryPersistence.fetchByG_UT(
1645                            serviceContext.getScopeGroupId(), urlTitle);
1646    
1647                    if ((urlTitleEntry != null) &&
1648                            (urlTitleEntry.getEntryId() != entryId)) {
1649    
1650                            urlTitle = getUniqueUrlTitle(
1651                                    entryId, serviceContext.getScopeGroupId(), urlTitle);
1652                    }
1653    
1654                    return urlTitle;
1655            }
1656    
1657            protected void notifySubscribers(
1658                            BlogsEntry entry, ServiceContext serviceContext,
1659                            Map<String, Serializable> workflowContext)
1660                    throws PortalException {
1661    
1662                    String entryURL = (String)workflowContext.get(
1663                            WorkflowConstants.CONTEXT_URL);
1664    
1665                    if (!entry.isApproved() || Validator.isNull(entryURL)) {
1666                            return;
1667                    }
1668    
1669                    BlogsSettings blogsSettings = BlogsSettings.getInstance(
1670                            entry.getGroupId());
1671    
1672                    boolean sendEmailEntryUpdated = GetterUtil.getBoolean(
1673                            serviceContext.getAttribute("sendEmailEntryUpdated"));
1674    
1675                    if (serviceContext.isCommandAdd() &&
1676                            blogsSettings.isEmailEntryAddedEnabled()) {
1677                    }
1678                    else if (sendEmailEntryUpdated && serviceContext.isCommandUpdate() &&
1679                                     blogsSettings.isEmailEntryUpdatedEnabled()) {
1680                    }
1681                    else {
1682                            return;
1683                    }
1684    
1685                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1686    
1687                    String entryTitle = entry.getTitle();
1688    
1689                    String fromName = blogsSettings.getEmailFromName();
1690                    String fromAddress = blogsSettings.getEmailFromAddress();
1691    
1692                    LocalizedValuesMap subjectLocalizedValuesMap = null;
1693                    LocalizedValuesMap bodyLocalizedValuesMap = null;
1694    
1695                    if (serviceContext.isCommandUpdate()) {
1696                            subjectLocalizedValuesMap =
1697                                    blogsSettings.getEmailEntryUpdatedSubject();
1698                            bodyLocalizedValuesMap = blogsSettings.getEmailEntryUpdatedBody();
1699                    }
1700                    else {
1701                            subjectLocalizedValuesMap =
1702                                    blogsSettings.getEmailEntryAddedSubject();
1703                            bodyLocalizedValuesMap = blogsSettings.getEmailEntryAddedBody();
1704                    }
1705    
1706                    SubscriptionSender subscriptionSender =
1707                            new GroupSubscriptionCheckSubscriptionSender(
1708                                    BlogsPermission.RESOURCE_NAME);
1709    
1710                    subscriptionSender.setClassPK(entry.getEntryId());
1711                    subscriptionSender.setClassName(entry.getModelClassName());
1712                    subscriptionSender.setCompanyId(entry.getCompanyId());
1713                    subscriptionSender.setContextAttribute(
1714                            "[$BLOGS_ENTRY_CONTENT$]",
1715                            StringUtil.shorten(HtmlUtil.stripHtml(entry.getContent()), 500),
1716                            false);
1717                    subscriptionSender.setContextAttributes(
1718                            "[$BLOGS_ENTRY_CREATE_DATE$]",
1719                            Time.getSimpleDate(entry.getCreateDate(), "yyyy/MM/dd"),
1720                            "[$BLOGS_ENTRY_DESCRIPTION$]", entry.getDescription(),
1721                            "[$BLOGS_ENTRY_SITE_NAME$]",
1722                                    group.getDescriptiveName(serviceContext.getLocale()),
1723                            "[$BLOGS_ENTRY_STATUS_BY_USER_NAME$]", entry.getStatusByUserName(),
1724                            "[$BLOGS_ENTRY_TITLE$]", entryTitle,
1725                            "[$BLOGS_ENTRY_UPDATE_COMMENT$]",
1726                            HtmlUtil.replaceNewLine(
1727                                    GetterUtil.getString(
1728                                            serviceContext.getAttribute("emailEntryUpdatedComment"))),
1729                            "[$BLOGS_ENTRY_URL$]", entryURL,
1730                            "[$BLOGS_ENTRY_USER_PORTRAIT_URL$]",
1731                            workflowContext.get(WorkflowConstants.CONTEXT_USER_PORTRAIT_URL),
1732                            "[$BLOGS_ENTRY_USER_URL$]",
1733                            workflowContext.get(WorkflowConstants.CONTEXT_USER_URL));
1734                    subscriptionSender.setContextUserPrefix("BLOGS_ENTRY");
1735                    subscriptionSender.setEntryTitle(entryTitle);
1736                    subscriptionSender.setEntryURL(entryURL);
1737                    subscriptionSender.setFrom(fromAddress, fromName);
1738                    subscriptionSender.setHtmlFormat(true);
1739                    subscriptionSender.setLocalizedBodyMap(bodyLocalizedValuesMap);
1740                    subscriptionSender.setLocalizedSubjectMap(subjectLocalizedValuesMap);
1741                    subscriptionSender.setMailId("blogs_entry", entry.getEntryId());
1742    
1743                    int notificationType =
1744                            UserNotificationDefinition.NOTIFICATION_TYPE_ADD_ENTRY;
1745    
1746                    if (serviceContext.isCommandUpdate()) {
1747                            notificationType =
1748                                    UserNotificationDefinition.NOTIFICATION_TYPE_UPDATE_ENTRY;
1749                    }
1750    
1751                    subscriptionSender.setNotificationType(notificationType);
1752    
1753                    subscriptionSender.setPortletId(PortletKeys.BLOGS);
1754                    subscriptionSender.setReplyToAddress(fromAddress);
1755                    subscriptionSender.setScopeGroupId(entry.getGroupId());
1756                    subscriptionSender.setServiceContext(serviceContext);
1757                    subscriptionSender.setUserId(entry.getUserId());
1758    
1759                    subscriptionSender.addPersistedSubscribers(
1760                            BlogsEntry.class.getName(), entry.getGroupId());
1761    
1762                    subscriptionSender.addPersistedSubscribers(
1763                            BlogsEntry.class.getName(), entry.getEntryId());
1764    
1765                    subscriptionSender.flushNotificationsAsync();
1766            }
1767    
1768            protected void pingGoogle(BlogsEntry entry, ServiceContext serviceContext)
1769                    throws PortalException {
1770    
1771                    if (!PropsValues.BLOGS_PING_GOOGLE_ENABLED || !entry.isApproved()) {
1772                            return;
1773                    }
1774    
1775                    String layoutFullURL = PortalUtil.getLayoutFullURL(
1776                            serviceContext.getScopeGroupId(), PortletKeys.BLOGS);
1777    
1778                    if (Validator.isNull(layoutFullURL)) {
1779                            return;
1780                    }
1781    
1782                    if (layoutFullURL.contains("://localhost")) {
1783                            if (_log.isDebugEnabled()) {
1784                                    _log.debug(
1785                                            "Not pinging Google because of localhost URL " +
1786                                                    layoutFullURL);
1787                            }
1788    
1789                            return;
1790                    }
1791    
1792                    Group group = groupPersistence.findByPrimaryKey(entry.getGroupId());
1793    
1794                    StringBundler sb = new StringBundler(6);
1795    
1796                    String name = group.getDescriptiveName();
1797                    String url = layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs";
1798                    String changesURL =
1799                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/rss";
1800    
1801                    sb.append("http://blogsearch.google.com/ping?name=");
1802                    sb.append(HttpUtil.encodeURL(name));
1803                    sb.append("&url=");
1804                    sb.append(HttpUtil.encodeURL(url));
1805                    sb.append("&changesURL=");
1806                    sb.append(HttpUtil.encodeURL(changesURL));
1807    
1808                    String location = sb.toString();
1809    
1810                    if (_log.isInfoEnabled()) {
1811                            _log.info("Pinging Google at " + location);
1812                    }
1813    
1814                    try {
1815                            String response = HttpUtil.URLtoString(sb.toString());
1816    
1817                            if (_log.isInfoEnabled()) {
1818                                    _log.info("Google ping response: " + response);
1819                            }
1820                    }
1821                    catch (IOException ioe) {
1822                            _log.error("Unable to ping Google at " + location, ioe);
1823                    }
1824            }
1825    
1826            protected void pingPingback(BlogsEntry entry, ServiceContext serviceContext)
1827                    throws PortalException {
1828    
1829                    if (!PropsValues.BLOGS_PINGBACK_ENABLED ||
1830                            !entry.isAllowPingbacks() || !entry.isApproved()) {
1831    
1832                            return;
1833                    }
1834    
1835                    HttpServletRequest request = serviceContext.getRequest();
1836    
1837                    if (request == null) {
1838                            return;
1839                    }
1840    
1841                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1842                            WebKeys.THEME_DISPLAY);
1843    
1844                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1845    
1846                    if (Validator.isNull(layoutFullURL)) {
1847                            return;
1848                    }
1849    
1850                    String sourceUri =
1851                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1852                                    entry.getUrlTitle();
1853    
1854                    Source source = new Source(entry.getContent());
1855    
1856                    List<StartTag> tags = source.getAllStartTags("a");
1857    
1858                    for (StartTag tag : tags) {
1859                            String targetUri = tag.getAttributeValue("href");
1860    
1861                            if (Validator.isNotNull(targetUri)) {
1862                                    try {
1863                                            LinkbackProducerUtil.sendPingback(sourceUri, targetUri);
1864                                    }
1865                                    catch (Exception e) {
1866                                            _log.error("Error while sending pingback " + targetUri, e);
1867                                    }
1868                            }
1869                    }
1870            }
1871    
1872            protected void pingTrackbacks(
1873                            BlogsEntry entry, String[] trackbacks, boolean pingOldTrackbacks,
1874                            ServiceContext serviceContext)
1875                    throws PortalException {
1876    
1877                    if (!PropsValues.BLOGS_TRACKBACK_ENABLED ||
1878                            !entry.isAllowTrackbacks() || !entry.isApproved()) {
1879    
1880                            return;
1881                    }
1882    
1883                    HttpServletRequest request = serviceContext.getRequest();
1884    
1885                    if (request == null) {
1886                            return;
1887                    }
1888    
1889                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
1890                            WebKeys.THEME_DISPLAY);
1891    
1892                    String layoutFullURL = PortalUtil.getLayoutFullURL(themeDisplay);
1893    
1894                    if (Validator.isNull(layoutFullURL)) {
1895                            return;
1896                    }
1897    
1898                    Map<String, String> parts = new HashMap<String, String>();
1899    
1900                    String excerpt = StringUtil.shorten(
1901                            HtmlUtil.extractText(entry.getContent()),
1902                            PropsValues.BLOGS_LINKBACK_EXCERPT_LENGTH);
1903                    String url =
1904                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "blogs/" +
1905                                    entry.getUrlTitle();
1906    
1907                    parts.put("title", entry.getTitle());
1908                    parts.put("excerpt", excerpt);
1909                    parts.put("url", url);
1910                    parts.put("blog_name", entry.getUserName());
1911    
1912                    Set<String> trackbacksSet = null;
1913    
1914                    if (ArrayUtil.isNotEmpty(trackbacks)) {
1915                            trackbacksSet = SetUtil.fromArray(trackbacks);
1916                    }
1917                    else {
1918                            trackbacksSet = new HashSet<String>();
1919                    }
1920    
1921                    if (pingOldTrackbacks) {
1922                            trackbacksSet.addAll(
1923                                    SetUtil.fromArray(StringUtil.split(entry.getTrackbacks())));
1924    
1925                            entry.setTrackbacks(StringPool.BLANK);
1926    
1927                            blogsEntryPersistence.update(entry);
1928                    }
1929    
1930                    Set<String> oldTrackbacks = SetUtil.fromArray(
1931                            StringUtil.split(entry.getTrackbacks()));
1932    
1933                    Set<String> validTrackbacks = new HashSet<String>();
1934    
1935                    for (String trackback : trackbacksSet) {
1936                            if (oldTrackbacks.contains(trackback)) {
1937                                    continue;
1938                            }
1939    
1940                            try {
1941                                    if (LinkbackProducerUtil.sendTrackback(trackback, parts)) {
1942                                            validTrackbacks.add(trackback);
1943                                    }
1944                            }
1945                            catch (Exception e) {
1946                                    _log.error("Error while sending trackback at " + trackback, e);
1947                            }
1948                    }
1949    
1950                    if (!validTrackbacks.isEmpty()) {
1951                            String newTrackbacks = StringUtil.merge(validTrackbacks);
1952    
1953                            if (Validator.isNotNull(entry.getTrackbacks())) {
1954                                    newTrackbacks += StringPool.COMMA + entry.getTrackbacks();
1955                            }
1956    
1957                            entry.setTrackbacks(newTrackbacks);
1958    
1959                            blogsEntryPersistence.update(entry);
1960                    }
1961            }
1962    
1963            protected BlogsEntry startWorkflowInstance(
1964                            long userId, BlogsEntry entry, ServiceContext serviceContext)
1965                    throws PortalException {
1966    
1967                    Map<String, Serializable> workflowContext =
1968                            new HashMap<String, Serializable>();
1969    
1970                    workflowContext.put(
1971                            WorkflowConstants.CONTEXT_URL, getEntryURL(entry, serviceContext));
1972    
1973                    String userPortraitURL = StringPool.BLANK;
1974                    String userURL = StringPool.BLANK;
1975    
1976                    if (serviceContext.getThemeDisplay() != null) {
1977                            User user = userPersistence.findByPrimaryKey(userId);
1978    
1979                            userPortraitURL = user.getPortraitURL(
1980                                    serviceContext.getThemeDisplay());
1981                            userURL = user.getDisplayURL(serviceContext.getThemeDisplay());
1982                    }
1983    
1984                    workflowContext.put(
1985                            WorkflowConstants.CONTEXT_USER_PORTRAIT_URL, userPortraitURL);
1986                    workflowContext.put(WorkflowConstants.CONTEXT_USER_URL, userURL);
1987    
1988                    return WorkflowHandlerRegistryUtil.startWorkflowInstance(
1989                            entry.getCompanyId(), entry.getGroupId(), userId,
1990                            BlogsEntry.class.getName(), entry.getEntryId(), entry,
1991                            serviceContext, workflowContext);
1992            }
1993    
1994            protected void validate(
1995                            String title, String content, long smallImageFileEntryId)
1996                    throws PortalException {
1997    
1998                    if (Validator.isNull(title)) {
1999                            throw new EntryTitleException();
2000                    }
2001                    else if (Validator.isNull(content)) {
2002                            throw new EntryContentException();
2003                    }
2004    
2005                    String[] imageExtensions = PrefsPropsUtil.getStringArray(
2006                            PropsKeys.BLOGS_IMAGE_EXTENSIONS, StringPool.COMMA);
2007    
2008                    if (smallImageFileEntryId != 0) {
2009                            FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
2010                                    smallImageFileEntryId);
2011    
2012                            boolean validSmallImageExtension = false;
2013    
2014                            for (String _imageExtension : imageExtensions) {
2015                                    if (StringPool.STAR.equals(_imageExtension) ||
2016                                            _imageExtension.equals(
2017                                                    StringPool.PERIOD + fileEntry.getExtension())) {
2018    
2019                                            validSmallImageExtension = true;
2020    
2021                                            break;
2022                                    }
2023                            }
2024    
2025                            if (!validSmallImageExtension) {
2026                                    throw new EntrySmallImageNameException(
2027                                            "Invalid small image for file entry " +
2028                                                    smallImageFileEntryId);
2029                            }
2030    
2031                            long smallImageMaxSize = PrefsPropsUtil.getLong(
2032                                    PropsKeys.BLOGS_IMAGE_SMALL_MAX_SIZE);
2033    
2034                            if ((smallImageMaxSize > 0) &&
2035                                    (fileEntry.getSize() > smallImageMaxSize)) {
2036    
2037                                    throw new EntrySmallImageSizeException();
2038                            }
2039                    }
2040            }
2041    
2042            @BeanReference(type = CommentManager.class)
2043            protected CommentManager commentManager;
2044    
2045            private static Log _log = LogFactoryUtil.getLog(
2046                    BlogsEntryLocalServiceImpl.class);
2047    
2048    }