diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java new file mode 100644 index 0000000..37628a3 --- /dev/null +++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java @@ -0,0 +1,280 @@ +package com.klaro.acquirecore.framework; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; + +/** + * TxCore - Spring Boot equivalent of C txcore.h/txcore.c + * Provides transaction context, buffer, request/response DTOs, and result codes. + */ +public final class TxCore { + + private TxCore() {} + + // ===== TxResult - equivalent to C tx_result_t enum ===== + + public enum TxResult { + OK(0), ERROR(-1), TIMEOUT(-2), ROLLBACK(-3), NESTED(-4); + + private final int code; + + TxResult(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public static TxResult fromCode(int code) { + for (TxResult r : values()) { + if (r.code == code) return r; + } + return ERROR; + } + + public boolean isSuccess() { + return this == OK; + } + + public String toErrorString() { + return switch (this) { + case OK -> "OK"; + case ERROR -> "Error"; + case TIMEOUT -> "Timeout"; + case ROLLBACK -> "Rollback"; + case NESTED -> "Nested transaction not supported"; + }; + } + } + + // ===== TxBuffer - equivalent to C txbuf_t struct ===== + + public static final class TxBuffer { + private static final int MAX_BUFSIZE = 4096; + private final ByteBuffer buffer; + private final Map data; + + public TxBuffer() { + this.buffer = ByteBuffer.allocate(MAX_BUFSIZE); + this.data = new HashMap<>(); + } + + public TxBuffer(int capacity) { + this.buffer = ByteBuffer.allocate(Math.min(capacity, MAX_BUFSIZE)); + this.data = new HashMap<>(); + } + + public int write(byte[] src) { + if (src == null || buffer.remaining() < src.length) return -1; + buffer.put(src); + return src.length; + } + + public int read(byte[] dest) { + if (dest == null || buffer.remaining() < dest.length) return -1; + buffer.get(dest); + return dest.length; + } + + public byte[] toByteArray() { + byte[] result = new byte[buffer.position()]; + buffer.flip(); + buffer.get(result); + return result; + } + + public void put(String key, Object value) { + data.put(key, value); + } + + @SuppressWarnings("unchecked") + public T get(String key) { + return (T) data.get(key); + } + + public Map getData() { + return new HashMap<>(data); + } + + public void clear() { + buffer.clear(); + data.clear(); + } + + public void rewind() { + buffer.rewind(); + } + + public int size() { + return buffer.position(); + } + + public int remaining() { + return buffer.remaining(); + } + } + + // ===== TxContext - equivalent to C tx_context_t struct ===== + + public static final class TxContext { + private static final AtomicLong txnCounter = new AtomicLong(0); + + private final long txnId; + private final int flags; + private final TxBuffer buffer; + private final Map userData; + + public TxContext() { + this(0); + } + + public TxContext(int flags) { + this.txnId = txnCounter.incrementAndGet(); + this.flags = flags; + this.buffer = new TxBuffer(); + this.userData = new HashMap<>(); + } + + public long getTxnId() { + return txnId; + } + + public int getFlags() { + return flags; + } + + public TxBuffer getBuffer() { + return buffer; + } + + public void setUserData(String key, Object value) { + userData.put(key, value); + } + + @SuppressWarnings("unchecked") + public T getUserData(String key) { + return (T) userData.get(key); + } + + public void clearUserData() { + userData.clear(); + } + + public void resetBuffer() { + buffer.clear(); + } + + @Override + public String toString() { + return "TxContext{txnId=" + txnId + ", flags=" + flags + ", bufferSize=" + buffer.size() + "}"; + } + } + + // ===== TxRequest - equivalent to C input void* parameter ===== + + public static final class TxRequest { + private final String serviceName; + private final Map payload; + private final TxContext context; + + public TxRequest(String serviceName, Map payload, TxContext context) { + this.serviceName = Objects.requireNonNull(serviceName); + this.payload = payload != null ? Map.copyOf(payload) : Map.of(); + this.context = context; + } + + public static TxRequest of(String serviceName) { + return new TxRequest(serviceName, Map.of(), null); + } + + public static TxRequest of(String serviceName, Map payload) { + return new TxRequest(serviceName, payload, null); + } + + public String getServiceName() { + return serviceName; + } + + public Map getPayload() { + return payload; + } + + public TxContext getContext() { + return context; + } + + @SuppressWarnings("unchecked") + public T get(String key) { + return (T) payload.get(key); + } + + public boolean has(String key) { + return payload.containsKey(key); + } + } + + // ===== TxResponse - equivalent to C output void* parameter ===== + + public static final class TxResponse { + private final TxResult result; + private final Map data; + private final String errorMessage; + + private TxResponse(TxResult result, Map data, String errorMessage) { + this.result = Objects.requireNonNull(result); + this.data = data != null ? Map.copyOf(data) : Map.of(); + this.errorMessage = errorMessage; + } + + public static TxResponse success() { + return new TxResponse(TxResult.OK, Map.of(), null); + } + + public static TxResponse success(Map data) { + return new TxResponse(TxResult.OK, data, null); + } + + public static TxResponse error(TxResult result) { + return new TxResponse(result, Map.of(), result.toErrorString()); + } + + public static TxResponse error(TxResult result, String message) { + return new TxResponse(result, Map.of(), message); + } + + public static TxResponse error(String message) { + return new TxResponse(TxResult.ERROR, Map.of(), message); + } + + public TxResult getResult() { + return result; + } + + public Map getData() { + return data; + } + + public String getErrorMessage() { + return errorMessage; + } + + public boolean isSuccess() { + return result.isSuccess(); + } + + @SuppressWarnings("unchecked") + public T get(String key) { + return (T) data.get(key); + } + + public TxResponse with(String key, Object value) { + Map newData = new HashMap<>(this.data); + newData.put(key, value); + return new TxResponse(this.result, newData, this.errorMessage); + } + } +}