From 2ce26273d23936d6706af03471d6c555215740a5 Mon Sep 17 00:00:00 2001 From: "semin.baek" Date: Fri, 14 Mar 2025 17:19:31 +0900 Subject: [PATCH] =?UTF-8?q?Settings=20->=20AgentConfigReader,=20AgentConfi?= =?UTF-8?q?gDto=20=EB=B3=80=EA=B2=BD=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/settings-examples/dfxagent.json | 2 +- .../dfx/agent/config/AgentConfigDto.java | 29 +++++-- .../dfx/agent/config/AgentConfigReader.java | 37 ++++++++ .../agent/config/DfxAgentConfiguration.java | 87 ++++++++++--------- .../dfx/agent/config/StartupRunner.java | 1 - .../dfx/agent/config/WebServerCustomizer.java | 4 +- .../listener/service/ListenerService.java | 23 ----- .../dfx/agent/task/TaskExecutorService.java | 23 ++--- .../agent/task/dropbox/DropBoxService.java | 24 ++++- 9 files changed, 142 insertions(+), 88 deletions(-) diff --git a/src/docs/settings-examples/dfxagent.json b/src/docs/settings-examples/dfxagent.json index 4688348..912f9e8 100644 --- a/src/docs/settings-examples/dfxagent.json +++ b/src/docs/settings-examples/dfxagent.json @@ -13,7 +13,7 @@ "drop-box-id-list": ["drop3", "drop4"] } ], - "datasource": [ + "datasource-config": [ { "dataSourceId": "dfcms", "driverClassName": "org.postgresql.Driver", diff --git a/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java b/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java index 917d95b..c72c53d 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java @@ -9,7 +9,7 @@ public class AgentConfigDto { private String hostId; private int listenPort; private List knownAgent; - private List datasource; + private List datasourceConfig; private List sqlMapperLocations; private DropBoxConfig dropBox; private List postman; @@ -23,7 +23,7 @@ public class AgentConfigDto { } @Data - public static class DataSource { + public static class DataSourceConfig { private String dataSourceId; private String driverClassName; private String url; @@ -40,7 +40,7 @@ public class AgentConfigDto { @Data public static class DropBox { private String dropBoxId; - private String taskType; + private TaskType taskType; private String dataSourceId; private String sqlId; private String saveDirectoryRoot; @@ -49,7 +49,7 @@ public class AgentConfigDto { @Data public static class Postman { private String postmanId; - private String taskType; + private TaskType taskType; private PostmanAction action; private PostmanMessage message; private String recipientHostId; @@ -59,7 +59,7 @@ public class AgentConfigDto { @Data public static class PostmanAction { - private String type; + private ActionType type; private String command; private List parametersKeyList; private String cron; @@ -67,8 +67,25 @@ public class AgentConfigDto { @Data public static class PostmanMessage { - private String messageType; + private MessageType messageType; private String dataSourceId; private String sqlId; } + + public static enum ActionType { + TRIGGER, + SCHEDULED + } + + public static enum MessageType { + SAVE_DB_DATA, + SAVE_FILE; + } + + public static enum TaskType { + DB_READ_THEN_SEND, + SAVE_DB_TABLE, + RECEIVE_FILE + } + } diff --git a/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigReader.java b/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigReader.java index cfe3d97..9a8cfd9 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigReader.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigReader.java @@ -1,4 +1,41 @@ package com.bsmlab.dfx.agent.config; +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; + +@Slf4j +@Component +@Getter public class AgentConfigReader { + private AgentConfigDto agentConfigDto = null; + + public void loadConfigFile(String configFilePath) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + this.agentConfigDto = objectMapper.readValue(new File(configFilePath), AgentConfigDto.class); + } catch (DatabindException e) { + log.error("cannot parse a setting file. {}", configFilePath, e); + log.error(e.getMessage(), e); + } catch (IOException e) { + log.error("cannot read a setting file. {}", configFilePath); + log.error(e.getMessage(), e); + } + } + + public AgentConfigDto.DropBox getDropBox(String dropBoxId) { + AgentConfigDto.DropBox found = null; + for(AgentConfigDto.DropBox dropBox : this.agentConfigDto.getDropBox().getDropBoxList()) { + if(dropBox.getDropBoxId().equals(dropBoxId)) { + found = dropBox; + break; + } + } + return found; + } } 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 5bf1c19..5f9eff0 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java @@ -1,6 +1,5 @@ package com.bsmlab.dfx.agent.config; -import com.bsmlab.dfx.agent.config.datasource.DataSourceDto; import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; import com.bsmlab.dfx.agent.config.datasource.DynamicRoutingDataSource; import io.micrometer.common.util.StringUtils; @@ -31,6 +30,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -58,8 +58,8 @@ public class DfxAgentConfiguration { private Map temporarySqlSessionFactoryMap = new HashMap<>(); Map temporaryTransactionManagerMap = new HashMap<>(); - @Bean("settings") - public Settings loadSettings() { + @Bean(name = "agentConfigReader") + public AgentConfigReader agentConfigReader() { if(StringUtils.isBlank(this.embeddedDbFileDirectory)) { log.error("cannot found a embedded DB file. {}", this.embeddedDbFileDirectory); log.error("exit application"); @@ -70,65 +70,70 @@ public class DfxAgentConfiguration { log.error("exit application"); System.exit(0); } - Settings settings = new Settings(); - settings.loadSettingFile(this.settingFile); - return settings; + AgentConfigReader agentConfigReader = new AgentConfigReader(); + agentConfigReader.loadConfigFile(this.settingFile); + return agentConfigReader; } @Bean(name = "dynamicRoutingDataSource") - public DynamicRoutingDataSource dynamicRoutingDataSource(Settings settings) { + public DynamicRoutingDataSource dynamicRoutingDataSource(AgentConfigReader agentConfigReader) { DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(); Map sqlSessionFactoryMap = new HashMap<>(); Map transactionManagerMap = new HashMap<>(); - Map dataSourceDtoMap = settings.getDataSourceDtoMap(); - for(String dataSourceId : dataSourceDtoMap.keySet()) { - DataSourceDto dataSourceDto = dataSourceDtoMap.get(dataSourceId); - BasicDataSource dataSource = new BasicDataSource(); - dataSource.setDriverClassName(dataSourceDto.getDriverClassName()); - dataSource.setUrl(dataSourceDto.getUrl()); - dataSource.setUsername(dataSourceDto.getUsername()); - dataSource.setPassword(dataSourceDto.getPassword()); - if(oracle.jdbc.driver.OracleDriver.class.getCanonicalName().equals(dataSourceDto.getDriverClassName())) { - dataSource.setValidationQuery("SELECT 1 FROM DUAL"); - } - else if(org.postgresql.Driver.class.getCanonicalName().equals(dataSourceDto.getDriverClassName())) { - dataSource.setValidationQuery("SELECT 1"); - } - else if(com.mysql.jdbc.Driver.class.getCanonicalName().equals(dataSourceDto.getDriverClassName())) { - dataSource.setValidationQuery("SELECT 1"); - } - else if(org.mariadb.jdbc.Driver.class.getCanonicalName().equals(dataSourceDto.getDriverClassName())) { - dataSource.setValidationQuery("SELECT 1"); - } - else if(com.ibm.db2.jcc.DB2Driver.class.getCanonicalName().equals(dataSourceDto.getDriverClassName())) { - dataSource.setValidationQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1"); - } - dataSource.setTestOnBorrow(false); - dataSource.setTestOnReturn(false); - dataSource.setTestOnCreate(true); - dataSource.setTestWhileIdle(true); - dataSource.setInitialSize(3); - dataSource.setMinIdle(3); - dataSource.setMaxIdle(30); - dataSource.setMaxTotal(30); + List dataSourceConfigList = agentConfigReader.getAgentConfigDto().getDatasourceConfig(); + for(AgentConfigDto.DataSourceConfig dataSourceConfig : dataSourceConfigList) { + BasicDataSource dataSource = createBasicDataSource(dataSourceConfig); SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); try { - sqlSessionFactoryMap.put(dataSourceId, sqlSessionFactoryBean.getObject()); + sqlSessionFactoryMap.put(dataSourceConfig.getDataSourceId(), sqlSessionFactoryBean.getObject()); } catch (Exception e) { log.error("DynamicRoutingDataSource 생성 중 오류: {}", e.getMessage(), e); throw new RuntimeException(e); } DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource); - transactionManagerMap.put(dataSourceId, transactionManager); - dynamicRoutingDataSource.addDataSource(dataSourceId, dataSource); + transactionManagerMap.put(dataSourceConfig.getDataSourceId(), transactionManager); + dynamicRoutingDataSource.addDataSource(dataSourceConfig.getDataSourceId(), dataSource); } this.temporarySqlSessionFactoryMap = sqlSessionFactoryMap; this.temporaryTransactionManagerMap = transactionManagerMap; return dynamicRoutingDataSource; } + private static BasicDataSource createBasicDataSource(AgentConfigDto.DataSourceConfig dataSourceConfig) { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(dataSourceConfig.getDriverClassName()); + dataSource.setUrl(dataSourceConfig.getUrl()); + dataSource.setUsername(dataSourceConfig.getUsername()); + dataSource.setPassword(dataSourceConfig.getPassword()); + + if(oracle.jdbc.driver.OracleDriver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) { + dataSource.setValidationQuery("SELECT 1 FROM DUAL"); + } + else if(org.postgresql.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) { + dataSource.setValidationQuery("SELECT 1"); + } + else if(com.mysql.jdbc.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) { + dataSource.setValidationQuery("SELECT 1"); + } + else if(org.mariadb.jdbc.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) { + dataSource.setValidationQuery("SELECT 1"); + } + else if(com.ibm.db2.jcc.DB2Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) { + dataSource.setValidationQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1"); + } + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setTestOnCreate(true); + dataSource.setTestWhileIdle(true); + dataSource.setInitialSize(3); + dataSource.setMinIdle(3); + dataSource.setMaxIdle(30); + dataSource.setMaxTotal(30); + return dataSource; + } + @Bean(name = "dynamicDataSourceService") public DynamicDataSourceService dynamicDataSourceService() { DynamicDataSourceService dynamicDataSourceService = new DynamicDataSourceService(); diff --git a/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java b/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java index 8e5a82d..8382470 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java @@ -10,7 +10,6 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component public class StartupRunner implements ApplicationRunner { - private final Settings settings; @Override public void run(ApplicationArguments args) throws Exception { diff --git a/src/main/java/com/bsmlab/dfx/agent/config/WebServerCustomizer.java b/src/main/java/com/bsmlab/dfx/agent/config/WebServerCustomizer.java index 8552989..2c03068 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/WebServerCustomizer.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/WebServerCustomizer.java @@ -10,10 +10,10 @@ import org.springframework.stereotype.Component; @Slf4j @RequiredArgsConstructor public class WebServerCustomizer implements WebServerFactoryCustomizer { - private final Settings settings; + private final AgentConfigReader agentConfigReader; @Override public void customize(ConfigurableServletWebServerFactory factory) { - int port = settings.getListenPort(); + int port = agentConfigReader.getAgentConfigDto().getListenPort(); factory.setPort(port); factory.setContextPath("/"); } diff --git a/src/main/java/com/bsmlab/dfx/agent/listener/service/ListenerService.java b/src/main/java/com/bsmlab/dfx/agent/listener/service/ListenerService.java index c596f5f..687f1e5 100644 --- a/src/main/java/com/bsmlab/dfx/agent/listener/service/ListenerService.java +++ b/src/main/java/com/bsmlab/dfx/agent/listener/service/ListenerService.java @@ -19,29 +19,6 @@ import org.springframework.stereotype.Service; @Service public class ListenerService { private final DropBoxService dropBoxService; - private final ListenerMapper listenerMapper; - private final SqlExecuteService sqlExecuteService; - - public AckDto saveNewMessage(String messageJsonString) { - AckDto ackDto = null; - try { - ReceiveMessageDto receiveMessageDto = MessageUtils.toReceiveMessageDto(messageJsonString); - int counter = listenerMapper.selectReceiveMessageCountByPk(receiveMessageDto); - if(counter > 0) { - ackDto = AckDto.builder().result(AckDto.RECEIVE_FAIL).message("이전 전송한 메시지 중 중복된 UUID가 존재합니다.").build(); - } - else { - listenerMapper.insertReceiveMessage(receiveMessageDto); - - ackDto = AckDto.builder().result(AckDto.RECEIVE_SUCCESS).build(); - - } - } catch (IllegalMessageException | NullMessageException | InCompleteMessageException e) { - log.error("{}", e, e); - ackDto = AckDto.builder().result(AckDto.RECEIVE_FAIL).message(e.getLocalizedMessage()).build(); - } - return ackDto; - } public AckDto receiveMessage(String messageJsonString) { AckDto ackDto = null; diff --git a/src/main/java/com/bsmlab/dfx/agent/task/TaskExecutorService.java b/src/main/java/com/bsmlab/dfx/agent/task/TaskExecutorService.java index 277b9f6..6dcda71 100644 --- a/src/main/java/com/bsmlab/dfx/agent/task/TaskExecutorService.java +++ b/src/main/java/com/bsmlab/dfx/agent/task/TaskExecutorService.java @@ -1,16 +1,19 @@ package com.bsmlab.dfx.agent.task; -import com.bsmlab.dfx.agent.config.Settings; +import com.bsmlab.dfx.agent.config.AgentConfigDto; +import com.bsmlab.dfx.agent.config.AgentConfigReader; import com.bsmlab.dfx.agent.config.datasource.SqlExecuteService; import com.bsmlab.dfx.agent.listener.dto.ReceiveMessageDto; -import com.bsmlab.dfx.agent.task.dropbox.DropBoxDto; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; -import java.io.*; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.ObjectInputStream; import java.util.List; import java.util.Map; @@ -18,25 +21,23 @@ import java.util.Map; @RequiredArgsConstructor @Slf4j public class TaskExecutorService { - private final Settings settings; + private final AgentConfigReader agentConfigReader; private final SqlExecuteService sqlExecuteService; @Async("threadPoolTaskExecutor") public void processDropBox(String messageFilePath) { try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(messageFilePath))) { ReceiveMessageDto receiveMessageDto = (ReceiveMessageDto)objectInputStream.readObject(); - DropBoxDto dropBoxDto = settings.getDropBoxDto(receiveMessageDto.getRecipientDropBoxId()); - if("SAVE_DATA_TABLE".equals(dropBoxDto.getTaskType())) { - //public Map insert(String dataSourceId, String sqlId, Map parameter) { - String dataString = receiveMessageDto.getData(); - List> dataMapList = null; //(List>)receiveMessageDto.getData(); + AgentConfigDto.DropBox dropBox = agentConfigReader.getDropBox(receiveMessageDto.getRecipientDropBoxId()); + if(dropBox.getTaskType() == AgentConfigDto.TaskType.SAVE_DB_TABLE) { ObjectMapper objectMapper = new ObjectMapper(); + List> dataMapList = null; dataMapList = (List>) objectMapper.readValue(receiveMessageDto.getData(), List.class); for(Map dataMap : dataMapList) { - sqlExecuteService.insert(dropBoxDto.getDataSourceId(), dropBoxDto.getSqlId(), dataMap); + sqlExecuteService.insert(dropBox.getDataSourceId(), dropBox.getSqlId(), dataMap); } } - else if("RECEIVE_FILE".equals(dropBoxDto.getTaskType())) { + else if(dropBox.getTaskType() == AgentConfigDto.TaskType.RECEIVE_FILE) { } } catch (FileNotFoundException e) { diff --git a/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxService.java b/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxService.java index 0cd4619..eb292c5 100644 --- a/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxService.java +++ b/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxService.java @@ -1,5 +1,6 @@ package com.bsmlab.dfx.agent.task.dropbox; +import com.bsmlab.dfx.agent.config.AgentConfigReader; import com.bsmlab.dfx.agent.config.Settings; import com.bsmlab.dfx.agent.listener.dto.ReceiveMessageDto; import lombok.RequiredArgsConstructor; @@ -15,13 +16,22 @@ import java.util.concurrent.ConcurrentLinkedQueue; @Service @RequiredArgsConstructor @Slf4j +/** + * Listener 가 메시지를 수신한 경우 DropBoxService 를 사용하여 파일 기록과 동시에 공유메모리(queue)에 파일 경로를 저장한다. (DropBoxService.add()) + * TaskExecutorStarter 에서 생성한 처리 쓰레드가 DropBoxService.poll() 을 호출하여 메시지 파일을 가져가서 처리한다. + */ public class DropBoxService { - private final Settings settings; + private final AgentConfigReader agentConfigReader; private ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); + /** + * 수신한 메시지(ReceiveMessageDto)는 하루 이내에 UUID가 중복되지 않아야 한다. 일일 UUID 중복을 체크한다. + * @param receiveMessageDto + * @return + */ public boolean isExistToday(ReceiveMessageDto receiveMessageDto) { boolean isExist = false; - File root = new File(settings.getMessageStorageRootPath()); + File root = new File(agentConfigReader.getAgentConfigDto().getDropBox().getMessageStorageRoot()); Date today = new Date(System.currentTimeMillis()); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd/"); String todayDirectoryString = root.getAbsolutePath() + "/" + dateFormat.format(today); @@ -36,8 +46,12 @@ public class DropBoxService { return isExist; } + /** + * 수신한 메시지를 파일로 저장하고 공유메모리(queue)에 파일 경로를 등록한다. + * @param receiveMessageDto 수신한 메지시의 인스턴스 + */ public void add(ReceiveMessageDto receiveMessageDto) { - File root = new File(settings.getMessageStorageRootPath()); + File root = new File(agentConfigReader.getAgentConfigDto().getDropBox().getMessageStorageRoot()); Date today = new Date(System.currentTimeMillis()); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd/hh"); String targetDirectoryString = root.getAbsolutePath() + "/" + dateFormat.format(today); @@ -58,6 +72,10 @@ public class DropBoxService { } } + /** + * 공유메모리(queue)의 파임 경로를 획득한다. + * @return ReceiveMessageDto의 serialize 파일 경로 + */ public String poll() { return queue.poll(); }