Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions src/main/java/com/github/sttk/sabi/DataHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ public record FailToCastDataConn(String name, String castToType) {}
*/
public record RuntimeExceptionOccurred() {}

/**
* Represents an error reason that occurred when failing to cast the {@code DataHub} instance
* itself to the expected data access interface type for a {@link Logic}.
*
* @param castFromType The actual type of the {@code DataHub} instance that failed to cast.
*/
public record FailToCastDataHub(String castFromType) {}

private final DataHubInner inner = new DataHubInner();

/** Constructs a new {@code DataHub} instance. */
Expand Down Expand Up @@ -161,4 +169,68 @@ void rollback() {
void end() {
inner.end();
}

/**
* Executes the provided application {@link Logic} without transactional boundaries. The {@code
* DataHub} instance is treated as the data access object {@code D} to the {@link Logic}'s {@code
* run} method.
*
* @param <D> The type of the data access object, which typically is {@code DataHub} or an
* interface implemented by {@code DataHub} that {@link Logic} expects.
* @param logic The application logic to execute.
* @throws Err if an {@link Err} or {@link RuntimeException} occurs during logic execution or if
* the {@code DataHub} cannot be cast to the expected data access type.
*/
public <D> void run(Logic<D> logic) throws Err {
D data;
try {
@SuppressWarnings("unchecked")
D d = (D) this;
data = d;
} catch (Exception e) {
throw new Err(new FailToCastDataHub(this.getClass().getName()));
}
try {
this.begin();
logic.run(data);
} catch (Err | RuntimeException e) {
throw e;
} finally {
this.end();
}
}

/**
* Executes the provided application {@link Logic} within a transactional context. The {@code
* DataHub} instance is treated as the data access object {@code D} to the {@link Logic}'s {@code
* run} method. If the logic completes successfully, a commit operation is attempted. If any
* {@link Err}, {@link RuntimeException}, or {@link Error} occurs, a rollback operation is
* performed.
*
* @param <D> The type of the data access object, which typically is {@code DataHub} or an
* interface implemented by {@code DataHub} that {@link Logic} expects.
* @param logic The application logic to execute transactionally.
* @throws Err if an {@link Err}, {@link RuntimeException}, or {@link Error} occurs during logic
* execution, pre-commit, or commit. The original exception is re-thrown after rollback.
*/
public <D> void txn(Logic<D> logic) throws Err {
D data;
try {
@SuppressWarnings("unchecked")
D d = (D) this;
data = d;
} catch (Exception e) {
throw new Err(new FailToCastDataHub(this.getClass().getName()));
}
try {
this.begin();
logic.run(data);
this.commit();
} catch (Err | RuntimeException | Error e) {
this.rollback();
throw e;
} finally {
this.end();
}
}
}
76 changes: 0 additions & 76 deletions src/main/java/com/github/sttk/sabi/Sabi.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@
* }</code></pre>
*/
public final class Sabi {
/**
* Represents an error reason that occurred when failing to cast the {@code DataHub} instance
* itself to the expected data access interface type for a {@link Logic}.
*
* @param castFromType The actual type of the {@code DataHub} instance that failed to cast.
*/
public record FailToCastDataHub(String castFromType) {}

private Sabi() {}

/**
Expand Down Expand Up @@ -71,72 +63,4 @@ public static void uses(String name, DataSrc ds) {
public static AutoCloseable setup() throws Err {
return DataHubInner.setupGlobals();
}

/**
* Executes the provided application {@link Logic} without transactional boundaries. The {@code
* DataHub} instance in the parameters is passed as the data access object {@code D} to the {@link
* Logic}'s {@code run} method.
*
* @param <D> The type of the data access object, which typically is {@code DataHub} or an
* interface implemented by {@code DataHub} that {@link Logic} expects.
* @param logic The application logic to execute.
* @param hub An instance of a DataHub subclass that inherits the data interface for logic
* arguments.
* @throws Err if an {@link Err} or {@link RuntimeException} occurs during logic execution or if
* the {@code DataHub} cannot be cast to the expected data access type.
*/
public static <D> void run(Logic<D> logic, DataHub hub) throws Err {
D data;
try {
@SuppressWarnings("unchecked")
D d = (D) hub;
data = d;
} catch (Exception e) {
throw new Err(new FailToCastDataHub(hub.getClass().getName()));
}
try {
hub.begin();
logic.run(data);
} catch (Err | RuntimeException e) {
throw e;
} finally {
hub.end();
}
}

/**
* Executes the provided application {@link Logic} within a transactional context. The {@code
* DataHub} instance in the parameter is passed as the data access object {@code D} to the {@link
* Logic}'s {@code run} method. If the logic completes successfully, a commit operation is
* attempted. If any {@link Err}, {@link RuntimeException}, or {@link Error} occurs, a rollback
* operation is performed.
*
* @param <D> The type of the data access object, which typically is {@code DataHub} or an
* interface implemented by {@code DataHub} that {@link Logic} expects.
* @param logic The application logic to execute transactionally.
* @param hub An instance of a DataHub subclass that inherits the data interface for logic
* arguments.
* @throws Err if an {@link Err}, {@link RuntimeException}, or {@link Error} occurs during logic
* execution, pre-commit, or commit. The original exception is re-thrown after rollback.
*/
public static <D> void txn(Logic<D> logic, DataHub hub) throws Err {
D data;
try {
@SuppressWarnings("unchecked")
D d = (D) hub;
data = d;
} catch (Exception e) {
throw new Err(new FailToCastDataHub(hub.getClass().getName()));
}
try {
hub.begin();
logic.run(data);
hub.commit();
} catch (Err | RuntimeException | Error e) {
hub.rollback();
throw e;
} finally {
hub.end();
}
}
}
18 changes: 9 additions & 9 deletions src/test/java/com/github/sttk/sabi/internal/DataAccTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ void test() {
try (var ac = Sabi.setup()) {
suppressWarnings_unused(ac);
try (var data = new SampleDataHub()) {
Sabi.run(new SampleLogic(), data);
data.run(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down Expand Up @@ -362,7 +362,7 @@ void test() {
data.uses("foo", new FooDataSrc(1, "hello", logger, false));
data.uses("bar", new BarDataSrc(2, logger, false));

Sabi.run(new SampleLogic(), data);
data.run(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down Expand Up @@ -394,7 +394,7 @@ void test_not_run_logic_if_fail_to_setup_local_data_src() {
data.uses("foo", new FooDataSrc(1, "hello", logger, true));
data.uses("bar", new BarDataSrc(2, logger, false));

Sabi.run(new SampleLogic(), data);
data.run(new SampleLogic());
} catch (Err e) {
switch (e.getReason()) {
case DataHub.FailToSetupLocalDataSrcs r -> {
Expand Down Expand Up @@ -437,7 +437,7 @@ void test() {
try (var data = new SampleDataHub()) {
data.uses("foo", new FooDataSrc(2, "Hello", logger, false));

Sabi.run(new SampleLogic(), data);
data.run(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down Expand Up @@ -482,7 +482,7 @@ void test() {
try (var ac = Sabi.setup()) {
suppressWarnings_unused(ac);
try (var data = new SampleDataHub()) {
Sabi.txn(new SampleLogic(), data);
data.txn(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down Expand Up @@ -533,7 +533,7 @@ void test() {
data.uses("foo", new FooDataSrc(1, "Hello", logger, false));
data.uses("bar", new BarDataSrc(2, logger, false));

Sabi.txn(new SampleLogic(), data);
data.txn(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down Expand Up @@ -571,7 +571,7 @@ void test_not_run_logic_if_fail_to_setup_local_data_src() {
data.uses("foo", new FooDataSrc(1, "Hello", logger, true));
data.uses("bar", new BarDataSrc(2, logger, false));

Sabi.txn(new SampleLogic(), data);
data.txn(new SampleLogic());
} catch (Err e) {
switch (e.getReason()) {
case DataHub.FailToSetupLocalDataSrcs r -> {
Expand Down Expand Up @@ -600,7 +600,7 @@ void test_not_run_logic_in_txn_and_rollback() {
data.uses("foo", new FooDataSrc(1, "Hello", logger, false));
data.uses("bar", new BarDataSrc(2, logger, false));

Sabi.txn(new FailingLogic(), data);
data.txn(new FailingLogic());
} catch (Err e) {
assertThat(e.getReason()).isEqualTo("ZZZ");
} catch (Exception e) {
Expand Down Expand Up @@ -643,7 +643,7 @@ void test() {
try (var data = new SampleDataHub()) {
data.uses("foo", new FooDataSrc(2, "Hello", logger, false));

Sabi.txn(new SampleLogic(), data);
data.txn(new SampleLogic());
} catch (Exception e) {
fail(e);
}
Expand Down