diff --git a/common/src/main/java/io/edurt/datacap/common/OptionalUtils.java b/common/src/main/java/io/edurt/datacap/common/OptionalUtils.java index 6f71a0d6..c7560898 100644 --- a/common/src/main/java/io/edurt/datacap/common/OptionalUtils.java +++ b/common/src/main/java/io/edurt/datacap/common/OptionalUtils.java @@ -1,27 +1,27 @@ package io.edurt.datacap.common; -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; - import java.util.Optional; public class OptionalUtils { private OptionalUtils() {} - public static boolean isEmpty(Optional optional) + public static boolean checkEmpty(Optional optional) { boolean flag = false; if (optional.isPresent()) { - if (ObjectUtils.isEmpty(optional.get()) && StringUtils.isEmpty(optional.get())) { - flag = true; - } + flag = true; } return flag; } + public static boolean isEmpty(Optional optional) + { + return !checkEmpty(optional); + } + public static boolean isNotEmpty(Optional optional) { - return !isEmpty(optional); + return checkEmpty(optional); } } diff --git a/server/src/main/etc/conf/plugins/native/redis.json b/server/src/main/etc/conf/plugins/native/redis.json new file mode 100644 index 00000000..3d61c465 --- /dev/null +++ b/server/src/main/etc/conf/plugins/native/redis.json @@ -0,0 +1,33 @@ +{ + "name": "Redis", + "supportTime": "2022-12-01", + "configures": [ + { + "field": "name", + "type": "String", + "required": true, + "message": "name is a required field, please be sure to enter" + }, + { + "field": "host", + "type": "String", + "required": true, + "value": "127.0.0.1", + "message": "host is a required field, please be sure to enter" + }, + { + "field": "port", + "type": "Number", + "required": true, + "min": 1, + "max": 65535, + "value": 6379, + "message": "port is a required field, please be sure to enter" + }, + { + "field": "password", + "type": "String", + "group": "authorization" + } + ] +} diff --git a/server/src/main/java/io/edurt/datacap/server/common/IConfigureCommon.java b/server/src/main/java/io/edurt/datacap/server/common/IConfigureCommon.java index ced0805e..db8bc589 100644 --- a/server/src/main/java/io/edurt/datacap/server/common/IConfigureCommon.java +++ b/server/src/main/java/io/edurt/datacap/server/common/IConfigureCommon.java @@ -1,18 +1,23 @@ package io.edurt.datacap.server.common; import com.google.common.base.Preconditions; +import io.edurt.datacap.server.entity.SourceEntity; +import io.edurt.datacap.server.plugin.configure.IConfigure; import io.edurt.datacap.server.plugin.configure.IConfigureField; import io.edurt.datacap.server.plugin.configure.IConfigureFieldName; import io.edurt.datacap.server.plugin.configure.IConfigureFieldType; import io.edurt.datacap.spi.FormatType; import io.edurt.datacap.spi.model.Configure; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; public class IConfigureCommon { @@ -64,6 +69,109 @@ public class IConfigureCommon return configure; } + public static IConfigure preparedConfigure(IConfigure configure, SourceEntity source) + { + configure.getConfigures().forEach(v -> { + switch (v.getField()) { + case name: + v.setValue(source.getName()); + break; + case host: + v.setValue(source.getHost()); + break; + case port: + v.setValue(source.getPort()); + break; + case username: + v.setValue(source.getUsername()); + break; + case password: + v.setValue(source.getPassword()); + break; + case database: + v.setValue(source.getDatabase()); + break; + case ssl: + v.setValue(source.getSsl()); + break; + case catalog: + v.setValue(source.getCatalog()); + break; + case configures: + List> fields = new ArrayList<>(); + if (ObjectUtils.isNotEmpty(source.getConfigures())) { + source.getConfigures().entrySet().forEach(entry -> { + Map map = new LinkedHashMap<>(); + map.put(IConfigureFieldName.field.name(), entry.getKey()); + map.put(IConfigureFieldName.value.name(), entry.getValue()); + fields.add(map); + }); + } + v.setValue(fields); + break; + } + }); + return configure; + } + + public static SourceEntity preparedSourceEntity(List configures) + { + SourceEntity configure = new SourceEntity(); + configures.forEach(v -> { + switch (v.getField()) { + case name: + configure.setName(IConfigureCommon.getStringValue(configures, IConfigureFieldName.name)); + case host: + configure.setHost(IConfigureCommon.getStringValue(configures, IConfigureFieldName.host)); + break; + case port: + configure.setPort(IConfigureCommon.getIntegerValue(configures, IConfigureFieldName.port)); + break; + case username: + configure.setUsername(IConfigureCommon.getStringValue(configures, IConfigureFieldName.username)); + break; + case password: + configure.setPassword(IConfigureCommon.getStringValue(configures, IConfigureFieldName.password)); + break; + case database: + String database = IConfigureCommon.getStringValue(configures, IConfigureFieldName.database); + configure.setDatabase(database); + break; + case catalog: + String catalog = IConfigureCommon.getStringValue(configures, IConfigureFieldName.catalog); + configure.setCatalog(catalog); + break; + case ssl: + configure.setSsl(IConfigureCommon.getBooleanValue(configures, IConfigureFieldName.ssl)); + break; + case configures: + configure.setConfigure(JSON.toJSON(IConfigureCommon.getMapValue(configures, IConfigureFieldName.configures))); + break; + } + }); + return configure; + } + + public static List filterNotEmpty(List configures) + { + return configures.stream().filter(v -> !isEmpty(v)).collect(Collectors.toList()); + } + + public static boolean isEmpty(IConfigureField field) + { + boolean flag = true; + switch (field.getType()) { + case String: + if (ObjectUtils.isNotEmpty(field.getValue())) { + flag = StringUtils.isEmpty(String.valueOf(field.getValue())); + } + break; + default: + flag = false; + } + return flag; + } + public static IConfigureField getConfigure(List configures, IConfigureFieldName key) { Optional configureFieldOptional = configures.stream().filter(v -> v.getField().equals(key)).findFirst(); diff --git a/server/src/main/java/io/edurt/datacap/server/controller/user/SourceController.java b/server/src/main/java/io/edurt/datacap/server/controller/user/SourceController.java index fb109b2f..e9b70d4b 100644 --- a/server/src/main/java/io/edurt/datacap/server/controller/user/SourceController.java +++ b/server/src/main/java/io/edurt/datacap/server/controller/user/SourceController.java @@ -34,12 +34,14 @@ public class SourceController this.sourceService = sourceService; } + @Deprecated @PostMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) public Response save(@RequestBody @Validated(ValidationGroup.Crud.Create.class) SourceEntity configure) { return this.sourceService.saveOrUpdate(configure); } + @Deprecated @PutMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) public Response update(@RequestBody @Validated(ValidationGroup.Crud.Update.class) SourceEntity configure) { diff --git a/server/src/main/java/io/edurt/datacap/server/controller/user/v2/SourceV2Controller.java b/server/src/main/java/io/edurt/datacap/server/controller/user/v2/SourceV2Controller.java index c50769b0..6c6d27e5 100644 --- a/server/src/main/java/io/edurt/datacap/server/controller/user/v2/SourceV2Controller.java +++ b/server/src/main/java/io/edurt/datacap/server/controller/user/v2/SourceV2Controller.java @@ -2,11 +2,15 @@ package io.edurt.datacap.server.controller.user.v2; import io.edurt.datacap.server.body.SourceBody; import io.edurt.datacap.server.common.Response; +import io.edurt.datacap.server.entity.SourceEntity; import io.edurt.datacap.server.service.SourceService; import io.edurt.datacap.server.validation.ValidationGroup; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -27,4 +31,22 @@ public class SourceV2Controller { return this.sourceService.testConnectionV2(configure); } + + @PostMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) + public Response save(@RequestBody @Validated(ValidationGroup.Crud.Create.class) SourceBody configure) + { + return this.sourceService.saveOrUpdateV2(configure); + } + + @PutMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) + public Response update(@RequestBody @Validated(ValidationGroup.Crud.Update.class) SourceBody configure) + { + return this.sourceService.saveOrUpdateV2(configure); + } + + @GetMapping(value = "{id}") + public Response getInfo(@PathVariable(value = "id") Long id) + { + return this.sourceService.getByIdV2(id); + } } diff --git a/server/src/main/java/io/edurt/datacap/server/entity/SourceEntity.java b/server/src/main/java/io/edurt/datacap/server/entity/SourceEntity.java index 6ade9f9d..594dcf6f 100644 --- a/server/src/main/java/io/edurt/datacap/server/entity/SourceEntity.java +++ b/server/src/main/java/io/edurt/datacap/server/entity/SourceEntity.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonIncludeProperties; import com.fasterxml.jackson.annotation.JsonProperty; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.edurt.datacap.server.common.JSON; +import io.edurt.datacap.server.plugin.configure.IConfigure; import io.edurt.datacap.server.validation.ValidationGroup; import lombok.Data; import lombok.NoArgsConstructor; @@ -104,6 +105,9 @@ public class SourceEntity @Transient private Map configures; + @Transient + private IConfigure schema; + @ManyToOne @JoinColumn(name = "user_id") @JsonIncludeProperties(value = {"id", "username"}) diff --git a/server/src/main/java/io/edurt/datacap/server/service/SourceService.java b/server/src/main/java/io/edurt/datacap/server/service/SourceService.java index 219127c9..ce4d89a2 100644 --- a/server/src/main/java/io/edurt/datacap/server/service/SourceService.java +++ b/server/src/main/java/io/edurt/datacap/server/service/SourceService.java @@ -12,6 +12,7 @@ import java.util.Map; public interface SourceService { + @Deprecated Response saveOrUpdate(SourceEntity configure); Response> getAll(int offset, int limit); @@ -30,4 +31,8 @@ public interface SourceService Response shared(SharedSourceBody configure); Response testConnectionV2(SourceBody configure); + + Response saveOrUpdateV2(SourceBody configure); + + Response getByIdV2(Long id); } diff --git a/server/src/main/java/io/edurt/datacap/server/service/impl/SourceServiceImpl.java b/server/src/main/java/io/edurt/datacap/server/service/impl/SourceServiceImpl.java index 1f461d25..dfcf3d87 100644 --- a/server/src/main/java/io/edurt/datacap/server/service/impl/SourceServiceImpl.java +++ b/server/src/main/java/io/edurt/datacap/server/service/impl/SourceServiceImpl.java @@ -55,6 +55,7 @@ public class SourceServiceImpl this.environment = environment; } + @Deprecated @Override public Response saveOrUpdate(SourceEntity configure) { @@ -117,21 +118,19 @@ public class SourceServiceImpl public Response>> getPlugins() { Map> pluginMap = new ConcurrentHashMap<>(); - this.injector.getInstance(Key.get(new TypeLiteral>() {})) - .stream() - .forEach(plugin -> { - PluginEntity entity = new PluginEntity(); - entity.setName(plugin.name()); - entity.setDescription(plugin.description()); - entity.setType(plugin.type().name()); - entity.setConfigure(PluginCommon.loadConfigure(plugin.type().name(), plugin.name(), plugin.name(), environment)); - List plugins = pluginMap.get(plugin.type().name()); - if (ObjectUtils.isEmpty(plugins)) { - plugins = new ArrayList<>(); - } - plugins.add(entity); - pluginMap.put(plugin.type().name(), plugins); - }); + this.injector.getInstance(Key.get(new TypeLiteral>() {})).stream().forEach(plugin -> { + PluginEntity entity = new PluginEntity(); + entity.setName(plugin.name()); + entity.setDescription(plugin.description()); + entity.setType(plugin.type().name()); + entity.setConfigure(PluginCommon.loadConfigure(plugin.type().name(), plugin.name(), plugin.name(), environment)); + List plugins = pluginMap.get(plugin.type().name()); + if (ObjectUtils.isEmpty(plugins)) { + plugins = new ArrayList<>(); + } + plugins.add(entity); + pluginMap.put(plugin.type().name(), plugins); + }); return Response.success(pluginMap); } @@ -175,15 +174,15 @@ public class SourceServiceImpl } // Filter required - List requiredMismatchConfigures = configure.getConfigure().getConfigures().stream().filter(v -> v.isRequired()) - .filter(v -> ObjectUtils.isEmpty(v.getValue())) - .collect(Collectors.toList()); + List requiredMismatchConfigures = configure.getConfigure().getConfigures().stream().filter(v -> v.isRequired()).filter(v -> ObjectUtils.isEmpty(v.getValue())).collect(Collectors.toList()); if (requiredMismatchConfigures.size() > 0) { return Response.failure(ServiceState.PLUGIN_CONFIGURE_REQUIRED, IConfigureCommon.preparedMessage(requiredMismatchConfigures)); } Plugin plugin = pluginOptional.get(); - Configure _configure = IConfigureCommon.preparedConfigure(configure.getConfigure().getConfigures()); + // The filter parameter value is null data + List applyConfigures = IConfigureCommon.filterNotEmpty(configure.getConfigure().getConfigures()); + Configure _configure = IConfigureCommon.preparedConfigure(applyConfigures); plugin.connect(_configure); io.edurt.datacap.spi.model.Response response = plugin.execute(plugin.validator()); plugin.destroy(); @@ -192,4 +191,55 @@ public class SourceServiceImpl } return Response.failure(ServiceState.PLUGIN_EXECUTE_FAILED, response.getMessage()); } + + @Override + public Response saveOrUpdateV2(SourceBody configure) + { + Optional pluginOptional = PluginCommon.getPluginByNameAndType(this.injector, configure.getName(), configure.getType()); + if (!pluginOptional.isPresent()) { + return Response.failure(ServiceState.PLUGIN_NOT_FOUND); + } + + // Check configure + IConfigure iConfigure = PluginCommon.loadConfigure(configure.getType(), configure.getName(), configure.getName(), environment); + if (ObjectUtils.isEmpty(iConfigure) || iConfigure.getConfigures().size() != configure.getConfigure().getConfigures().size()) { + return Response.failure(ServiceState.PLUGIN_CONFIGURE_MISMATCH); + } + + // Filter required + List requiredMismatchConfigures = configure.getConfigure().getConfigures().stream().filter(v -> v.isRequired()).filter(v -> ObjectUtils.isEmpty(v.getValue())).collect(Collectors.toList()); + if (requiredMismatchConfigures.size() > 0) { + return Response.failure(ServiceState.PLUGIN_CONFIGURE_REQUIRED, IConfigureCommon.preparedMessage(requiredMismatchConfigures)); + } + + // The filter parameter value is null data + List applyConfigures = IConfigureCommon.filterNotEmpty(configure.getConfigure().getConfigures()); + SourceEntity source = IConfigureCommon.preparedSourceEntity(applyConfigures); + source.setProtocol(configure.getType()); + source.setType(configure.getName()); + source.setUser(UserDetailsService.getUser()); + if (ObjectUtils.isNotEmpty(configure.getId())) { + source.setId(configure.getId()); + } + return Response.success(this.sourceRepository.save(source)); + } + + @Override + public Response getByIdV2(Long id) + { + Optional optionalSource = this.sourceRepository.findById(id); + if (!optionalSource.isPresent()) { + return Response.failure(ServiceState.SOURCE_NOT_FOUND); + } + SourceEntity entity = optionalSource.get(); + SourceBody configure = new SourceBody(); + configure.setId(id); + configure.setName(entity.getType()); + configure.setType(entity.getProtocol()); + // Load default configure + IConfigure iConfigure = PluginCommon.loadConfigure(configure.getType(), configure.getName(), configure.getName(), environment); + configure.setConfigure(IConfigureCommon.preparedConfigure(iConfigure, entity)); + entity.setSchema(iConfigure); + return Response.success(entity); + } } diff --git a/web/console-fe/src/services/SourceV2Service.ts b/web/console-fe/src/services/SourceV2Service.ts new file mode 100644 index 00000000..2f22d9f4 --- /dev/null +++ b/web/console-fe/src/services/SourceV2Service.ts @@ -0,0 +1,26 @@ +import {ResponseModel} from "@/model/ResponseModel"; +import {isEmpty} from "lodash"; +import {HttpCommon} from "@/common/HttpCommon"; + +const baseUrl = "/api/v2/source"; + +class SourceV2Service +{ + saveAndUpdate(configure, isUpdate: boolean): Promise + { + configure.protocol = isEmpty(configure.protocol) ? 'HTTP' : configure.protocol; + if (isUpdate) { + return new HttpCommon().put(baseUrl, JSON.stringify(configure)); + } + else { + return new HttpCommon().post(baseUrl, JSON.stringify(configure)); + } + } + + getById(id: number): Promise + { + return new HttpCommon().get(baseUrl + "/" + id); + } +} + +export default new SourceV2Service(); diff --git a/web/console-fe/src/views/pages/admin/source/SourceDetail.vue b/web/console-fe/src/views/pages/admin/source/SourceDetail.vue index 6fbb2fe9..157dae5d 100644 --- a/web/console-fe/src/views/pages/admin/source/SourceDetail.vue +++ b/web/console-fe/src/views/pages/admin/source/SourceDetail.vue @@ -32,7 +32,7 @@
- +
@@ -52,7 +52,7 @@ - + @@ -119,8 +119,8 @@ import {SourceService} from "@/services/SourceService"; import {emptySource} from "@/views/pages/admin/source/SourceGenerate"; import {defineComponent, reactive, ref} from "vue"; import {Configure} from "@/model/Configure"; -import {Arrays} from "@/common/Arrays"; import {clone} from 'lodash' +import SourceV2Service from "@/services/SourceV2Service"; interface TestInfo { @@ -183,20 +183,16 @@ export default defineComponent({ handlerInitialize() { if (this.id > 0) { - new SourceService().getById(this.id) + SourceV2Service.getById(this.id) .then(response => { if (response.status) { this.formState = reactive(response.data); this.formState.type = this.formState.type + ' ' + this.formState.protocol; - if (response.data.configures) { - Object.keys(response.data.configures).forEach((value) => { - const configure: Configure = { - field: value, - value: response.data.configures[value] - }; - this.configure.push(configure); - }); - } + this.applyPlugin = response.data['schema']; + this.pluginConfigure = response.data['schema']['configures']; + // Clear + this.pluginTabs = ['source']; + this.pluginTabs = [...this.pluginTabs, ...Array.from(new Set(this.pluginConfigure.map(v => v.group)))]; } }); } @@ -213,13 +209,14 @@ export default defineComponent({ }, handlerSave() { - this.formState.configures = Arrays.arrayToObject(this.configure); - const applyConfigure = clone(this.formState); const temp = clone(this.formState.type).split(' '); - applyConfigure.type = temp[0]; - applyConfigure.protocol = temp[1]; - new SourceService() - .saveAndUpdate(applyConfigure, this.isUpdate) + const configure = { + id: this.id, + type: temp[1], + name: temp[0], + configure: this.applyPlugin + }; + SourceV2Service.saveAndUpdate(configure, this.isUpdate) .then((response) => { if (response.status) { this.$Message.success("Create successful");