[framework] TxCore → common-framework (ACM-FW-001)

This commit is contained in:
forge-bot 2026-07-18 10:10:45 +00:00
parent 63f85f0f81
commit 2ead4f104a

View file

@ -0,0 +1,96 @@
package com.klaro.acquirecore.framework;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.UUID;
import java.util.function.Supplier;
/**
* Transaction template providing @Transactional equivalent functionality.
* Migrated from txcore.c tx_begin/tx_commit/tx_rollback functions.
*/
@Component
public class TxTemplate {
/** Exception thrown when transaction execution fails. */
public static class TxExecutionException extends RuntimeException {
private final String txId;
private final TxContext.TxState state = TxContext.TxState.FAILED;
public TxExecutionException(String message) { super(message); this.txId = null; }
public TxExecutionException(String message, Throwable cause) { super(message, cause); this.txId = null; }
public TxExecutionException(String txId, String message) { super(message); this.txId = txId; }
public TxExecutionException(String txId, String message, Throwable cause) { super(message, cause); this.txId = txId; }
public String getTxId() { return txId; }
public TxContext.TxState getState() { return state; }
}
@Autowired
private TxServiceRegistry registry;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public TxResult execute(String serviceName, Supplier<Object> action) {
return execute(serviceName, new TxConfig(), action);
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
public TxResult execute(String serviceName, TxConfig config, Supplier<Object> action) {
String txId = UUID.randomUUID().toString();
TxContext context = new TxContext(txId, serviceName);
context.setStartTime(System.currentTimeMillis());
context.setState(TxContext.TxState.ACTIVE);
try {
Object result = action.get();
context.setEndTime(System.currentTimeMillis());
context.setState(TxContext.TxState.COMMITTED);
TxResult txResult = TxResult.ok(txId);
txResult.setData(result);
txResult.setDurationMs(context.getEndTime() - context.getStartTime());
return txResult;
} catch (Exception e) {
context.setEndTime(System.currentTimeMillis());
context.setState(TxContext.TxState.ROLLED_BACK);
context.setErrorMessage(e.getMessage());
TxResult txResult = TxResult.fail(txId, e.getMessage());
txResult.setDurationMs(context.getEndTime() - context.getStartTime());
throw new TxExecutionException(txId, "Transaction failed: " + e.getMessage(), e);
}
}
public TxContext begin(String serviceName) {
String txId = UUID.randomUUID().toString();
TxContext context = new TxContext(txId, serviceName);
context.setStartTime(System.currentTimeMillis());
context.setState(TxContext.TxState.PENDING);
return context;
}
public TxContext begin(String serviceName, TxConfig config) {
TxContext context = begin(serviceName);
context.setAttribute("config", config);
return context;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public TxResult commit(TxContext context) {
context.setEndTime(System.currentTimeMillis());
context.setState(TxContext.TxState.COMMITTED);
return TxResult.ok(context.getTxId());
}
public TxResult rollback(TxContext context, String reason) {
context.setEndTime(System.currentTimeMillis());
context.setState(TxContext.TxState.ROLLED_BACK);
context.setErrorMessage(reason);
return TxResult.fail(context.getTxId(), reason);
}
public TxResult executeViaRegistry(String serviceName, TxContext context) {
return registry.execute(serviceName, context);
}
public TxServiceRegistry getRegistry() { return registry; }
}