From 7b639a553dcc1c04a0580415e29e86a57164bfb0 Mon Sep 17 00:00:00 2001 From: "semin.baek" Date: Tue, 29 Apr 2025 15:59:28 +0900 Subject: [PATCH] =?UTF-8?q?MessageUtils=20ReceiveMessageDto=EC=9D=98=20?= =?UTF-8?q?=EC=A0=95=ED=95=A9=EC=84=B1=20=EC=B2=B4=ED=81=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20shutdown.sh=20=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=EB=A1=9C=EC=A7=81=20=EB=B0=8F=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/script/shutdown.sh | 27 ++++++ src/docs/script/startup.sh | 4 + .../dfxagent-bd-test-oracle.json | 2 +- .../agent/config/DfxAgentConfiguration.java | 43 ++++++++- .../agent/listener/ListenerController.java | 1 + .../agent/listener/dto/ReceiveMessageDto.java | 1 + .../dfx/agent/support/MessageUtils.java | 94 +++++++++---------- .../task/postman/PostmanSchedulerService.java | 3 +- 8 files changed, 125 insertions(+), 50 deletions(-) create mode 100644 src/docs/script/shutdown.sh create mode 100644 src/docs/script/startup.sh diff --git a/src/docs/script/shutdown.sh b/src/docs/script/shutdown.sh new file mode 100644 index 0000000..7985cf8 --- /dev/null +++ b/src/docs/script/shutdown.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +PID_FILE="proc/dfxagent.pid" + +# PID 파일 존재 여부 확인 +if [ ! -f "$PID_FILE" ]; then + echo "PID 파일이 없습니다: $PID_FILE" + exit 1 +fi + +# PID 읽기 +PID=$(cat "$PID_FILE") + +# PID가 숫자인지 검증 +if ! [[ "$PID" =~ ^[0-9]+$ ]]; then + echo "PID 파일에 잘못된 값이 들어있습니다: $PID" + exit 1 +fi + +# 프로세스 존재 여부 확인 (optional) +if ps -p "$PID" > /dev/null 2>&1; then + echo "프로세스 종료 중: PID=$PID" + kill -9 "$PID" + echo "종료 완료" +else + echo "PID=$PID 프로세스가 존재하지 않습니다." +fi diff --git a/src/docs/script/startup.sh b/src/docs/script/startup.sh new file mode 100644 index 0000000..68a53ae --- /dev/null +++ b/src/docs/script/startup.sh @@ -0,0 +1,4 @@ +#!/bin/sh +AGENT_HOME=/home/dfxagent/agent +TODAY=$(date "+%Y%m%d") +java -jar $AGENT_HOME/lib/dfxagent.jar --setting.file=$AGENT_HOME/conf/settings.json > $AGENT_HOME/logs/agent.$TODAY.log & \ No newline at end of file diff --git a/src/docs/settings-examples/dfxagent-bd-test-oracle.json b/src/docs/settings-examples/dfxagent-bd-test-oracle.json index 3d099cb..b371f60 100644 --- a/src/docs/settings-examples/dfxagent-bd-test-oracle.json +++ b/src/docs/settings-examples/dfxagent-bd-test-oracle.json @@ -37,7 +37,7 @@ "taskType": "DB_READ_THEN_SEND", "action": { "type": "SCHEDULED", - "cron": "0 */1 * * * *" + "cron": "0 0/1 * * * *" }, "message": { "messageType": "TRANSFER_DB_TO_DB", diff --git a/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java b/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java index 8f60244..bd19a2f 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java @@ -1,5 +1,6 @@ package com.bsmlab.dfx.agent.config; +import com.bsmlab.dfx.agent.DfxAgentApplication; import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; import com.bsmlab.dfx.agent.config.datasource.DynamicRoutingDataSource; import com.bsmlab.dfx.agent.config.datasource.RefreshableSqlSessionFactoryBean; @@ -21,7 +22,15 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.*; import java.util.concurrent.Executor; @@ -41,13 +50,14 @@ public class DfxAgentConfiguration { //example: setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json @Value("${setting.file}") private String settingFile; + private String pid; private Map temporarySqlSessionFactoryMap = new HashMap<>(); Map temporaryTransactionManagerMap = new HashMap<>(); // agent 설정 관리자. 대부분의 기능에 필요함 @Bean(name = "agentConfigReader") - public AgentConfigReader agentConfigReader() { // 실행확인됨 + public AgentConfigReader agentConfigReader() throws URISyntaxException, IOException { // 실행확인됨 if(StringUtils.isBlank(this.settingFile)) { log.error("cannot found a setting file. {}", this.settingFile); log.error("exit application"); @@ -55,6 +65,37 @@ public class DfxAgentConfiguration { } AgentConfigReader agentConfigReader = new AgentConfigReader(); agentConfigReader.loadConfigFile(this.settingFile); + // Process ID를 찾아 app_home/proc/pid 파일에 기록한다. 이후 shutdown.sh에서 해당 pid를 사용하여 kill -9 pid 를 실행한다. + this.pid = String.valueOf(ProcessHandle.current().pid()); + URL location = DfxAgentApplication.class.getProtectionDomain().getCodeSource().getLocation(); + URI uri = location.toURI(); + File file; + if ("file".equalsIgnoreCase(uri.getScheme())) { + // 파일 시스템 상의 경로 + file = new File(uri); + } + else if ("jar".equalsIgnoreCase(uri.getScheme()) || location.toString().startsWith("jar:")) { + // JAR 내부 경로일 경우 + String path = location.toString(); + log.debug("path: {}", path); + if (path.startsWith("jar:")) { + path = path.substring(4, path.indexOf("!") - 1); + path = path.substring(path.indexOf(":") + 1, path.lastIndexOf("/")); + } + log.debug("path: {}", path); + file = new File(path); + } + else { + // 파일 시스템 상의 경로 + file = new File(uri); + } + String procDirectoryPath = file.getParent() + File.separator + "proc"; + File procFile = new File(procDirectoryPath); + if(!procFile.exists()) { + procFile.mkdirs(); + } + Path pidFilePath = Path.of(procDirectoryPath + File.separator, "dfxagent.pid"); + Files.writeString(pidFilePath, pid, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); return agentConfigReader; } diff --git a/src/main/java/com/bsmlab/dfx/agent/listener/ListenerController.java b/src/main/java/com/bsmlab/dfx/agent/listener/ListenerController.java index 209ec67..72d961a 100644 --- a/src/main/java/com/bsmlab/dfx/agent/listener/ListenerController.java +++ b/src/main/java/com/bsmlab/dfx/agent/listener/ListenerController.java @@ -32,6 +32,7 @@ public class ListenerController { String contentType = request.getContentType(); if(contentType != null && contentType.contains("application/json")) { String bodyString = ServletUtils.getBodyString(request); + log.debug("from: {} receive a message: {}", request.getRemoteAddr(), bodyString); ackDto = listenerService.receiveMessage(bodyString); } else if(contentType != null && contentType.contains("multipart/form-data")) { diff --git a/src/main/java/com/bsmlab/dfx/agent/listener/dto/ReceiveMessageDto.java b/src/main/java/com/bsmlab/dfx/agent/listener/dto/ReceiveMessageDto.java index 7a23e75..464b8ec 100644 --- a/src/main/java/com/bsmlab/dfx/agent/listener/dto/ReceiveMessageDto.java +++ b/src/main/java/com/bsmlab/dfx/agent/listener/dto/ReceiveMessageDto.java @@ -7,6 +7,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +@ToString @Getter @Setter @Builder diff --git a/src/main/java/com/bsmlab/dfx/agent/support/MessageUtils.java b/src/main/java/com/bsmlab/dfx/agent/support/MessageUtils.java index 49f8242..d6a66d0 100644 --- a/src/main/java/com/bsmlab/dfx/agent/support/MessageUtils.java +++ b/src/main/java/com/bsmlab/dfx/agent/support/MessageUtils.java @@ -16,6 +16,7 @@ import java.util.*; public class MessageUtils { private MessageUtils() {}; + @SuppressWarnings("unchecked") public static ReceiveMessageDto toReceiveMessageDto(String messageJsonString) throws IllegalMessageException, NullMessageException, InCompleteMessageException { ReceiveMessageDto receiveMessageDto = null; ObjectMapper objectMapper = new ObjectMapper(); @@ -25,36 +26,29 @@ public class MessageUtils { if(map == null) { throw new NullMessageException(""); } - if(map.get("sender") == null) { - throw new InCompleteMessageException("sender 엘리먼트를 찾을 수 없습니다."); - } - else if(!(map.get("sender") instanceof Map)) { - throw new InCompleteMessageException("sender 엘리먼트의 데이터가 객체타입이 아닙니다."); - } - Map senderMap = (Map)map.get("sender"); String senderHostId; - if(senderMap.get("hostId") == null) { - throw new InCompleteMessageException("sender.hostId 엘리먼트를 찾을 수 없습니다."); + if(map.get("senderHostId") == null) { + throw new InCompleteMessageException("senderHostId 엘리먼트를 찾을 수 없습니다."); } - else if(StringUtils.isBlank(String.valueOf(senderMap.get("hostId")))) { - throw new InCompleteMessageException("sender.hostId 값을 찾을 수 없습니다."); + else if(StringUtils.isBlank(String.valueOf(map.get("senderHostId")))) { + throw new InCompleteMessageException("senderHostId 값을 찾을 수 없습니다."); } else { - senderHostId = String.valueOf(senderMap.get("hostId")); + senderHostId = String.valueOf(map.get("senderHostId")); } long senderTimestamp = 0; - if(senderMap.get("timestamp") == null) { - throw new InCompleteMessageException("sender.timestamp 엘리먼트를 찾을 수 없습니다."); + if(map.get("senderTimestamp") == null) { + throw new InCompleteMessageException("senderTimestamp 엘리먼트를 찾을 수 없습니다."); } - else if(StringUtils.isBlank(String.valueOf(senderMap.get("timestamp")))) { - throw new InCompleteMessageException("sender.timestamp 값을 찾을 수 없습니다."); + else if(StringUtils.isBlank(String.valueOf(map.get("senderTimestamp")))) { + throw new InCompleteMessageException("senderTimestamp 값을 찾을 수 없습니다."); } else { - String senderTimeStampString = String.valueOf(senderMap.get("timestamp")); + String senderTimeStampString = String.valueOf(map.get("senderTimestamp")); try { senderTimestamp = Long.parseLong(senderTimeStampString); } catch (NumberFormatException e) { - throw new InCompleteMessageException("sender.timestamp 값의 형식이 숫자형식이 아닙니다. " + senderTimeStampString); + throw new InCompleteMessageException("senderTimestamp 값의 형식이 숫자형식이 아닙니다. " + senderTimeStampString); } } String messageUuid; @@ -73,35 +67,6 @@ public class MessageUtils { throw new InCompleteMessageException("messageUuid 값의 형식이 숫자형식이 아닙니다. " + messageUuid); } } - long receivedTimestamp = System.currentTimeMillis(); - if(map.get("recipient") == null) { - throw new InCompleteMessageException("recipient 엘리먼트를 찾을 수 없습니다."); - } - else if(!(map.get("recipient") instanceof Map)) { - throw new InCompleteMessageException("recipient 엘리먼트의 데이터가 객체타입이 아닙니다."); - } - Map recipientMap = (Map)map.get("recipient"); - //TODO recipient - String recipientHostId; - if(recipientMap.get("hostId") == null) { - throw new InCompleteMessageException("recipient.hostId 엘리먼트를 찾을 수 없습니다."); - } - else if(StringUtils.isBlank(String.valueOf(recipientMap.get("hostId")))) { - throw new InCompleteMessageException("recipient.hostId 값을 찾을 수 없습니다."); - } - else { - recipientHostId = String.valueOf(recipientMap.get("hostId")); - } - String recipientDropBoxId; - if(recipientMap.get("dropBoxId") == null) { - throw new InCompleteMessageException("recipient.dropBoxId 엘리먼트를 찾을 수 없습니다."); - } - else if(StringUtils.isBlank(String.valueOf(recipientMap.get("dropBoxId")))) { - throw new InCompleteMessageException("recipient.dropBoxId 값을 찾을 수 없습니다."); - } - else { - recipientDropBoxId = String.valueOf(recipientMap.get("dropBoxId")); - } AgentConfigDto.MessageType messageType; if(map.get("messageType") == null) { throw new InCompleteMessageException("messageType 엘리먼트를 찾을 수 없습니다."); @@ -116,6 +81,41 @@ public class MessageUtils { } messageType = EnumUtils.getEnum(AgentConfigDto.MessageType.class, messageTypeString); } + long receivedTimestamp = 0; + if(map.get("receivedTimestamp") == null) { + throw new InCompleteMessageException("receivedTimestamp 엘리먼트를 찾을 수 없습니다."); + } + else if(StringUtils.isBlank(String.valueOf(map.get("receivedTimestamp")))) { + throw new InCompleteMessageException("receivedTimestamp 값을 찾을 수 없습니다."); + } + else { + String receivedTimestampString = String.valueOf(map.get("receivedTimestamp")); + try { + receivedTimestamp = Long.parseLong(receivedTimestampString); + } catch (NumberFormatException e) { + throw new InCompleteMessageException("receivedTimestamp 값의 형식이 숫자형식이 아닙니다. " + receivedTimestampString); + } + } + String recipientHostId; + if(map.get("recipientHostId") == null) { + throw new InCompleteMessageException("recipientHostId 엘리먼트를 찾을 수 없습니다."); + } + else if(StringUtils.isBlank(String.valueOf(map.get("recipientHostId")))) { + throw new InCompleteMessageException("recipientHostId 값을 찾을 수 없습니다."); + } + else { + recipientHostId = String.valueOf(map.get("recipientHostId")); + } + String recipientDropBoxId; + if(map.get("recipientDropBoxId") == null) { + throw new InCompleteMessageException("recipientDropBoxId 엘리먼트를 찾을 수 없습니다."); + } + else if(StringUtils.isBlank(String.valueOf(map.get("recipientDropBoxId")))) { + throw new InCompleteMessageException("recipientDropBoxId 값을 찾을 수 없습니다."); + } + else { + recipientDropBoxId = String.valueOf(map.get("recipientDropBoxId")); + } String dataString; if(map.get("data") == null) { throw new InCompleteMessageException("data 엘리먼트를 찾을 수 없습니다."); diff --git a/src/main/java/com/bsmlab/dfx/agent/task/postman/PostmanSchedulerService.java b/src/main/java/com/bsmlab/dfx/agent/task/postman/PostmanSchedulerService.java index bc9478a..bcd6190 100644 --- a/src/main/java/com/bsmlab/dfx/agent/task/postman/PostmanSchedulerService.java +++ b/src/main/java/com/bsmlab/dfx/agent/task/postman/PostmanSchedulerService.java @@ -89,7 +89,8 @@ public class PostmanSchedulerService { HttpEntity bodyEntity = new HttpEntity<>(receiveMessageDto, httpHeaders); RestTemplate restTemplate = new RestTemplate(); AgentConfigDto.KnownAgent knownAgent = agentConfigReader.getKnownAgent(postman.getRecipientHostId()); - String url = "https://" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + "/listen"; + String url = "http://" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + "/listen"; + log.debug("postman to {} send a message {}", receiveMessageDto.getRecipientHostId(), receiveMessageDto.toString()); String response = restTemplate.postForObject(url, bodyEntity, String.class); AckDto ackDto = objectMapper.readValue(response, new TypeReference() {}); if(AckDto.ResultType.RECEIVE_SUCCESS != ackDto.getResult()) {