package com.buschmais.xo.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import com.buschmais.xo.api.XOException;
import com.buschmais.xo.api.XOTransaction;
import com.buschmais.xo.spi.datastore.DatastoreTransaction;
public class XOTransactionImpl implements XOTransaction {
private final DatastoreTransaction datastoreTransaction;
private final Collection<Synchronization> defaultSynchronizations = new LinkedList<>();
private final Collection<Synchronization> synchronizations = new LinkedList<>();
private boolean rollbackOnly;
public XOTransactionImpl(DatastoreTransaction datastoreTransaction) {
this.datastoreTransaction = datastoreTransaction;
}
@Override
public XOTransaction begin() {
datastoreTransaction.begin();
return this;
}
@Override
public void commit() {
if (rollbackOnly) {
throw new XOException("Transaction is marked as rollback only.");
}
beforeCompletion();
boolean committed = false;
try {
datastoreTransaction.commit();
committed = true;
} finally {
afterCompletion(committed);
}
}
@Override
public void rollback() {
try {
datastoreTransaction.rollback();
} finally {
afterCompletion(false);
rollbackOnly = false;
}
}
@Override
public boolean isActive() {
return datastoreTransaction.isActive();
}
@Override
public void setRollbackOnly() {
rollbackOnly = true;
}
@Override
public boolean isRollbackOnly() {
return rollbackOnly;
}
@Override
public void registerSynchronization(Synchronization synchronization) {
synchronizations.add(synchronization);
}
@Override
public void unregisterSynchronization(Synchronization synchronization) {
synchronizations.remove(synchronization);
}
public void registerDefaultSynchronization(Synchronization synchronization) {
defaultSynchronizations.add(synchronization);
}
private void beforeCompletion() {
executeSynchronizations(synchronization -> synchronization.beforeCompletion());
}
private void afterCompletion(final boolean committed) {
executeSynchronizations(synchronization -> synchronization.afterCompletion(committed));
synchronizations.clear();
}
private void executeSynchronizations(SynchronizationOperation operation) {
for (Synchronization synchronization : defaultSynchronizations) {
operation.run(synchronization);
}
for (Synchronization synchronization : new ArrayList<>(synchronizations)) {
operation.run(synchronization);
}
}
@Override
public void close() {
if (rollbackOnly) {
rollback();
} else {
commit();
}
}
private interface SynchronizationOperation {
void run(Synchronization synchronization);
}
}