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

import com.github.sttk.sabi.internal.AsyncGroupImpl;

/**
* An interface for asynchronously executing multiple {@link Runner} instances and waiting for their
* completion.
* Manages asynchronous background tasks executed during data source and data connection lifecycle
* events.
*
* <p>An instance of {@code AsyncGroup} is passed to methods of {@link DataSrc} (such as {@link
* DataSrc#setup(AsyncGroup)}) and {@link DataConn} (such as {@link DataConn#commit(AsyncGroup)} and
* {@link DataConn#rollback(AsyncGroup)}). Implementations of data sources and data connections can
* register background asynchronous operations (such as parallel cleanup or pre-commit validations)
* using the {@link #add(Runner)} method.
*
* <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.
* <p>All registered {@link Runner} tasks are managed by this group and executed asynchronously. If
* any registered task fails, is interrupted, or throws an unhandled runtime exception,
* corresponding error records defined in this interface are produced to report the failure.
*/
public sealed interface AsyncGroup permits com.github.sttk.sabi.internal.AsyncGroupImpl {
public sealed interface AsyncGroup permits AsyncGroupImpl {

/**
* Represents the reason for a new {@link com.github.sttk.errs.Err} 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.Err}.
*/
/** Indicates that a registered {@link Runner} task failed during its execution. */
record RunnerFailed() {}

/**
* Represents the reason for an {@link com.github.sttk.errs.Err} exception object when the
* creation of a thread for asynchronous execution of a {@link Runner} fails.
*/
/** Indicates that a registered {@link Runner} task execution was interrupted. */
record RunnerInterrupted() {}

/** Represents an unexpected {@link RuntimeException} that occurred. */
record RuntimeExceptionOccurred() {}
/**
* Indicates that an unhandled runtime exception was thrown during the execution of a registered
* {@link Runner} task.
*/
record RuntimeExceptionOccured() {}

/**
* Adds a {@link Runner} to this group for asynchronous execution. The added runner will be
* executed in a separate thread.
* Adds a background task to be executed asynchronously by this group.
*
* <p>The task is encapsulated in a {@link Runner} functional interface and scheduled for parallel
* asynchronous execution.
*
* @param runner The {@link Runner} to be added and executed asynchronously.
* @param runner the {@link Runner} task to be added and executed asynchronously
*/
void add(final Runner runner);
void add(Runner runner);
}
32 changes: 18 additions & 14 deletions src/main/java/com/github/sttk/sabi/DataAcc.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,29 @@
import com.github.sttk.errs.Err;

/**
* An interface designed for implementing data access operations through default methods in its
* sub-interfaces.
* Provides access to named {@link DataConn} data connection instances.
*
* <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.
* <p>This interface defines the contract for retrieving managed data connections registered under
* specific names within a data access scope (such as a {@link DataHub}). Application business logic
* uses this interface to obtain connection objects required to perform database or external service
* operations.
*/
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.
* Retrieves a data connection associated with the specified data source name and casts it to the
* requested connection class type.
*
* <p>If a connection for the given {@code name} has already been created within the current
* transaction or execution scope, that connection instance is returned. Otherwise, a new
* connection is created via the corresponding registered data source.
*
* @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 Err if an error occurs while obtaining the data connection.
* @param <C> the expected type of {@link DataConn}
* @param name the registered logical name of the data source
* @param cls the {@link Class} representing the target connection type {@code C}
* @return the data connection instance associated with the specified name
* @throws Err if no data source with the specified name is found, if creating the connection
* fails or yields null, or if the connection cannot be cast to the target type
*/
<C extends DataConn> C getDataConn(String name, Class<C> cls) throws Err;
}
111 changes: 69 additions & 42 deletions src/main/java/com/github/sttk/sabi/DataConn.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,78 +5,105 @@
package com.github.sttk.sabi;

import com.github.sttk.errs.Err;
import java.util.List;

/**
* The interface that abstracts a connection per session to an external data service, such as a
* database, file system, or messaging service.
* Represents a data connection participating in transaction lifecycles managed by a {@link
* DataHub}.
*
* <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.
* <p>Implementations encapsulate connection state and operations for external resources such as
* relational databases, NoSQL stores, or web services. During a transaction, connections progress
* through pre-commit, commit, and post-commit phases, and support rollback and failure reporting
* when errors occur.
*/
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.
* Represents an error when one or more data connections fail during the pre-commit phase.
*
* @param ag An {@link AsyncGroup} that can be used to perform asynchronous operations if the
* commit process is time-consuming.
* @throws Err if an error occurs during the commit operation.
* @param errors the list of error entries detailing connection names and failure causes
*/
void commit(AsyncGroup ag) throws Err;
public record FailToPreCommitDataConn(List<ErrEntry> errors) {}

/**
* Performs any necessary pre-commit operations. This method is called before the {@link
* #commit(AsyncGroup)} method.
* Represents an error when one or more data connections fail during the commit phase.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous pre-commit tasks.
* @throws Err if an error occurs during the pre-commit operation.
* @param errors the list of error entries detailing connection names and failure causes
*/
default void preCommit(AsyncGroup ag) throws Err {}
public record FailToCommitDataConn(List<ErrEntry> errors) {}

/**
* Represents an error when one or more data connections fail during the post-commit phase.
*
* @param errors the list of error entries detailing connection names and failure causes
*/
public record FailToPostCommitDataConn(List<ErrEntry> errors) {}

///

/**
* Commits changes made through this connection.
*
* <p>Async background tasks may be registered to the provided {@link AsyncGroup} during commit
* processing.
*
* @param ag the asynchronous group for registering background tasks
* @throws Err if committing the transaction changes fails
*/
void commit(AsyncGroup ag) throws Err;

/**
* Performs any necessary post-commit operations. This method is called after the {@link
* #commit(AsyncGroup)} method has successfully completed.
* Prepares this connection for commit prior to the main commit phase.
*
* <p>The default implementation does nothing. Subclasses can override this method to perform
* pre-commit checks or flush pending writes.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous post-commit tasks.
* @param ag the asynchronous group for registering background tasks
* @throws Err if pre-commit preparation or validation fails
*/
default void postCommit(AsyncGroup ag) {}
default void preCommit(AsyncGroup ag) throws Err {}

/**
* 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.
* Performs post-commit operations after all connections in a transaction have successfully
* committed.
*
* @return {@code true} if a force-back is required, {@code false} otherwise.
* <p>The default implementation does nothing. Subclasses can override this method to perform
* cleanup or trigger post-commit notifications.
*
* @param ag the asynchronous group for registering background tasks
* @throws Err if post-commit processing fails
*/
default boolean shouldForceBack() {
return false;
}
default void postCommit(AsyncGroup ag) throws Err {}

/**
* Rolls back the changes made within the current session, discarding all operations performed
* since the last commit or rollback.
* Checks whether this connection has been successfully committed.
*
* @param ag An {@link AsyncGroup} that can be used to perform asynchronous operations if the
* rollback process is time-consuming.
* @return {@code true} if this connection was committed; {@code false} otherwise
*/
void rollback(AsyncGroup ag);
boolean isCommitted();

/**
* Performs a force-back operation to revert the committed changes when this connection had been
* already committed but the other connection had failed.
* Rolls back changes made through this connection.
*
* <p>This method is invoked when a transaction fails and must restore the connection or
* underlying storage to its pre-transaction state.
*
* @param ag An {@link AsyncGroup} that can be used for asynchronous force-back tasks.
* @param ag the asynchronous group for registering background tasks
* @throws Err if rolling back connection changes fails
*/
default void forceBack(AsyncGroup ag) {}
void rollback(AsyncGroup ag) throws Err;

/**
* Closes the connection to the external data service, releasing any associated resources. This
* method should be called to ensure proper resource management.
* Notifies this connection of a transaction failure with detailed failure reports.
*
* <p>The default implementation does nothing. Implementations can inspect failure reports to log
* diagnostics or take recovery actions.
*
* @param ag the asynchronous group for registering background tasks
* @param reports the list of transaction failure reports
*/
default void onTxnFailure(AsyncGroup ag, List<TxnFailureReport> reports) {}

/** Closes and disposes of this data connection, releasing any held resources. */
void close();
}
Loading