diff options
Diffstat (limited to 'container-core/src/main')
4 files changed, 204 insertions, 0 deletions
diff --git a/container-core/src/main/java/io/trygvis/container/log/Log.java b/container-core/src/main/java/io/trygvis/container/log/Log.java new file mode 100644 index 0000000..71e81d1 --- /dev/null +++ b/container-core/src/main/java/io/trygvis/container/log/Log.java @@ -0,0 +1,4 @@ +package io.trygvis.container.log; + +public @interface Log { +} diff --git a/container-core/src/main/java/io/trygvis/container/tx/PlatformTransactionManager.java b/container-core/src/main/java/io/trygvis/container/tx/PlatformTransactionManager.java new file mode 100644 index 0000000..3ab7b6f --- /dev/null +++ b/container-core/src/main/java/io/trygvis/container/tx/PlatformTransactionManager.java @@ -0,0 +1,188 @@ +package io.trygvis.container.tx; + +public class PlatformTransactionManager { + + public static Tx currentTx() { + return tx.get().tx(); + } + + public static interface TxFactory { + Tx create(TransactionIsolation isolation); + } + + static final ThreadLocal<TxEntry> tx = new ThreadLocal<TxEntry>() { + @Override + protected TxEntry initialValue() { + return new RootTxState(); + } + }; + + public abstract static class TxEntry { + abstract Tx tx(); + + abstract boolean isActive(); + + abstract TxEntry pop(); + } + + public static class NewTxTxEntry extends TxEntry { + private final TxEntry parent; + private final Tx tx; + + public NewTxTxEntry(TxEntry parent, Tx tx) { + this.parent = parent; + this.tx = tx; + } + + @Override + Tx tx() { + return tx; + } + + public boolean isActive() { + return true; + } + + @Override + TxEntry pop() { + return parent; + } + } + + public static class NestedTxEntry extends TxEntry { + private final NestedTxEntry parent; + + public NestedTxEntry(NestedTxEntry parent) { + this.parent = parent; + } + + @Override + Tx tx() { + return parent.tx(); + } + + public boolean isActive() { + return parent.isActive(); + } + + @Override + TxEntry pop() { + return parent; + } + } + + private final static class InactiveTxEntry extends TxEntry { + private final TxEntry parent; + + private InactiveTxEntry(TxEntry parent) { + this.parent = parent; + } + + @Override + public Tx tx() { + throw new RuntimeException("No transaction currently running."); + } + + @Override + public boolean isActive() { + return false; + } + + @Override + TxEntry pop() { + return parent; + } + } + + private final static class RootTxState extends TxEntry { + @Override + public Tx tx() { + throw new RuntimeException("No transaction currently running."); + } + + @Override + public boolean isActive() { + return false; + } + + @Override + TxEntry pop() { + throw new RuntimeException("Trying to pop root entry"); + } + } + + public enum TransactionIsolation { + ISOLATION_DEFAULT, + ISOLATION_READ_COMMITTED, + ISOLATION_READ_UNCOMMITTED, + ISOLATION_REPEATABLE_READ, + ISOLATION_SERIALIZABLE + } + + public enum TransactionPropagation { + PROPAGATION_NESTED, + // PROPAGATION_NEVER, + PROPAGATION_NOT_SUPPORTED, + PROPAGATION_REQUIRED, + PROPAGATION_REQUIRES_NEW, + PROPAGATION_SUPPORTS + } + + private final TxFactory txFactory; + private final TransactionPropagation defaultPropagation; + + public PlatformTransactionManager(TxFactory txFactory, TransactionPropagation defaultPropagation) { + this.txFactory = txFactory; + this.defaultPropagation = defaultPropagation; + } + + public <T> T doInTransaction(TransactionIsolation isolation, TransactionPropagation propagation, TransactionTemplate<T> transactionTemplate) { + final TxEntry prevEntry = PlatformTransactionManager.tx.get(); + final TxEntry currentEntry = nextTxEntry(prevEntry, isolation, propagation); + PlatformTransactionManager.tx.set(currentEntry); + + try { + return transactionTemplate.doInTransaction(); + } finally { + PlatformTransactionManager.tx.set(prevEntry); + } + } + + private TxEntry nextTxEntry(TxEntry prevEntry, TransactionIsolation isolation, TransactionPropagation propagation) { + TxEntry currentEntry; + switch (propagation) { + case PROPAGATION_NESTED: + throw new RuntimeException("Propagation 'nested' not supported."); + case PROPAGATION_NOT_SUPPORTED: + currentEntry = new InactiveTxEntry(prevEntry); + PlatformTransactionManager.tx.set(currentEntry); + break; + default: + throw new RuntimeException("Unknown transaction propagation: " + propagation); + case PROPAGATION_REQUIRED: + if (prevEntry.isActive()) { + currentEntry = new NestedTxEntry((NestedTxEntry) prevEntry); + } else { + Tx tx = txFactory.create(isolation); + currentEntry = new NewTxTxEntry(prevEntry, tx); + } + break; + case PROPAGATION_REQUIRES_NEW: + Tx tx = txFactory.create(isolation); + currentEntry = new NewTxTxEntry(prevEntry, tx); + break; + case PROPAGATION_SUPPORTS: + if (prevEntry.isActive()) { + currentEntry = new NestedTxEntry((NestedTxEntry) prevEntry); + } else { + currentEntry = new InactiveTxEntry(prevEntry); + } + break; + } + return currentEntry; + } + + public interface TransactionTemplate<T> { + T doInTransaction(); + } +} diff --git a/container-core/src/main/java/io/trygvis/container/tx/TransactionHolder.java b/container-core/src/main/java/io/trygvis/container/tx/TransactionHolder.java new file mode 100644 index 0000000..9f7e441 --- /dev/null +++ b/container-core/src/main/java/io/trygvis/container/tx/TransactionHolder.java @@ -0,0 +1,7 @@ +package io.trygvis.container.tx; + +public class TransactionHolder { + public static Tx currentTx() { + return PlatformTransactionManager.currentTx(); + } +} diff --git a/container-core/src/main/java/io/trygvis/container/tx/Tx.java b/container-core/src/main/java/io/trygvis/container/tx/Tx.java new file mode 100644 index 0000000..8ff9d05 --- /dev/null +++ b/container-core/src/main/java/io/trygvis/container/tx/Tx.java @@ -0,0 +1,5 @@ +package io.trygvis.container.tx; + +public interface Tx { + void rollback(); +} |