io.yawp.repository.Repository Maven / Gradle / Ivy
package io.yawp.repository;
import io.yawp.commons.http.RequestContext;
import io.yawp.driver.api.Driver;
import io.yawp.driver.api.DriverFactory;
import io.yawp.driver.api.TransactionDriver;
import io.yawp.repository.actions.ActionKey;
import io.yawp.repository.actions.ActionMethod;
import io.yawp.repository.actions.RepositoryActions;
import io.yawp.repository.hooks.RepositoryHooks;
import io.yawp.repository.pipes.RepositoryPipes;
import io.yawp.repository.query.QueryBuilder;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
public class Repository implements RepositoryApi {
private final static Logger logger = Logger.getLogger(Repository.class.getName());
private RepositoryFeatures repositoryFeatures;
private RequestContext requestContext;
private Namespace namespace;
private Driver driver;
private TransactionDriver tx;
private Repository() {
this.namespace = new Namespace(driver().namespace());
}
private Repository(String ns) {
this.namespace = new Namespace(ns, driver().namespace());
}
public static Repository r() {
return new Repository();
}
public static Repository r(String ns) {
return new Repository(ns);
}
@Override
public Repository namespace(String ns) {
namespace.setNs(ns);
return this;
}
@Override
public Namespace namespace() {
return namespace;
}
@Override
public String currentNamespace() {
return namespace.getNs();
}
@Override
public Repository setFeatures(RepositoryFeatures repositoryFeatures) {
this.repositoryFeatures = repositoryFeatures;
return this;
}
@Override
public Repository setRequestContext(RequestContext requestContext) {
this.requestContext = requestContext;
return this;
}
@Override
public Driver driver() {
if (driver != null) {
return driver;
}
driver = DriverFactory.getDriver(this);
return driver;
}
@Override
public AsyncRepository async() {
return new AsyncRepository(this);
}
@Override
public T saveWithHooks(T object) {
logger.finer("save object, hooks: true");
namespace.set(object.getClass());
try {
RepositoryHooks.beforeSave(this, object);
saveInternal(object);
RepositoryHooks.afterSave(this, object);
} finally {
namespace.reset();
}
return object;
}
@Override
public T save(T object) {
logger.finer("saving object, hooks: false");
namespace.set(object.getClass());
try {
saveInternal(object);
} finally {
namespace.reset();
}
return object;
}
@Override
public T fetch(IdRef id) {
namespace.set(id.getClazz());
try {
return driver().query().fetch(id);
} finally {
namespace.reset();
}
}
@Override
public FutureObject fetchAsync(IdRef id) {
namespace.set(id.getClazz());
try {
return driver().query().fetchAsync(id);
} finally {
namespace.reset();
}
}
protected FutureObject saveAsyncWithHooks(T object) {
namespace.set(object.getClass());
try {
RepositoryHooks.beforeSave(this, object);
FutureObject future = saveInternalAsync(object, true);
return future;
} finally {
namespace.reset();
}
}
protected FutureObject saveAsync(T object) {
namespace.set(object.getClass());
try {
FutureObject future = saveInternalAsync(object, false);
return future;
} finally {
namespace.reset();
}
}
private void saveInternal(Object object) {
boolean newTransaction = beginTransactionForPipesOnSave(object);
try {
updateExistingPipes(object);
driver().persistence().save(object);
fluxPipes(object);
if (newTransaction) {
commit();
}
} finally {
if (newTransaction && isTransationInProgress()) {
rollback();
}
}
logger.finer("saved");
}
private boolean beginTransactionForPipesOnSave(Object object) {
Class> endpointClazz = object.getClass();
if (!RepositoryPipes.isPipeSourceOrSink(this, endpointClazz)) {
return false;
}
return beginTransactionForPipes();
}
private boolean beginTransactionForPipesOnDestroy(IdRef> id) {
Class> endpointClazz = id.getClazz();
if (!RepositoryPipes.isPipeSource(this, endpointClazz)) {
return false;
}
return beginTransactionForPipes();
}
private boolean beginTransactionForPipes() {
if (isTransationInProgress()) {
return false;
}
begin();
return true;
}
private void fluxPipes(Object object) {
RepositoryPipes.flux(this, object);
}
private void refluxPipes(IdRef> id) {
RepositoryPipes.reflux(this, id);
}
private void updateExistingPipes(Object object) {
RepositoryPipes.updateExisting(this, object);
}
private FutureObject saveInternalAsync(T object, boolean enableHooks) {
FutureObject futureObject = driver().persistence().saveAsync(object);
futureObject.setEnableHooks(enableHooks);
return futureObject;
}
@Override
public Object action(IdRef> id, Class> clazz, ActionKey actionKey, String json, Map params) {
namespace.set(clazz);
try {
ActionMethod actionMethod = repositoryFeatures.getByClazz(clazz).getAction(actionKey);
return RepositoryActions.execute(this, actionMethod, id, json, params);
} finally {
namespace.reset();
}
}
@Override
public QueryBuilder queryWithHooks(Class clazz) {
QueryBuilder q = QueryBuilder.q(clazz, this);
RepositoryHooks.beforeQuery(this, q, clazz);
return q;
}
@Override
public QueryBuilder query(Class clazz) {
return QueryBuilder.q(clazz, this);
}
@Override
public void destroy(IdRef> id) {
namespace.set(id.getClazz());
try {
RepositoryHooks.beforeDestroy(this, id);
destroyInternal(id);
RepositoryHooks.afterDestroy(this, id);
} finally {
namespace.reset();
}
}
protected FutureObject destroyAsync(IdRef> id) {
namespace.set(id.getClazz());
try {
FutureObject future = destroyInternalAsync(id);
return future;
} finally {
namespace.reset();
}
}
private void destroyInternal(IdRef> id) {
boolean newTransaction = beginTransactionForPipesOnDestroy(id);
try {
refluxPipes(id);
driver().persistence().destroy(id);
// TODO: Pipes - cleanup sinks
if (newTransaction) {
commit();
}
} finally {
if (newTransaction && isTransationInProgress()) {
rollback();
}
}
}
private FutureObject destroyInternalAsync(IdRef> id) {
FutureObject futureObject = driver().persistence().destroyAsync(id);
return futureObject;
}
@Override
public Class> getClazzByKind(String kind) {
return repositoryFeatures.getClazzByKind(kind);
}
@Override
@SuppressWarnings("unchecked")
public EndpointFeatures getEndpointFeatures(Class endpoint) {
return (EndpointFeatures) repositoryFeatures.getByClazz(endpoint);
}
@Override
public EndpointFeatures> getEndpointFeatures(String endpointPath) {
return repositoryFeatures.getByPath(endpointPath);
}
@Override
public RepositoryFeatures getFeatures() {
return repositoryFeatures;
}
@Override
public IdRef parseId(Class clazz, String idString) {
return IdRef.parse(clazz, this, idString);
}
@Override
public List> parseIds(Class clazz, List idsString) {
return IdRef.parse(clazz, this, idsString);
}
@Override
public void begin() {
tx = driver().transaction().begin();
}
@Override
public void beginX() {
tx = driver().transaction().beginX();
}
@Override
public void rollback() {
if (tx == null) {
throw new RuntimeException("No transaction in progress");
}
try {
tx.rollback();
} finally {
tx = null;
}
}
@Override
public void commit() {
if (tx == null) {
throw new RuntimeException("No transaction in progress");
}
try {
tx.commit();
} finally {
tx = null;
}
}
@Override
public boolean isTransationInProgress() {
return tx != null;
}
@Override
public TransactionDriver currentTransaction() {
return this.tx;
}
@Override
public RequestContext getRequestContext() {
return requestContext;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy