|
|
@ -4,16 +4,22 @@ import com.databasir.core.domain.DomainErrors; |
|
|
|
import lombok.RequiredArgsConstructor; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.io.IOUtils; |
|
|
|
import org.apache.commons.lang3.ClassUtils; |
|
|
|
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.*; |
|
|
|
import java.net.MalformedURLException; |
|
|
|
import java.net.URL; |
|
|
|
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; |
|
|
|
|
|
|
@ -27,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); |
|
|
@ -36,10 +42,24 @@ public class DriverResources { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public String resolveSqlDriverNameFromJar(String driverFileUrl) { |
|
|
|
public Optional<File> 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 = doDownload(driverFileUrl, tempFilePath); |
|
|
|
String className = doResolveSqlDriverNameFromJar(driverFile); |
|
|
|
File driverFile = download(driverFileUrl, tempFilePath); |
|
|
|
String className = resolveDriverClassName(driverFile); |
|
|
|
try { |
|
|
|
Files.deleteIfExists(driverFile.toPath()); |
|
|
|
} catch (IOException e) { |
|
|
@ -48,19 +68,40 @@ public class DriverResources { |
|
|
|
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(); |
|
|
|
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()); |
|
|
|
} |
|
|
|
return this.doDownload(driverFileUrl, filePath); |
|
|
|
|
|
|
|
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 doDownload(String driverFileUrl, String filePath) { |
|
|
|
Path path = Path.of(filePath); |
|
|
|
private File download(String driverFileUrl, String targetFile) { |
|
|
|
Path path = Path.of(targetFile); |
|
|
|
|
|
|
|
// create parent directory
|
|
|
|
if (Files.notExists(path)) { |
|
|
@ -68,7 +109,7 @@ public class DriverResources { |
|
|
|
try { |
|
|
|
Files.createFile(path); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("create file error " + filePath, e); |
|
|
|
log.error("create file error " + targetFile, e); |
|
|
|
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
@ -81,52 +122,55 @@ public class DriverResources { |
|
|
|
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); |
|
|
|
log.info("{} download success ", targetFile); |
|
|
|
return file; |
|
|
|
} else { |
|
|
|
log.error("{} download error from {}: {} ", filePath, driverFileUrl, response); |
|
|
|
log.error("{} download error from {}: {} ", targetFile, driverFileUrl, response); |
|
|
|
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception("驱动下载失败:" |
|
|
|
+ response.getStatusCode() |
|
|
|
+ ", " |
|
|
|
+ response.getStatusText()); |
|
|
|
} |
|
|
|
}); |
|
|
|
} catch (IllegalArgumentException e) { |
|
|
|
log.error(filePath + " download driver error", e); |
|
|
|
} catch (RestClientException e) { |
|
|
|
log.error(targetFile + " download driver error", e); |
|
|
|
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.exception(e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private String doResolveSqlDriverNameFromJar(File driverFile) { |
|
|
|
JarFile jarFile = null; |
|
|
|
public void validateJar(String driverFileUrl, String className) { |
|
|
|
String tempFilePath = "temp/" + UUID.randomUUID() + ".jar"; |
|
|
|
File driverFile = download(driverFileUrl, tempFilePath); |
|
|
|
URLClassLoader loader = null; |
|
|
|
try { |
|
|
|
jarFile = new JarFile(driverFile); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("resolve driver class name error", e); |
|
|
|
throw DomainErrors.DRIVER_CLASS_NAME_OBTAIN_ERROR.exception(e.getMessage()); |
|
|
|
loader = new URLClassLoader( |
|
|
|
new URL[]{driverFile.toURI().toURL()}, |
|
|
|
this.getClass().getClassLoader() |
|
|
|
); |
|
|
|
} catch (MalformedURLException e) { |
|
|
|
log.error("load driver jar error ", e); |
|
|
|
throw DomainErrors.DOWNLOAD_DRIVER_ERROR.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_NAME_OBTAIN_ERROR.exception(e.getMessage()); |
|
|
|
Class clazz = Class.forName(className, false, loader); |
|
|
|
boolean isValid = ClassUtils.getAllInterfaces(clazz) |
|
|
|
.stream() |
|
|
|
.anyMatch(cls -> cls.getName().equals("java.sql.Driver")); |
|
|
|
if (!isValid) { |
|
|
|
throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception("不合法的驱动类,请重新指定"); |
|
|
|
} |
|
|
|
} catch (ClassNotFoundException e) { |
|
|
|
log.error("init driver error", e); |
|
|
|
throw DomainErrors.DRIVER_CLASS_NOT_FOUND.exception("驱动初始化异常, 请检查驱动类名:" + e.getMessage()); |
|
|
|
} finally { |
|
|
|
IOUtils.closeQuietly(reader, ex -> log.error("close reader error", ex)); |
|
|
|
IOUtils.closeQuietly(loader); |
|
|
|
try { |
|
|
|
Files.deleteIfExists(driverFile.toPath()); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("delete driver error " + tempFilePath, e); |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
.orElseThrow(DomainErrors.DRIVER_CLASS_NAME_OBTAIN_ERROR::exception); |
|
|
|
IOUtils.closeQuietly(jarFile, ex -> log.error("close jar file error", ex)); |
|
|
|
return driverClassName; |
|
|
|
} |
|
|
|
|
|
|
|
private String driverFilePath(String baseDir, String databaseType) { |
|
|
|