Skip to content
Merged
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
149 changes: 82 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The examples of declaring that repository and the dependency on this package in

### For Maven

```
```xml
<dependencies>
<dependency>
<groupId>io.github.sttk</groupId>
Expand All @@ -63,7 +63,7 @@ The examples of declaring that repository and the dependency on this package in

### For Gradle

```
```groovy
repositories {
mavenCentral()
}
Expand All @@ -74,103 +74,107 @@ dependencies {

## Usage

### 1. Implementing DataSrc and DataConn

First, you'll define `DataSrc` which manages connections to external data services and creates `DataConn`. Then, you'll define `DataConn` which represents a session-specific connection and implements transactional operations.

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.DataSrc;
import com.github.sttk.sabi.DataConn;
import com.github.sttk.sabi.AsyncGroup;

class FooDataSrc implements DataSrc {
@Override public void setup(AsyncGroup ag) throws Err {}
@Override public void close() {}
@Override public DataConn createDataConn() throws Err { return new FooDataConn(); }
}

class FooDataConn implements DataConn {
@Override public void commit(AsyncGroup ag) throws Err {}
@Override public void rollback(AsyncGroup ag) {}
@Override public void close(AsyncGroup ag) {}
}

class BarDataSrc implements DataSrc {
@Override public void setup(AsyncGroup ag) throws Err {}
@Override public void close() {}
@Override public DataConn createDataConn() throws Err { return new BarDataConn(); }
}

class BarDataConn implements DataConn {
@Override public void commit(AsyncGroup ag) throws Err {}
@Override public void rollback(AsyncGroup ag) {}
@Override public void close(AsyncGroup ag) {}
}
```

### 2. Implementing logic functions and data interfaces
### 1. Implementing a logic function and a data access interface

Define interfaces and functions that express your application logic. These interfaces are independent of specific data source implementations, improving testability.
First, define a functional interface that represents your application logic, along with its dedicated data access interface. This interface is independent of specific data source implementations, improving testability.

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.Logic;

interface MyData {
String getText() throws Err;
void setText(String text) throws Err;
}
```
```java
import com.github.sttk.errs.Err;

class MyLogic implements Logic<MyData> {
@Override public void run(MyData data) throws Err {
@Override
public void run(MyData data) throws Err {
String text = data.getText();
data.setText(text);
}
}
```

### 3. Implementing DataAcc derived classes
### 2. Implementing DataAcc derived interfaces

The `DataAcc` interface abstracts access to data connections. The methods defined here will be used to obtain data connections via `DataHub` and perform actual data operations.
The `DataAcc` interface provides a simple mechanism to retrieve `DataConn` objects. However, it's the derived interfaces (like `GettingDataAcc` and `SettingDataAcc` in this example) that define the application-specific methods for accessing data. These methods then use `DataHub#getDataConn` to obtain the appropriate `DataConn` and perform the actual data operations.

```java
interface AllLogicData extends MyData {}
```

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.DataAcc;

interface GettingDataAcc extends DataAcc, MyData {
@Override default String getText() throws Err {
var conn = getDataConn("foo", FooDataConn.class);
// ...
interface GettingDataAcc extends DataAcc, AllLogicData {
default String getText() throws Err {
return "output text";
}
}
```

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.DataAcc;
import com.github.sttk.sabi_redis.RedisDataConn;
import com.github.sttk.sabi_stdio.StdioDataConn; // This is a conceptual, non-existent DataConn.
import java.io.InputStream;
import java.io.PrintStream;

interface SettingDataAcc extends DataAcc, AllLogicData {
default void setText(String text) throws Err {
var redisDc = getDataConn("redis", RedisDataConn.class);
var redisConn = redisDc.getConnection();
var commands = redisConn.sync();
try {
commands.set("sample", text);
} catch (Exception e) {
throw new Err("fail to set value", e);
}

interface SettingDataAcc extends DataAcc, MyData {
@Override default void setText(String text) throws Err {
var conn = getDataConn("bar", BarDataConn.class);
// ...
redisDc.addRollback(rConn -> {
var cmd = rConn.sync();
try {
cmd.del("sample");
} catch (Exception e) {
throw new Err("fail to roll back", e);
}
});

var stdioDc = getDataConn("stdio", StdioDataConn.class);
stdioDc.addPostCommit((InputStream in, PrintStream out, PrintStream err) -> {
out.printf("%s", text);
});
}
}
```

### 4. Integrating data interfaces and DataAcc derived classes into `DataHub`
### 3. Integrating data interfaces and DataAcc derived interfaces into DataHub

The `DataHub` is the central component that manages all `DataSrc` and `DataConn`, providing access to them for your application logic. By implementing the data interface (`MyData`) from step 2 and the `DataAcc` class from step 3 on `DataHub`, you integrate them.
The `DataHub` is the central component that manages all `DataSrc` and `DataConn`,
providing access to them for your application logic.
By implementing the data interface (`MyData`) from step 1. and the `DataAcc` classes
from step 2. on `DataHub`, you integrate them.

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.DataHub;

class MyDataHub extends DataHub implements GettingDataAcc, SettingDataAcc {}
class MyDataHub extends DataHub implements GettingDataAcc, SettingDataAcc {
public MyDataHub() {}
}
```

### 5. Using logic functions and `DataHub`
### 4. Using logic functions and DataHub

Inside your init function, register your global `DataSrc`. Next, main function calls run function, and inside run function, setup the sabi framework. Then, create an instance of `DataHub` and register the necessary local `DataSrc` using the Uses method. Finally, use the txn method of `DataHub` to execute your defined application logic function (`MyLogic`) within a transaction. This automatically handles transaction commits and rollbacks.
Inside your `static` block, register your global `DataSrc`. Next, `main` function calls `run` function, and inside `run` function, set up the sabi framework. Then, create an instance of `DataHub` and register the necessary local `DataSrc` using the `Sabi.uses` method. Finally, use the `DataHub#run` method or `DataHub#txn` method to execute your defined application logic function (`MyLogic`) without or within a transaction.

```java
import com.github.sttk.errs.Err;
import com.github.sttk.sabi.DataHub;
import com.github.sttk.sabi.Sabi;

public class Main {
Expand All @@ -179,22 +183,33 @@ public class Main {
Sabi.uses("foo", new FooDataSrc());
}

static MyLogic myLogic = new MyLogic();

public static void main(String[] args) {
// Set up the sabi framework.
try (var ac = Sabi.setup()) {
try {
run();
} catch (Exception e) {
System.err.println(e.toString());
System.exit(1);
}
}

static void run() throws Err {
// Set up the sabi framework
try (var ac = Sabi.setup()) {

// Creates a new instance of DataHub.
var hub = new MyDataHub();
try (var data = new MyDataHub()) {

// Register session-local DataSrc to DataHub.
hub.uses("bar", new BarDataSrc());
// Register session-local DataSrc with DataHub
data.uses("bar", new BarDataSrc());

// Execute application logic within a transaction.
// MyLogic performs data operations via DataHub.
hub.txn(new MyLogic());
// Execute application logic without a transaction control.
data.run(myLogic);

} catch (Exception e) {
System.exit(1);
// If you need to execute logic within a transaction, use the `txn` method instead of `run`
// data.txn(myLogic);
}
}
}
}
Expand Down