mirror of
https://gitee.com/devlive-community/datacap.git
synced 2024-11-29 18:48:23 +08:00
feat(plugin): support install plugin for tar
This commit is contained in:
parent
c7cf964089
commit
85c34e7acf
19
.github/workflows/bofore_checker.yml
vendored
19
.github/workflows/bofore_checker.yml
vendored
@ -44,6 +44,8 @@ jobs:
|
||||
|
||||
before_checker_bugs:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- before_checker_ui
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@ -61,11 +63,26 @@ jobs:
|
||||
- name: Run SpotBugs for server
|
||||
run: ./mvnw clean install spotbugs:spotbugs -Dcheckstyle.skip -Dgpg.skip -Dskip.pnpm -DskipTests=true -f core/datacap-server/pom.xml
|
||||
|
||||
before_checker_package:
|
||||
before_checker_test:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- before_checker_style
|
||||
- before_checker_bugs
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Maven Checker Style
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
- run: chmod 755 ./mvnw
|
||||
- run: ./mvnw clean install package test -Dspotbugs.skip -Dgpg.skip -Dcheckstyle.skip -Dskip.pnpm
|
||||
|
||||
before_checker_package:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- before_checker_test
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
@ -2,6 +2,7 @@ package io.edurt.datacap.plugin;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -10,6 +11,7 @@ import java.nio.file.Paths;
|
||||
@Builder
|
||||
public class PluginConfigure
|
||||
{
|
||||
@Setter
|
||||
private Path pluginsDir;
|
||||
private boolean autoReload;
|
||||
private long scanInterval;
|
||||
|
@ -7,6 +7,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.utils.DateUtils;
|
||||
import io.edurt.datacap.plugin.loader.PluginClassLoader;
|
||||
import io.edurt.datacap.plugin.loader.PluginLoaderFactory;
|
||||
import io.edurt.datacap.plugin.loader.TarPluginLoader;
|
||||
import io.edurt.datacap.plugin.utils.PluginClassLoaderUtils;
|
||||
import io.edurt.datacap.plugin.utils.VersionUtils;
|
||||
import lombok.Getter;
|
||||
@ -33,7 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
@SuppressFBWarnings(value = {"NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"})
|
||||
@SuppressFBWarnings(value = {"NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", "EI_EXPOSE_REP2"})
|
||||
public class PluginManager
|
||||
{
|
||||
// 插件配置
|
||||
@ -140,11 +141,13 @@ public class PluginManager
|
||||
throw new IllegalArgumentException("Source path and target directory cannot be null or empty");
|
||||
}
|
||||
|
||||
// 验证源路径是否存在
|
||||
// Verify source path exists
|
||||
if (!Files.exists(sourcePath)) {
|
||||
log.error("Source plugin path does not exist: {}", sourcePath);
|
||||
return false;
|
||||
// 对于本地文件才验证存在性
|
||||
// Only verify existence for local files
|
||||
if (!sourcePath.toString().startsWith("http") && !sourcePath.toString().startsWith("https")) {
|
||||
if (!Files.exists(sourcePath)) {
|
||||
log.error("Source plugin path does not exist: {}", sourcePath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证目标目录名称合法性
|
||||
@ -217,6 +220,15 @@ public class PluginManager
|
||||
// 检测并处理插件类型
|
||||
// Detect and handle plugin type
|
||||
try {
|
||||
// 检测并处理插件类型
|
||||
// Detect and handle plugin type
|
||||
if ("tar".equals(extension)
|
||||
|| "tar.gz".equals(extension)
|
||||
|| "tgz".equals(extension)
|
||||
|| "gz".equals(extension)
|
||||
) {
|
||||
installed.set(installTarPlugin(sourcePath, tempDir));
|
||||
}
|
||||
// Properties 插件
|
||||
// Properties plugin
|
||||
if ("properties".equals(extension)) {
|
||||
@ -266,7 +278,7 @@ public class PluginManager
|
||||
throws IOException
|
||||
{
|
||||
if (Files.exists(pluginPath)) {
|
||||
String timestamp = DateUtils.formatYMDHMSWithInterval();
|
||||
String timestamp = DateUtils.formatYMDHMS();
|
||||
Path backupPath = pluginPath.getParent().resolve(pluginPath.getFileName() + ".backup." + timestamp);
|
||||
|
||||
try {
|
||||
@ -441,6 +453,50 @@ public class PluginManager
|
||||
return true;
|
||||
}
|
||||
|
||||
// 安装 Tar 类型插件
|
||||
// Install Tar type plugin
|
||||
private boolean installTarPlugin(Path sourcePath, Path tempDir)
|
||||
throws IOException
|
||||
{
|
||||
// 直接使用 TarPluginLoader 处理
|
||||
// Directly use TarPluginLoader to handle
|
||||
TarPluginLoader tarPluginLoader = new TarPluginLoader();
|
||||
// 先加载插件到临时目录
|
||||
// Load plugins to temporary directory
|
||||
List<Plugin> plugins = tarPluginLoader.load(sourcePath, tempDir);
|
||||
if (!plugins.isEmpty()) {
|
||||
// 查找解压后的子目录
|
||||
// Find extracted subdirectory
|
||||
try (Stream<Path> paths = Files.list(tempDir)) {
|
||||
Optional<Path> subDir = paths
|
||||
.filter(Files::isDirectory)
|
||||
.findFirst();
|
||||
|
||||
if (subDir.isPresent()) {
|
||||
// 如果存在子目录,将其内容移动到临时目录根目录
|
||||
// If subdirectory exists, move its contents to temp directory root
|
||||
Path source = subDir.get();
|
||||
try (Stream<Path> files = Files.list(source)) {
|
||||
files.forEach(file -> {
|
||||
try {
|
||||
Path target = tempDir.resolve(file.getFileName());
|
||||
Files.move(file, target);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("Failed to move file: {} to {}", file, tempDir, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 删除空的子目录
|
||||
// Delete empty subdirectory
|
||||
Files.delete(source);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 复制目录
|
||||
// Copy directory
|
||||
private void copyDirectory(Path source, Path target)
|
||||
|
@ -74,6 +74,22 @@ public class TarPluginLoader
|
||||
*/
|
||||
@Override
|
||||
public List<Plugin> load(Path path)
|
||||
{
|
||||
return load(path, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载插件到指定目录
|
||||
* Load plugins to specified directory
|
||||
*
|
||||
* @param path 插件路径或 URL
|
||||
* Plugin path or URL
|
||||
* @param targetDir 目标解压目录,如果为null则使用临时目录
|
||||
* Target extraction directory, use temporary directory if null
|
||||
* @return 加载的插件列表
|
||||
* List of loaded plugins
|
||||
*/
|
||||
public List<Plugin> load(Path path, Path targetDir)
|
||||
{
|
||||
try {
|
||||
// 如果是 URL 路径,先下载到本地
|
||||
@ -82,9 +98,9 @@ public class TarPluginLoader
|
||||
path = downloadTarFile(path.toString().replace(":/", "://"));
|
||||
}
|
||||
|
||||
// 创建临时解压目录
|
||||
// Create temporary directory for extraction
|
||||
Path extractDir = createTempDirectory();
|
||||
// 使用指定的目录或创建临时目录
|
||||
// Use specified directory or create temporary directory
|
||||
Path extractDir = targetDir != null ? targetDir : createTempDirectory();
|
||||
|
||||
// 解压 tar 文件
|
||||
// Extract tar file
|
||||
@ -94,9 +110,11 @@ public class TarPluginLoader
|
||||
// Load plugins from extracted directory
|
||||
List<Plugin> plugins = loadPluginsFromDirectory(extractDir);
|
||||
|
||||
// 清理临时目录
|
||||
// Cleanup temporary directory
|
||||
cleanupTempDirectory(extractDir);
|
||||
// 如果使用的是临时目录,则清理
|
||||
// Clean up if using temporary directory
|
||||
if (targetDir == null) {
|
||||
cleanupTempDirectory(extractDir);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import com.google.inject.Injector;
|
||||
import io.edurt.datacap.common.utils.EnvironmentUtils;
|
||||
import io.edurt.datacap.plugin.PluginManager;
|
||||
import io.edurt.datacap.plugin.utils.PluginPathUtils;
|
||||
import io.edurt.datacap.spi.PluginLoader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -37,10 +36,10 @@ public class PluginConfiguration
|
||||
|
||||
// 开发模式下生效
|
||||
// In development mode, it is effective
|
||||
if (EnvironmentUtils.isIdeEnvironment()) {
|
||||
log.info("Development mode is development mode");
|
||||
config.setPluginsDir(projectRoot.resolve(Path.of(String.join("/", root, "plugins.properties"))));
|
||||
}
|
||||
// if (EnvironmentUtils.isIdeEnvironment()) {
|
||||
// log.info("Development mode is development mode");
|
||||
// config.setPluginsDir(projectRoot.resolve(Path.of(String.join("/", root, "plugins.properties"))));
|
||||
// }
|
||||
|
||||
log.info("Plugins directory: {}", config.getPluginsDir());
|
||||
PluginManager pluginManager = new PluginManager(config);
|
||||
@ -52,6 +51,6 @@ public class PluginConfiguration
|
||||
@Bean
|
||||
public Injector injector()
|
||||
{
|
||||
return Guice.createInjector(new PluginLoader());
|
||||
return Guice.createInjector();
|
||||
}
|
||||
}
|
||||
|
@ -40,23 +40,23 @@ public class ScheduleRunnerConfigure
|
||||
@Override
|
||||
public void run(String... args)
|
||||
{
|
||||
// this.scheduledRepository.findAllByActiveIsTrueAndIsSystemIsTrue()
|
||||
// .forEach(task -> {
|
||||
// log.info("Add new task [ {} ] to scheduler", task.getName());
|
||||
// switch (task.getType()) {
|
||||
// case SOURCE_SYNCHRONIZE:
|
||||
// SyncMetadataScheduledRunnable syncMetadataScheduledRunnable = new SyncMetadataScheduledRunnable(task.getName(), injector, sourceRepository, sourceService);
|
||||
// this.scheduledCronRegistrar.addCronTask(syncMetadataScheduledRunnable, task.getExpression());
|
||||
// executorService.submit(syncMetadataScheduledRunnable);
|
||||
// break;
|
||||
// case SOURCE_CHECK:
|
||||
// CheckScheduledRunnable checkScheduledRunnable = new CheckScheduledRunnable(task.getName(), this.injector, this.sourceRepository);
|
||||
// this.scheduledCronRegistrar.addCronTask(checkScheduledRunnable, task.getExpression());
|
||||
// executorService.submit(checkScheduledRunnable);
|
||||
// break;
|
||||
// default:
|
||||
// log.warn("Unsupported task type [ {} ]", task.getType());
|
||||
// }
|
||||
// });
|
||||
this.scheduledRepository.findAllByActiveIsTrueAndIsSystemIsTrue()
|
||||
.forEach(task -> {
|
||||
log.info("Add new task [ {} ] to scheduler", task.getName());
|
||||
switch (task.getType()) {
|
||||
case SOURCE_SYNCHRONIZE:
|
||||
SyncMetadataScheduledRunnable syncMetadataScheduledRunnable = new SyncMetadataScheduledRunnable(task.getName(), injector, sourceRepository, sourceService);
|
||||
this.scheduledCronRegistrar.addCronTask(syncMetadataScheduledRunnable, task.getExpression());
|
||||
executorService.submit(syncMetadataScheduledRunnable);
|
||||
break;
|
||||
case SOURCE_CHECK:
|
||||
CheckScheduledRunnable checkScheduledRunnable = new CheckScheduledRunnable(task.getName(), this.injector, this.sourceRepository);
|
||||
this.scheduledCronRegistrar.addCronTask(checkScheduledRunnable, task.getExpression());
|
||||
executorService.submit(checkScheduledRunnable);
|
||||
break;
|
||||
default:
|
||||
log.warn("Unsupported task type [ {} ]", task.getType());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +1,47 @@
|
||||
package io.edurt.datacap.server.controller;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.executor.ExecutorService;
|
||||
import io.edurt.datacap.plugin.PluginManager;
|
||||
import io.edurt.datacap.plugin.PluginMetadata;
|
||||
import io.edurt.datacap.scheduler.SchedulerService;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/v1/plugin")
|
||||
public class PluginController
|
||||
{
|
||||
private final PluginManager pluginManager;
|
||||
private final Injector injector;
|
||||
|
||||
public PluginController(PluginManager pluginManager, Injector injector)
|
||||
public PluginController(PluginManager pluginManager)
|
||||
{
|
||||
this.pluginManager = pluginManager;
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public CommonResponse<Map<String, Set<String>>> getPlugins()
|
||||
{
|
||||
Map<String, Set<String>> plugins = Maps.newHashMap();
|
||||
Set<String> executors = injector.getInstance(Key.get(new TypeLiteral<Set<ExecutorService>>() {}))
|
||||
.stream()
|
||||
.map(ExecutorService::name)
|
||||
.collect(Collectors.toSet());
|
||||
plugins.put("executor", executors);
|
||||
|
||||
Set<String> schedulers = injector.getInstance(Key.get(new TypeLiteral<Set<SchedulerService>>() {}))
|
||||
.stream()
|
||||
.map(SchedulerService::name)
|
||||
.collect(Collectors.toSet());
|
||||
plugins.put("scheduler", schedulers);
|
||||
return CommonResponse.success(plugins);
|
||||
}
|
||||
|
||||
@GetMapping(value = {"filter"})
|
||||
public CommonResponse<List<PluginMetadata>> getPluginByType(@RequestParam String type)
|
||||
public CommonResponse<List<PluginMetadata>> getPlugins()
|
||||
{
|
||||
return CommonResponse.success(pluginManager.getPluginInfos());
|
||||
}
|
||||
|
||||
// @PostMapping(value = "install")
|
||||
@PostMapping(value = "install")
|
||||
public CommonResponse<Boolean> installPlugin(@RequestBody PluginInstallRequest request)
|
||||
{
|
||||
return CommonResponse.success(pluginManager.installPlugin(Path.of(request.url), request.name));
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class PluginInstallRequest
|
||||
{
|
||||
private String url;
|
||||
// 插件名称,默认作为插件的安装目录
|
||||
// Plugin name, default as the installation directory
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.edurt.datacap.service.audit;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.State;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.common.utils.CodeUtils;
|
||||
@ -42,6 +43,7 @@ import static java.util.Objects.requireNonNull;
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP2"})
|
||||
public class AuditPluginHandler
|
||||
{
|
||||
private final ThreadLocal<PluginAuditEntity> threadLocalPluginAudit = new ThreadLocal<>();
|
||||
|
@ -85,7 +85,7 @@ import static java.util.Objects.requireNonNull;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@SuppressFBWarnings(value = {"REC_CATCH_EXCEPTION", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", "EI_EXPOSE_REP2"})
|
||||
@SuppressFBWarnings(value = {"REC_CATCH_EXCEPTION", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", "EI_EXPOSE_REP2", "DLS_DEAD_LOCAL_STORE"})
|
||||
public class DataSetServiceImpl
|
||||
implements DataSetService
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.ServiceState;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.common.sql.SqlBuilder;
|
||||
@ -24,6 +25,7 @@ import java.io.File;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP2"})
|
||||
public class ExecuteServiceImpl
|
||||
implements ExecuteService
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@SuppressFBWarnings(value = {"DM_BOXED_PRIMITIVE_FOR_PARSING", "DM_DEFAULT_ENCODING"})
|
||||
@SuppressFBWarnings(value = {"DM_BOXED_PRIMITIVE_FOR_PARSING", "DM_DEFAULT_ENCODING", "EI_EXPOSE_REP2"})
|
||||
public class PluginAuditServiceImpl
|
||||
implements PluginAuditService
|
||||
{
|
||||
|
@ -3,7 +3,6 @@ package io.edurt.datacap.service.service.impl;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.NodeType;
|
||||
import io.edurt.datacap.common.enums.ServiceState;
|
||||
@ -20,7 +19,6 @@ import io.edurt.datacap.service.body.SourceBody;
|
||||
import io.edurt.datacap.service.common.ConfigureUtils;
|
||||
import io.edurt.datacap.service.common.PluginUtils;
|
||||
import io.edurt.datacap.service.configure.IConfigure;
|
||||
import io.edurt.datacap.service.configure.IConfigureField;
|
||||
import io.edurt.datacap.service.entity.ColumnEntity;
|
||||
import io.edurt.datacap.service.entity.DatabaseEntity;
|
||||
import io.edurt.datacap.service.entity.PageEntity;
|
||||
@ -70,7 +68,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@SuppressFBWarnings(value = {"RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", "REC_CATCH_EXCEPTION", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"})
|
||||
@SuppressFBWarnings(value = {"RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", "REC_CATCH_EXCEPTION", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", "EI_EXPOSE_REP2"})
|
||||
public class SourceServiceImpl
|
||||
implements SourceService
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.edurt.datacap.service.service.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.edurt.datacap.common.enums.ServiceState;
|
||||
import io.edurt.datacap.common.response.CommonResponse;
|
||||
import io.edurt.datacap.common.sql.SqlBuilder;
|
||||
@ -65,6 +66,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP2"})
|
||||
public class TableServiceImpl
|
||||
implements TableService
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@SuppressFBWarnings(value = {"DLS_DEAD_LOCAL_STORE"})
|
||||
@SuppressFBWarnings(value = {"DLS_DEAD_LOCAL_STORE", "EI_EXPOSE_REP2"})
|
||||
public class UploadServiceImpl
|
||||
implements UploadService
|
||||
{
|
||||
|
@ -1,13 +0,0 @@
|
||||
package io.edurt.datacap.spi;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
@Slf4j
|
||||
public class PluginLoader
|
||||
extends AbstractModule
|
||||
{
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package io.edurt.datacap.spi.connection;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.edurt.datacap.plugin.PluginContextManager;
|
||||
import io.edurt.datacap.plugin.loader.PluginClassLoader;
|
||||
import io.edurt.datacap.spi.model.Response;
|
||||
@ -83,7 +82,6 @@ public class JdbcConnection
|
||||
protected java.sql.Connection openConnection()
|
||||
{
|
||||
JdbcConfigure jdbcConfigure = getJdbcConfigure();
|
||||
Preconditions.checkNotNull(jdbcConfigure.getPlugin(), "Plugin cannot be null");
|
||||
|
||||
try {
|
||||
PluginClassLoader pluginClassLoader = jdbcConfigure.getPlugin().getPluginClassLoader();
|
||||
@ -140,7 +138,10 @@ public class JdbcConnection
|
||||
{
|
||||
private final Driver driver;
|
||||
|
||||
DriverShim(Driver d) {this.driver = d;}
|
||||
DriverShim(Driver d)
|
||||
{
|
||||
this.driver = d;
|
||||
}
|
||||
|
||||
public Connection connect(String url, Properties info)
|
||||
throws SQLException
|
||||
@ -160,11 +161,20 @@ public class JdbcConnection
|
||||
return driver.getPropertyInfo(url, info);
|
||||
}
|
||||
|
||||
public int getMajorVersion() {return driver.getMajorVersion();}
|
||||
public int getMajorVersion()
|
||||
{
|
||||
return driver.getMajorVersion();
|
||||
}
|
||||
|
||||
public int getMinorVersion() {return driver.getMinorVersion();}
|
||||
public int getMinorVersion()
|
||||
{
|
||||
return driver.getMinorVersion();
|
||||
}
|
||||
|
||||
public boolean jdbcCompliant() {return driver.jdbcCompliant();}
|
||||
public boolean jdbcCompliant()
|
||||
{
|
||||
return driver.jdbcCompliant();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger()
|
||||
|
@ -18,7 +18,8 @@ import java.util.Optional;
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
|
||||
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2", "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", "CT_CONSTRUCTOR_THROW",
|
||||
"NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"})
|
||||
public class Configure
|
||||
{
|
||||
@NonNull
|
||||
|
@ -1,46 +0,0 @@
|
||||
package io.edurt.datacap.spi.connection;
|
||||
|
||||
import io.edurt.datacap.spi.model.Response;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class JdbcConnectionTest
|
||||
{
|
||||
private JdbcConfigure jdbcConfigure;
|
||||
private Response response;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
this.jdbcConfigure = new JdbcConfigure();
|
||||
this.jdbcConfigure.setJdbcType("datacap");
|
||||
this.jdbcConfigure.setJdbcDriver("io.edurt.datacap.DataCapDriver");
|
||||
this.jdbcConfigure.setHost("127.0.0.1");
|
||||
this.jdbcConfigure.setPort(9096);
|
||||
|
||||
this.response = new Response();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatJdbcUrl()
|
||||
{
|
||||
Connection connection = new JdbcConnection(this.jdbcConfigure, this.response);
|
||||
Assert.assertEquals(connection.formatJdbcUrl(), "jdbc:datacap://127.0.0.1:9096");
|
||||
|
||||
this.jdbcConfigure.setSsl(Optional.ofNullable(true));
|
||||
connection = new JdbcConnection(this.jdbcConfigure, this.response);
|
||||
Assert.assertEquals(connection.formatJdbcUrl(), "jdbc:datacap://127.0.0.1:9096?ssl=true");
|
||||
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("useUnicode", "true");
|
||||
env.put("zeroDateTimeBehavior", "convertToNull");
|
||||
this.jdbcConfigure.setEnv(Optional.ofNullable(env));
|
||||
connection = new JdbcConnection(this.jdbcConfigure, this.response);
|
||||
Assert.assertEquals(connection.formatJdbcUrl(), "jdbc:datacap://127.0.0.1:9096?ssl=true&useUnicode=true&zeroDateTimeBehavior=convertToNull");
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package io.edurt.datacap.spi.connection.http;
|
||||
|
||||
import io.edurt.datacap.spi.connection.HttpConfigure;
|
||||
import io.edurt.datacap.spi.connection.HttpConnection;
|
||||
import io.edurt.datacap.spi.model.Response;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpClientTest
|
||||
{
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
HttpConfigure httpConfigure = new HttpConfigure();
|
||||
httpConfigure.setAutoConnected(Boolean.FALSE);
|
||||
httpConfigure.setRetry(0);
|
||||
httpConfigure.setParams(null);
|
||||
httpConfigure.setProtocol("https");
|
||||
httpConfigure.setHost("datacap.incubator.edurt.io");
|
||||
httpConfigure.setPort(443);
|
||||
httpConfigure.setMethod(HttpMethod.GET);
|
||||
httpConfigure.setPath("blog/index.html");
|
||||
HttpConnection httpConnection = new HttpConnection(httpConfigure, new Response());
|
||||
HttpClient httpClient = HttpClient.getInstance(httpConfigure, httpConnection);
|
||||
String response = httpClient.execute();
|
||||
Assert.assertNotNull(response);
|
||||
}
|
||||
}
|
@ -9,11 +9,6 @@ class PluginService
|
||||
{
|
||||
return new HttpUtils().get(`${ DEFAULT_PATH }`)
|
||||
}
|
||||
|
||||
filterByType(type: string): Promise<ResponseModel>
|
||||
{
|
||||
return new HttpUtils().get(`${ DEFAULT_PATH }/filter`, { type })
|
||||
}
|
||||
}
|
||||
|
||||
export default new PluginService()
|
||||
|
@ -172,7 +172,7 @@ const loadMetadata = async () => {
|
||||
const data = await response.json()
|
||||
metadata.value = data
|
||||
|
||||
const installResponse = await PluginService.filterByType('plugin')
|
||||
const installResponse = await PluginService.getPlugins()
|
||||
if (!installResponse.status) {
|
||||
// @ts-ignore
|
||||
proxy?.$Message.error({ content: response.message, showIcon: true })
|
||||
|
9
docs/docs/api/plugin/install.md
Normal file
9
docs/docs/api/plugin/install.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
title: 安装插件
|
||||
---
|
||||
|
||||
请求地址:`/api/v1/plugin/install`
|
||||
|
||||
请求方式:`POST`
|
||||
|
||||
## Request
|
37
docs/docs/api/plugin/plugin.md
Normal file
37
docs/docs/api/plugin/plugin.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
title: 插件列表
|
||||
---
|
||||
|
||||
请求地址:`/api/v1/plugin`
|
||||
|
||||
请求方式:`GET`
|
||||
|
||||
## Response
|
||||
|
||||
=== "示例"
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "TxtConvert",
|
||||
"version": "2024.4.0-SNAPSHOT",
|
||||
"state": "CREATED",
|
||||
"loadTimestamp": 1732353263492,
|
||||
"loadTime": "2024-11-23 17:14:23",
|
||||
"type": "CONVERT",
|
||||
"loaderName": "io.edurt.datacap.plugin.loader.PropertiesPluginLoader"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
=== "参数"
|
||||
|
||||
| 名称 | 类型 | 是否必须 | 描述 |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | String | 是 | 插件名称 |
|
||||
| `version` | String | 是 | 插件版本 |
|
||||
| `state` | String | 是 | 插件状态 |
|
||||
| `loadTimestamp` | Long | 是 | 插件加载时间戳 |
|
||||
| `loadTime` | String | 是 | 插件加载时间 |
|
||||
| `type` | String | 是 | 插件类型 |
|
||||
| `loaderName` | String | 是 | 插件加载器名称 |
|
@ -131,6 +131,7 @@ plugins:
|
||||
NavDeploy: 安装部署
|
||||
ApiHome: 开放 API
|
||||
ApiUser: 用户 API
|
||||
ApiPlugin: 插件 API
|
||||
- locale: en
|
||||
name: English
|
||||
build: true
|
||||
@ -152,6 +153,7 @@ plugins:
|
||||
NavDeploy: Install Deploy
|
||||
ApiHome: Open API
|
||||
ApiUser: User API
|
||||
ApiPlugin: Plugin API
|
||||
- search
|
||||
- git-revision-date-localized:
|
||||
enable_creation_date: true
|
||||
@ -284,5 +286,8 @@ nav:
|
||||
- ApiUser:
|
||||
- api/user/register.md
|
||||
- api/user/login.md
|
||||
- ApiPlugin:
|
||||
- api/plugin/plugin.md
|
||||
- api/plugin/install.md
|
||||
- useCases.md
|
||||
- partners.md
|
||||
|
@ -1,30 +0,0 @@
|
||||
package io.edurt.datacap.lib.http;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpClientTest
|
||||
{
|
||||
private HttpConfigure configure;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
configure = new HttpConfigure();
|
||||
configure.setAutoConnected(Boolean.FALSE);
|
||||
configure.setRetry(0);
|
||||
configure.setParams(null);
|
||||
configure.setProtocol("https");
|
||||
configure.setHost("datacap.edurt.io");
|
||||
configure.setPort(443);
|
||||
configure.setMethod(HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute()
|
||||
{
|
||||
HttpClient client = new HttpClient(this.configure);
|
||||
Assert.assertNotNull(client.execute());
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package io.edurt.datacap.lib.logger.logback;
|
||||
|
||||
import io.edurt.datacap.lib.logger.LoggerExecutor;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class LogbackExecutorTest
|
||||
{
|
||||
private final String directory = System.getProperty("user.dir");
|
||||
private final String name = this.getClass().getName() + ".log";
|
||||
private LoggerExecutor loggerExecutor;
|
||||
private Logger logger;
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
this.loggerExecutor = new LogbackExecutor(this.directory, this.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLogger()
|
||||
{
|
||||
logger = (Logger) loggerExecutor.getLogger();
|
||||
logger.info("info");
|
||||
logger.debug("debug");
|
||||
logger.error("error");
|
||||
logger.warn("warn");
|
||||
logger.trace("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destroy()
|
||||
{
|
||||
loggerExecutor.destroy();
|
||||
Assert.assertTrue(logger == null);
|
||||
}
|
||||
}
|
1
pom.xml
1
pom.xml
@ -104,6 +104,7 @@
|
||||
<module>test/datacap-test-plugin</module>
|
||||
<module>test/datacap-test-convert</module>
|
||||
<module>test/datacap-test-core</module>
|
||||
<module>test/datacap-test-lib</module>
|
||||
</modules>
|
||||
|
||||
<name>datacap</name>
|
||||
|
63
test/datacap-test-lib/pom.xml
Normal file
63
test/datacap-test-lib/pom.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap</artifactId>
|
||||
<version>2024.4.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>datacap-test-lib</artifactId>
|
||||
<description>DataCap - Test - Lib</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-http</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.edurt.datacap</groupId>
|
||||
<artifactId>datacap-logger</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,30 @@
|
||||
package io.edurt.datacap.test.lib.http
|
||||
|
||||
import io.edurt.datacap.lib.http.HttpClient
|
||||
import io.edurt.datacap.lib.http.HttpConfigure
|
||||
import io.edurt.datacap.lib.http.HttpMethod
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Test
|
||||
|
||||
class HttpClientTest
|
||||
{
|
||||
private val configure: HttpConfigure = HttpConfigure()
|
||||
|
||||
init
|
||||
{
|
||||
configure.autoConnected = java.lang.Boolean.FALSE
|
||||
configure.retry = 0
|
||||
configure.params = null
|
||||
configure.protocol = "https"
|
||||
configure.host = "datacap.devlive.org"
|
||||
configure.port = 443
|
||||
configure.method = HttpMethod.GET
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test()
|
||||
{
|
||||
val client: HttpClient = HttpClient(this.configure)
|
||||
assertNotNull(client.execute())
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.edurt.datacap.test.lib.logger
|
||||
|
||||
import io.edurt.datacap.lib.logger.logback.LogbackExecutor
|
||||
import org.junit.Test
|
||||
import org.slf4j.Logger
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class LogbackExecutorTest
|
||||
{
|
||||
private val directory: String = System.getProperty("user.dir")
|
||||
private val name = javaClass.name + ".log"
|
||||
private val loggerExecutor: LogbackExecutor = LogbackExecutor(directory, name)
|
||||
private var logger: Logger = loggerExecutor.getLogger()
|
||||
|
||||
@Test
|
||||
fun getLogger()
|
||||
{
|
||||
logger.info("info")
|
||||
logger.debug("debug")
|
||||
logger.error("error")
|
||||
logger.warn("warn")
|
||||
logger.trace("trace")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun destroy()
|
||||
{
|
||||
loggerExecutor.destroy()
|
||||
assertNotNull(logger)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user