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
25 changes: 25 additions & 0 deletions src/main/java/com/github/sttk/sabi/AsyncGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,35 @@
*/
package com.github.sttk.sabi;

/**
* An interface for asynchronously executing multiple {@link Runner} instances and waiting for their
* completion.
*
* <p>Implementations of this interface allow adding multiple {@link Runner} objects, which are then
* executed concurrently. The group waits until all added runners have finished their execution. Any
* errors occurring during the execution of a {@link Runner} are stored and can be retrieved by
* their names in a map.
*/
public interface AsyncGroup {

/**
* Represents the reason for a new {@link com.github.sttk.errs.Exc} exception object when an
* exception occurred during the execution of a {@link Runner} and the exception class was not the
* {@link com.github.sttk.errs.Exc}.
*/
record RunnerFailed() {}

/**
* Represents the reason for an {@link com.github.sttk.errs.Exc} exception object when the
* creation of a thread for asynchronous execution of a {@link Runner} fails.
*/
record RunnerInterrupted() {}

/**
* Adds a {@link Runner} to this group for asynchronous execution. The added runner will be
* executed in a separate thread.
*
* @param runner The {@link Runner} to be added and executed asynchronously.
*/
void add(final Runner runner);
}
20 changes: 20 additions & 0 deletions src/main/java/com/github/sttk/sabi/DataAcc.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@

import com.github.sttk.errs.Exc;

/**
* An interface designed for implementing data access operations through default methods in its
* sub-interfaces.
*
* <p>Sub-interfaces of {@code DataAcc} are expected to define and implement data access methods as
* default methods. Within these default methods, the connection to the underlying data store should
* be obtained using the {@link #getDataConn(String, Class)} method provided by this interface. This
* design promotes a clear separation of concerns, allowing data access logic to be encapsulated
* within the interface itself.
*/
public interface DataAcc {
/**
* Retrieves a connection to a data store. This method is intended to be used by default methods
* in sub-interfaces to obtain the necessary connection for performing data access operations.
*
* @param <C> The type of the data connection, which must extend {@link DataConn}.
* @param name The name identifying the specific data connection to retrieve.
* @param cls The {@link Class} object representing the type of the desired data connection.
* @return A data connection object of the specified type.
* @throws Exc if an error occurs while obtaining the data connection.
*/
<C extends DataConn> C getDataConn(String name, Class<C> cls) throws Exc;
}
57 changes: 57 additions & 0 deletions src/main/java/com/github/sttk/sabi/DataConn.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,77 @@

import com.github.sttk.errs.Exc;

/**
* The interface that abstracts a connection per session to an external data service, such as a
* database, file system, or messaging service.
*
* <p>Its primary purpose is to enable cohesive transaction operations across multiple external data
* services within a single transaction context. Implementations of this interface provide the
* concrete input/output operations for their respective data services.
*
* <p>Methods declared within this interface are designed to handle transactional logic. The
* AsyncGroup parameter in various methods allows for asynchronous processing when commit or
* rollback operations are time-consuming.
*/
public interface DataConn {
/**
* Commits the changes made within the current session to the external data service. This method
* is responsible for finalizing all operations performed since the last commit or rollback.
*
* @param ag An {@link AsyncGroup} that can be used to perform asynchronous operations if the
* commit process is time-consuming.
* @throws Exc if an error occurs during the commit operation.
*/
void commit(AsyncGroup ag) throws Exc;

/**
* Performs any necessary pre-commit operations. This method is called before the {@link
* #commit(AsyncGroup)} method.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous pre-commit tasks.
* @throws Exc if an error occurs during the pre-commit operation.
*/
default void preCommit(AsyncGroup ag) throws Exc {}

/**
* Performs any necessary post-commit operations. This method is called after the {@link
* #commit(AsyncGroup)} method has successfully completed.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous post-commit tasks.
*/
default void postCommit(AsyncGroup ag) {}

/**
* Indicates whether a force-back operation should be performed. A force-back is a mechanism to
* revert the committed changes when this connection had been already committed but the other
* connection had failed.
*
* @return {@code true} if a force-back is required, {@code false} otherwise.
*/
default boolean shouldForceBack() {
return false;
}

/**
* Rolls back the changes made within the current session, discarding all operations performed
* since the last commit or rollback.
*
* @param ag An {@link AsyncGroup} that can be used to perform asynchronous operations if the
* rollback process is time-consuming.
*/
void rollback(AsyncGroup ag);

/**
* Performs a force-back operation to revert the committed changes when this connection had been
* already committed but the other connection had failed.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous force-back tasks.
*/
default void forceBack(AsyncGroup ag) {}

/**
* Closes the connection to the external data service, releasing any associated resources. This
* method should be called to ensure proper resource management.
*/
void close();
}
129 changes: 128 additions & 1 deletion src/main/java/com/github/sttk/sabi/DataHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,137 @@
import com.github.sttk.sabi.internal.DataHubInner;
import java.util.Map;

/**
* {@code DataHub} is a central component in the Sabi framework that manages {@link DataSrc} and
* {@link DataConn} instances, facilitating data access and transaction management. It implements
* both {@link DataAcc} for data access operations and {@link AutoCloseable} for resource
* management.
*
* <p>This class allows for the registration and unregistration of local {@link DataSrc} objects,
* and provides methods to execute application logic with or without transactional boundaries.
*/
public class DataHub implements DataAcc, AutoCloseable {
/**
* Represents an error reason that occurred when failing to set up global {@link DataSrc}
* instances.
*
* @param errors A map containing the names of the data sources and the corresponding exceptions
* that occurred during their setup.
*/
public record FailToSetupGlobalDataSrcs(Map<String, Exc> errors) {}

/**
* Represents an error reason that occurred when failing to set up local {@link DataSrc}
* instances.
*
* @param errors A map containing the names of the data sources and the corresponding exceptions
* that occurred during their setup.
*/
public record FailToSetupLocalDataSrcs(Map<String, Exc> errors) {}

/**
* Represents an error reason that occurred when failing to commit one or more {@link DataConn}
* instances.
*
* @param errors A map containing the names of the data connections and the corresponding
* exceptions that occurred during their commit.
*/
public record FailToCommitDataConn(Map<String, Exc> errors) {}

/**
* Represents an error reason that occurred when failing to pre-commit one or more {@link
* DataConn} instances.
*
* @param errors A map containing the names of the data connections and the corresponding
* exceptions that occurred during their pre-commit.
*/
public record FailToPreCommitDataConn(Map<String, Exc> errors) {}

/**
* Represents an error reason where no {@link DataSrc} was found to create a {@link DataConn} with
* the specified name and type.
*
* @param name The name of the data source requested.
* @param dataConnType The type of the data connection requested.
*/
public record NoDataSrcToCreateDataConn(String name, String dataConnType) {}

/**
* Represents an error reason that occurred when failing to create a {@link DataConn} instance.
*
* @param name The name of the data source from which the connection was attempted.
* @param dataConnType The type of the data connection that failed to be created.
*/
public record FailToCreateDataConn(String name, String dataConnType) {}

/**
* Represents an error reason where the created {@link DataConn} instance was null.
*
* @param name The name of the data source.
* @param dataConnType The type of the data connection expected.
*/
public record CreatedDataConnIsNull(String name, String dataConnType) {}

/**
* Represents an error reason that occurred when failing to cast a {@link DataConn} to the
* requested type.
*
* @param name The name of the data connection.
* @param castToType The type to which the data connection was attempted to be cast.
*/
public record FailToCastDataConn(String name, String castToType) {}

/**
* 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) {}

public record RuntimeExceptionOccured() {}
/**
* Represents an unexpected {@link RuntimeException} that occurred during pre-commit or commit
* operations.
*/
public record RuntimeExceptionOccurred() {}

private final DataHubInner inner = new DataHubInner();

/** Constructs a new {@code DataHub} instance. */
public DataHub() {}

/**
* Registers a local {@link DataSrc} with the specified name for use within this {@code DataHub}
* instance. This allows specific data sources to be managed independently from globally
* registered ones.
*
* @param name The unique name for the {@link DataSrc}.
* @param ds The {@link DataSrc} instance to register.
*/
public void uses(String name, DataSrc ds) {
inner.uses(name, ds);
}

/**
* Unregisters a local {@link DataSrc} with the given name from this {@code DataHub} instance.
*
* @param name The name of the {@link DataSrc} to unregister.
*/
public void disuses(String name) {
inner.disuses(name);
}

/**
* Executes the provided application {@link Logic} without transactional boundaries. The {@code
* DataHub} instance itself 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.
* @throws Exc if an {@link Exc} 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 Exc {
D data;
try {
Expand All @@ -60,6 +158,19 @@ public <D> void run(Logic<D> logic) throws Exc {
}
}

/**
* Executes the provided application {@link Logic} within a transactional context. The {@code
* DataHub} instance 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 Exc}, {@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 Exc if an {@link Exc}, {@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 Exc {
D data;
try {
Expand All @@ -82,11 +193,27 @@ public <D> void txn(Logic<D> logic) throws Exc {
}
}

/**
* Retrieves a {@link DataConn} instance from the managed data sources. This method is part of the
* {@link DataAcc} interface implementation.
*
* @param <C> The type of the {@link DataConn} to retrieve, which must extend {@link DataConn}.
* @param name The name of the data source from which to get the connection.
* @param cls The {@link Class} object representing the desired type of the data connection.
* @return A {@link DataConn} instance of the specified type.
* @throws Exc if no data source is found, if the connection cannot be created, if the created
* connection is null, or if the connection cannot be cast to the specified class.
*/
@Override
public <C extends DataConn> C getDataConn(String name, Class<C> cls) throws Exc {
return inner.getDataConn(name, cls);
}

/**
* Closes all {@link DataConn} instances managed by this {@code DataHub}, releasing their
* resources. This method is part of the {@link AutoCloseable} interface and should be called to
* ensure proper resource cleanup, ideally in a try-with-resources statement.
*/
@Override
public void close() {
inner.close();
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/github/sttk/sabi/DataSrc.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,39 @@

import com.github.sttk.errs.Exc;

/**
* The interface that abstracts a data source responsible for managing connections to external data
* services, such as databases, file systems, or messaging services.
*
* <p>It receives configuration for connecting to an external data service and then creates and
* supplies a {@link DataConn} instance, representing a single session connection.
*/
public interface DataSrc {
/**
* Sets up the data source, performing any necessary initialization or configuration to establish
* connectivity to the external data service. This method is typically called once at the
* application startup.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous setup operations, especially
* if initialization is time-consuming.
* @throws Exc if an error occurs during the setup process.
*/
void setup(AsyncGroup ag) throws Exc;

/**
* Closes the data source, releasing all resources and shutting down connections managed by this
* source. This method should be called when the application is shutting down to ensure proper
* resource cleanup.
*/
void close();

/**
* Creates and returns a new {@link DataConn} instance, representing a single session connection
* to the external data service. Each call to this method should yield a new, independent
* connection.
*
* @return A new {@link DataConn} instance for a session.
* @throws Exc if an error occurs while creating the data connection.
*/
DataConn createDataConn() throws Exc;
}
21 changes: 21 additions & 0 deletions src/main/java/com/github/sttk/sabi/Logic.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,28 @@

import com.github.sttk.errs.Exc;

/**
* Represents the application's business logic, designed to separate data access concerns from the
* core logic.
*
* <p>Implementations of this functional interface should focus solely on the business logic,
* utilizing the provided {@code data} object of type {@code D} for all data access operations. The
* {@link #run(Object)} method should not contain any direct data access code; instead, it should
* delegate such operations to methods of the {@code D} object.
*
* <p>If an exceptional condition occurs during the execution of the logic, an {@link Exc} object
* should be thrown.
*
* @param <D> The type of the data access object through which data operations are performed.
*/
@FunctionalInterface
public interface Logic<D> {
/**
* Executes the application's business logic. This method should implement the core logic, relying
* on the {@code data} object for all data access needs.
*
* @param data The data access object, providing methods for interacting with data.
* @throws Exc if an error or exceptional condition occurs during the logic execution.
*/
void run(D data) throws Exc;
}
Loading
Loading