001    /**
002     * Copyright (c) 2000-2013 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.bookmarks.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.json.JSONFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONObject;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.search.Field;
024    import com.liferay.portal.kernel.search.Hits;
025    import com.liferay.portal.kernel.search.Indexable;
026    import com.liferay.portal.kernel.search.IndexableType;
027    import com.liferay.portal.kernel.search.Indexer;
028    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
029    import com.liferay.portal.kernel.search.SearchContext;
030    import com.liferay.portal.kernel.search.Sort;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.ContentTypes;
033    import com.liferay.portal.kernel.util.OrderByComparator;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.Validator;
036    import com.liferay.portal.kernel.workflow.WorkflowConstants;
037    import com.liferay.portal.model.Group;
038    import com.liferay.portal.model.ResourceConstants;
039    import com.liferay.portal.model.User;
040    import com.liferay.portal.service.ServiceContext;
041    import com.liferay.portal.service.ServiceContextUtil;
042    import com.liferay.portal.util.Portal;
043    import com.liferay.portal.util.PortletKeys;
044    import com.liferay.portal.util.SubscriptionSender;
045    import com.liferay.portlet.asset.model.AssetEntry;
046    import com.liferay.portlet.asset.model.AssetLinkConstants;
047    import com.liferay.portlet.bookmarks.EntryURLException;
048    import com.liferay.portlet.bookmarks.model.BookmarksEntry;
049    import com.liferay.portlet.bookmarks.model.BookmarksFolder;
050    import com.liferay.portlet.bookmarks.model.BookmarksFolderConstants;
051    import com.liferay.portlet.bookmarks.service.base.BookmarksEntryLocalServiceBaseImpl;
052    import com.liferay.portlet.bookmarks.social.BookmarksActivityKeys;
053    import com.liferay.portlet.bookmarks.util.BookmarksUtil;
054    import com.liferay.portlet.bookmarks.util.comparator.EntryModifiedDateComparator;
055    import com.liferay.portlet.social.model.SocialActivityConstants;
056    import com.liferay.portlet.trash.model.TrashEntry;
057    
058    import java.util.ArrayList;
059    import java.util.Date;
060    import java.util.List;
061    import java.util.Locale;
062    import java.util.Map;
063    
064    import javax.portlet.PortletPreferences;
065    
066    /**
067     * @author Brian Wing Shun Chan
068     * @author Raymond Aug??
069     * @author Levente Hud??k
070     */
071    public class BookmarksEntryLocalServiceImpl
072            extends BookmarksEntryLocalServiceBaseImpl {
073    
074            @Indexable(type = IndexableType.REINDEX)
075            @Override
076            public BookmarksEntry addEntry(
077                            long userId, long groupId, long folderId, String name, String url,
078                            String description, ServiceContext serviceContext)
079                    throws PortalException, SystemException {
080    
081                    // Entry
082    
083                    User user = userPersistence.findByPrimaryKey(userId);
084    
085                    if (Validator.isNull(name)) {
086                            name = url;
087                    }
088    
089                    Date now = new Date();
090    
091                    validate(url);
092    
093                    long entryId = counterLocalService.increment();
094    
095                    BookmarksEntry entry = bookmarksEntryPersistence.create(entryId);
096    
097                    entry.setUuid(serviceContext.getUuid());
098                    entry.setGroupId(groupId);
099                    entry.setCompanyId(user.getCompanyId());
100                    entry.setUserId(user.getUserId());
101                    entry.setUserName(user.getFullName());
102                    entry.setCreateDate(serviceContext.getCreateDate(now));
103                    entry.setModifiedDate(serviceContext.getModifiedDate(now));
104                    entry.setFolderId(folderId);
105                    entry.setName(name);
106                    entry.setUrl(url);
107                    entry.setDescription(description);
108                    entry.setExpandoBridgeAttributes(serviceContext);
109    
110                    bookmarksEntryPersistence.update(entry);
111    
112                    // Resources
113    
114                    resourceLocalService.addModelResources(entry, serviceContext);
115    
116                    // Asset
117    
118                    updateAsset(
119                            userId, entry, serviceContext.getAssetCategoryIds(),
120                            serviceContext.getAssetTagNames(),
121                            serviceContext.getAssetLinkEntryIds());
122    
123                    // Social
124    
125                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
126    
127                    extraDataJSONObject.put("title", entry.getName());
128    
129                    socialActivityLocalService.addActivity(
130                            userId, groupId, BookmarksEntry.class.getName(), entryId,
131                            BookmarksActivityKeys.ADD_ENTRY, extraDataJSONObject.toString(), 0);
132    
133                    // Subscriptions
134    
135                    notifySubscribers(entry, serviceContext);
136    
137                    return entry;
138            }
139    
140            @Override
141            public void deleteEntries(long groupId, long folderId)
142                    throws PortalException, SystemException {
143    
144                    deleteEntries(groupId, folderId, true);
145            }
146    
147            @Override
148            public void deleteEntries(
149                            long groupId, long folderId, boolean includeTrashedEntries)
150                    throws PortalException, SystemException {
151    
152                    List<BookmarksEntry> entries = bookmarksEntryPersistence.findByG_F(
153                            groupId, folderId);
154    
155                    for (BookmarksEntry entry : entries) {
156                            if (includeTrashedEntries || !entry.isInTrash()) {
157                                    bookmarksEntryLocalService.deleteEntry(entry);
158                            }
159                    }
160            }
161    
162            @Indexable(type = IndexableType.DELETE)
163            @Override
164            public BookmarksEntry deleteEntry(BookmarksEntry entry)
165                    throws PortalException, SystemException {
166    
167                    // Entry
168    
169                    bookmarksEntryPersistence.remove(entry);
170    
171                    // Resources
172    
173                    resourceLocalService.deleteResource(
174                            entry, ResourceConstants.SCOPE_INDIVIDUAL);
175    
176                    // Asset
177    
178                    assetEntryLocalService.deleteEntry(
179                            BookmarksEntry.class.getName(), entry.getEntryId());
180    
181                    // Expando
182    
183                    expandoRowLocalService.deleteRows(entry.getEntryId());
184    
185                    // Subscriptions
186    
187                    subscriptionLocalService.deleteSubscriptions(
188                            entry.getCompanyId(), BookmarksEntry.class.getName(),
189                            entry.getEntryId());
190    
191                    // Trash
192    
193                    trashEntryLocalService.deleteEntry(
194                            BookmarksEntry.class.getName(), entry.getEntryId());
195    
196                    return entry;
197            }
198    
199            @Indexable(type = IndexableType.DELETE)
200            @Override
201            public BookmarksEntry deleteEntry(long entryId)
202                    throws PortalException, SystemException {
203    
204                    BookmarksEntry entry = bookmarksEntryPersistence.findByPrimaryKey(
205                            entryId);
206    
207                    return deleteEntry(entry);
208            }
209    
210            @Override
211            public List<BookmarksEntry> getEntries(
212                            long groupId, long folderId, int start, int end)
213                    throws SystemException {
214    
215                    return bookmarksEntryPersistence.findByG_F_S(
216                            groupId, folderId, WorkflowConstants.STATUS_APPROVED, start, end);
217            }
218    
219            @Override
220            public List<BookmarksEntry> getEntries(
221                            long groupId, long folderId, int start, int end,
222                            OrderByComparator orderByComparator)
223                    throws SystemException {
224    
225                    return bookmarksEntryPersistence.findByG_F_S(
226                            groupId, folderId, WorkflowConstants.STATUS_APPROVED, start, end,
227                            orderByComparator);
228            }
229    
230            @Override
231            public int getEntriesCount(long groupId, long folderId)
232                    throws SystemException {
233    
234                    return bookmarksEntryPersistence.countByG_F_S(
235                            groupId, folderId, WorkflowConstants.STATUS_APPROVED);
236            }
237    
238            @Override
239            public BookmarksEntry getEntry(long entryId)
240                    throws PortalException, SystemException {
241    
242                    return bookmarksEntryPersistence.findByPrimaryKey(entryId);
243            }
244    
245            @Override
246            public int getFoldersEntriesCount(long groupId, List<Long> folderIds)
247                    throws SystemException {
248    
249                    return bookmarksEntryPersistence.countByG_F_S(
250                            groupId,
251                            ArrayUtil.toArray(folderIds.toArray(new Long[folderIds.size()])),
252                            WorkflowConstants.STATUS_APPROVED);
253            }
254    
255            @Override
256            public List<BookmarksEntry> getGroupEntries(
257                            long groupId, int start, int end)
258                    throws SystemException {
259    
260                    return bookmarksEntryPersistence.findByG_S(
261                            groupId, WorkflowConstants.STATUS_APPROVED, start, end,
262                            new EntryModifiedDateComparator());
263            }
264    
265            @Override
266            public List<BookmarksEntry> getGroupEntries(
267                            long groupId, long userId, int start, int end)
268                    throws SystemException {
269    
270                    OrderByComparator orderByComparator = new EntryModifiedDateComparator();
271    
272                    if (userId <= 0) {
273                            return bookmarksEntryPersistence.findByG_S(
274                                    groupId, WorkflowConstants.STATUS_APPROVED, start, end,
275                                    orderByComparator);
276                    }
277                    else {
278                            return bookmarksEntryPersistence.findByG_U_S(
279                                    groupId, userId, WorkflowConstants.STATUS_APPROVED, start, end,
280                                    orderByComparator);
281                    }
282            }
283    
284            @Override
285            public int getGroupEntriesCount(long groupId) throws SystemException {
286                    return bookmarksEntryPersistence.countByG_S(
287                            groupId, WorkflowConstants.STATUS_APPROVED);
288            }
289    
290            @Override
291            public int getGroupEntriesCount(long groupId, long userId)
292                    throws SystemException {
293    
294                    if (userId <= 0) {
295                            return getGroupEntriesCount(groupId);
296                    }
297                    else {
298                            return bookmarksEntryPersistence.countByG_U_S(
299                                    groupId, userId, WorkflowConstants.STATUS_APPROVED);
300                    }
301            }
302    
303            @Override
304            public List<BookmarksEntry> getNoAssetEntries() throws SystemException {
305                    return bookmarksEntryFinder.findByNoAssets();
306            }
307    
308            @Indexable(type = IndexableType.REINDEX)
309            @Override
310            public BookmarksEntry moveEntry(long entryId, long parentFolderId)
311                    throws PortalException, SystemException {
312    
313                    BookmarksEntry entry = getBookmarksEntry(entryId);
314    
315                    entry.setFolderId(parentFolderId);
316    
317                    bookmarksEntryPersistence.update(entry);
318    
319                    return entry;
320            }
321    
322            @Override
323            public BookmarksEntry moveEntryFromTrash(
324                            long userId, long entryId, long parentFolderId)
325                    throws PortalException, SystemException {
326    
327                    BookmarksEntry entry = getBookmarksEntry(entryId);
328    
329                    if (entry.isInTrash()) {
330                            restoreEntryFromTrash(userId, entryId);
331                    }
332                    else {
333                            updateStatus(userId, entry, entry.getStatus());
334                    }
335    
336                    return bookmarksEntryLocalService.moveEntry(entryId, parentFolderId);
337            }
338    
339            @Indexable(type = IndexableType.REINDEX)
340            @Override
341            public BookmarksEntry moveEntryToTrash(long userId, BookmarksEntry entry)
342                    throws PortalException, SystemException {
343    
344                    return updateStatus(userId, entry, WorkflowConstants.STATUS_IN_TRASH);
345            }
346    
347            @Indexable(type = IndexableType.REINDEX)
348            @Override
349            public BookmarksEntry moveEntryToTrash(long userId, long entryId)
350                    throws PortalException, SystemException {
351    
352                    BookmarksEntry entry = getEntry(entryId);
353    
354                    return moveEntryToTrash(userId, entry);
355            }
356    
357            @Override
358            public BookmarksEntry openEntry(long userId, BookmarksEntry entry)
359                    throws SystemException {
360    
361                    entry.setVisits(entry.getVisits() + 1);
362    
363                    bookmarksEntryPersistence.update(entry);
364    
365                    assetEntryLocalService.incrementViewCounter(
366                            userId, BookmarksEntry.class.getName(), entry.getEntryId(), 1);
367    
368                    return entry;
369            }
370    
371            @Override
372            public BookmarksEntry openEntry(long userId, long entryId)
373                    throws PortalException, SystemException {
374    
375                    BookmarksEntry entry = bookmarksEntryPersistence.findByPrimaryKey(
376                            entryId);
377    
378                    return openEntry(userId, entry);
379            }
380    
381            @Indexable(type = IndexableType.REINDEX)
382            @Override
383            public BookmarksEntry restoreEntryFromTrash(long userId, long entryId)
384                    throws PortalException, SystemException {
385    
386                    BookmarksEntry entry = bookmarksEntryPersistence.findByPrimaryKey(
387                            entryId);
388    
389                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
390                            BookmarksEntry.class.getName(), entryId);
391    
392                    return updateStatus(userId, entry, trashEntry.getStatus());
393            }
394    
395            @Override
396            public Hits search(
397                            long groupId, long userId, long creatorUserId, int status,
398                            int start, int end)
399                    throws PortalException, SystemException {
400    
401                    Indexer indexer = IndexerRegistryUtil.getIndexer(
402                            BookmarksEntry.class.getName());
403    
404                    SearchContext searchContext = new SearchContext();
405    
406                    searchContext.setAttribute(Field.STATUS, status);
407    
408                    if (creatorUserId > 0) {
409                            searchContext.setAttribute(
410                                    Field.USER_ID, String.valueOf(creatorUserId));
411                    }
412    
413                    searchContext.setAttribute("paginationType", "none");
414    
415                    Group group = groupLocalService.getGroup(groupId);
416    
417                    searchContext.setCompanyId(group.getCompanyId());
418    
419                    searchContext.setEnd(end);
420                    searchContext.setGroupIds(new long[] {groupId});
421                    searchContext.setSorts(new Sort(Field.MODIFIED_DATE, true));
422                    searchContext.setStart(start);
423                    searchContext.setUserId(userId);
424    
425                    return indexer.search(searchContext);
426            }
427    
428            @Override
429            public void subscribeEntry(long userId, long entryId)
430                    throws PortalException, SystemException {
431    
432                    BookmarksEntry entry = bookmarksEntryPersistence.findByPrimaryKey(
433                            entryId);
434    
435                    subscriptionLocalService.addSubscription(
436                            userId, entry.getGroupId(), BookmarksEntry.class.getName(),
437                            entryId);
438            }
439    
440            @Override
441            public void unsubscribeEntry(long userId, long entryId)
442                    throws PortalException, SystemException {
443    
444                    subscriptionLocalService.deleteSubscription(
445                            userId, BookmarksEntry.class.getName(), entryId);
446            }
447    
448            @Override
449            public void updateAsset(
450                            long userId, BookmarksEntry entry, long[] assetCategoryIds,
451                            String[] assetTagNames, long[] assetLinkEntryIds)
452                    throws PortalException, SystemException {
453    
454                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
455                            userId, entry.getGroupId(), entry.getCreateDate(),
456                            entry.getModifiedDate(), BookmarksEntry.class.getName(),
457                            entry.getEntryId(), entry.getUuid(), 0, assetCategoryIds,
458                            assetTagNames, true, null, null, null, ContentTypes.TEXT_PLAIN,
459                            entry.getName(), entry.getDescription(), null, entry.getUrl(), null,
460                            0, 0, null, false);
461    
462                    assetLinkLocalService.updateLinks(
463                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
464                            AssetLinkConstants.TYPE_RELATED);
465            }
466    
467            @Indexable(type = IndexableType.REINDEX)
468            @Override
469            public BookmarksEntry updateEntry(
470                            long userId, long entryId, long groupId, long folderId, String name,
471                            String url, String description, ServiceContext serviceContext)
472                    throws PortalException, SystemException {
473    
474                    // Entry
475    
476                    BookmarksEntry entry = bookmarksEntryPersistence.findByPrimaryKey(
477                            entryId);
478    
479                    if (Validator.isNull(name)) {
480                            name = url;
481                    }
482    
483                    validate(url);
484    
485                    entry.setModifiedDate(serviceContext.getModifiedDate(null));
486                    entry.setFolderId(folderId);
487                    entry.setName(name);
488                    entry.setUrl(url);
489                    entry.setDescription(description);
490                    entry.setExpandoBridgeAttributes(serviceContext);
491    
492                    bookmarksEntryPersistence.update(entry);
493    
494                    // Asset
495    
496                    updateAsset(
497                            userId, entry, serviceContext.getAssetCategoryIds(),
498                            serviceContext.getAssetTagNames(),
499                            serviceContext.getAssetLinkEntryIds());
500    
501                    // Social
502    
503                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
504    
505                    extraDataJSONObject.put("title", entry.getName());
506    
507                    socialActivityLocalService.addActivity(
508                            userId, entry.getGroupId(), BookmarksEntry.class.getName(), entryId,
509                            BookmarksActivityKeys.UPDATE_ENTRY, extraDataJSONObject.toString(),
510                            0);
511    
512                    // Subscriptions
513    
514                    notifySubscribers(entry, serviceContext);
515    
516                    return entry;
517            }
518    
519            @Override
520            public BookmarksEntry updateStatus(
521                            long userId, BookmarksEntry entry, int status)
522                    throws PortalException, SystemException {
523    
524                    // Entry
525    
526                    User user = userPersistence.findByPrimaryKey(userId);
527    
528                    int oldStatus = entry.getStatus();
529    
530                    entry.setStatus(status);
531                    entry.setStatusByUserId(userId);
532                    entry.setStatusByUserName(user.getScreenName());
533                    entry.setStatusDate(new Date());
534    
535                    bookmarksEntryPersistence.update(entry);
536    
537                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
538    
539                    extraDataJSONObject.put("title", entry.getName());
540    
541                    if (status == WorkflowConstants.STATUS_APPROVED) {
542    
543                            // Asset
544    
545                            assetEntryLocalService.updateVisible(
546                                    BookmarksEntry.class.getName(), entry.getEntryId(), true);
547    
548                            // Social
549    
550                            socialActivityLocalService.addActivity(
551                                    userId, entry.getGroupId(), BookmarksEntry.class.getName(),
552                                    entry.getEntryId(),
553                                    SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
554                                    extraDataJSONObject.toString(), 0);
555                    }
556                    else if (status == WorkflowConstants.STATUS_IN_TRASH) {
557    
558                            // Asset
559    
560                            assetEntryLocalService.updateVisible(
561                                    BookmarksEntry.class.getName(), entry.getEntryId(), false);
562    
563                            // Social
564    
565                            socialActivityLocalService.addActivity(
566                                    userId, entry.getGroupId(), BookmarksEntry.class.getName(),
567                                    entry.getEntryId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
568                                    extraDataJSONObject.toString(), 0);
569                    }
570    
571                    // Trash
572    
573                    if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
574                            trashEntryLocalService.deleteEntry(
575                                    BookmarksEntry.class.getName(), entry.getEntryId());
576                    }
577                    else if (status == WorkflowConstants.STATUS_IN_TRASH) {
578                            trashEntryLocalService.addTrashEntry(
579                                    userId, entry.getGroupId(), BookmarksEntry.class.getName(),
580                                    entry.getEntryId(), oldStatus, null, null);
581                    }
582    
583                    return entry;
584            }
585    
586            protected long getFolder(BookmarksEntry entry, long folderId)
587                    throws SystemException {
588    
589                    if ((entry.getFolderId() != folderId) &&
590                            (folderId != BookmarksFolderConstants.DEFAULT_PARENT_FOLDER_ID)) {
591    
592                            BookmarksFolder newFolder =
593                                    bookmarksFolderPersistence.fetchByPrimaryKey(folderId);
594    
595                            if ((newFolder == null) ||
596                                    (entry.getGroupId() != newFolder.getGroupId())) {
597    
598                                    folderId = entry.getFolderId();
599                            }
600                    }
601    
602                    return folderId;
603            }
604    
605            protected void notifySubscribers(
606                            BookmarksEntry entry, ServiceContext serviceContext)
607                    throws PortalException, SystemException {
608    
609                    String layoutFullURL = serviceContext.getLayoutFullURL();
610    
611                    if (Validator.isNull(layoutFullURL)) {
612                            return;
613                    }
614    
615                    PortletPreferences preferences =
616                            ServiceContextUtil.getPortletPreferences(serviceContext);
617    
618                    if (preferences == null) {
619                            long ownerId = entry.getGroupId();
620                            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
621                            long plid = PortletKeys.PREFS_PLID_SHARED;
622                            String portletId = PortletKeys.BOOKMARKS;
623                            String defaultPreferences = null;
624    
625                            preferences = portletPreferencesLocalService.getPreferences(
626                                    entry.getCompanyId(), ownerId, ownerType, plid, portletId,
627                                    defaultPreferences);
628                    }
629    
630                    if ((serviceContext.isCommandAdd() &&
631                             !BookmarksUtil.getEmailEntryAddedEnabled(preferences)) ||
632                            (serviceContext.isCommandUpdate() &&
633                             !BookmarksUtil.getEmailEntryUpdatedEnabled(preferences))) {
634    
635                            return;
636                    }
637    
638                    String statusByUserName = StringPool.BLANK;
639    
640                    try {
641                            User user = userLocalService.getUserById(
642                                    serviceContext.getGuestOrUserId());
643    
644                            statusByUserName = user.getFullName();
645                    }
646                    catch (Exception e) {
647                            _log.error(e, e);
648                    }
649    
650                    String entryURL =
651                            layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "bookmarks" +
652                                    StringPool.SLASH + entry.getEntryId();
653    
654                    String fromAddress = BookmarksUtil.getEmailFromAddress(
655                            preferences, entry.getCompanyId());
656                    String fromName = BookmarksUtil.getEmailFromName(
657                            preferences, entry.getCompanyId());
658    
659                    Map<Locale, String> localizedSubjectMap = null;
660                    Map<Locale, String> localizedBodyMap = null;
661    
662                    if (serviceContext.isCommandUpdate()) {
663                            localizedSubjectMap = BookmarksUtil.getEmailEntryUpdatedSubjectMap(
664                                    preferences);
665                            localizedBodyMap = BookmarksUtil.getEmailEntryUpdatedBodyMap(
666                                    preferences);
667                    }
668                    else {
669                            localizedSubjectMap = BookmarksUtil.getEmailEntryAddedSubjectMap(
670                                    preferences);
671                            localizedBodyMap = BookmarksUtil.getEmailEntryAddedBodyMap(
672                                    preferences);
673                    }
674    
675                    SubscriptionSender subscriptionSender = new SubscriptionSender();
676    
677                    subscriptionSender.setCompanyId(entry.getCompanyId());
678                    subscriptionSender.setContextAttributes(
679                            "[$BOOKMARKS_ENTRY_STATUS_BY_USER_NAME$]", statusByUserName,
680                            "[$BOOKMARKS_ENTRY_URL$]", entryURL);
681                    subscriptionSender.setContextUserPrefix("BOOKMARKS_ENTRY");
682                    subscriptionSender.setFrom(fromAddress, fromName);
683                    subscriptionSender.setHtmlFormat(true);
684                    subscriptionSender.setLocalizedBodyMap(localizedBodyMap);
685                    subscriptionSender.setLocalizedSubjectMap(localizedSubjectMap);
686                    subscriptionSender.setMailId("bookmarks_entry", entry.getEntryId());
687                    subscriptionSender.setPortletId(PortletKeys.BOOKMARKS);
688                    subscriptionSender.setReplyToAddress(fromAddress);
689                    subscriptionSender.setScopeGroupId(entry.getGroupId());
690                    subscriptionSender.setServiceContext(serviceContext);
691                    subscriptionSender.setUserId(entry.getUserId());
692    
693                    subscriptionSender.addPersistedSubscribers(
694                            BookmarksEntry.class.getName(), entry.getEntryId());
695    
696                    BookmarksFolder folder = entry.getFolder();
697    
698                    List<Long> folderIds = new ArrayList<Long>();
699    
700                    if (folder != null) {
701                            folderIds.add(folder.getFolderId());
702    
703                            folderIds.addAll(folder.getAncestorFolderIds());
704                    }
705    
706                    for (long curFolderId : folderIds) {
707                            subscriptionSender.addPersistedSubscribers(
708                                    BookmarksFolder.class.getName(), curFolderId);
709                    }
710    
711                    subscriptionSender.addPersistedSubscribers(
712                            BookmarksFolder.class.getName(), entry.getGroupId());
713    
714                    subscriptionSender.flushNotificationsAsync();
715            }
716    
717            protected void validate(String url) throws PortalException {
718                    if (!Validator.isUrl(url)) {
719                            throw new EntryURLException();
720                    }
721            }
722    
723            private static Log _log = LogFactoryUtil.getLog(
724                    BookmarksEntryLocalServiceImpl.class);
725    
726    }