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