[framework] TxCore → common-framework (TxContext·MessageCodec) #1
1 changed files with 280 additions and 0 deletions
|
|
@ -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<String, Object> 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> T get(String key) {
|
||||
return (T) data.get(key);
|
||||
}
|
||||
|
||||
public Map<String, Object> 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<String, Object> 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> 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<String, Object> payload;
|
||||
private final TxContext context;
|
||||
|
||||
public TxRequest(String serviceName, Map<String, Object> 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<String, Object> payload) {
|
||||
return new TxRequest(serviceName, payload, null);
|
||||
}
|
||||
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
public Map<String, Object> getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public TxContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> 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<String, Object> data;
|
||||
private final String errorMessage;
|
||||
|
||||
private TxResponse(TxResult result, Map<String, Object> 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<String, Object> 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<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key) {
|
||||
return (T) data.get(key);
|
||||
}
|
||||
|
||||
public TxResponse with(String key, Object value) {
|
||||
Map<String, Object> newData = new HashMap<>(this.data);
|
||||
newData.put(key, value);
|
||||
return new TxResponse(this.result, newData, this.errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in a new issue