forked from Archives/Athou_commafeed
refactor into a service
This commit is contained in:
@@ -1,14 +1,13 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import org.apache.commons.jexl2.JexlContext;
|
import org.apache.commons.jexl2.JexlContext;
|
||||||
import org.apache.commons.jexl2.JexlEngine;
|
import org.apache.commons.jexl2.JexlEngine;
|
||||||
import org.apache.commons.jexl2.JexlException;
|
import org.apache.commons.jexl2.JexlException;
|
||||||
@@ -25,8 +24,7 @@ import org.jsoup.Jsoup;
|
|||||||
|
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
public class FeedEntryFilteringService {
|
||||||
public class FeedEntryFilter {
|
|
||||||
|
|
||||||
private static final JexlEngine ENGINE = initEngine();
|
private static final JexlEngine ENGINE = initEngine();
|
||||||
|
|
||||||
@@ -69,9 +67,9 @@ public class FeedEntryFilter {
|
|||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String filter;
|
private ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
public boolean matchesEntry(FeedEntry entry) throws FeedEntryFilterException {
|
public boolean filterMatchesEntry(String filter, FeedEntry entry) throws FeedEntryFilterException {
|
||||||
if (StringUtils.isBlank(filter)) {
|
if (StringUtils.isBlank(filter)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -90,7 +88,7 @@ public class FeedEntryFilter {
|
|||||||
context.set("url", entry.getUrl().toLowerCase());
|
context.set("url", entry.getUrl().toLowerCase());
|
||||||
|
|
||||||
Callable<Object> callable = script.callable(context);
|
Callable<Object> callable = script.callable(context);
|
||||||
Future<Object> future = Executors.newFixedThreadPool(1).submit(callable);
|
Future<Object> future = executor.submit(callable);
|
||||||
Object result = null;
|
Object result = null;
|
||||||
try {
|
try {
|
||||||
result = future.get(500, TimeUnit.MILLISECONDS);
|
result = future.get(500, TimeUnit.MILLISECONDS);
|
||||||
@@ -13,13 +13,12 @@ import org.apache.commons.codec.digest.DigestUtils;
|
|||||||
|
|
||||||
import com.commafeed.backend.dao.FeedEntryDAO;
|
import com.commafeed.backend.dao.FeedEntryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter;
|
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryContent;
|
import com.commafeed.backend.model.FeedEntryContent;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
|
import com.commafeed.backend.service.FeedEntryFilteringService.FeedEntryFilterException;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||||
@@ -29,6 +28,7 @@ public class FeedUpdateService {
|
|||||||
private final FeedEntryDAO feedEntryDAO;
|
private final FeedEntryDAO feedEntryDAO;
|
||||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||||
private final FeedEntryContentService feedEntryContentService;
|
private final FeedEntryContentService feedEntryContentService;
|
||||||
|
private final FeedEntryFilteringService feedEntryFilteringService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this is NOT thread-safe
|
* this is NOT thread-safe
|
||||||
@@ -49,10 +49,9 @@ public class FeedUpdateService {
|
|||||||
|
|
||||||
// if filter does not match the entry, mark it as read
|
// if filter does not match the entry, mark it as read
|
||||||
for (FeedSubscription sub : subscriptions) {
|
for (FeedSubscription sub : subscriptions) {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter(sub.getFilter());
|
|
||||||
boolean matches = true;
|
boolean matches = true;
|
||||||
try {
|
try {
|
||||||
matches = filter.matchesEntry(entry);
|
matches = feedEntryFilteringService.filterMatchesEntry(sub.getFilter(), entry);
|
||||||
} catch (FeedEntryFilterException e) {
|
} catch (FeedEntryFilterException e) {
|
||||||
log.error("could not evaluate filter {}", sub.getFilter(), e);
|
log.error("could not evaluate filter {}", sub.getFilter(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ import com.commafeed.backend.cache.CacheService;
|
|||||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter;
|
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
|
||||||
import com.commafeed.backend.feed.FeedEntryKeyword;
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
import com.commafeed.backend.feed.FeedFetcher;
|
import com.commafeed.backend.feed.FeedFetcher;
|
||||||
import com.commafeed.backend.feed.FeedQueues;
|
import com.commafeed.backend.feed.FeedQueues;
|
||||||
@@ -62,6 +60,8 @@ import com.commafeed.backend.model.UserSettings.ReadingMode;
|
|||||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||||
import com.commafeed.backend.opml.OPMLExporter;
|
import com.commafeed.backend.opml.OPMLExporter;
|
||||||
import com.commafeed.backend.opml.OPMLImporter;
|
import com.commafeed.backend.opml.OPMLImporter;
|
||||||
|
import com.commafeed.backend.service.FeedEntryFilteringService;
|
||||||
|
import com.commafeed.backend.service.FeedEntryFilteringService.FeedEntryFilterException;
|
||||||
import com.commafeed.backend.service.FeedEntryService;
|
import com.commafeed.backend.service.FeedEntryService;
|
||||||
import com.commafeed.backend.service.FeedService;
|
import com.commafeed.backend.service.FeedService;
|
||||||
import com.commafeed.backend.service.FeedSubscriptionService;
|
import com.commafeed.backend.service.FeedSubscriptionService;
|
||||||
@@ -119,6 +119,7 @@ public class FeedREST {
|
|||||||
private final FeedService feedService;
|
private final FeedService feedService;
|
||||||
private final FeedEntryService feedEntryService;
|
private final FeedEntryService feedEntryService;
|
||||||
private final FeedSubscriptionService feedSubscriptionService;
|
private final FeedSubscriptionService feedSubscriptionService;
|
||||||
|
private final FeedEntryFilteringService feedEntryFilteringService;
|
||||||
private final FeedQueues queues;
|
private final FeedQueues queues;
|
||||||
private final OPMLImporter opmlImporter;
|
private final OPMLImporter opmlImporter;
|
||||||
private final OPMLExporter opmlExporter;
|
private final OPMLExporter opmlExporter;
|
||||||
@@ -440,7 +441,7 @@ public class FeedREST {
|
|||||||
Preconditions.checkNotNull(req.getId());
|
Preconditions.checkNotNull(req.getId());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new FeedEntryFilter(req.getFilter()).matchesEntry(TEST_ENTRY);
|
feedEntryFilteringService.filterMatchesEntry(req.getFilter(), TEST_ENTRY);
|
||||||
} catch (FeedEntryFilterException e) {
|
} catch (FeedEntryFilterException e) {
|
||||||
Throwable root = Throwables.getRootCause(e);
|
Throwable root = Throwables.getRootCause(e);
|
||||||
return Response.status(Status.BAD_REQUEST).entity(root.getMessage()).build();
|
return Response.status(Status.BAD_REQUEST).entity(root.getMessage()).build();
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.service;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedEntryFilter.FeedEntryFilterException;
|
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.FeedEntryContent;
|
import com.commafeed.backend.model.FeedEntryContent;
|
||||||
|
import com.commafeed.backend.service.FeedEntryFilteringService.FeedEntryFilterException;
|
||||||
|
|
||||||
public class FeedEntryFilterTest {
|
public class FeedEntryFilteringServiceTest {
|
||||||
|
|
||||||
|
private FeedEntryFilteringService service;
|
||||||
|
|
||||||
private FeedEntry entry;
|
private FeedEntry entry;
|
||||||
private FeedEntryContent content;
|
private FeedEntryContent content;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
|
service = new FeedEntryFilteringService();
|
||||||
|
|
||||||
entry = new FeedEntry();
|
entry = new FeedEntry();
|
||||||
entry.setUrl("https://github.com/Athou/commafeed");
|
entry.setUrl("https://github.com/Athou/commafeed");
|
||||||
|
|
||||||
@@ -28,44 +32,37 @@ public class FeedEntryFilterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void emptyFilterMatchesFilter() throws FeedEntryFilterException {
|
public void emptyFilterMatchesFilter() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter(null);
|
Assert.assertTrue(service.filterMatchesEntry(null, entry));
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blankFilterMatchesFilter() throws FeedEntryFilterException {
|
public void blankFilterMatchesFilter() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("");
|
Assert.assertTrue(service.filterMatchesEntry("", entry));
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleExpression() throws FeedEntryFilterException {
|
public void simpleExpression() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("author eq 'athou'");
|
Assert.assertTrue(service.filterMatchesEntry("author eq 'athou'", entry));
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FeedEntryFilterException.class)
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
public void newIsDisabled() throws FeedEntryFilterException {
|
public void newIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq new ('java.lang.String', 'athou')");
|
service.filterMatchesEntry("null eq new ('java.lang.String', 'athou')", entry);
|
||||||
filter.matchesEntry(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FeedEntryFilterException.class)
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
public void getClassMethodIsDisabled() throws FeedEntryFilterException {
|
public void getClassMethodIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.getClass()");
|
service.filterMatchesEntry("null eq ''.getClass()", entry);
|
||||||
filter.matchesEntry(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dotClassIsDisabled() throws FeedEntryFilterException {
|
public void dotClassIsDisabled() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("null eq ''.class");
|
Assert.assertTrue(service.filterMatchesEntry("null eq ''.class", entry));
|
||||||
Assert.assertTrue(filter.matchesEntry(entry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FeedEntryFilterException.class)
|
@Test(expected = FeedEntryFilterException.class)
|
||||||
public void cannotLoopForever() throws FeedEntryFilterException {
|
public void cannotLoopForever() throws FeedEntryFilterException {
|
||||||
FeedEntryFilter filter = new FeedEntryFilter("while(true) {}");
|
service.filterMatchesEntry("while(true) {}", entry);
|
||||||
filter.matchesEntry(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user