From cf7d4cce9cd2f10585f87efdb00a51a5528a31fa Mon Sep 17 00:00:00 2001 From: Athou Date: Mon, 8 Apr 2013 13:06:53 +0200 Subject: [PATCH] major improvement in the way data is stored --- .../backend/dao/FeedCategoryService.java | 6 +- .../backend/dao/FeedEntryService.java | 136 +----------- .../backend/dao/FeedEntryStatusService.java | 161 ++++++++++++-- .../backend/dao/FeedSubscriptionService.java | 8 +- .../com/commafeed/backend/dao/GenericDAO.java | 7 +- .../backend/model/FeedEntryStatus.java | 10 +- .../model/extended/FeedEntryWithStatus.java | 59 ----- .../pages/GoogleImportRedirectPage.java | 2 +- .../frontend/rest/resources/AbstractREST.java | 23 +- .../rest/resources/AdminUsersREST.java | 3 +- .../frontend/rest/resources/EntriesREST.java | 203 +++++------------- .../rest/resources/SubscriptionsREST.java | 17 +- src/main/resources/META-INF/orm.xml | 43 ++-- src/main/resources/META-INF/persistence.xml | 3 +- 14 files changed, 274 insertions(+), 407 deletions(-) delete mode 100644 src/main/java/com/commafeed/backend/model/extended/FeedEntryWithStatus.java diff --git a/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java b/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java index 8d92a431..c2f7df73 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedCategoryService.java @@ -19,7 +19,11 @@ import com.uaihebert.model.EasyCriteria; public class FeedCategoryService extends GenericDAO { public List findAll(User user) { - return findByField(MF.i(MF.p(FeedCategory.class).getUser()), user); + EasyCriteria criteria = createCriteria(); + criteria.andEquals(MF.i(proxy().getUser()), user); + + criteria.innerJoinFetch(MF.i(proxy().getUser())); + return criteria.getResultList(); } public FeedCategory findById(User user, Long id) { diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryService.java b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java index 9a7cfad8..6af7c4f4 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedEntryService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryService.java @@ -3,27 +3,19 @@ package com.commafeed.backend.dao; import java.util.Calendar; import java.util.Collection; import java.util.List; -import java.util.Set; import javax.ejb.Stateless; import javax.inject.Inject; -import javax.persistence.Query; import javax.persistence.TypedQuery; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import com.commafeed.backend.model.Feed; -import com.commafeed.backend.model.FeedCategory; import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntryStatus; import com.commafeed.backend.model.FeedSubscription; -import com.commafeed.backend.model.User; -import com.commafeed.backend.model.extended.FeedEntryWithStatus; -import com.commafeed.frontend.utils.ModelFactory.MF; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; @Stateless @SuppressWarnings("serial") @@ -36,9 +28,7 @@ public class FeedEntryService extends GenericDAO { FeedSubscriptionService feedSubscriptionService; public void updateEntries(String url, Collection entries) { - Feed feed = Iterables.getFirst( - feedService.findByField(MF.i(MF.p(Feed.class).getUrl()), url), - null); + Feed feed = feedService.findByUrl(url); List guids = Lists.newArrayList(); for (FeedEntry entry : entries) { guids.add(entry.getGuid()); @@ -56,7 +46,6 @@ public class FeedEntryService extends GenericDAO { } if (foundEntry == null) { addFeedToEntry(entry, feed); - save(entry); } else { boolean foundFeed = false; for (Feed existingFeed : foundEntry.getFeeds()) { @@ -68,7 +57,6 @@ public class FeedEntryService extends GenericDAO { if (!foundFeed) { addFeedToEntry(foundEntry, feed); - update(foundEntry); } } } @@ -80,12 +68,13 @@ public class FeedEntryService extends GenericDAO { private void addFeedToEntry(FeedEntry entry, Feed feed) { entry.getFeeds().add(feed); + saveOrUpdate(entry); List subscriptions = feedSubscriptionService .findByFeed(feed); for (FeedSubscription sub : subscriptions) { FeedEntryStatus status = new FeedEntryStatus(); status.setEntry(entry); - status.setUser(sub.getUser()); + status.setSubscription(sub); em.persist(status); } @@ -98,123 +87,4 @@ public class FeedEntryService extends GenericDAO { return query.getResultList(); } - public List getEntriesByKeywords(User user, - String keywords) { - return getEntriesByKeywords(user, keywords, -1, -1); - } - - public List getEntriesByKeywords(User user, - String keywords, int offset, int limit) { - Query query = em.createNamedQuery("Entry.allByKeywords"); - query.setParameter("userId", user.getId()); - query.setParameter("user", user); - - String joinedKeywords = StringUtils.join( - keywords.toLowerCase().split(" "), "%"); - query.setParameter("keywords", "%" + joinedKeywords + "%"); - if (offset > -1) { - query.setFirstResult(offset); - } - if (limit > -1) { - query.setMaxResults(limit); - } - return buildList(query.getResultList()); - } - - public List getEntries(User user, boolean unreadOnly) { - return getEntries(user, unreadOnly, -1, -1); - } - - public List getEntries(User user, boolean unreadOnly, - int offset, int limit) { - String queryName = null; - if (unreadOnly) { - queryName = "Entry.unread"; - } else { - queryName = "Entry.all"; - } - Query query = em.createNamedQuery(queryName); - query.setParameter("userId", user.getId()); - query.setParameter("user", user); - if (offset > -1) { - query.setFirstResult(offset); - } - if (limit > -1) { - query.setMaxResults(limit); - } - return buildList(query.getResultList()); - } - - public Long getUnreadCount(Feed feed, User user) { - TypedQuery query = em.createNamedQuery("Entry.unreadByFeedCount", - Long.class); - query.setParameter("feed", feed); - query.setParameter("userId", user.getId()); - return query.getSingleResult(); - } - - public List getEntries(Feed feed, User user, - boolean unreadOnly) { - return getEntries(feed, user, unreadOnly, -1, -1); - } - - public List getEntries(Feed feed, User user, - boolean unreadOnly, int offset, int limit) { - String queryName = null; - if (unreadOnly) { - queryName = "Entry.unreadByFeed"; - } else { - queryName = "Entry.allByFeed"; - } - Query query = em.createNamedQuery(queryName); - query.setParameter("feed", feed); - query.setParameter("userId", user.getId()); - if (offset > -1) { - query.setFirstResult(offset); - } - if (limit > -1) { - query.setMaxResults(limit); - } - - return buildList(query.getResultList()); - } - - public List getEntries(List categories, - User user, boolean unreadOnly) { - return getEntries(categories, user, unreadOnly, -1, -1); - } - - public List getEntries(List categories, - User user, boolean unreadOnly, int offset, int limit) { - String queryName = null; - if (unreadOnly) { - queryName = "Entry.unreadByCategories"; - } else { - queryName = "Entry.allByCategories"; - } - Query query = em.createNamedQuery(queryName); - query.setParameter("categories", categories); - query.setParameter("userId", user.getId()); - query.setParameter("user", user); - if (offset > -1) { - query.setFirstResult(offset); - } - if (limit > -1) { - query.setMaxResults(limit); - } - return buildList(query.getResultList()); - } - - @SuppressWarnings("rawtypes") - private List buildList(List list) { - Set result = Sets.newLinkedHashSet(); - for (Object object : list) { - Object[] array = (Object[]) object; - FeedEntry entry = (FeedEntry) array[0]; - FeedEntryStatus status = (FeedEntryStatus) array[1]; - FeedEntryWithStatus fews = new FeedEntryWithStatus(entry, status); - result.add(fews); - } - return Lists.newArrayList(result); - } } diff --git a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java index 7ee1cce2..cf7d407a 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedEntryStatusService.java @@ -1,37 +1,172 @@ package com.commafeed.backend.dao; import java.util.List; +import java.util.Map; import javax.ejb.Stateless; +import javax.inject.Inject; import javax.persistence.NoResultException; +import javax.persistence.Query; +import javax.persistence.TypedQuery; -import com.commafeed.backend.model.FeedEntry; +import org.apache.commons.lang.StringUtils; + +import com.commafeed.backend.model.Feed; +import com.commafeed.backend.model.FeedCategory; import com.commafeed.backend.model.FeedEntryStatus; import com.commafeed.backend.model.User; -import com.commafeed.frontend.utils.ModelFactory.MF; -import com.uaihebert.factory.EasyCriteriaFactory; -import com.uaihebert.model.EasyCriteria; +import com.google.api.client.util.Lists; +import com.google.api.client.util.Maps; @Stateless @SuppressWarnings("serial") public class FeedEntryStatusService extends GenericDAO { - public List findAll(User user) { - return findByField(MF.i(proxy().getUser()), user); - } + @Inject + FeedCategoryService feedCategoryService; - public FeedEntryStatus getStatus(User user, FeedEntry entry) { - EasyCriteria criteria = EasyCriteriaFactory - .createQueryCriteria(em, getType()); - criteria.andEquals(MF.i(proxy().getUser()), user); - criteria.andEquals(MF.i(proxy().getEntry()), entry); + public FeedEntryStatus findById(User user, Long id) { + TypedQuery query = em.createNamedQuery( + "EntryStatus.byId", FeedEntryStatus.class); + query.setParameter("user", user); + query.setParameter("id", id); FeedEntryStatus status = null; try { - status = criteria.getSingleResult(); + status = query.getSingleResult(); } catch (NoResultException e) { status = null; } return status; } + + public List getStatusesByKeywords(User user, + String keywords) { + return getStatusesByKeywords(user, keywords, -1, -1); + } + + public List getStatusesByKeywords(User user, + String keywords, int offset, int limit) { + TypedQuery query = em.createNamedQuery( + "EntryStatus.allByKeywords", FeedEntryStatus.class); + query.setParameter("user", user); + + String joinedKeywords = StringUtils.join( + keywords.toLowerCase().split(" "), "%"); + query.setParameter("keywords", "%" + joinedKeywords + "%"); + if (offset > -1) { + query.setFirstResult(offset); + } + if (limit > -1) { + query.setMaxResults(limit); + } + return query.getResultList(); + } + + public List getStatuses(User user, boolean unreadOnly) { + return getStatuses(user, unreadOnly, -1, -1); + } + + public List getStatuses(User user, boolean unreadOnly, + int offset, int limit) { + String queryName = unreadOnly ? "EntryStatus.unread" + : "EntryStatus.all"; + TypedQuery query = em.createNamedQuery(queryName, + FeedEntryStatus.class); + query.setParameter("user", user); + if (offset > -1) { + query.setFirstResult(offset); + } + if (limit > -1) { + query.setMaxResults(limit); + } + return query.getResultList(); + } + + /** + * Map between subscriptionId and unread count + */ + @SuppressWarnings("rawtypes") + public Map getUnreadCount(User user) { + Map map = Maps.newHashMap(); + Query query = em.createNamedQuery("EntryStatus.unreadCounts"); + query.setParameter("user", user); + List resultList = query.getResultList(); + for (Object o : resultList) { + Object[] array = (Object[]) o; + map.put((Long) array[0], (Long) array[1]); + } + return map; + } + + public List getStatuses(Feed feed, User user, + boolean unreadOnly) { + return getStatuses(feed, user, unreadOnly, -1, -1); + } + + public List getStatuses(Feed feed, User user, + boolean unreadOnly, int offset, int limit) { + String queryName = unreadOnly ? "EntryStatus.unreadByFeed" + : "EntryStatus.allByFeed"; + TypedQuery query = em.createNamedQuery(queryName, + FeedEntryStatus.class); + query.setParameter("feed", feed); + query.setParameter("user", user); + if (offset > -1) { + query.setFirstResult(offset); + } + if (limit > -1) { + query.setMaxResults(limit); + } + + return query.getResultList(); + } + + public List getStatuses(List categories, + User user, boolean unreadOnly) { + return getStatuses(categories, user, unreadOnly, -1, -1); + } + + public List getStatuses(List categories, + User user, boolean unreadOnly, int offset, int limit) { + String queryName = unreadOnly ? "EntryStatus.unreadByCategories" + : "EntryStatus.allByCategories"; + TypedQuery query = em.createNamedQuery(queryName, + FeedEntryStatus.class); + query.setParameter("categories", categories); + query.setParameter("user", user); + if (offset > -1) { + query.setFirstResult(offset); + } + if (limit > -1) { + query.setMaxResults(limit); + } + return query.getResultList(); + } + + public void markFeedEntries(User user, Feed feed) { + List statuses = getStatuses(feed, user, true); + update(markList(statuses)); + } + + public void markCategoryEntries(User user, List categories) { + List statuses = getStatuses(categories, user, true); + update(markList(statuses)); + } + + public void markAllEntries(User user) { + List statuses = getStatuses(user, true); + update(markList(statuses)); + } + + private List markList(List statuses) { + List list = Lists.newArrayList(); + for (FeedEntryStatus status : statuses) { + if (!status.isRead()) { + status.setRead(true); + list.add(status); + } + } + return list; + } } diff --git a/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java b/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java index bcba38e0..d5f76bb4 100644 --- a/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java +++ b/src/main/java/com/commafeed/backend/dao/FeedSubscriptionService.java @@ -41,7 +41,13 @@ public class FeedSubscriptionService extends GenericDAO { } public List findAll(User user) { - return findByField(MF.i(proxy().getUser()), user); + EasyCriteria criteria = createCriteria(); + criteria.andEquals(MF.i(proxy().getUser()), user); + + criteria.innerJoinFetch(MF.i(proxy().getFeed())); + criteria.innerJoinFetch(MF.i(proxy().getUser())); + criteria.leftJoinFetch(MF.i(proxy().getCategory())); + return criteria.getResultList(); } public List findWithoutCategories(User user) { diff --git a/src/main/java/com/commafeed/backend/dao/GenericDAO.java b/src/main/java/com/commafeed/backend/dao/GenericDAO.java index 5a0b3330..da2318cc 100644 --- a/src/main/java/com/commafeed/backend/dao/GenericDAO.java +++ b/src/main/java/com/commafeed/backend/dao/GenericDAO.java @@ -1,6 +1,7 @@ package com.commafeed.backend.dao; import java.io.Serializable; +import java.util.Arrays; import java.util.List; import javax.annotation.PostConstruct; @@ -37,12 +38,16 @@ public abstract class GenericDAO implements em.persist(object); } - public void update(T... objects) { + public void update(List objects) { for (Object object : objects) { em.merge(object); } } + public void update(T... objects) { + update(Arrays.asList(objects)); + } + public void saveOrUpdate(AbstractModel m) { if (m.getId() == null) { em.persist(m); diff --git a/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java b/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java index c1575891..de09f162 100644 --- a/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java +++ b/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java @@ -13,7 +13,7 @@ public class FeedEntryStatus extends AbstractModel { @ManyToOne @JoinColumn(nullable = false) - private User user; + private FeedSubscription subscription; @ManyToOne @JoinColumn(nullable = false) @@ -23,12 +23,12 @@ public class FeedEntryStatus extends AbstractModel { private boolean read; private boolean starred; - public User getUser() { - return user; + public FeedSubscription getSubscription() { + return subscription; } - public void setUser(User user) { - this.user = user; + public void setSubscription(FeedSubscription subscription) { + this.subscription = subscription; } public FeedEntry getEntry() { diff --git a/src/main/java/com/commafeed/backend/model/extended/FeedEntryWithStatus.java b/src/main/java/com/commafeed/backend/model/extended/FeedEntryWithStatus.java deleted file mode 100644 index f1199574..00000000 --- a/src/main/java/com/commafeed/backend/model/extended/FeedEntryWithStatus.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.commafeed.backend.model.extended; - -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; - -import com.commafeed.backend.model.FeedEntry; -import com.commafeed.backend.model.FeedEntryStatus; - -public class FeedEntryWithStatus { - private FeedEntry entry; - private FeedEntryStatus status; - - public FeedEntryWithStatus(FeedEntry entry, FeedEntryStatus status) { - this.entry = entry; - this.status = status; - } - - @Override - public int hashCode() { - return new HashCodeBuilder(17, 37).append(entry.getId()) - .append(status == null ? null : status.getId()).toHashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (obj.getClass() != getClass()) { - return false; - } - FeedEntryWithStatus rhs = (FeedEntryWithStatus) obj; - return new EqualsBuilder() - .append(status == null ? null : status.getId(), - rhs.status == null ? null : rhs.status.getId()) - .append(entry.getId(), rhs.entry.getId()).isEquals(); - - } - - public FeedEntry getEntry() { - return entry; - } - - public void setEntry(FeedEntry entry) { - this.entry = entry; - } - - public FeedEntryStatus getStatus() { - return status; - } - - public void setStatus(FeedEntryStatus status) { - this.status = status; - } - -} diff --git a/src/main/java/com/commafeed/frontend/pages/GoogleImportRedirectPage.java b/src/main/java/com/commafeed/frontend/pages/GoogleImportRedirectPage.java index 4e0f8a53..6d8b89a9 100644 --- a/src/main/java/com/commafeed/frontend/pages/GoogleImportRedirectPage.java +++ b/src/main/java/com/commafeed/frontend/pages/GoogleImportRedirectPage.java @@ -38,7 +38,7 @@ public class GoogleImportRedirectPage extends WebPage { builder.addParameter("redirect_uri", redirectUri); builder.addParameter("response_type", "code"); builder.addParameter("scope", SCOPE); - builder.addParameter("approval_prompt", "force"); + builder.addParameter("approval_prompt", "auto"); builder.addParameter("client_id", clientId); builder.addParameter("state", String.valueOf(CommaFeedSession.get().getUser().getId())); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java index 1d7d687a..58b7b3c2 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AbstractREST.java @@ -1,7 +1,6 @@ package com.commafeed.frontend.rest.resources; import java.lang.reflect.Method; -import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -19,6 +18,7 @@ import javax.ws.rs.core.Response.Status; import org.apache.wicket.ThreadContext; import org.apache.wicket.authentication.IAuthenticationStrategy; +import org.apache.wicket.authroles.authorization.strategies.role.Roles; import org.apache.wicket.protocol.http.servlet.ServletWebRequest; import org.apache.wicket.protocol.http.servlet.ServletWebResponse; import org.apache.wicket.request.cycle.RequestCycle; @@ -94,11 +94,13 @@ public abstract class AbstractREST { CommaFeedSession session = (CommaFeedSession) app .fetchCreateAndSetSession(cycle); - IAuthenticationStrategy authenticationStrategy = app - .getSecuritySettings().getAuthenticationStrategy(); - String[] data = authenticationStrategy.load(); - if (data != null && data.length > 1) { - session.signIn(data[0], data[1]); + if (session.getUser() == null) { + IAuthenticationStrategy authenticationStrategy = app + .getSecuritySettings().getAuthenticationStrategy(); + String[] data = authenticationStrategy.load(); + if (data != null && data.length > 1) { + session.signIn(data[0], data[1]); + } } } @@ -137,11 +139,10 @@ public abstract class AbstractREST { } private boolean checkRole(User user, SecurityCheck annotation) { - Set roles = userRoleService.getRoles(user); - if (!roles.contains(annotation.value())) { - return false; - } - return true; + Roles roles = CommaFeedSession.get().getRoles(); + boolean authorized = roles.hasAnyRole(new Roles(annotation.value() + .name())); + return authorized; } } diff --git a/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java b/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java index d9fa09be..884e775c 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/AdminUsersREST.java @@ -134,7 +134,8 @@ public class AdminUsersREST extends AbstractREST { return Response.status(Status.FORBIDDEN) .entity("You cannot delete the admin user.").build(); } - feedEntryStatusService.delete(feedEntryStatusService.findAll(user)); + feedEntryStatusService.delete(feedEntryStatusService.getStatuses(user, + false)); feedSubscriptionService.delete(feedSubscriptionService.findAll(user)); feedCategoryService.delete(feedCategoryService.findAll(user)); userSettingsService.delete(userSettingsService.findByUser(user)); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java index cb5779eb..fb669a47 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/EntriesREST.java @@ -1,29 +1,25 @@ package com.commafeed.frontend.rest.resources; import java.util.List; -import java.util.Map; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.lang.StringUtils; -import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.FeedCategory; import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntryStatus; import com.commafeed.backend.model.FeedSubscription; -import com.commafeed.backend.model.extended.FeedEntryWithStatus; import com.commafeed.frontend.model.Entries; import com.commafeed.frontend.model.Entry; -import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; @Path("entries") public class EntriesREST extends AbstractREST { @@ -59,34 +55,37 @@ public class EntriesREST extends AbstractREST { if (subscription != null) { entries.setName(subscription.getTitle()); entries.setMessage(subscription.getFeed().getMessage()); - entries.getEntries().addAll( - buildEntries(subscription, offset, limit, unreadOnly)); + + List unreadEntries = feedEntryStatusService + .getStatuses(subscription.getFeed(), getUser(), + unreadOnly, offset, limit); + for (FeedEntryStatus status : unreadEntries) { + entries.getEntries().add(buildEntry(status)); + } } } else { - List subs = feedSubscriptionService - .findAll(getUser()); - Map subMapping = Maps.uniqueIndex(subs, - new Function() { - public Long apply(FeedSubscription sub) { - return sub.getFeed().getId(); - } - }); - if (ALL.equals(id)) { entries.setName("All"); - entries.getEntries().addAll( - buildEntries(subMapping, offset, limit, unreadOnly)); + List unreadEntries = feedEntryStatusService + .getStatuses(getUser(), unreadOnly, offset, limit); + for (FeedEntryStatus status : unreadEntries) { + entries.getEntries().add(buildEntry(status)); + } + } else { FeedCategory feedCategory = feedCategoryService.findById( getUser(), Long.valueOf(id)); if (feedCategory != null) { List childrenCategories = feedCategoryService .findAllChildrenCategories(getUser(), feedCategory); - entries.getEntries().addAll( - buildEntries(childrenCategories, subMapping, - offset, limit, unreadOnly)); + List unreadEntries = feedEntryStatusService + .getStatuses(childrenCategories, getUser(), + unreadOnly, offset, limit); + for (FeedEntryStatus status : unreadEntries) { + entries.getEntries().add(buildEntry(status)); + } entries.setName(feedCategory.getName()); } } @@ -96,79 +95,21 @@ public class EntriesREST extends AbstractREST { return entries; } - private List buildEntries(Map subMapping, - int offset, int limit, boolean unreadOnly) { - List entries = Lists.newArrayList(); - - List unreadEntries = feedEntryService.getEntries( - getUser(), unreadOnly, offset, limit); - for (FeedEntryWithStatus feedEntry : unreadEntries) { - FeedSubscription sub = null; - for (Feed feed : feedEntry.getEntry().getFeeds()) { - sub = subMapping.get(feed.getId()); - if (sub != null) { - break; - } - } - entries.add(populateEntry(buildEntry(feedEntry), sub)); - } - - return entries; - } - - private List buildEntries(FeedSubscription subscription, int offset, - int limit, boolean unreadOnly) { - List entries = Lists.newArrayList(); - - List unreadEntries = feedEntryService.getEntries( - subscription.getFeed(), getUser(), unreadOnly, offset, limit); - for (FeedEntryWithStatus feedEntry : unreadEntries) { - entries.add(populateEntry(buildEntry(feedEntry), subscription)); - } - - return entries; - } - - private List buildEntries(List categories, - Map subMapping, int offset, int limit, - boolean unreadOnly) { - List entries = Lists.newArrayList(); - - List unreadEntries = feedEntryService.getEntries( - categories, getUser(), unreadOnly, offset, limit); - for (FeedEntryWithStatus feedEntry : unreadEntries) { - FeedSubscription sub = null; - for (Feed feed : feedEntry.getEntry().getFeeds()) { - sub = subMapping.get(feed.getId()); - if (sub != null) { - break; - } - } - entries.add(populateEntry(buildEntry(feedEntry), sub)); - } - - return entries; - } - - private Entry buildEntry(FeedEntryWithStatus feedEntryWithStatus) { + private Entry buildEntry(FeedEntryStatus status) { Entry entry = new Entry(); - FeedEntry feedEntry = feedEntryWithStatus.getEntry(); - entry.setId(String.valueOf(feedEntry.getId())); + FeedEntry feedEntry = status.getEntry(); + entry.setId(String.valueOf(status.getId())); entry.setTitle(feedEntry.getTitle()); entry.setContent(feedEntry.getContent()); entry.setDate(feedEntry.getUpdated()); entry.setUrl(feedEntry.getUrl()); - FeedEntryStatus status = feedEntryWithStatus.getStatus(); - entry.setRead(status == null ? false : status.isRead()); + entry.setRead(status.isRead()); - return entry; - } + entry.setFeedName(status.getSubscription().getTitle()); + entry.setFeedId(String.valueOf(status.getSubscription().getId())); - private Entry populateEntry(Entry entry, FeedSubscription sub) { - entry.setFeedName(sub.getTitle()); - entry.setFeedId(String.valueOf(sub.getId())); return entry; } @@ -181,70 +122,40 @@ public class EntriesREST extends AbstractREST { Preconditions.checkNotNull(read); if (type == Type.entry) { - FeedEntry entry = feedEntryService.findById(Long.valueOf(id)); - markEntry(entry, read); + FeedEntryStatus status = feedEntryStatusService.findById(getUser(), + Long.valueOf(id)); + status.setRead(read); + feedEntryStatusService.update(status); } else if (type == Type.feed) { if (read) { - Feed feed = feedSubscriptionService.findById(Long.valueOf(id)) - .getFeed(); - List entries = feedEntryService - .getEntries(feed, getUser(), true); - for (FeedEntryWithStatus entry : entries) { - markEntry(entry, read); - } + FeedSubscription subscription = feedSubscriptionService + .findById(getUser(), Long.valueOf(id)); + feedEntryStatusService.markFeedEntries(getUser(), + subscription.getFeed()); } else { - return Response.status(Status.FORBIDDEN) - .entity("Operation not supported").build(); + throw new WebApplicationException(Response.status( + Status.INTERNAL_SERVER_ERROR).build()); } } else if (type == Type.category) { if (read) { - List entries = null; - if (ALL.equals(id)) { - entries = feedEntryService.getEntries(getUser(), true); + feedEntryStatusService.markAllEntries(getUser()); } else { - FeedCategory feedCategory = feedCategoryService.findById( - getUser(), Long.valueOf(id)); - List childrenCategories = feedCategoryService - .findAllChildrenCategories(getUser(), feedCategory); - - entries = feedEntryService.getEntries(childrenCategories, - getUser(), true); - } - for (FeedEntryWithStatus entry : entries) { - markEntry(entry, read); + List categories = feedCategoryService + .findAllChildrenCategories(getUser(), + feedCategoryService.findById(getUser(), + Long.valueOf(id))); + feedEntryStatusService.markCategoryEntries(getUser(), + categories); } } else { - return Response.status(Status.FORBIDDEN) - .entity("Operation not supported").build(); + throw new WebApplicationException(Response.status( + Status.INTERNAL_SERVER_ERROR).build()); } } return Response.ok(Status.OK).build(); } - private void markEntry(FeedEntry entry, boolean read) { - FeedEntryStatus status = feedEntryStatusService.getStatus(getUser(), - entry); - if (status == null) { - status = new FeedEntryStatus(); - status.setUser(getUser()); - status.setEntry(entry); - } - status.setRead(read); - feedEntryStatusService.saveOrUpdate(status); - } - - private void markEntry(FeedEntryWithStatus entryWithStatus, boolean read) { - FeedEntryStatus status = entryWithStatus.getStatus(); - if (status == null) { - status = new FeedEntryStatus(); - status.setUser(getUser()); - status.setEntry(entryWithStatus.getEntry()); - } - status.setRead(read); - feedEntryStatusService.saveOrUpdate(status); - } - @Path("search") @GET public Entries searchEntries(@QueryParam("keywords") String keywords) { @@ -252,27 +163,11 @@ public class EntriesREST extends AbstractREST { Entries entries = new Entries(); - List subs = feedSubscriptionService - .findAll(getUser()); - Map subMapping = Maps.uniqueIndex(subs, - new Function() { - public Long apply(FeedSubscription sub) { - return sub.getFeed().getId(); - } - }); - List list = Lists.newArrayList(); - List entriesWithStatus = feedEntryService - .getEntriesByKeywords(getUser(), keywords); - for (FeedEntryWithStatus feedEntry : entriesWithStatus) { - FeedSubscription sub = null; - for (Feed feed : feedEntry.getEntry().getFeeds()) { - sub = subMapping.get(feed.getId()); - if (sub != null) { - break; - } - } - list.add(populateEntry(buildEntry(feedEntry), sub)); + List entriesStatus = feedEntryStatusService + .getStatusesByKeywords(getUser(), keywords); + for (FeedEntryStatus status : entriesStatus) { + list.add(buildEntry(status)); } entries.setName("Search for : " + keywords); diff --git a/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java b/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java index 3609e14c..3c6ba5b4 100644 --- a/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java +++ b/src/main/java/com/commafeed/frontend/rest/resources/SubscriptionsREST.java @@ -3,6 +3,7 @@ package com.commafeed.frontend.rest.resources; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -164,16 +165,19 @@ public class SubscriptionsREST extends AbstractREST { List categories = feedCategoryService.findAll(getUser()); List subscriptions = feedSubscriptionService .findAll(getUser()); + Map unreadCount = feedEntryStatusService + .getUnreadCount(getUser()); - Category root = buildCategory(null, categories, subscriptions); + Category root = buildCategory(null, categories, subscriptions, + unreadCount); root.setId("all"); root.setName("All"); return root; } - Category buildCategory(Long id, List categories, - List subscriptions) { + private Category buildCategory(Long id, List categories, + List subscriptions, Map unreadCount) { Category category = new Category(); category.setId(String.valueOf(id)); category.setExpanded(true); @@ -183,7 +187,7 @@ public class SubscriptionsREST extends AbstractREST { || (c.getParent() != null && ObjectUtils.equals(c .getParent().getId(), id))) { Category child = buildCategory(c.getId(), categories, - subscriptions); + subscriptions, unreadCount); child.setId(String.valueOf(c.getId())); child.setName(c.getName()); child.setExpanded(!c.isCollapsed()); @@ -206,9 +210,8 @@ public class SubscriptionsREST extends AbstractREST { sub.setName(subscription.getTitle()); sub.setMessage(subscription.getFeed().getMessage()); sub.setFeedUrl(subscription.getFeed().getLink()); - long size = feedEntryService.getUnreadCount( - subscription.getFeed(), getUser()); - sub.setUnread(size); + Long size = unreadCount.get(subscription.getId()); + sub.setUnread(size == null ? 0 : size); category.getFeeds().add(sub); } } diff --git a/src/main/resources/META-INF/orm.xml b/src/main/resources/META-INF/orm.xml index 5c112453..4ef8ea9d 100644 --- a/src/main/resources/META-INF/orm.xml +++ b/src/main/resources/META-INF/orm.xml @@ -10,34 +10,39 @@ - select DISTINCT e from FeedEntry e LEFT JOIN FETCH e.feeds where e.guid in (:guids) order by e.updated desc + select DISTINCT e from FeedEntry e JOIN FETCH e.feeds where e.guid in (:guids) - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed member of e.feeds) and not exists (select s3 from FeedEntryStatus s3 where s3.entry = e and s3.user =:user and s3.read=true) order by e.updated desc - - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId)LEFT JOIN FETCH e.feeds where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed member of e.feeds) order by e.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user and s.id=:id - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where :feed member of e.feeds and not exists (select s2 from FeedEntryStatus s2 where s2.entry=e and s2.user.id=:userId and s2.read=true) order by e.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user and s.read=false order by s.entry.updated desc - - select count(e) from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) where :feed member of e.feeds and not exists (select s2 from FeedEntryStatus s2 where s2.entry=e and s2.user.id=:userId and s2.read=true) - - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where :feed member of e.feeds order by e.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user order by s.entry.updated desc - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed member of e.feeds and s2.category in (:categories) ) and not exists (select s3 from FeedEntryStatus s3 where s3.entry = e and s3.user =:user and s3.read=true) order by e.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.feed=:feed and s.read=false order by s.entry.updated desc - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed member of e.feeds and s2.category in (:categories) ) order by e.updated desc + + select s.subscription.id, count(s) from FeedEntryStatus s where s.subscription.user=:user and s.read=false group by s.subscription.id + + + select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.feed=:feed order by s.entry.updated desc - - select e, s from FeedEntry e LEFT JOIN e.statuses s WITH (s.user.id=:userId) LEFT JOIN FETCH e.feeds where exists (select s2 from FeedSubscription s2 where s2.user=:user and s2.feed member of e.feeds) and (lower(e.content) like :keywords or lower(e.title) like :keywords) order by e.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.category in (:categories) and s.read=false order by s.entry.updated desc + + select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.category in (:categories) order by s.entry.updated desc + + + + select s from FeedEntryStatus s where s.subscription.user=:user and (lower(s.entry.content) like :keywords or lower(s.entry.title) like :keywords) order by s.entry.updated desc + + \ No newline at end of file diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index 6cb94b87..d39e6a5a 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -5,11 +5,12 @@ http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> - org.hibernate.ejb.HibernatePersistence + org.hibernate.ejb.HibernatePersistence ${jpa.datasource.name} + \ No newline at end of file