Compare commits

...
This repository has been archived on 2026-07-19. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.

7 commits

7 changed files with 342 additions and 18 deletions

View file

@ -0,0 +1,3 @@
# ACM-FW-001-attempt-1-run-93ee9ccb3cf3
Forge 이슈 작업 브랜치 `forge/ACM-FW-001-attempt-1-run-93ee9ccb3cf3`.

View file

@ -0,0 +1,30 @@
package com.klaro.acquirecore.framework;
/**
* Transaction configuration DTO. Migrated from txcore.h tx_config_t.
*/
public class TxConfig {
private int timeoutSeconds = 30;
private int maxRetries = 3;
private boolean autoCommit = false;
private String isolationLevel = "READ_COMMITTED";
private boolean rollbackOnException = true;
public TxConfig() {}
public TxConfig(int timeoutSeconds, int maxRetries) {
this.timeoutSeconds = timeoutSeconds;
this.maxRetries = maxRetries;
}
public int getTimeoutSeconds() { return timeoutSeconds; }
public void setTimeoutSeconds(int timeoutSeconds) { this.timeoutSeconds = timeoutSeconds; }
public int getMaxRetries() { return maxRetries; }
public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; }
public boolean isAutoCommit() { return autoCommit; }
public void setAutoCommit(boolean autoCommit) { this.autoCommit = autoCommit; }
public String getIsolationLevel() { return isolationLevel; }
public void setIsolationLevel(String isolationLevel) { this.isolationLevel = isolationLevel; }
public boolean isRollbackOnException() { return rollbackOnException; }
public void setRollbackOnException(boolean rollbackOnException) { this.rollbackOnException = rollbackOnException; }
}

View file

