diff --git a/.github/workflows/bofore_checker.yml b/.github/workflows/bofore_checker.yml index ab1b97f5..5ea4f0d2 100644 --- a/.github/workflows/bofore_checker.yml +++ b/.github/workflows/bofore_checker.yml @@ -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 diff --git a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginConfigure.java b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginConfigure.java index 9e16ed59..8996838e 100644 --- a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginConfigure.java +++ b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginConfigure.java @@ -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; diff --git a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginManager.java b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginManager.java index 92836ab1..cefe9d1d 100644 --- a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginManager.java +++ b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/PluginManager.java @@ -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 plugins = tarPluginLoader.load(sourcePath, tempDir); + if (!plugins.isEmpty()) { + // 查找解压后的子目录 + // Find extracted subdirectory + try (Stream paths = Files.list(tempDir)) { + Optional 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 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) diff --git a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/loader/TarPluginLoader.java b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/loader/TarPluginLoader.java index 4c9d93cd..7cc3906f 100644 --- a/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/loader/TarPluginLoader.java +++ b/core/datacap-plugin/src/main/java/io/edurt/datacap/plugin/loader/TarPluginLoader.java @@ -74,6 +74,22 @@ public class TarPluginLoader */ @Override public List 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 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 plugins = loadPluginsFromDirectory(extractDir); - // 清理临时目录 - // Cleanup temporary directory - cleanupTempDirectory(extractDir); + // 如果使用的是临时目录,则清理 + // Clean up if using temporary directory + if (targetDir == null) { + cleanupTempDirectory(extractDir); + } return plugins; } diff --git a/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/PluginConfiguration.java b/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/PluginConfiguration.java index 26d26b4c..4183fcde 100644 --- a/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/PluginConfiguration.java +++ b/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/PluginConfiguration.java @@ -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(); } } diff --git a/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/ScheduleRunnerConfigure.java b/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/ScheduleRunnerConfigure.java index 3cfea058..09ac0abf 100644 --- a/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/ScheduleRunnerConfigure.java +++ b/core/datacap-server/src/main/java/io/edurt/datacap/server/configure/ScheduleRunnerConfigure.java @@ -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()); + } + }); } } diff --git a/core/datacap-server/src/main/java/io/edurt/datacap/server/controller/PluginController.java b/core/datacap-server/src/main/java/io/edurt/datacap/server/controller/PluginController.java index 683cddd6..670cb7df 100644 --- a/core/datacap-server/src/main/java/io/edurt/datacap/server/controller/PluginController.java +++ b/core/datacap-server/src/main/java/io/edurt/datacap/server/controller/PluginController.java @@ -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>> getPlugins() - { - Map> plugins = Maps.newHashMap(); - Set executors = injector.getInstance(Key.get(new TypeLiteral>() {})) - .stream() - .map(ExecutorService::name) - .collect(Collectors.toSet()); - plugins.put("executor", executors); - - Set schedulers = injector.getInstance(Key.get(new TypeLiteral>() {})) - .stream() - .map(SchedulerService::name) - .collect(Collectors.toSet()); - plugins.put("scheduler", schedulers); - return CommonResponse.success(plugins); - } - - @GetMapping(value = {"filter"}) - public CommonResponse> getPluginByType(@RequestParam String type) + public CommonResponse> getPlugins() { return CommonResponse.success(pluginManager.getPluginInfos()); } -// @PostMapping(value = "install") + @PostMapping(value = "install") + public CommonResponse 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; + } } diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/audit/AuditPluginHandler.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/audit/AuditPluginHandler.java index f5153a33..ed3387e5 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/audit/AuditPluginHandler.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/audit/AuditPluginHandler.java @@ -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 threadLocalPluginAudit = new ThreadLocal<>(); diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/DataSetServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/DataSetServiceImpl.java index 6794969f..8ba38832 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/DataSetServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/DataSetServiceImpl.java @@ -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 { diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/ExecuteServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/ExecuteServiceImpl.java index 744af865..d1f3dd45 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/ExecuteServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/ExecuteServiceImpl.java @@ -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 { diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/PluginAuditServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/PluginAuditServiceImpl.java index 8c19756c..41ceafec 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/PluginAuditServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/PluginAuditServiceImpl.java @@ -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 { diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/SourceServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/SourceServiceImpl.java index eff7c7a2..117abaf1 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/SourceServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/SourceServiceImpl.java @@ -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 { diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/TableServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/TableServiceImpl.java index be970a45..e721bec1 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/TableServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/TableServiceImpl.java @@ -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 { diff --git a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/UploadServiceImpl.java b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/UploadServiceImpl.java index ec98599a..edfc4bde 100644 --- a/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/UploadServiceImpl.java +++ b/core/datacap-service/src/main/java/io/edurt/datacap/service/service/impl/UploadServiceImpl.java @@ -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 { diff --git a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/PluginLoader.java b/core/datacap-spi/src/main/java/io/edurt/datacap/spi/PluginLoader.java deleted file mode 100644 index 5f188ac3..00000000 --- a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/PluginLoader.java +++ /dev/null @@ -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 -{ -} diff --git a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/connection/JdbcConnection.java b/core/datacap-spi/src/main/java/io/edurt/datacap/spi/connection/JdbcConnection.java index a1cbd0b3..a4509c4d 100644 --- a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/connection/JdbcConnection.java +++ b/core/datacap-spi/src/main/java/io/edurt/datacap/spi/connection/JdbcConnection.java @@ -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() diff --git a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/model/Configure.java b/core/datacap-spi/src/main/java/io/edurt/datacap/spi/model/Configure.java index 7c5a5e0c..eddcfa6b 100644 --- a/core/datacap-spi/src/main/java/io/edurt/datacap/spi/model/Configure.java +++ b/core/datacap-spi/src/main/java/io/edurt/datacap/spi/model/Configure.java @@ -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 diff --git a/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/JdbcConnectionTest.java b/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/JdbcConnectionTest.java deleted file mode 100644 index cb7c502a..00000000 --- a/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/JdbcConnectionTest.java +++ /dev/null @@ -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 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"); - } -} \ No newline at end of file diff --git a/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/http/HttpClientTest.java b/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/http/HttpClientTest.java deleted file mode 100644 index cf86a0b9..00000000 --- a/core/datacap-spi/src/test/java/io/edurt/datacap/spi/connection/http/HttpClientTest.java +++ /dev/null @@ -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); - } -} diff --git a/core/datacap-ui/src/services/plugin.ts b/core/datacap-ui/src/services/plugin.ts index ce6353d7..a1c7292a 100644 --- a/core/datacap-ui/src/services/plugin.ts +++ b/core/datacap-ui/src/services/plugin.ts @@ -9,11 +9,6 @@ class PluginService { return new HttpUtils().get(`${ DEFAULT_PATH }`) } - - filterByType(type: string): Promise - { - return new HttpUtils().get(`${ DEFAULT_PATH }/filter`, { type }) - } } export default new PluginService() diff --git a/core/datacap-ui/src/views/pages/store/StoreHome.vue b/core/datacap-ui/src/views/pages/store/StoreHome.vue index ef47a669..9f5e5741 100644 --- a/core/datacap-ui/src/views/pages/store/StoreHome.vue +++ b/core/datacap-ui/src/views/pages/store/StoreHome.vue @@ -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 }) diff --git a/docs/docs/api/plugin/install.md b/docs/docs/api/plugin/install.md new file mode 100644 index 00000000..cf554ff3 --- /dev/null +++ b/docs/docs/api/plugin/install.md @@ -0,0 +1,9 @@ +--- +title: 安装插件 +--- + +请求地址:`/api/v1/plugin/install` + +请求方式:`POST` + +## Request \ No newline at end of file diff --git a/docs/docs/api/plugin/plugin.md b/docs/docs/api/plugin/plugin.md new file mode 100644 index 00000000..df39936d --- /dev/null +++ b/docs/docs/api/plugin/plugin.md @@ -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 | 是 | 插件加载器名称 | diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 68d3484c..a7b6cb95 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -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 diff --git a/lib/datacap-http/src/test/java/io/edurt/datacap/lib/http/HttpClientTest.java b/lib/datacap-http/src/test/java/io/edurt/datacap/lib/http/HttpClientTest.java deleted file mode 100644 index 1b4f5b20..00000000 --- a/lib/datacap-http/src/test/java/io/edurt/datacap/lib/http/HttpClientTest.java +++ /dev/null @@ -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()); - } -} diff --git a/lib/datacap-logger/src/test/java/io/edurt/datacap/lib/logger/logback/LogbackExecutorTest.java b/lib/datacap-logger/src/test/java/io/edurt/datacap/lib/logger/logback/LogbackExecutorTest.java deleted file mode 100644 index a5a02c0a..00000000 --- a/lib/datacap-logger/src/test/java/io/edurt/datacap/lib/logger/logback/LogbackExecutorTest.java +++ /dev/null @@ -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); - } -} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2bd757e7..bae1119e 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,7 @@ test/datacap-test-plugin test/datacap-test-convert test/datacap-test-core + test/datacap-test-lib datacap diff --git a/test/datacap-test-lib/pom.xml b/test/datacap-test-lib/pom.xml new file mode 100644 index 00000000..fc2eabf6 --- /dev/null +++ b/test/datacap-test-lib/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + io.edurt.datacap + datacap + 2024.4.0-SNAPSHOT + ../../pom.xml + + + datacap-test-lib + DataCap - Test - Lib + + + + org.jetbrains.kotlin + kotlin-reflect + test + + + junit + junit + ${junit.version} + test + + + io.edurt.datacap + datacap-http + test + + + io.edurt.datacap + datacap-logger + ${project.version} + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + test-compile + + test-compile + + + + ${project.basedir}/src/test/kotlin + + + + + + + + + diff --git a/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/http/HttpClientTest.kt b/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/http/HttpClientTest.kt new file mode 100644 index 00000000..58c06eb3 --- /dev/null +++ b/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/http/HttpClientTest.kt @@ -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()) + } +} diff --git a/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/logger/LogbackExecutorTest.kt b/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/logger/LogbackExecutorTest.kt new file mode 100644 index 00000000..fdbf3e9b --- /dev/null +++ b/test/datacap-test-lib/src/test/kotlin/io/edurt/datacap/test/lib/logger/LogbackExecutorTest.kt @@ -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) + } +}