summaryrefslogtreecommitdiff
path: root/container-core
diff options
context:
space:
mode:
Diffstat (limited to 'container-core')
-rw-r--r--container-core/pom.xml32
-rw-r--r--container-core/src/main/java/io/trygvis/container/log/Log.java4
-rw-r--r--container-core/src/main/java/io/trygvis/container/tx/PlatformTransactionManager.java188
-rw-r--r--container-core/src/main/java/io/trygvis/container/tx/TransactionHolder.java7
-rw-r--r--container-core/src/main/java/io/trygvis/container/tx/Tx.java5
5 files changed, 236 insertions, 0 deletions
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>container-playground</artifactId>
+ <groupId>io.trygvis.container</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>container-core</artifactId>
+ <properties>
+ <version.spring>3.2.2.RELEASE</version.spring>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <version>${version.spring}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ <version>${version.spring}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-tx</artifactId>
+ <version>${version.spring}</version>
+ </dependency>
+ </dependencies>
+</project>
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();
+}