unit of work refactoring

This commit is contained in:
Athou
2014-12-12 08:57:50 +01:00
parent ccf18758fb
commit 2e475c35cc
7 changed files with 67 additions and 124 deletions

View File

@@ -5,17 +5,26 @@ import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.context.internal.ManagedSessionContext;
public abstract class UnitOfWork<T> {
public class UnitOfWork {
private SessionFactory sessionFactory;
public UnitOfWork(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
@FunctionalInterface
public static interface SessionRunner {
public void runInSession();
}
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();
if (ManagedSessionContext.hasBind(sessionFactory)) {
throw new IllegalStateException("Already in a unit of work!");
@@ -25,11 +34,11 @@ public abstract class UnitOfWork<T> {
ManagedSessionContext.bind(session);
session.beginTransaction();
try {
t = runInSession();
t = sessionRunner.runInSession();
commitTransaction(session);
} catch (Exception e) {
rollbackTransaction(session);
this.<RuntimeException> rethrow(e);
UnitOfWork.<RuntimeException> rethrow(e);
}
} finally {
session.close();
@@ -38,14 +47,14 @@ public abstract class UnitOfWork<T> {
return t;
}
private void rollbackTransaction(Session session) {
private static void rollbackTransaction(Session session) {
final Transaction txn = session.getTransaction();
if (txn != null && txn.isActive()) {
txn.rollback();
}
}
private void commitTransaction(Session session) {
private static void commitTransaction(Session session) {
final Transaction txn = session.getTransaction();
if (txn != null && txn.isActive()) {
txn.commit();
@@ -53,7 +62,7 @@ public abstract class UnitOfWork<T> {
}
@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;
}

View File

@@ -68,12 +68,7 @@ public class FeedRefreshTaskGiver implements Managed {
public void run() {
while (!executor.isShutdown()) {
try {
FeedRefreshContext context = new UnitOfWork<FeedRefreshContext>(sessionFactory) {
@Override
protected FeedRefreshContext runInSession() throws Exception {
return queues.take();
}
}.run();
FeedRefreshContext context = UnitOfWork.run(sessionFactory, () -> queues.take());
if (context != null) {
feedRefreshed.mark();
worker.updateFeed(context);

View File

@@ -120,12 +120,7 @@ public class FeedRefreshUpdater implements Managed {
if (!lastEntries.contains(cacheKey)) {
log.debug("cache miss for {}", entry.getUrl());
if (subscriptions == null) {
subscriptions = new UnitOfWork<List<FeedSubscription>>(sessionFactory) {
@Override
protected List<FeedSubscription> runInSession() throws Exception {
return feedSubscriptionDAO.findByFeed(feed);
}
}.run();
subscriptions = UnitOfWork.run(sessionFactory, () -> feedSubscriptionDAO.findByFeed(feed));
}
ok &= addEntry(feed, entry, subscriptions);
entryCacheMiss.mark();
@@ -190,12 +185,7 @@ public class FeedRefreshUpdater implements Managed {
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
if (locked1 && locked2) {
boolean inserted = new UnitOfWork<Boolean>(sessionFactory) {
@Override
protected Boolean runInSession() throws Exception {
return feedUpdateService.addEntry(feed, entry, subscriptions);
}
}.run();
boolean inserted = UnitOfWork.run(sessionFactory, () -> feedUpdateService.addEntry(feed, entry, subscriptions));
if (inserted) {
entryInserted.mark();
}

View File

@@ -17,8 +17,6 @@ import com.commafeed.backend.dao.FeedEntryDAO;
import com.commafeed.backend.dao.FeedEntryDAO.FeedCapacity;
import com.commafeed.backend.dao.FeedEntryStatusDAO;
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
@@ -42,13 +40,7 @@ public class DatabaseCleaningService {
long total = 0;
int deleted = 0;
do {
deleted = new UnitOfWork<Integer>(sessionFactory) {
@Override
protected Integer runInSession() throws Exception {
List<Feed> feeds = feedDAO.findWithoutSubscriptions(1);
return feedDAO.delete(feeds);
};
}.run();
deleted = UnitOfWork.run(sessionFactory, () -> feedDAO.delete(feedDAO.findWithoutSubscriptions(1)));
total += deleted;
log.info("removed {} feeds without subscriptions", total);
} while (deleted != 0);
@@ -61,12 +53,7 @@ public class DatabaseCleaningService {
long total = 0;
int deleted = 0;
do {
deleted = new UnitOfWork<Integer>(sessionFactory) {
@Override
protected Integer runInSession() throws Exception {
return feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE);
}
}.run();
deleted = UnitOfWork.run(sessionFactory, () -> feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE));
total += deleted;
log.info("removed {} contents without entries", total);
} while (deleted != 0);
@@ -77,13 +64,8 @@ public class DatabaseCleaningService {
public long cleanEntriesForFeedsExceedingCapacity(final int maxFeedCapacity) {
long total = 0;
while (true) {
List<FeedCapacity> feeds = new UnitOfWork<List<FeedCapacity>>(sessionFactory) {
@Override
protected List<FeedCapacity> runInSession() throws Exception {
return feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, BATCH_SIZE);
}
}.run();
List<FeedCapacity> feeds = UnitOfWork.run(sessionFactory,
() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, BATCH_SIZE));
if (feeds.isEmpty()) {
break;
}
@@ -92,12 +74,8 @@ public class DatabaseCleaningService {
long remaining = feed.getCapacity() - maxFeedCapacity;
do {
final long rem = remaining;
int deleted = new UnitOfWork<Integer>(sessionFactory) {
@Override
protected Integer runInSession() throws Exception {
return feedEntryDAO.deleteOldEntries(feed.getId(), Math.min(BATCH_SIZE, rem));
};
}.run();
int deleted = UnitOfWork.run(sessionFactory,
() -> feedEntryDAO.deleteOldEntries(feed.getId(), Math.min(BATCH_SIZE, rem)));
total += deleted;
remaining -= deleted;
log.info("removed {} entries for feeds exceeding capacity", total);
@@ -113,13 +91,8 @@ public class DatabaseCleaningService {
long total = 0;
int deleted = 0;
do {
deleted = new UnitOfWork<Integer>(sessionFactory) {
@Override
protected Integer runInSession() throws Exception {
List<FeedEntryStatus> list = feedEntryStatusDAO.getOldStatuses(olderThan, BATCH_SIZE);
return feedEntryStatusDAO.delete(list);
}
}.run();
deleted = UnitOfWork.run(sessionFactory,
() -> feedEntryStatusDAO.delete(feedEntryStatusDAO.getOldStatuses(olderThan, BATCH_SIZE)));
total += deleted;
log.info("cleaned {} old read statuses", total);
} while (deleted != 0);

View File

@@ -44,15 +44,10 @@ public class StartupService implements Managed {
@Override
public void start() throws Exception {
updateSchema();
new UnitOfWork<Void>(sessionFactory) {
@Override
protected Void runInSession() throws Exception {
if (userDAO.count() == 0) {
initialData();
}
return null;
}
}.run();
long count = UnitOfWork.run(sessionFactory, () -> userDAO.count());
if (count == 0) {
UnitOfWork.run(sessionFactory, () -> initialData());
}
}
private void updateSchema() {

View File

@@ -32,23 +32,12 @@ public class CustomCssServlet extends HttpServlet {
protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/css");
final Optional<User> user = new UnitOfWork<Optional<User>>(sessionFactory) {
@Override
protected Optional<User> runInSession() throws Exception {
return new SessionHelper(req).getLoggedInUser();
}
}.run();
final Optional<User> user = UnitOfWork.run(sessionFactory, () -> new SessionHelper(req).getLoggedInUser());
if (!user.isPresent()) {
return;
}
UserSettings settings = new UnitOfWork<UserSettings>(sessionFactory) {
@Override
protected UserSettings runInSession() {
return userSettingsDAO.findByUser(user.get());
}
}.run();
UserSettings settings = UnitOfWork.run(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
if (settings == null || settings.getCustomCss() == null) {
return;
}

View File

@@ -51,17 +51,11 @@ public class NextUnreadServlet extends HttpServlet {
final String categoryId = req.getParameter(PARAM_CATEGORYID);
String orderParam = req.getParameter(PARAM_READINGORDER);
final Optional<User> user = new UnitOfWork<Optional<User>>(sessionFactory) {
@Override
protected Optional<User> runInSession() throws Exception {
SessionHelper sessionHelper = new SessionHelper(req);
Optional<User> loggedInUser = sessionHelper.getLoggedInUser();
if (loggedInUser.isPresent()) {
userService.performPostLoginActivities(loggedInUser.get());
}
return loggedInUser;
}
}.run();
SessionHelper sessionHelper = new SessionHelper(req);
Optional<User> user = sessionHelper.getLoggedInUser();
if (user.isPresent()) {
UnitOfWork.run(sessionFactory, () -> userService.performPostLoginActivities(user.get()));
}
if (!user.isPresent()) {
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
return;
@@ -69,32 +63,31 @@ public class NextUnreadServlet extends HttpServlet {
final ReadingOrder order = StringUtils.equals(orderParam, "asc") ? ReadingOrder.asc : ReadingOrder.desc;
FeedEntryStatus status = new UnitOfWork<FeedEntryStatus>(sessionFactory) {
@Override
protected FeedEntryStatus runInSession() throws Exception {
FeedEntryStatus status = null;
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1,
order, true, false, null);
status = Iterables.getFirst(statuses, null);
} else {
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
if (category != null) {
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null,
null, 0, 1, order, true, false, null);
status = Iterables.getFirst(statuses, null);
FeedEntryStatus status = UnitOfWork.run(
sessionFactory,
() -> {
FeedEntryStatus s = null;
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1,
order, true, false, null);
s = Iterables.getFirst(statuses, null);
} else {
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
if (category != null) {
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null,
null, 0, 1, order, true, false, null);
s = Iterables.getFirst(statuses, null);
}
}
}
if (status != null) {
status.setRead(true);
feedEntryStatusDAO.saveOrUpdate(status);
}
return status;
}
}.run();
if (s != null) {
s.setRead(true);
feedEntryStatusDAO.saveOrUpdate(s);
}
return s;
});
if (status == null) {
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
@@ -103,5 +96,4 @@ public class NextUnreadServlet extends HttpServlet {
resp.sendRedirect(resp.encodeRedirectURL(url));
}
}
}