diff --git a/src/docs/settings-examples/dfxagent-bd-test-cubrid.json b/src/docs/settings-examples/dfxagent-bd-test-cubrid.json index 60e57d0..97dda05 100644 --- a/src/docs/settings-examples/dfxagent-bd-test-cubrid.json +++ b/src/docs/settings-examples/dfxagent-bd-test-cubrid.json @@ -1,35 +1,28 @@ { + "description": "워크스테이션에서 실행함. 개발PC의 agent와 연결. 메시지 수신 후 cubrid 저장", "myHostId": "bd-test-cubrid", "myListenPort": 17801, "knownAgentList": [ - { - "hostId": "bd-test-oracle", - "hostName": "192.168.0.16", - "listenPort": 16801, - "dropBoxIdList": [ - "drop-tto-db" - ] - } ], "dataSourceConfig": [ { - "dataSourceId": "oracle", - "driverClassName": "org.postgresql.Driver", - "url": "jdbc:oracle:thin:@192.168.0.221:1521:xe", + "dataSourceId": "cubrid", + "driverClassName": "cubrid.jdbc.driver.CUBRIDDriver", + "url": "jdbc:cubrid:14.63.185.105:33000:amif:ami::", "username": "ami", "password": "fox12#$%" } ], "sqlMapperLocations": [ - "D:/projects/bsm-lab/dfx/dfxagent/src/docs/mapper-examples/**/*.xml" + "/home/dfxagent/agent/conf/mappers/**/*.xml" ], "dropBox": { - "receivedMessageStorageRoot": "D:/projects/bsm-lab/dfx/dfxagent/src/docs/messages/received", - "processedMessageStorageRoot": "D:/projects/bsm-lab/dfx/dfxagent/src/docs/messages/processed", - "failureMessageStorageRoot": "D:/projects/bsm-lab/dfx/dfxagent/src/docs/messages/failure", + "receivedMessageStorageRoot": "/home/dfxagent/agent/messages/received", + "processedMessageStorageRoot": "/home/dfxagent/agent/messages/processed", + "failureMessageStorageRoot": "/home/dfxagent/agent/messages/failure", "dropBoxList": [ { - "dropBoxId": "bd-test-cubrid", + "dropBoxId": "db-bd-cubrid-save", "taskType": "RECEIVE_DB_TO_DB_SAVE", "dataSourceId": "cubrid", "sqlId": "address.dropbox.cubrid.ttoBd.insertTtoBd" diff --git a/src/docs/settings-examples/dfxagent-bd-test-oracle.json b/src/docs/settings-examples/dfxagent-bd-test-oracle.json index ce84b3d..3d099cb 100644 --- a/src/docs/settings-examples/dfxagent-bd-test-oracle.json +++ b/src/docs/settings-examples/dfxagent-bd-test-oracle.json @@ -1,10 +1,11 @@ { + "description": "개발PC에서 실행함. 웍스테이션 에이전트(bd-test-cubrid)와 연결. 웍스테이션 oracle 에서 TTO_BD 테이블을 조회하여 bd-test-cubrid 에이전트에게 전달함", "myHostId": "bd-test-oracle", "myListenPort": 16801, "knownAgentList": [ { "hostId": "bd-test-cubrid", - "hostName": "192.168.0.16", + "hostName": "mkami.foxsoft.kr", "listenPort": 17801, "dropBoxIdList": [ "drop-tto-db" @@ -13,9 +14,9 @@ ], "dataSourceConfig": [ { - "dataSourceId": "oracle", - "driverClassName": "org.postgresql.Driver", - "url": "jdbc:oracle:thin:@192.168.0.221:1521:xe", + "dataSourceId": "ds-oracle", + "driverClassName": "oracle.jdbc.driver.OracleDriver", + "url": "jdbc:oracle:thin:@mkami.foxsoft.kr:1521:xe", "username": "ami", "password": "fox12#$%" } @@ -40,11 +41,11 @@ }, "message": { "messageType": "TRANSFER_DB_TO_DB", - "dataSourceId": "oracle", + "dataSourceId": "ds-oracle", "sqlId": "address.postman.oracle.ttoBd.selectTtoBd10" }, "recipientHostId": "bd-test-cubrid", - "recipientDropBoxId": "drop-tto-db", + "recipientDropBoxId": "db-bd-cubrid-save", "routingHostIdList": [ "bd-test-oracle", "bd-test-cubrid" 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 af0f27f..1ee71ec 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/AgentConfigDto.java @@ -6,6 +6,7 @@ import java.util.List; @Data public class AgentConfigDto { + private String description; private String myHostId; private int myListenPort; private List knownAgentList; diff --git a/src/main/java/com/bsmlab/dfx/agent/config/BeanInitializer.java b/src/main/java/com/bsmlab/dfx/agent/config/BeanInitializer.java new file mode 100644 index 0000000..ef08172 --- /dev/null +++ b/src/main/java/com/bsmlab/dfx/agent/config/BeanInitializer.java @@ -0,0 +1,39 @@ +package com.bsmlab.dfx.agent.config; + +import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; +import com.bsmlab.dfx.agent.task.dropbox.DropBoxTaskExecutorService; +import com.bsmlab.dfx.agent.task.postman.PostmanSchedulerService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class BeanInitializer implements SmartInitializingSingleton { + private final DfxAgentConfiguration dfxAgentConfiguration; + private final DynamicDataSourceService dynamicDataSourceService; + private final PostmanSchedulerService postmanSchedulerService; + private final DropBoxTaskExecutorService dropBoxTaskExecutorService; + + @Override + public void afterSingletonsInstantiated() { + System.out.println("🔥 BeanInitializer afterSingletonsInstantiated() 진입!"); + log.info("✅ BeanInitializer 작동 확인"); + /* + // DfxAgentConfiguration 에서 생성한 빈 중 DataSource 관련 설정을 마무리한다. + dynamicDataSourceService.setSqlSessionFactoryMap(dfxAgentConfiguration.getTemporarySqlSessionFactoryMap()); + dynamicDataSourceService.setTransactionManagerMap(dfxAgentConfiguration.getTemporaryTransactionManagerMap()); + + // PostmanSchedulerService, DropBoxTaskExecutorService 는 @RequiredArgsConstructor 이기 때문에 자동으로 injection 된다 + // 그 후 @PostConstruct 로직이 실행될 것이다. + log.debug("BeanInitializer afterSingletonsInstantiated [run]"); + log.debug("{} ready", postmanSchedulerService.getClass().getName()); + log.debug("{} ready", dropBoxTaskExecutorService.getClass().getName()); + //TODO 4. Worker 쓰레드 생성 + + */ + + } +} 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 0460dd4..f3b32fe 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/DfxAgentConfiguration.java @@ -2,7 +2,9 @@ package com.bsmlab.dfx.agent.config; import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; import com.bsmlab.dfx.agent.config.datasource.DynamicRoutingDataSource; +import com.bsmlab.dfx.agent.config.datasource.RefreshableSqlSessionFactoryBean; import io.micrometer.common.util.StringUtils; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.dbcp2.BasicDataSource; @@ -13,24 +15,24 @@ import org.mybatis.spring.annotation.MapperScans; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.io.IOException; +import java.util.*; import java.util.concurrent.Executor; @Slf4j +@Getter @Configuration @RequiredArgsConstructor @MapperScans({ @MapperScan("com.bsmlab.dfx.agent") }) public class DfxAgentConfiguration { - private static final String DB_SOURCE_FILE_PATH = "./storages/dfxagent.mv.db"; - // gradle bootRun 실행 설정 // bootRun --args=" --setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json" // command line java 실행 설정 @@ -58,16 +60,25 @@ public class DfxAgentConfiguration { // 다중 데이터 소스 생성 @Bean(name = "dynamicRoutingDataSource") - public DynamicRoutingDataSource dynamicRoutingDataSource(AgentConfigReader agentConfigReader) { // 실행확인됨 + public DynamicRoutingDataSource dynamicRoutingDataSource(AgentConfigReader agentConfigReader) throws IOException { // 실행확인됨 DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(); Map sqlSessionFactoryMap = new HashMap<>(); Map transactionManagerMap = new HashMap<>(); + List xmlPathList = agentConfigReader.getAgentConfigDto().getSqlMapperLocations(); + List resourceList = new ArrayList<>(); + PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(); + for(String pathString : xmlPathList) { + Resource[] resourceArray = pathMatchingResourcePatternResolver.getResources("file:" + pathString); + resourceList.addAll(Arrays.asList(resourceArray)); + } + List dataSourceConfigList = agentConfigReader.getAgentConfigDto().getDataSourceConfig(); for(AgentConfigDto.DataSourceConfig dataSourceConfig : dataSourceConfigList) { BasicDataSource dataSource = createBasicDataSource(dataSourceConfig); - SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); + SqlSessionFactoryBean sqlSessionFactoryBean = new RefreshableSqlSessionFactoryBean();//new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); + sqlSessionFactoryBean.setMapperLocations(resourceList.toArray(new Resource[0])); try { sqlSessionFactoryMap.put(dataSourceConfig.getDataSourceId(), sqlSessionFactoryBean.getObject()); } catch (Exception e) { 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 eb55ee1..fd66e30 100644 --- a/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java +++ b/src/main/java/com/bsmlab/dfx/agent/config/StartupRunner.java @@ -1,5 +1,6 @@ package com.bsmlab.dfx.agent.config; +import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; import com.bsmlab.dfx.agent.task.dropbox.DropBoxTaskExecutorService; import com.bsmlab.dfx.agent.task.postman.PostmanSchedulerService; import lombok.RequiredArgsConstructor; @@ -12,16 +13,25 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component public class StartupRunner implements ApplicationRunner { + private final DfxAgentConfiguration dfxAgentConfiguration; + private final DynamicDataSourceService dynamicDataSourceService; private final PostmanSchedulerService postmanSchedulerService; private final DropBoxTaskExecutorService dropBoxTaskExecutorService; @Override public void run(ApplicationArguments args) throws Exception { + System.out.println("✅ StartupRunner.run() 호출됨"); + // DfxAgentConfiguration 에서 생성한 빈 중 DataSource 관련 설정을 마무리한다. + dynamicDataSourceService.setSqlSessionFactoryMap(dfxAgentConfiguration.getTemporarySqlSessionFactoryMap()); + dynamicDataSourceService.setTransactionManagerMap(dfxAgentConfiguration.getTemporaryTransactionManagerMap()); + // PostmanSchedulerService, DropBoxTaskExecutorService 는 @RequiredArgsConstructor 이기 때문에 자동으로 injection 된다 // 그 후 @PostConstruct 로직이 실행될 것이다. log.debug("StartupRunner start [run]"); log.debug("{} ready", postmanSchedulerService.getClass().getName()); log.debug("{} ready", dropBoxTaskExecutorService.getClass().getName()); //TODO 4. Worker 쓰레드 생성 + postmanSchedulerService.launch(); + dropBoxTaskExecutorService.launch(); } } diff --git a/src/main/java/com/bsmlab/dfx/agent/event/ContextReadyListener.java b/src/main/java/com/bsmlab/dfx/agent/event/ContextReadyListener.java new file mode 100644 index 0000000..56750ea --- /dev/null +++ b/src/main/java/com/bsmlab/dfx/agent/event/ContextReadyListener.java @@ -0,0 +1,46 @@ +package com.bsmlab.dfx.agent.event; + +import com.bsmlab.dfx.agent.config.DfxAgentConfiguration; +import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService; +import com.bsmlab.dfx.agent.task.dropbox.DropBoxTaskExecutorService; +import com.bsmlab.dfx.agent.task.postman.PostmanSchedulerService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class ContextReadyListener implements ApplicationListener { + private final DfxAgentConfiguration dfxAgentConfiguration; + private final DynamicDataSourceService dynamicDataSourceService; + private final PostmanSchedulerService postmanSchedulerService; + private final DropBoxTaskExecutorService dropBoxTaskExecutorService; + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + System.out.println("🔥 ContextReadyListener onApplicationEvent() 진입!"); + log.info("✅ ContextReadyListener 작동 확인"); + /* + // DfxAgentConfiguration 에서 생성한 빈 중 DataSource 관련 설정을 마무리한다. + dynamicDataSourceService.setSqlSessionFactoryMap(dfxAgentConfiguration.getTemporarySqlSessionFactoryMap()); + dynamicDataSourceService.setTransactionManagerMap(dfxAgentConfiguration.getTemporaryTransactionManagerMap()); + + // PostmanSchedulerService, DropBoxTaskExecutorService 는 @RequiredArgsConstructor 이기 때문에 자동으로 injection 된다 + // 그 후 @PostConstruct 로직이 실행될 것이다. + log.debug("ContextReadyListener onApplicationEvent [run]"); + log.debug("{} ready", postmanSchedulerService.getClass().getName()); + log.debug("{} ready", dropBoxTaskExecutorService.getClass().getName()); + //TODO 4. Worker 쓰레드 생성 + + */ + + } + + @Override + public boolean supportsAsyncExecution() { + return ApplicationListener.super.supportsAsyncExecution(); + } +} 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 3446f11..7a23e75 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 @@ -21,7 +21,7 @@ public class ReceiveMessageDto implements Serializable { private String recipientHostId; private String recipientDropBoxId; private String data; - private List attachFileList = new ArrayList<>(); + private List attachFileList;// = new ArrayList<>(); private ProcessStatus processStatus; public static enum ProcessStatus { diff --git a/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxTaskExecutorService.java b/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxTaskExecutorService.java index 4dac70d..83c2322 100644 --- a/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxTaskExecutorService.java +++ b/src/main/java/com/bsmlab/dfx/agent/task/dropbox/DropBoxTaskExecutorService.java @@ -8,8 +8,6 @@ import com.bsmlab.dfx.agent.listener.dto.ReceiveMessageDto; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.micrometer.common.util.StringUtils; -import jakarta.annotation.PostConstruct; -import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.EnumUtils; @@ -34,29 +32,28 @@ public class DropBoxTaskExecutorService { private final AgentConfigReader agentConfigReader; private final SqlExecuteService sqlExecuteService; private final DropBoxService dropBoxService; - @Getter - private List scheduledTypePostmanList; /** * 수신한 메시지를 처리하는 쓰레드 * DB 저장 로직과 파일 또는 파일 + 메타데이터 저장 로직으로 구성됨 - * @param messageFilePath + * @param messageFilePath 메지시 파일 절대 경로 */ + @SuppressWarnings("unchecked") @Async("dropBoxProcessorThreadPoolTaskExecutor") public void processDropBox(String messageFilePath) { ReceiveMessageDto receiveMessageDto = ReceiveMessageDto.builder().build(); - ReceiveMessageDto.ProcessStatus processStatus = null; + ReceiveMessageDto.ProcessStatus processStatus; String processMessage = ""; - String messageUuid = ""; + String messageUuid; try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(messageFilePath))) { receiveMessageDto = (ReceiveMessageDto)objectInputStream.readObject(); messageUuid = receiveMessageDto.getMessageUuid(); AgentConfigDto.DropBox dropBox = agentConfigReader.getDropBox(receiveMessageDto.getRecipientDropBoxId()); - log.info("process messageUuid:{} dropBoxId: {}", receiveMessageDto.getMessageUuid(), dropBox.getDropBoxId()); + log.info("process messageUuid:{} dropBoxId: {}", messageUuid, dropBox.getDropBoxId()); //1. DB 저장 메시지 처리 if(dropBox.getTaskType() == AgentConfigDto.TaskType.RECEIVE_DB_TO_DB_SAVE) { ObjectMapper objectMapper = new ObjectMapper(); - List> dataMapList = null; + List> dataMapList; dataMapList = (List>) objectMapper.readValue(receiveMessageDto.getData(), List.class); for(Map dataMap : dataMapList) { sqlExecuteService.insert(dropBox.getDataSourceId(), dropBox.getSqlId(), dataMap); @@ -66,7 +63,7 @@ public class DropBoxTaskExecutorService { // 1.2 파일 수신 메시지 처리 // 파일은 ListenService 에서 이미 저장하였음. meta-data 가 있는 경우 DB 저장 ObjectMapper objectMapper = new ObjectMapper(); - List> dataMapList = null; + List> dataMapList; dataMapList = (List>) objectMapper.readValue(receiveMessageDto.getData(), List.class); for(String attachFilePath : receiveMessageDto.getAttachFileList()) { String fileName = attachFilePath.substring(attachFilePath.lastIndexOf("/") + 1); @@ -140,7 +137,7 @@ public class DropBoxTaskExecutorService { String url = "https://" + knownAgent.getHostName() + ":" + knownAgent.getListenPort() + "/telegram"; String response = restTemplate.postForObject(url, bodyEntity, String.class); ObjectMapper objectMapper = new ObjectMapper(); - AckDto responseAckDto = null; + AckDto responseAckDto; try { responseAckDto = objectMapper.readValue(response, AckDto.class); log.info("message processing is done. {}", receiveMessageDto.getMessageUuid()); @@ -151,8 +148,7 @@ public class DropBoxTaskExecutorService { } } - @PostConstruct - public void run() { // 실행확인됨 + public void launch() { // 실행확인됨 log.debug("{} @PostConstruct Run", this.getClass().getName()); while(true) { try { 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 39b3876..bc9478a 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 @@ -9,7 +9,6 @@ import com.bsmlab.dfx.agent.support.exception.DfxException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -36,7 +35,7 @@ import java.util.concurrent.ScheduledFuture; @Slf4j @RequiredArgsConstructor public class PostmanSchedulerService { - private final ThreadPoolTaskScheduler threadPoolTaskScheduler; + private final ThreadPoolTaskScheduler scheduledPostmanThreadPoolTaskScheduler; private final AgentConfigReader agentConfigReader; private final SqlExecuteService sqlExecuteService; private Map> scheduledFutureMap = new HashMap<>(); @@ -46,7 +45,7 @@ public class PostmanSchedulerService { AgentConfigDto.Postman postman = this.postmanMap.get(postmanId); this.stop(postmanId); String cron = postman.getAction().getCron(); - ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(() -> run(postman), new CronTrigger(cron)); + ScheduledFuture scheduledFuture = scheduledPostmanThreadPoolTaskScheduler.schedule(() -> run(postman), new CronTrigger(cron)); scheduledFutureMap.put(postmanId, scheduledFuture); } @@ -58,13 +57,14 @@ public class PostmanSchedulerService { } } - @PostConstruct public void launch() { // 실행확인됨 log.debug("{} @PostConstruct Run", this.getClass().getName()); List postmanList = agentConfigReader.getScheduledTypePostmanList(); - for(AgentConfigDto.Postman postman : postmanList) { - this.postmanMap.put(postman.getPostmanId(), postman); - this.startPostman(postman.getPostmanId()); + if(postmanList != null) { + for(AgentConfigDto.Postman postman : postmanList) { + this.postmanMap.put(postman.getPostmanId(), postman); + this.startPostman(postman.getPostmanId()); + } } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d525cfc..acb0e80 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,10 @@ spring: application: name: DFX Agent + servlet: + multipart: + max-file-size: 1GB + max-request-size: 1GB logging: level: com.bsmlab.dfx.agent: DEBUG