parent
c01e2d3c36
commit
8a56c9a3af
@ -1 +1 @@
|
|||||||
rootProject.name = 'agent'
|
rootProject.name = 'dfxagent'
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"datasource": [
|
||||||
|
{
|
||||||
|
"dataSourceId": "dfcms",
|
||||||
|
"driverClassName": "org.postgresql.Driver",
|
||||||
|
"url": "jdbc:postgresql://bsm-lab.com:5432/defree?currentSchema=DFCMS",
|
||||||
|
"username": "defreeadmin",
|
||||||
|
"password": "qortpals1!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dataSourceId": "mochastory",
|
||||||
|
"driverClassName": "com.mysql.jdbc.Driver",
|
||||||
|
"url": "jdbc:mysql://bsm-lab.com:3306/MOCHASTORY?allowPublicKeyRetrieval=true",
|
||||||
|
"username": "MOCHASTORY",
|
||||||
|
"password": "MOCHASTORY"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sqlMapperLocations": ["D:/projects/bsm-lab/dfx/dfxagent/src/docs/mapper-examples/**/*.xml"]
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
datasource:
|
||||||
|
dfcms:
|
||||||
|
driverClassName: org.postgresql.Driver
|
||||||
|
url: jdbc:postgresql://bsm-lab.com:5432/defree?currentSchema=DFCMS
|
||||||
|
username: defreeadmin
|
||||||
|
password: qortpals1!
|
||||||
|
mochastory:
|
||||||
|
driverClassName: com.mysql.jdbc.Driver
|
||||||
|
url: jdbc:mysql://bsm-lab.com:3306/MOCHASTORY?allowPublicKeyRetrieval=true
|
||||||
|
username: MOCHASTORY
|
||||||
|
password: MOCHASTORY
|
||||||
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
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.boot.env.YamlPropertySourceLoader;
|
|
||||||
import org.springframework.core.io.support.ResourcePropertySource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class DfxAgengConfiguration {
|
|
||||||
private String settingFilePath;
|
|
||||||
public void loadConfiguraion() {
|
|
||||||
//setting.file=D:\projects\bsm-lab\dfx\run\dfxagent.json
|
|
||||||
String embeddedDbFileDirectory = System.getProperty("embedded.db.file.directory");
|
|
||||||
this.settingFilePath = System.getProperty("setting.file");
|
|
||||||
try {
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
Map<String, Object> settingMap = mapper.readValue(new File(this.settingFilePath), Map.class);
|
|
||||||
} catch (DatabindException e) {
|
|
||||||
log.error("cannot parse a setting file. {}", this.settingFilePath, e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("cannot found a setting file. {}", this.settingFilePath);
|
|
||||||
log.error("-Dsetting.file=[file path] needed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSettingFilePath() {
|
|
||||||
return this.settingFilePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package com.bsmlab.dfx.agent.config;
|
||||||
|
|
||||||
|
import com.bsmlab.dfx.agent.config.datasource.RefreshableSqlSessionFactoryBean;
|
||||||
|
import io.micrometer.common.util.StringUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DfxAgentConfiguration {
|
||||||
|
public final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
// java -jar dfxagent.jar --embedded.db.file.directory=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples --setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json
|
||||||
|
// embedded.db.file.directory=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples
|
||||||
|
@Value("${embedded.db.file.directory}")
|
||||||
|
private String embeddedDbFileDirectory;
|
||||||
|
// setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json
|
||||||
|
@Value("${setting.file}")
|
||||||
|
private String settingFile;
|
||||||
|
|
||||||
|
@Bean("settings")
|
||||||
|
public Settings loadSettings() {
|
||||||
|
if(StringUtils.isBlank(this.embeddedDbFileDirectory)) {
|
||||||
|
log.error("cannot found a embedded DB file. {}", this.embeddedDbFileDirectory);
|
||||||
|
log.error("exit application");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
if(StringUtils.isBlank(this.settingFile)) {
|
||||||
|
log.error("cannot found a setting file. {}", this.settingFile);
|
||||||
|
log.error("exit application");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
Settings settings = new Settings();
|
||||||
|
settings.loadSettingFile(this.settingFile);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SqlSessionFactoryBean sqlSessionFactoryBean () {
|
||||||
|
RefreshableSqlSessionFactoryBean sqlSessionFactoryBean = new RefreshableSqlSessionFactoryBean();
|
||||||
|
//setMapperLocations(Resource[] mapperLocations)
|
||||||
|
Settings settings = applicationContext.getBean(Settings.class);
|
||||||
|
Resource[] mapperLocations = settings.getMapperLocations();
|
||||||
|
sqlSessionFactoryBean.setMapperLocations(mapperLocations);
|
||||||
|
return sqlSessionFactoryBean;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.bsmlab.dfx.agent.config;
|
||||||
|
|
||||||
|
import com.bsmlab.dfx.agent.config.datasource.DataSourceDto;
|
||||||
|
import com.fasterxml.jackson.databind.DatabindException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class Settings {
|
||||||
|
private Map<String, DataSourceDto> dataSourceDtoMap = new HashMap<>();
|
||||||
|
private Resource[] mapperLocations;
|
||||||
|
public void loadSettingFile(String settingFilePath) {
|
||||||
|
try {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
Map<String, Object> settingMap = objectMapper.readValue(new File(settingFilePath), Map.class);
|
||||||
|
this.mapperLocations = this.createMapperLocations(settingMap);
|
||||||
|
log.debug("settingMap: {}", settingMap);
|
||||||
|
this.parseDataSources(settingMap);
|
||||||
|
} catch (DatabindException e) {
|
||||||
|
log.error("cannot parse a setting file. {}", settingFilePath, e);
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("cannot read a setting file. {}", settingFilePath);
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void parseDataSources(Map<String, Object> settingMap) {
|
||||||
|
List<Map<String, String>> dataSourceMapList = (List<Map<String, String>>)settingMap.get("datasource");
|
||||||
|
for(Map<String, String> dataSourceMap : dataSourceMapList) {
|
||||||
|
DataSourceDto dataSourceDto = DataSourceDto.builder()
|
||||||
|
.dataSourceId(dataSourceMap.get("dataSourceId")).driverClassName(dataSourceMap.get("driverClassName"))
|
||||||
|
.url(dataSourceMap.get("url")).username(dataSourceMap.get("username")).password(dataSourceMap.get("password"))
|
||||||
|
.build();
|
||||||
|
dataSourceDtoMap.put(dataSourceDto.getDataSourceId(), dataSourceDto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource[] createMapperLocations(Map<String, Object> settingMap) throws FileNotFoundException {
|
||||||
|
Resource[] resources = null;
|
||||||
|
if(ObjectUtils.isNotEmpty(settingMap.get("mapperLocations"))) {
|
||||||
|
String[] locationStringList = (String[])settingMap.get("mapperLocations");
|
||||||
|
resources = new Resource[locationStringList.length];
|
||||||
|
int i = 0;
|
||||||
|
for(String location : locationStringList) {
|
||||||
|
resources[i] = new InputStreamResource(new FileInputStream(new File(location)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource[] getMapperLocations() {
|
||||||
|
return this.mapperLocations;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.bsmlab.dfx.agent.config.datasource;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class DataSourceDto {
|
||||||
|
private String dataSourceId;
|
||||||
|
private String driverClassName;
|
||||||
|
private String url;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.bsmlab.dfx.agent.config.datasource;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class DataSourcePool {
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
package com.bsmlab.dfx.agent.config.datasource;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@DependsOn(value = {"settings"})
|
||||||
|
public class RefreshableSqlSessionFactoryBean extends SqlSessionFactoryBean implements DisposableBean {
|
||||||
|
private SqlSessionFactory proxy;
|
||||||
|
private int interval = 500;
|
||||||
|
private Timer timer;
|
||||||
|
private TimerTask task;
|
||||||
|
private Resource[] mapperLocations;
|
||||||
|
private boolean running = false;
|
||||||
|
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||||
|
private final Lock r = rwl.readLock();
|
||||||
|
private final Lock w = rwl.writeLock();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMapperLocations(Resource[] mapperLocations) {
|
||||||
|
super.setMapperLocations(mapperLocations);
|
||||||
|
this.mapperLocations = mapperLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterval(int interval) {
|
||||||
|
this.interval = interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() throws Exception {
|
||||||
|
if(log.isInfoEnabled()) {
|
||||||
|
log.info("> Refresh SqlMapper");
|
||||||
|
log.info("======================================================================================");
|
||||||
|
}
|
||||||
|
w.lock();
|
||||||
|
try {
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
} finally {
|
||||||
|
w.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
super.afterPropertiesSet();
|
||||||
|
setRefreshable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRefreshable() {
|
||||||
|
proxy = (SqlSessionFactory) Proxy.newProxyInstance(
|
||||||
|
SqlSessionFactory.class.getClassLoader(),
|
||||||
|
new Class[]{SqlSessionFactory.class},
|
||||||
|
new InvocationHandler() {
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||||
|
return method.invoke(getParentObject(), args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
task = new TimerTask() {
|
||||||
|
private Map<Resource, Long> map = new HashMap<>();
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
if(isModified()) {
|
||||||
|
try {
|
||||||
|
refresh();
|
||||||
|
} catch(Exception e) {
|
||||||
|
log.error("caught exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isModified() {
|
||||||
|
boolean retVal = false;
|
||||||
|
if(mapperLocations != null) {
|
||||||
|
for(int i = 0; i < mapperLocations.length; i++) {
|
||||||
|
Resource mappingLocation = mapperLocations[i];
|
||||||
|
retVal |= findModifiedResource(mappingLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean findModifiedResource(Resource resource) {
|
||||||
|
boolean retVal = false;
|
||||||
|
List<String> modifiedResources = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
long modified = resource.lastModified();
|
||||||
|
|
||||||
|
if(map.containsKey(resource)) {
|
||||||
|
long lastModified = ((Long) map.get(resource)) .longValue();
|
||||||
|
|
||||||
|
if(lastModified != modified) {
|
||||||
|
map.put(resource, modified);
|
||||||
|
|
||||||
|
//modifiedResources.add(resource.getDescription()); // 전체경로
|
||||||
|
modifiedResources.add(resource.getFilename()); // 파일명
|
||||||
|
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
map.put(resource, modified);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("caught exception", e);
|
||||||
|
}
|
||||||
|
if(retVal) {
|
||||||
|
if(log.isInfoEnabled()) {
|
||||||
|
log.info("======================================================================================");
|
||||||
|
log.info("> Update File name : " + modifiedResources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timer = new Timer(true);
|
||||||
|
resetInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getParentObject() throws Exception {
|
||||||
|
r.lock();
|
||||||
|
try {
|
||||||
|
return super.getObject();
|
||||||
|
} finally {
|
||||||
|
r.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlSessionFactory getObject() {
|
||||||
|
return this.proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends SqlSessionFactory> getObjectType() {
|
||||||
|
return (this.proxy != null ? this.proxy.getClass() : SqlSessionFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCheckInterval(int ms) {
|
||||||
|
interval = ms;
|
||||||
|
if(timer != null) {
|
||||||
|
resetInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetInterval() {
|
||||||
|
if(running) {
|
||||||
|
timer.cancel();
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(interval > 0) {
|
||||||
|
timer.schedule(task, 0, interval); running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() throws Exception {
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,14 @@
|
|||||||
package com.bsmlab.dfx.agent;
|
package com.bsmlab.dfx.agent;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
class DfxAgentApplicationTests {
|
class DfxAgentApplicationTests {
|
||||||
|
// @Autowired
|
||||||
|
// private DfxAgengConfiguration dfxAgengConfiguration;
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
void contextLoads() {
|
// void contextLoads() {
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in new issue