major improvement in the way data is stored

This commit is contained in:
Athou
2013-04-08 13:06:53 +02:00
parent 028982477e
commit cf7d4cce9c
14 changed files with 274 additions and 407 deletions

View File

@@ -19,7 +19,11 @@ import com.uaihebert.model.EasyCriteria;
public class FeedCategoryService extends GenericDAO<FeedCategory> {
public List<FeedCategory> findAll(User user) {
return findByField(MF.i(MF.p(FeedCategory.class).getUser()), user);
EasyCriteria<FeedCategory> 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) {

View File

@@ -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<FeedEntry> {
FeedSubscriptionService feedSubscriptionService;
public void updateEntries(String url, Collection<FeedEntry> entries) {
Feed feed = Iterables.getFirst(
feedService.findByField(MF.i(MF.p(Feed.class).getUrl()), url),
null);
Feed feed = feedService.findByUrl(url);
List<String> guids = Lists.newArrayList();
for (FeedEntry entry : entries) {
guids.add(entry.getGuid());
@@ -56,7 +46,6 @@ public class FeedEntryService extends GenericDAO<FeedEntry> {
}
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<FeedEntry> {
if (!foundFeed) {
addFeedToEntry(foundEntry, feed);
update(foundEntry);
}
}
}
@@ -80,12 +68,13 @@ public class FeedEntryService extends GenericDAO<FeedEntry> {
private void addFeedToEntry(FeedEntry entry, Feed feed) {
entry.getFeeds().add(feed);
saveOrUpdate(entry);
List<FeedSubscription> 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<FeedEntry> {
return query.getResultList();
}
public List<FeedEntryWithStatus> getEntriesByKeywords(User user,
String keywords) {
return getEntriesByKeywords(user, keywords, -1, -1);
}
public List<FeedEntryWithStatus> 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<FeedEntryWithStatus> getEntries(User user, boolean unreadOnly) {
return getEntries(user, unreadOnly, -1, -1);
}
public List<FeedEntryWithStatus> 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<Long> query = em.createNamedQuery("Entry.unreadByFeedCount",
Long.class);
query.setParameter("feed", feed);
query.setParameter("userId", user.getId());
return query.getSingleResult();
}
public List<FeedEntryWithStatus> getEntries(Feed feed, User user,
boolean unreadOnly) {
return getEntries(feed, user, unreadOnly, -1, -1);
}
public List<FeedEntryWithStatus> 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<FeedEntryWithStatus> getEntries(List<FeedCategory> categories,
User user, boolean unreadOnly) {
return getEntries(categories, user, unreadOnly, -1, -1);
}
public List<FeedEntryWithStatus> getEntries(List<FeedCategory> 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<FeedEntryWithStatus> buildList(List list) {
Set<FeedEntryWithStatus> 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);
}
}

View File

@@ -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<FeedEntryStatus> {
public List<FeedEntryStatus> findAll(User user) {
return findByField(MF.i(proxy().getUser()), user);
}
@Inject
FeedCategoryService feedCategoryService;
public FeedEntryStatus getStatus(User user, FeedEntry entry) {
EasyCriteria<FeedEntryStatus> 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<FeedEntryStatus> 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<FeedEntryStatus> getStatusesByKeywords(User user,
String keywords) {
return getStatusesByKeywords(user, keywords, -1, -1);
}
public List<FeedEntryStatus> getStatusesByKeywords(User user,
String keywords, int offset, int limit) {
TypedQuery<FeedEntryStatus> 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<FeedEntryStatus> getStatuses(User user, boolean unreadOnly) {
return getStatuses(user, unreadOnly, -1, -1);
}
public List<FeedEntryStatus> getStatuses(User user, boolean unreadOnly,
int offset, int limit) {
String queryName = unreadOnly ? "EntryStatus.unread"
: "EntryStatus.all";
TypedQuery<FeedEntryStatus> 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<Long, Long> getUnreadCount(User user) {
Map<Long, Long> 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<FeedEntryStatus> getStatuses(Feed feed, User user,
boolean unreadOnly) {
return getStatuses(feed, user, unreadOnly, -1, -1);
}
public List<FeedEntryStatus> getStatuses(Feed feed, User user,
boolean unreadOnly, int offset, int limit) {
String queryName = unreadOnly ? "EntryStatus.unreadByFeed"
: "EntryStatus.allByFeed";
TypedQuery<FeedEntryStatus> 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<FeedEntryStatus> getStatuses(List<FeedCategory> categories,
User user, boolean unreadOnly) {
return getStatuses(categories, user, unreadOnly, -1, -1);
}
public List<FeedEntryStatus> getStatuses(List<FeedCategory> categories,
User user, boolean unreadOnly, int offset, int limit) {
String queryName = unreadOnly ? "EntryStatus.unreadByCategories"
: "EntryStatus.allByCategories";
TypedQuery<FeedEntryStatus> 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<FeedEntryStatus> statuses = getStatuses(feed, user, true);
update(markList(statuses));
}
public void markCategoryEntries(User user, List<FeedCategory> categories) {
List<FeedEntryStatus> statuses = getStatuses(categories, user, true);
update(markList(statuses));
}
public void markAllEntries(User user) {
List<FeedEntryStatus> statuses = getStatuses(user, true);
update(markList(statuses));
}
private List<FeedEntryStatus> markList(List<FeedEntryStatus> statuses) {
List<FeedEntryStatus> list = Lists.newArrayList();
for (FeedEntryStatus status : statuses) {
if (!status.isRead()) {
status.setRead(true);
list.add(status);
}
}
return list;
}
}

View File

@@ -41,7 +41,13 @@ public class FeedSubscriptionService extends GenericDAO<FeedSubscription> {
}
public List<FeedSubscription> findAll(User user) {
return findByField(MF.i(proxy().getUser()), user);
EasyCriteria<FeedSubscription> 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<FeedSubscription> findWithoutCategories(User user) {

View File

@@ -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<T extends AbstractModel> implements
em.persist(object);
}
public void update(T... objects) {
public void update(List<T> 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);

View File

@@ -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() {

View File

@@ -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;
}
}

View File

@@ -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()));

View File

@@ -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<Role> 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;
}
}

View File

@@ -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));

View File

@@ -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<FeedEntryStatus> unreadEntries = feedEntryStatusService
.getStatuses(subscription.getFeed(), getUser(),
unreadOnly, offset, limit);
for (FeedEntryStatus status : unreadEntries) {
entries.getEntries().add(buildEntry(status));
}
}
} else {
List<FeedSubscription> subs = feedSubscriptionService
.findAll(getUser());
Map<Long, FeedSubscription> subMapping = Maps.uniqueIndex(subs,
new Function<FeedSubscription, Long>() {
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<FeedEntryStatus> 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<FeedCategory> childrenCategories = feedCategoryService
.findAllChildrenCategories(getUser(), feedCategory);
entries.getEntries().addAll(
buildEntries(childrenCategories, subMapping,
offset, limit, unreadOnly));
List<FeedEntryStatus> 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<Entry> buildEntries(Map<Long, FeedSubscription> subMapping,
int offset, int limit, boolean unreadOnly) {
List<Entry> entries = Lists.newArrayList();
List<FeedEntryWithStatus> 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<Entry> buildEntries(FeedSubscription subscription, int offset,
int limit, boolean unreadOnly) {
List<Entry> entries = Lists.newArrayList();
List<FeedEntryWithStatus> unreadEntries = feedEntryService.getEntries(
subscription.getFeed(), getUser(), unreadOnly, offset, limit);
for (FeedEntryWithStatus feedEntry : unreadEntries) {
entries.add(populateEntry(buildEntry(feedEntry), subscription));
}
return entries;
}
private List<Entry> buildEntries(List<FeedCategory> categories,
Map<Long, FeedSubscription> subMapping, int offset, int limit,
boolean unreadOnly) {
List<Entry> entries = Lists.newArrayList();
List<FeedEntryWithStatus> 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<FeedEntryWithStatus> 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<FeedEntryWithStatus> entries = null;
if (ALL.equals(id)) {
entries = feedEntryService.getEntries(getUser(), true);
feedEntryStatusService.markAllEntries(getUser());
} else {
FeedCategory feedCategory = feedCategoryService.findById(
getUser(), Long.valueOf(id));
List<FeedCategory> childrenCategories = feedCategoryService
.findAllChildrenCategories(getUser(), feedCategory);
entries = feedEntryService.getEntries(childrenCategories,
getUser(), true);
}
for (FeedEntryWithStatus entry : entries) {
markEntry(entry, read);
List<FeedCategory> 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<FeedSubscription> subs = feedSubscriptionService
.findAll(getUser());
Map<Long, FeedSubscription> subMapping = Maps.uniqueIndex(subs,
new Function<FeedSubscription, Long>() {
public Long apply(FeedSubscription sub) {
return sub.getFeed().getId();
}
});
List<Entry> list = Lists.newArrayList();
List<FeedEntryWithStatus> 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<FeedEntryStatus> entriesStatus = feedEntryStatusService
.getStatusesByKeywords(getUser(), keywords);
for (FeedEntryStatus status : entriesStatus) {
list.add(buildEntry(status));
}
entries.setName("Search for : " + keywords);

View File

@@ -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<FeedCategory> categories = feedCategoryService.findAll(getUser());
List<FeedSubscription> subscriptions = feedSubscriptionService
.findAll(getUser());
Map<Long, Long> 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<FeedCategory> categories,
List<FeedSubscription> subscriptions) {
private Category buildCategory(Long id, List<FeedCategory> categories,
List<FeedSubscription> subscriptions, Map<Long, Long> 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);
}
}

View File

@@ -10,34 +10,39 @@
</named-query>
<named-query name="Entry.byGuids">
<query>select DISTINCT e from FeedEntry e LEFT JOIN FETCH e.feeds where e.guid in (:guids) order by e.updated desc</query>
<query>select DISTINCT e from FeedEntry e JOIN FETCH e.feeds where e.guid in (:guids)</query>
</named-query>
<named-query name="Entry.unread">
<query>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</query>
</named-query>
<named-query name="Entry.all">
<query>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</query>
<named-query name="EntryStatus.byId">
<query>select s from FeedEntryStatus s where s.subscription.user=:user and s.id=:id</query>
</named-query>
<named-query name="Entry.unreadByFeed">
<query>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</query>
<named-query name="EntryStatus.unread">
<query>select s from FeedEntryStatus s where s.subscription.user=:user and s.read=false order by s.entry.updated desc</query>
</named-query>
<named-query name="Entry.unreadByFeedCount">
<query>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)</query>
</named-query>
<named-query name="Entry.allByFeed">
<query>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</query>
<named-query name="EntryStatus.all">
<query>select s from FeedEntryStatus s where s.subscription.user=:user order by s.entry.updated desc</query>
</named-query>
<named-query name="Entry.unreadByCategories">
<query>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</query>
<named-query name="EntryStatus.unreadByFeed">
<query>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</query>
</named-query>
<named-query name="Entry.allByCategories">
<query>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</query>
<named-query name="EntryStatus.unreadCounts">
<query>select s.subscription.id, count(s) from FeedEntryStatus s where s.subscription.user=:user and s.read=false group by s.subscription.id</query>
</named-query>
<named-query name="EntryStatus.allByFeed">
<query>select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.feed=:feed order by s.entry.updated desc</query>
</named-query>
<named-query name="Entry.allByKeywords">
<query>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</query>
<named-query name="EntryStatus.unreadByCategories">
<query>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</query>
</named-query>
<named-query name="EntryStatus.allByCategories">
<query>select s from FeedEntryStatus s where s.subscription.user=:user and s.subscription.category in (:categories) order by s.entry.updated desc</query>
</named-query>
<named-query name="EntryStatus.allByKeywords">
<query>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</query>
</named-query>
</entity-mappings>

View File

@@ -5,11 +5,12 @@
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>${jpa.datasource.name}</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="${jpa.show_sql}" />
<property name="hibernate.default_batch_fetch_size" value="100" />
</properties>
</persistence-unit>
</persistence>