[framework] TxCore → common-framework (TxContext·MessageCodec) (ACM-FW-001)
This commit is contained in:
parent
9b43defd7d
commit
d15ff5673c
1 changed files with 124 additions and 15 deletions
|
|
@ -1,24 +1,133 @@
|
||||||
package com.klaro.acquirecore.framework;
|
package com.klaro.acquirecore.framework;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
import java.util.Map;
|
||||||
* 레거시 {@code msg_layout.h} 고정길이 전문(電文) 코덱의 Spring 빈 자리표시자.
|
|
||||||
*
|
|
||||||
* <p>실 전환에서는 고정길이(positional) 바이트 레이아웃 ↔ DTO 바인딩을 담당한다
|
|
||||||
* (BeanIO 또는 커스텀 코덱). 지금은 스켈레톤이 빈으로 뜨는지만 증명한다.
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class MessageCodec {
|
|
||||||
|
|
||||||
/** 고정길이 필드를 우측을 공백으로 채워 정규화한다 (자리표시자 구현). */
|
/**
|
||||||
public String padRight(String value, int width) {
|
* Message codec interface and JSON implementation.
|
||||||
if (value == null) {
|
* Provides encoding/decoding of TxRequest and TxResponse.
|
||||||
value = "";
|
*/
|
||||||
|
public interface MessageCodec {
|
||||||
|
|
||||||
|
byte[] encodeRequest(TxRequest request);
|
||||||
|
TxRequest decodeRequest(byte[] data);
|
||||||
|
byte[] encodeResponse(TxResponse response);
|
||||||
|
TxResponse decodeResponse(byte[] data);
|
||||||
|
String getContentType();
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class JsonMessageCodec implements MessageCodec {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public JsonMessageCodec() {
|
||||||
|
this.objectMapper = new ObjectMapper()
|
||||||
|
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
|
||||||
|
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||||
}
|
}
|
||||||
if (value.length() >= width) {
|
|
||||||
return value.substring(0, width);
|
@Override
|
||||||
|
public byte[] encodeRequest(TxRequest request) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsBytes(new RequestDto(
|
||||||
|
request.getServiceName(),
|
||||||
|
request.getPayload(),
|
||||||
|
request.getContext() != null ? request.getContext().getTxnId() : null
|
||||||
|
));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new CodecException("Failed to encode request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TxRequest decodeRequest(byte[] data) {
|
||||||
|
try {
|
||||||
|
RequestDto dto = objectMapper.readValue(data, RequestDto.class);
|
||||||
|
return new TxRequest(dto.serviceName, dto.payload, null);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new CodecException("Failed to decode request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] encodeResponse(TxResponse response) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsBytes(new ResponseDto(
|
||||||
|
response.getResult().name(),
|
||||||
|
response.getResult().getCode(),
|
||||||
|
response.getData(),
|
||||||
|
response.getErrorMessage()
|
||||||
|
));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new CodecException("Failed to encode response", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TxResponse decodeResponse(byte[] data) {
|
||||||
|
try {
|
||||||
|
ResponseDto dto = objectMapper.readValue(data, ResponseDto.class);
|
||||||
|
return new TxResponse(
|
||||||
|
TxCore.TxResult.fromCode(dto.resultCode),
|
||||||
|
dto.data,
|
||||||
|
dto.errorMessage
|
||||||
|
);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new CodecException("Failed to decode response", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return "application/json";
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T decode(byte[] data, Class<T> type) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(data, type);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new CodecException("Failed to decode data", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RequestDto {
|
||||||
|
public String serviceName;
|
||||||
|
public Map<String, Object> payload;
|
||||||
|
public Long txnId;
|
||||||
|
|
||||||
|
public RequestDto() {}
|
||||||
|
|
||||||
|
public RequestDto(String serviceName, Map<String, Object> payload, Long txnId) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
this.payload = payload;
|
||||||
|
this.txnId = txnId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ResponseDto {
|
||||||
|
public String result;
|
||||||
|
public int resultCode;
|
||||||
|
public Map<String, Object> data;
|
||||||
|
public String errorMessage;
|
||||||
|
|
||||||
|
public ResponseDto() {}
|
||||||
|
|
||||||
|
public ResponseDto(String result, int resultCode, Map<String, Object> data, String errorMessage) {
|
||||||
|
this.result = result;
|
||||||
|
this.resultCode = resultCode;
|
||||||
|
this.data = data;
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodecException extends RuntimeException {
|
||||||
|
public CodecException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
}
|
}
|
||||||
return String.format("%-" + width + "s", value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue