From 9c9be799f14bde814bd5d79846b3c30b9045ecfd Mon Sep 17 00:00:00 2001 From: vran Date: Mon, 18 Apr 2022 11:07:54 +0800 Subject: [PATCH] feat: optimize drvier resource code --- .../resources/application-local.properties | 3 +- .../database/service/DatabaseTypeService.java | 6 +- .../CustomDatabaseConnectionFactory.java | 6 +- .../driver/DriverResources.java | 195 +++++++++--------- .../service/DatabaseTypeServiceTest.java | 14 ++ 5 files changed, 123 insertions(+), 101 deletions(-) diff --git a/api/src/main/resources/application-local.properties b/api/src/main/resources/application-local.properties index 9933c49..7d146b2 100644 --- a/api/src/main/resources/application-local.properties +++ b/api/src/main/resources/application-local.properties @@ -9,4 +9,5 @@ spring.flyway.locations=classpath:db/migration databasir.db.url=localhost:3306 databasir.db.username=root databasir.db.password=123456 -databasir.db.driver-directory=drivers \ No newline at end of file +databasir.db.driver-directory=drivers +databasir.jwt.secret=DatabasirJwtSecret \ No newline at end of file diff --git a/core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java b/core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java index 8db700a..ceff088 100644 --- a/core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java +++ b/core/src/main/java/com/databasir/core/domain/database/service/DatabaseTypeService.java @@ -62,7 +62,7 @@ public class DatabaseTypeService { // 名称修改,下载地址修改需要删除原有的 driver if (!Objects.equals(request.getDatabaseType(), data.getDatabaseType()) || !Objects.equals(request.getJdbcDriverFileUrl(), data.getJdbcDriverFileUrl())) { - driverResources.delete(data.getDatabaseType()); + driverResources.deleteByDatabaseType(data.getDatabaseType()); } }); @@ -74,7 +74,7 @@ public class DatabaseTypeService { throw DomainErrors.MUST_NOT_MODIFY_SYSTEM_DEFAULT_DATABASE_TYPE.exception(); } databaseTypeDao.deleteById(id); - driverResources.delete(data.getDatabaseType()); + driverResources.deleteByDatabaseType(data.getDatabaseType()); }); } @@ -110,7 +110,7 @@ public class DatabaseTypeService { } public String resolveDriverClassName(DriverClassNameResolveRequest request) { - return driverResources.resolveSqlDriverNameFromJar(request.getJdbcDriverFileUrl()); + return driverResources.resolveDriverClassName(request.getJdbcDriverFileUrl()); } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java b/core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java index bf0f860..f37df45 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java +++ b/core/src/main/java/com/databasir/core/infrastructure/connection/CustomDatabaseConnectionFactory.java @@ -36,8 +36,10 @@ public class CustomDatabaseConnectionFactory implements DatabaseConnectionFactor @Override public Connection getConnection(Context context) throws SQLException { - DatabaseTypePojo type = databaseTypeDao.selectByDatabaseType(context.getDatabaseType()); - File driverFile = driverResources.loadOrDownload(context.getDatabaseType(), type.getJdbcDriverFileUrl()); + String databaseType = context.getDatabaseType(); + DatabaseTypePojo type = databaseTypeDao.selectByDatabaseType(databaseType); + File driverFile = driverResources.loadOrDownloadByDatabaseType(databaseType, type.getJdbcDriverFileUrl()); + URLClassLoader loader = null; try { loader = new URLClassLoader( diff --git a/core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java b/core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java index 4bc9683..a498287 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java +++ b/core/src/main/java/com/databasir/core/infrastructure/driver/DriverResources.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.util.StreamUtils; +import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import java.io.*; @@ -18,6 +19,7 @@ import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; import java.util.UUID; import java.util.jar.JarFile; @@ -31,7 +33,7 @@ public class DriverResources { private final RestTemplate restTemplate; - public void delete(String databaseType) { + public void deleteByDatabaseType(String databaseType) { Path path = Paths.get(driverFilePath(driverBaseDirectory, databaseType)); try { Files.deleteIfExists(path); @@ -40,9 +42,105 @@ public class DriverResources { } } + public Optional loadByDatabaseType(String databaseType) { + Path path = Paths.get(driverFilePath(driverBaseDirectory, databaseType)); + if (Files.exists(path)) { + return Optional.of(path.toFile()); + } else { + return Optional.empty(); + } + } + + public File loadOrDownloadByDatabaseType(String databaseType, String driverFileUrl) { + return loadByDatabaseType(databaseType) + .orElseGet(() -> download(driverFileUrl, driverFilePath(driverBaseDirectory, databaseType))); + } + + public String resolveDriverClassName(String driverFileUrl) { + String tempFilePath = "temp/" + UUID.randomUUID() + ".jar"; + File driverFile = download(driverFileUrl, tempFilePath); + String className = resolveDriverClassName(driverFile); + try { + Files.deleteIfExists(driverFile.toPath()); + } catch (IOException e) { + log.error("delete driver error " + tempFilePath, e); + } + return className; + } + + public String resolveDriverClassName(File driverFile) { + JarFile jarFile = null; + try { + jarFile = new JarFile(driverFile); + } catch (IOException e) { + log.error("resolve driver class name error", e); + throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception(e.getMessage()); + } + + final JarFile driverJar = jarFile; + String driverClassName = jarFile.stream() + .filter(entry -> entry.getName().contains("META-INF/services/java.sql.Driver")) + .findFirst() + .map(entry -> { + InputStream stream = null; + BufferedReader reader = null; + try { + stream = driverJar.getInputStream(entry); + reader = new BufferedReader(new InputStreamReader(stream)); + return reader.readLine(); + } catch (IOException e) { + log.error("resolve driver class name error", e); + throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception(e.getMessage()); + } finally { + IOUtils.closeQuietly(reader, ex -> log.error("close reader error", ex)); + } + }) + .orElseThrow(DomainErrors.DRIVER_CLASS_NOT_FOUND::exception); + IOUtils.closeQuietly(jarFile, ex -> log.error("close jar file error", ex)); + return driverClassName; + } + + private File download(String driverFileUrl, String targetFile) { + Path path = Path.of(targetFile); + + // create parent directory + if (Files.notExists(path)) { + path.getParent().toFile().mkdirs(); + try { + Files.createFile(path); + } catch (IOException e) { + log.error("create file error " + targetFile, e); + throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); + } + } + + // download + try { + return restTemplate.execute(driverFileUrl, HttpMethod.GET, null, response -> { + if (response.getStatusCode().is2xxSuccessful()) { + File file = path.toFile(); + FileOutputStream out = new FileOutputStream(file); + StreamUtils.copy(response.getBody(), out); + IOUtils.closeQuietly(out, ex -> log.error("close file error", ex)); + log.info("{} download success ", targetFile); + return file; + } else { + log.error("{} download error from {}: {} ", targetFile, driverFileUrl, response); + throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:" + + response.getStatusCode() + + ", " + + response.getStatusText()); + } + }); + } catch (RestClientException e) { + log.error(targetFile + " download driver error", e); + throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); + } + } + public void validateJar(String driverFileUrl, String className) { String tempFilePath = "temp/" + UUID.randomUUID() + ".jar"; - File driverFile = doDownload(driverFileUrl, tempFilePath); + File driverFile = download(driverFileUrl, tempFilePath); URLClassLoader loader = null; try { loader = new URLClassLoader( @@ -75,99 +173,6 @@ public class DriverResources { } } - public String resolveSqlDriverNameFromJar(String driverFileUrl) { - String tempFilePath = "temp/" + UUID.randomUUID() + ".jar"; - File driverFile = doDownload(driverFileUrl, tempFilePath); - String className = doResolveSqlDriverNameFromJar(driverFile); - try { - Files.deleteIfExists(driverFile.toPath()); - } catch (IOException e) { - log.error("delete driver error " + tempFilePath, e); - } - return className; - } - - public File loadOrDownload(String databaseType, String driverFileUrl) { - String filePath = driverFilePath(driverBaseDirectory, databaseType); - Path path = Path.of(filePath); - if (Files.exists(path)) { - // ignore - log.debug("{} already exists, ignore download from {}", filePath, driverFileUrl); - return path.toFile(); - } - return this.doDownload(driverFileUrl, filePath); - } - - private File doDownload(String driverFileUrl, String filePath) { - Path path = Path.of(filePath); - - // create parent directory - if (Files.notExists(path)) { - path.getParent().toFile().mkdirs(); - try { - Files.createFile(path); - } catch (IOException e) { - log.error("create file error " + filePath, e); - throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); - } - } - - // download - try { - return restTemplate.execute(driverFileUrl, HttpMethod.GET, null, response -> { - if (response.getStatusCode().is2xxSuccessful()) { - File file = path.toFile(); - FileOutputStream out = new FileOutputStream(file); - StreamUtils.copy(response.getBody(), out); - IOUtils.closeQuietly(out, ex -> log.error("close file error", ex)); - log.info("{} download success ", filePath); - return file; - } else { - log.error("{} download error from {}: {} ", filePath, driverFileUrl, response); - throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:" - + response.getStatusCode() - + ", " - + response.getStatusText()); - } - }); - } catch (IllegalArgumentException e) { - log.error(filePath + " download driver error", e); - throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); - } - } - - private String doResolveSqlDriverNameFromJar(File driverFile) { - JarFile jarFile = null; - try { - jarFile = new JarFile(driverFile); - } catch (IOException e) { - log.error("resolve driver class name error", e); - throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception(e.getMessage()); - } - - final JarFile driverJar = jarFile; - String driverClassName = jarFile.stream() - .filter(entry -> entry.getName().contains("META-INF/services/java.sql.Driver")) - .findFirst() - .map(entry -> { - InputStream stream = null; - BufferedReader reader = null; - try { - stream = driverJar.getInputStream(entry); - reader = new BufferedReader(new InputStreamReader(stream)); - return reader.readLine(); - } catch (IOException e) { - log.error("resolve driver class name error", e); - throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception(e.getMessage()); - } finally { - IOUtils.closeQuietly(reader, ex -> log.error("close reader error", ex)); - } - }) - .orElseThrow(DomainErrors.DRIVER_CLASS_NOT_FOUND::exception); - IOUtils.closeQuietly(jarFile, ex -> log.error("close jar file error", ex)); - return driverClassName; - } - private String driverFilePath(String baseDir, String databaseType) { String fileName = databaseType + ".jar"; String filePath; diff --git a/core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java b/core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java index ed2d134..8d03586 100644 --- a/core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java +++ b/core/src/test/java/com/databasir/core/domain/database/service/DatabaseTypeServiceTest.java @@ -5,14 +5,20 @@ import com.databasir.core.BaseTest; import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.database.data.DatabaseTypeCreateRequest; import com.databasir.core.domain.database.data.DatabaseTypeUpdateRequest; +import com.databasir.core.infrastructure.driver.DriverResources; import com.databasir.dao.impl.DatabaseTypeDao; import com.databasir.dao.tables.pojos.DatabaseTypePojo; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.jdbc.Sql; import org.springframework.transaction.annotation.Transactional; +import static org.mockito.ArgumentMatchers.anyString; + @Transactional class DatabaseTypeServiceTest extends BaseTest { @@ -22,6 +28,14 @@ class DatabaseTypeServiceTest extends BaseTest { @Autowired private DatabaseTypeDao databaseTypeDao; + @MockBean + private DriverResources driverResources; + + @BeforeEach + public void setUp() { + Mockito.doNothing().when(driverResources).validateJar(anyString(), anyString()); + } + @Test void create() { DatabaseTypeCreateRequest request = new DatabaseTypeCreateRequest();