mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
unit of work refactoring
This commit is contained in:
@@ -5,17 +5,26 @@ import org.hibernate.SessionFactory;
|
|||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.context.internal.ManagedSessionContext;
|
import org.hibernate.context.internal.ManagedSessionContext;
|
||||||
|
|
||||||
public abstract class UnitOfWork<T> {
|
public class UnitOfWork {
|
||||||
|
|
||||||
private SessionFactory sessionFactory;
|
@FunctionalInterface
|
||||||
|
public static interface SessionRunner {
|
||||||
public UnitOfWork(SessionFactory sessionFactory) {
|
public void runInSession();
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract T runInSession() throws Exception;
|
@FunctionalInterface
|
||||||
|
public static interface SessionRunnerReturningValue<T> {
|
||||||
|
public T runInSession();
|
||||||
|
}
|
||||||
|
|
||||||
public T run() {
|
public static void run(SessionFactory sessionFactory, SessionRunner sessionRunner) {
|
||||||
|
run(sessionFactory, () -> {
|
||||||
|
sessionRunner.runInSession();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T run(SessionFactory sessionFactory, SessionRunnerReturningValue<T> sessionRunner) {
|
||||||
final Session session = sessionFactory.openSession();
|
final Session session = sessionFactory.openSession();
|
||||||
if (ManagedSessionContext.hasBind(sessionFactory)) {
|
if (ManagedSessionContext.hasBind(sessionFactory)) {
|
||||||
throw new IllegalStateException("Already in a unit of work!");
|
throw new IllegalStateException("Already in a unit of work!");
|
||||||
@@ -25,11 +34,11 @@ public abstract class UnitOfWork<T> {
|
|||||||
ManagedSessionContext.bind(session);
|
ManagedSessionContext.bind(session);
|
||||||
session.beginTransaction();
|
session.beginTransaction();
|
||||||
try {
|
try {
|
||||||
t = runInSession();
|
t = sessionRunner.runInSession();
|
||||||
commitTransaction(session);
|
commitTransaction(session);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
rollbackTransaction(session);
|
rollbackTransaction(session);
|
||||||
this.<RuntimeException> rethrow(e);
|
UnitOfWork.<RuntimeException> rethrow(e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
session.close();
|
||||||
@@ -38,14 +47,14 @@ public abstract class UnitOfWork<T> {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rollbackTransaction(Session session) {
|
private static void rollbackTransaction(Session session) {
|
||||||
final Transaction txn = session.getTransaction();
|
final Transaction txn = session.getTransaction();
|
||||||
if (txn != null && txn.isActive()) {
|
if (txn != null && txn.isActive()) {
|
||||||
txn.rollback();
|
txn.rollback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commitTransaction(Session session) {
|
private static void commitTransaction(Session session) {
|
||||||
final Transaction txn = session.getTransaction();
|
final Transaction txn = session.getTransaction();
|
||||||
if (txn != null && txn.isActive()) {
|
if (txn != null && txn.isActive()) {
|
||||||
txn.commit();
|
txn.commit();
|
||||||
@@ -53,7 +62,7 @@ public abstract class UnitOfWork<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <E extends Exception> void rethrow(Exception e) throws E {
|
private static <E extends Exception> void rethrow(Exception e) throws E {
|
||||||
throw (E) e;
|
throw (E) e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,12 +68,7 @@ public class FeedRefreshTaskGiver implements Managed {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (!executor.isShutdown()) {
|
while (!executor.isShutdown()) {
|
||||||
try {
|
try {
|
||||||
FeedRefreshContext context = new UnitOfWork<FeedRefreshContext>(sessionFactory) {
|
FeedRefreshContext context = UnitOfWork.run(sessionFactory, () -> queues.take());
|
||||||
@Override
|
|
||||||
protected FeedRefreshContext runInSession() throws Exception {
|
|
||||||
return queues.take();
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
feedRefreshed.mark();
|
feedRefreshed.mark();
|
||||||
worker.updateFeed(context);
|
worker.updateFeed(context);
|
||||||
|
|||||||
@@ -120,12 +120,7 @@ public class FeedRefreshUpdater implements Managed {
|
|||||||
if (!lastEntries.contains(cacheKey)) {
|
if (!lastEntries.contains(cacheKey)) {
|
||||||
log.debug("cache miss for {}", entry.getUrl());
|
log.debug("cache miss for {}", entry.getUrl());
|
||||||
if (subscriptions == null) {
|
if (subscriptions == null) {
|
||||||
subscriptions = new UnitOfWork<List<FeedSubscription>>(sessionFactory) {
|
subscriptions = UnitOfWork.run(sessionFactory, () -> feedSubscriptionDAO.findByFeed(feed));
|
||||||
@Override
|
|
||||||
protected List<FeedSubscription> runInSession() throws Exception {
|
|
||||||
return feedSubscriptionDAO.findByFeed(feed);
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
}
|
}
|
||||||
ok &= addEntry(feed, entry, subscriptions);
|
ok &= addEntry(feed, entry, subscriptions);
|
||||||
entryCacheMiss.mark();
|
entryCacheMiss.mark();
|
||||||
@@ -190,12 +185,7 @@ public class FeedRefreshUpdater implements Managed {
|
|||||||
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
||||||
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
||||||
if (locked1 && locked2) {
|
if (locked1 && locked2) {
|
||||||
boolean inserted = new UnitOfWork<Boolean>(sessionFactory) {
|
boolean inserted = UnitOfWork.run(sessionFactory, () -> feedUpdateService.addEntry(feed, entry, subscriptions));
|
||||||
@Override
|
|
||||||
protected Boolean runInSession() throws Exception {
|
|
||||||
return feedUpdateService.addEntry(feed, entry, subscriptions);
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
if (inserted) {
|
if (inserted) {
|
||||||
entryInserted.mark();
|
entryInserted.mark();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import com.commafeed.backend.dao.FeedEntryDAO;
|
|||||||
import com.commafeed.backend.dao.FeedEntryDAO.FeedCapacity;
|
import com.commafeed.backend.dao.FeedEntryDAO.FeedCapacity;
|
||||||
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||||
import com.commafeed.backend.dao.UnitOfWork;
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
import com.commafeed.backend.model.Feed;
|
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains utility methods for cleaning the database
|
* Contains utility methods for cleaning the database
|
||||||
@@ -42,13 +40,7 @@ public class DatabaseCleaningService {
|
|||||||
long total = 0;
|
long total = 0;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
do {
|
do {
|
||||||
deleted = new UnitOfWork<Integer>(sessionFactory) {
|
deleted = UnitOfWork.run(sessionFactory, () -> feedDAO.delete(feedDAO.findWithoutSubscriptions(1)));
|
||||||
@Override
|
|
||||||
protected Integer runInSession() throws Exception {
|
|
||||||
List<Feed> feeds = feedDAO.findWithoutSubscriptions(1);
|
|
||||||
return feedDAO.delete(feeds);
|
|
||||||
};
|
|
||||||
}.run();
|
|
||||||
total += deleted;
|
total += deleted;
|
||||||
log.info("removed {} feeds without subscriptions", total);
|
log.info("removed {} feeds without subscriptions", total);
|
||||||
} while (deleted != 0);
|
} while (deleted != 0);
|
||||||
@@ -61,12 +53,7 @@ public class DatabaseCleaningService {
|
|||||||
long total = 0;
|
long total = 0;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
do {
|
do {
|
||||||
deleted = new UnitOfWork<Integer>(sessionFactory) {
|
deleted = UnitOfWork.run(sessionFactory, () -> feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE));
|
||||||
@Override
|
|
||||||
protected Integer runInSession() throws Exception {
|
|
||||||
return feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE);
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
total += deleted;
|
total += deleted;
|
||||||
log.info("removed {} contents without entries", total);
|
log.info("removed {} contents without entries", total);
|
||||||
} while (deleted != 0);
|
} while (deleted != 0);
|
||||||
@@ -77,13 +64,8 @@ public class DatabaseCleaningService {
|
|||||||
public long cleanEntriesForFeedsExceedingCapacity(final int maxFeedCapacity) {
|
public long cleanEntriesForFeedsExceedingCapacity(final int maxFeedCapacity) {
|
||||||
long total = 0;
|
long total = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
List<FeedCapacity> feeds = new UnitOfWork<List<FeedCapacity>>(sessionFactory) {
|
List<FeedCapacity> feeds = UnitOfWork.run(sessionFactory,
|
||||||
@Override
|
() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, BATCH_SIZE));
|
||||||
protected List<FeedCapacity> runInSession() throws Exception {
|
|
||||||
return feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, BATCH_SIZE);
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
|
|
||||||
if (feeds.isEmpty()) {
|
if (feeds.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -92,12 +74,8 @@ public class DatabaseCleaningService {
|
|||||||
long remaining = feed.getCapacity() - maxFeedCapacity;
|
long remaining = feed.getCapacity() - maxFeedCapacity;
|
||||||
do {
|
do {
|
||||||
final long rem = remaining;
|
final long rem = remaining;
|
||||||
int deleted = new UnitOfWork<Integer>(sessionFactory) {
|
int deleted = UnitOfWork.run(sessionFactory,
|
||||||
@Override
|
() -> feedEntryDAO.deleteOldEntries(feed.getId(), Math.min(BATCH_SIZE, rem)));
|
||||||
protected Integer runInSession() throws Exception {
|
|
||||||
return feedEntryDAO.deleteOldEntries(feed.getId(), Math.min(BATCH_SIZE, rem));
|
|
||||||
};
|
|
||||||
}.run();
|
|
||||||
total += deleted;
|
total += deleted;
|
||||||
remaining -= deleted;
|
remaining -= deleted;
|
||||||
log.info("removed {} entries for feeds exceeding capacity", total);
|
log.info("removed {} entries for feeds exceeding capacity", total);
|
||||||
@@ -113,13 +91,8 @@ public class DatabaseCleaningService {
|
|||||||
long total = 0;
|
long total = 0;
|
||||||
int deleted = 0;
|
int deleted = 0;
|
||||||
do {
|
do {
|
||||||
deleted = new UnitOfWork<Integer>(sessionFactory) {
|
deleted = UnitOfWork.run(sessionFactory,
|
||||||
@Override
|
() -> feedEntryStatusDAO.delete(feedEntryStatusDAO.getOldStatuses(olderThan, BATCH_SIZE)));
|
||||||
protected Integer runInSession() throws Exception {
|
|
||||||
List<FeedEntryStatus> list = feedEntryStatusDAO.getOldStatuses(olderThan, BATCH_SIZE);
|
|
||||||
return feedEntryStatusDAO.delete(list);
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
total += deleted;
|
total += deleted;
|
||||||
log.info("cleaned {} old read statuses", total);
|
log.info("cleaned {} old read statuses", total);
|
||||||
} while (deleted != 0);
|
} while (deleted != 0);
|
||||||
|
|||||||
@@ -44,15 +44,10 @@ public class StartupService implements Managed {
|
|||||||
@Override
|
@Override
|
||||||
public void start() throws Exception {
|
public void start() throws Exception {
|
||||||
updateSchema();
|
updateSchema();
|
||||||
new UnitOfWork<Void>(sessionFactory) {
|
long count = UnitOfWork.run(sessionFactory, () -> userDAO.count());
|
||||||
@Override
|
if (count == 0) {
|
||||||
protected Void runInSession() throws Exception {
|
UnitOfWork.run(sessionFactory, () -> initialData());
|
||||||
if (userDAO.count() == 0) {
|
}
|
||||||
initialData();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSchema() {
|
private void updateSchema() {
|
||||||
|
|||||||
@@ -32,23 +32,12 @@ public class CustomCssServlet extends HttpServlet {
|
|||||||
protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
resp.setContentType("text/css");
|
resp.setContentType("text/css");
|
||||||
|
|
||||||
final Optional<User> user = new UnitOfWork<Optional<User>>(sessionFactory) {
|
final Optional<User> user = UnitOfWork.run(sessionFactory, () -> new SessionHelper(req).getLoggedInUser());
|
||||||
@Override
|
|
||||||
protected Optional<User> runInSession() throws Exception {
|
|
||||||
return new SessionHelper(req).getLoggedInUser();
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSettings settings = new UnitOfWork<UserSettings>(sessionFactory) {
|
UserSettings settings = UnitOfWork.run(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
|
||||||
@Override
|
|
||||||
protected UserSettings runInSession() {
|
|
||||||
return userSettingsDAO.findByUser(user.get());
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
|
|
||||||
if (settings == null || settings.getCustomCss() == null) {
|
if (settings == null || settings.getCustomCss() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,17 +51,11 @@ public class NextUnreadServlet extends HttpServlet {
|
|||||||
final String categoryId = req.getParameter(PARAM_CATEGORYID);
|
final String categoryId = req.getParameter(PARAM_CATEGORYID);
|
||||||
String orderParam = req.getParameter(PARAM_READINGORDER);
|
String orderParam = req.getParameter(PARAM_READINGORDER);
|
||||||
|
|
||||||
final Optional<User> user = new UnitOfWork<Optional<User>>(sessionFactory) {
|
SessionHelper sessionHelper = new SessionHelper(req);
|
||||||
@Override
|
Optional<User> user = sessionHelper.getLoggedInUser();
|
||||||
protected Optional<User> runInSession() throws Exception {
|
if (user.isPresent()) {
|
||||||
SessionHelper sessionHelper = new SessionHelper(req);
|
UnitOfWork.run(sessionFactory, () -> userService.performPostLoginActivities(user.get()));
|
||||||
Optional<User> loggedInUser = sessionHelper.getLoggedInUser();
|
}
|
||||||
if (loggedInUser.isPresent()) {
|
|
||||||
userService.performPostLoginActivities(loggedInUser.get());
|
|
||||||
}
|
|
||||||
return loggedInUser;
|
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
if (!user.isPresent()) {
|
if (!user.isPresent()) {
|
||||||
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
|
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
|
||||||
return;
|
return;
|
||||||
@@ -69,32 +63,31 @@ public class NextUnreadServlet extends HttpServlet {
|
|||||||
|
|
||||||
final ReadingOrder order = StringUtils.equals(orderParam, "asc") ? ReadingOrder.asc : ReadingOrder.desc;
|
final ReadingOrder order = StringUtils.equals(orderParam, "asc") ? ReadingOrder.asc : ReadingOrder.desc;
|
||||||
|
|
||||||
FeedEntryStatus status = new UnitOfWork<FeedEntryStatus>(sessionFactory) {
|
FeedEntryStatus status = UnitOfWork.run(
|
||||||
@Override
|
sessionFactory,
|
||||||
protected FeedEntryStatus runInSession() throws Exception {
|
() -> {
|
||||||
FeedEntryStatus status = null;
|
FeedEntryStatus s = null;
|
||||||
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
|
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
|
||||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
|
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
|
||||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1,
|
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1,
|
||||||
order, true, false, null);
|
order, true, false, null);
|
||||||
status = Iterables.getFirst(statuses, null);
|
s = Iterables.getFirst(statuses, null);
|
||||||
} else {
|
} else {
|
||||||
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
|
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
|
||||||
if (category != null) {
|
if (category != null) {
|
||||||
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
|
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
|
||||||
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
|
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
|
||||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null,
|
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null,
|
||||||
null, 0, 1, order, true, false, null);
|
null, 0, 1, order, true, false, null);
|
||||||
status = Iterables.getFirst(statuses, null);
|
s = Iterables.getFirst(statuses, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (s != null) {
|
||||||
if (status != null) {
|
s.setRead(true);
|
||||||
status.setRead(true);
|
feedEntryStatusDAO.saveOrUpdate(s);
|
||||||
feedEntryStatusDAO.saveOrUpdate(status);
|
}
|
||||||
}
|
return s;
|
||||||
return status;
|
});
|
||||||
}
|
|
||||||
}.run();
|
|
||||||
|
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
|
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
|
||||||
@@ -103,5 +96,4 @@ public class NextUnreadServlet extends HttpServlet {
|
|||||||
resp.sendRedirect(resp.encodeRedirectURL(url));
|
resp.sendRedirect(resp.encodeRedirectURL(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user