initial support for entry filtering

This commit is contained in:
Athou
2014-11-04 11:23:58 +01:00
parent 7151db0909
commit 5f28fd4114
8 changed files with 193 additions and 3 deletions

View File

@@ -0,0 +1,89 @@
package com.commafeed.backend.feed;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.JexlInfo;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.jexl2.introspection.JexlMethod;
import org.apache.commons.jexl2.introspection.JexlPropertyGet;
import org.apache.commons.jexl2.introspection.Uberspect;
import org.apache.commons.jexl2.introspection.UberspectImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.LogFactory;
import com.commafeed.backend.model.FeedEntry;
@RequiredArgsConstructor
public class FeedEntryFilter {
private static final JexlEngine ENGINE = initEngine();
private static JexlEngine initEngine() {
// classloader that prevents object creation
ClassLoader cl = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return null;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
return null;
}
};
// uberspect that prevents access to .class and .getClass()
Uberspect uberspect = new UberspectImpl(LogFactory.getLog(JexlEngine.class)) {
@Override
public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) {
if ("class".equals(identifier)) {
return null;
}
return super.getPropertyGet(obj, identifier, info);
}
@Override
public JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info) {
if ("getClass".equals(method)) {
return null;
}
return super.getMethod(obj, method, args, info);
}
};
JexlEngine engine = new JexlEngine(uberspect, null, null, null);
engine.setClassLoader(cl);
return engine;
}
private final String filter;
public boolean matchesEntry(FeedEntry entry) {
if (StringUtils.isBlank(filter)) {
return true;
}
Expression expression = ENGINE.createExpression(filter);
JexlContext context = new MapContext();
context.set("title", entry.getContent().getTitle().toLowerCase());
context.set("author", entry.getContent().getAuthor().toLowerCase());
context.set("content", entry.getContent().getContent().toLowerCase());
context.set("url", entry.getUrl().toLowerCase());
return (boolean) expression.evaluate(context);
}
@Data
private static class Model {
private String title;
private String author;
private String content;
private String url;
}
}

View File

@@ -193,7 +193,7 @@ public class FeedRefreshUpdater implements Managed {
boolean inserted = new UnitOfWork<Boolean>(sessionFactory) {
@Override
protected Boolean runInSession() throws Exception {
return feedUpdateService.addEntry(feed, entry);
return feedUpdateService.addEntry(feed, entry, subscriptions);
}
}.run();
if (inserted) {

View File

@@ -40,4 +40,7 @@ public class FeedSubscription extends AbstractModel {
private Integer position;
@Column(length = 4096)
private String filter = "author.contains('a')";
}

View File

@@ -1,6 +1,7 @@
package com.commafeed.backend.service;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -10,21 +11,26 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
import com.commafeed.backend.dao.FeedEntryDAO;
import com.commafeed.backend.dao.FeedEntryStatusDAO;
import com.commafeed.backend.feed.FeedEntryFilter;
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryContent;
import com.commafeed.backend.model.FeedEntryStatus;
import com.commafeed.backend.model.FeedSubscription;
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class FeedUpdateService {
private final FeedEntryDAO feedEntryDAO;
private final FeedEntryStatusDAO feedEntryStatusDAO;
private final FeedEntryContentService feedEntryContentService;
/**
* this is NOT thread-safe
*/
public boolean addEntry(Feed feed, FeedEntry entry) {
public boolean addEntry(Feed feed, FeedEntry entry, List<FeedSubscription> subscriptions) {
Long existing = feedEntryDAO.findExisting(entry.getGuid(), feed);
if (existing != null) {
@@ -36,8 +42,18 @@ public class FeedUpdateService {
entry.setContent(content);
entry.setInserted(new Date());
entry.setFeed(feed);
feedEntryDAO.saveOrUpdate(entry);
// if filter does not match the entry, mark it as read
for (FeedSubscription sub : subscriptions) {
FeedEntryFilter filter = new FeedEntryFilter(sub.getFilter());
if (!filter.matchesEntry(entry)) {
FeedEntryStatus status = new FeedEntryStatus(sub.getUser(), sub, entry);
status.setRead(true);
feedEntryStatusDAO.saveOrUpdate(status);
}
}
return true;
}
}