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;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class DfxAgentApplicationTests {
|
||||
// @Autowired
|
||||
// private DfxAgengConfiguration dfxAgengConfiguration;
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
// @Test
|
||||
// void contextLoads() {
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in new issue