From 6ba3b6fc452265fb595b7f32055423c606ed77fd Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 1 Aug 2013 22:26:13 +0200 Subject: o Initial import. --- container-core/pom.xml | 32 ++++ .../main/java/io/trygvis/container/log/Log.java | 4 + .../container/tx/PlatformTransactionManager.java | 188 +++++++++++++++++++++ .../io/trygvis/container/tx/TransactionHolder.java | 7 + .../src/main/java/io/trygvis/container/tx/Tx.java | 5 + 5 files changed, 236 insertions(+) create mode 100644 container-core/pom.xml create mode 100644 container-core/src/main/java/io/trygvis/container/log/Log.java create mode 100644 container-core/src/main/java/io/trygvis/container/tx/PlatformTransactionManager.java create mode 100644 container-core/src/main/java/io/trygvis/container/tx/TransactionHolder.java create mode 100644 container-core/src/main/java/io/trygvis/container/tx/Tx.java (limited to 'container-core') diff --git a/container-core/pom.xml b/container-core/pom.xml new file mode 100644 index 0000000..e16c761 --- /dev/null +++ b/container-core/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + container-playground + io.trygvis.container + 1.0-SNAPSHOT + + container-core + + 3.2.2.RELEASE + + + + org.springframework + spring-beans + ${version.spring} + + + org.springframework + spring-jdbc + ${version.spring} + + + org.springframework + spring-tx + ${version.spring} + + + 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 tx = new ThreadLocal() { + @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 doInTransaction(TransactionIsolation isolation, TransactionPropagation propagation, TransactionTemplate 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 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(); +} -- cgit v1.2.3