package me.moodcat.util;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.persist.UnitOfWork;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
/**
* A Callable that is ran in a {@link UnitOfWork}. Used for database interaction in threads outside
* the servlet and thus not filtered by the {@code PersistFilter}. Assumes the PersistService to
* be started.
*
* @param <V>
* return type of the unit of work.
*/
@Slf4j
public class CallableInUnitOfWork<V> implements Callable<V> {
/**
* The work provider of which the unit of work is done.
*/
private final Provider<UnitOfWork> workProvider;
/**
* The callable which is executed when the work has been finished.
*/
private final Callable<V> callable;
@Inject
public CallableInUnitOfWork(final Provider<UnitOfWork> workProvider,
final Callable<V> callable) {
this.workProvider = workProvider;
this.callable = callable;
}
@Override
public V call() throws Exception {
final UnitOfWork work = workProvider.get();
try {
work.begin();
return callable.call();
} catch (final Throwable t) {
log.error(t.getMessage(), t);
throw t;
} finally {
work.end();
}
}
/**
* Factory for {@link Callable Callables} that should be ran in a {@link UnitOfWork}.
*/
public static class CallableInUnitOfWorkFactory {
/**
* The provider of the work.
*/
private final Provider<UnitOfWork> workProvider;
@Inject
public CallableInUnitOfWorkFactory(final Provider<UnitOfWork> workProvider) {
this.workProvider = workProvider;
}
/**
* Create a {@link Callable} in {@link UnitOfWork}.
*
* @param callable
* {@code Callable} to run in {@code UnitOfWork}
* @param <T>
* Type of {@code Callable}
* @return the {@code CallableInUnitOfWork}
*/
public <T> Callable<T> create(final Callable<T> callable) {
return new CallableInUnitOfWork<>(workProvider, callable);
}
}
}