@ -1,31 +1,53 @@
package com.klaro.acquirecore.framework;
import java.util.HashMap;
import java.util.Map;
import java.util.HashMap;
/**
* 레거시 TxCore {@code TXBUF} (고정 슬롯 / 버퍼) Spring 대체 자리표시자.
*
* <p> 전환에서는 요청/응답 DTO(record) 정형 필드를 담고, 컨텍스트는
* 서비스 체인({@code tx_call}) 전달되는 느슨한 / 상태만 보관한다.
* Transaction context DTO holding state for a single transaction lifecycle.
* Migrated from txcore.h tx_context_t struct.
*/
public final class TxContext {
public class TxContext {
private final Map<String, Object> slots = new HashMap<>();
/** TXBUF 필드 설정 (레거시 {@code Fchg} 상당). */
public TxContext put(String key, Object value) {
slots.put(key, value);
return this;
/** Transaction state enumeration. Migrated from txcore.h tx_state_t. */
public enum TxState {
IDLE, PENDING, ACTIVE, COMMITTED, ROLLED_BACK, FAILED
}
/** TXBUF 필드 조회 (레거시 {@code Fget} 상당). */
public Object get(String key) {
return slots.get(key);
private String txId;
private String serviceName;
private TxState state;
private long startTime;
private long endTime;
private Map<String, Object> attributes;
private String errorMessage;
public TxContext() {
this.attributes = new HashMap<>();
this.state = TxState.IDLE;
}
/** 적재된 슬롯 개수. */
public int size() {
return slots.size();
public TxContext(String txId, String serviceName) {
this();
this.txId = txId;
this.serviceName = serviceName;
}
public String getTxId() { return txId; }
public void setTxId(String txId) { this.txId = txId; }
public String getServiceName() { return serviceName; }
public void setServiceName(String serviceName) { this.serviceName = serviceName; }
public TxState getState() { return state; }
public void setState(TxState state) { this.state = state; }
public long getStartTime() { return startTime; }
public void setStartTime(long startTime) { this.startTime = startTime; }
public long getEndTime() { return endTime; }
public void setEndTime(long endTime) { this.endTime = endTime; }
public Map<String, Object> getAttributes() { return attributes; }
public void setAttributes(Map<String, Object> attributes) { this.attributes = attributes; }
public Object getAttribute(String key) { return attributes.get(key); }
public void setAttribute(String key, Object value) { attributes.put(key, value); }
public String getErrorMessage() { return errorMessage; }
public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
public boolean isActive() { return state == TxState.ACTIVE || state == TxState.PENDING; }
}

View file

@ -0,0 +1,57 @@
package com.klaro.acquirecore.framework;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.function.Supplier;
/**
* TxCore main entry point. Migrated from txcore.h/txcore.c.
* Provides centralized transaction management facade.
*/
@Component
public class TxCore {
private final TxServiceRegistry registry;
private final TxTemplate template;
@Autowired
public TxCore(TxServiceRegistry registry, TxTemplate template) {
this.registry = registry;
this.template = template;
}
public TxServiceRegistry getRegistry() { return registry; }
public TxTemplate getTemplate() { return template; }
public TxResult executeTransaction(String serviceName, Supplier<Object> action) {
return template.execute(serviceName, action);
}
public TxResult executeTransaction(String serviceName, TxConfig config, Supplier<Object> action) {
return template.execute(serviceName, config, action);
}
public void registerService(String serviceName, TxServiceRegistry.TxServiceHandler handler) {
registry.registerService(serviceName, handler);
}
public void registerService(String serviceName, TxServiceRegistry.TxServiceHandler handler, TxConfig config) {
registry.registerService(serviceName, handler, config);
}
public boolean hasService(String serviceName) {
return registry.hasService(serviceName);
}
public TxContext beginTransaction(String serviceName) {
return template.begin(serviceName);
}
public TxResult commitTransaction(TxContext context) {
return template.commit(context);
}
public TxResult rollbackTransaction(TxContext context, String reason) {
return template.rollback(context, reason);
}
}

View file

@ -0,0 +1,47 @@
package com.klaro.acquirecore.framework;
/**
* Transaction result DTO. Migrated from txcore.h tx_result_t.
*/
public class TxResult {
private boolean success;
private String txId;
private String message;
private Object data;
private long durationMs;
public TxResult() {}
public TxResult(boolean success, String txId) {
this.success = success;
this.txId = txId;
}
public TxResult(boolean success, String txId, String message) {
this(success, txId);
this.message = message;
}
public static TxResult ok(String txId) {
return new TxResult(true, txId, "Transaction committed successfully");
}
public static TxResult ok(String txId, String message) {
return new TxResult(true, txId, message);
}
public static TxResult fail(String txId, String message) {
return new TxResult(false, txId, message);
}
public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; }
public String getTxId() { return txId; }
public void setTxId(String txId) { this.txId = txId; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public Object getData() { return data; }
public void setData(Object data) { this.data = data; }
public long getDurationMs() { return durationMs; }
public void setDurationMs(long durationMs) { this.durationMs = durationMs; }
}

View file

@ -0,0 +1,69 @@
package com.klaro.acquirecore.framework;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
/**
* Service registry for transaction services. Migrated from txcore.c tx_service_registry.
* Replaces TX_SERVICE/registry pattern with @Service dispatch.
*/
@Service
public class TxServiceRegistry {
/** Functional interface for transaction service handlers. */
@FunctionalInterface
public interface TxServiceHandler {
TxResult execute(TxContext context);
}
private final Map<String, TxServiceHandler> services = new ConcurrentHashMap<>();
private final Map<String, TxConfig> serviceConfigs = new ConcurrentHashMap<>();
@PostConstruct
public void initialize() {}
public void registerService(String serviceName, TxServiceHandler handler) {
services.put(serviceName, handler);
}
public void registerService(String serviceName, TxServiceHandler handler, TxConfig config) {
services.put(serviceName, handler);
serviceConfigs.put(serviceName, config);
}
public void unregisterService(String serviceName) {
services.remove(serviceName);
serviceConfigs.remove(serviceName);
}
public TxServiceHandler getService(String serviceName) {
return services.get(serviceName);
}
public boolean hasService(String serviceName) {
return services.containsKey(serviceName);
}
public TxConfig getConfig(String serviceName) {
return serviceConfigs.getOrDefault(serviceName, new TxConfig());
}
public TxResult execute(String serviceName, TxContext context) {
TxServiceHandler handler = services.get(serviceName);
if (handler == null) {
return TxResult.fail(context.getTxId(), "Service not found: " + serviceName);
}
return handler.execute(context);
}
public void forEachService(BiConsumer<String, TxServiceHandler> action) {
services.forEach(action);
}
public int getServiceCount() {
return services.size();
}
}

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; }
}