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