From 17d44216a4795d9b5a93a35b1457a2ead1f2b2c8 Mon Sep 17 00:00:00 2001 From: Kirs Date: Mon, 28 Dec 2020 11:25:00 +0800 Subject: [PATCH] [Feature#4310][Alert-SPI] Plug-ins containing UI components provide display pages (#4311) * [Feature#4310][Alert-SPI] Plug-ins containing UI components provide display pages *Some plugins (such as alert plugin) need to provide UI interfaces to users. *We use from-creat to dynamically generate UI interfaces. Related parameters are mainly provided by pluginParams. *From-create can generate dynamic ui based on this parameter. this closes #4310 * add license head * rename * add ut * add license * add query plugin detail interface * fix error --- .../alert/plugin/AlertPluginManager.java | 3 +- .../api/controller/UiPluginController.java | 93 +++++++++++++++++++ .../dolphinscheduler/api/enums/Status.java | 14 ++- .../api/service/UiPluginService.java | 33 +++++++ .../api/service/impl/UiPluginServiceImpl.java | 74 +++++++++++++++ .../api/service/UiPluginServiceTest.java | 86 +++++++++++++++++ .../common/enums/PluginType.java | 70 ++++++++++++++ .../dao/mapper/PluginDefineMapper.java | 8 ++ .../dao/mapper/PluginDefineMapper.xml | 9 +- pom.xml | 1 + 10 files changed, 385 insertions(+), 6 deletions(-) create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UiPluginController.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UiPluginService.java create mode 100644 dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UiPluginServiceImpl.java create mode 100644 dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UiPluginServiceTest.java create mode 100644 dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/PluginType.java diff --git a/dolphinscheduler-alert/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java b/dolphinscheduler-alert/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java index d9e1906028..a660087c89 100644 --- a/dolphinscheduler-alert/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java +++ b/dolphinscheduler-alert/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java @@ -22,6 +22,7 @@ import static java.util.Objects.requireNonNull; import static com.google.common.base.Preconditions.checkState; +import org.apache.dolphinscheduler.common.enums.PluginType; import org.apache.dolphinscheduler.dao.entity.PluginDefine; import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; import org.apache.dolphinscheduler.spi.alert.AlertChannel; @@ -91,7 +92,7 @@ public class AlertPluginManager extends AbstractDolphinPluginManager { String nameEn = alertChannelFactory.getName(); String paramsJson = PluginParamsTransfer.transferParamsToJson(params); - PluginDefine pluginDefine = new PluginDefine(nameEn, "alert", paramsJson); + PluginDefine pluginDefine = new PluginDefine(nameEn, PluginType.ALERT.getDesc(), paramsJson); pluginDao.addOrUpdatePluginDefine(pluginDefine); } } diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UiPluginController.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UiPluginController.java new file mode 100644 index 0000000000..0d159333ee --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UiPluginController.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.controller; + +import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PLUGINS_ERROR; + +import org.apache.dolphinscheduler.api.exceptions.ApiException; +import org.apache.dolphinscheduler.api.service.UiPluginService; +import org.apache.dolphinscheduler.api.utils.Result; +import org.apache.dolphinscheduler.common.Constants; +import org.apache.dolphinscheduler.common.enums.PluginType; +import org.apache.dolphinscheduler.dao.entity.User; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import springfox.documentation.annotations.ApiIgnore; + +/** + * UiPluginController + * Some plugins (such as alert plugin) need to provide UI interfaces to users. + * We use from-creat to dynamically generate UI interfaces. Related parameters are mainly provided by pluginParams. + * From-create can generate dynamic ui based on this parameter. + */ +@Api(tags = "UI_PLUGINS", position = 1) +@RestController +@RequestMapping("ui-plugins") +public class UiPluginController extends BaseController { + + private static final Logger logger = LoggerFactory.getLogger(UiPluginController.class); + + @Autowired + UiPluginService uiPluginService; + + @ApiOperation(value = "queryUiPluginsByType", notes = "QUERY_UI_PLUGINS_BY_TYPE") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pluginType", value = "pluginType", required = true, dataType = "PluginType"), + }) + @PostMapping(value = "/queryUiPluginsByType") + @ResponseStatus(HttpStatus.CREATED) + @ApiException(QUERY_PLUGINS_ERROR) + public Result queryUiPluginsByType(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @RequestParam(value = "pluginType") PluginType pluginType) { + + logger.info("query plugins by type , pluginType: {}", pluginType); + Map result = uiPluginService.queryUiPluginsByType(pluginType); + return returnDataList(result); + } + + @ApiOperation(value = "queryUiPluginDetailById", notes = "QUERY_UI_PLUGIN_DETAIL_BY_ID") + @ApiImplicitParams({ + @ApiImplicitParam(name = "id", value = "id", required = true, dataType = "PluginType"), + }) + @PostMapping(value = "/queryUiPluginsByID") + @ResponseStatus(HttpStatus.CREATED) + @ApiException(QUERY_PLUGINS_ERROR) + public Result queryUiPluginDetailById(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, + @RequestParam("pluginId") Integer pluginId) { + + logger.info("query plugin detail by id , pluginId: {}", pluginId); + Map result = uiPluginService.queryUiPluginDetailById(pluginId); + return returnDataList(result); + } +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java index a890e5c1ed..ca85d60829 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java @@ -180,12 +180,12 @@ public enum Status { MOVE_PROCESS_DEFINITION_ERROR(10150, "move process definition from {0} to {1} error : {2}", "从{0}移动工作流到{1}错误 : {2}"), SWITCH_PROCESS_DEFINITION_VERSION_ERROR(10151, "Switch process definition version error", "切换工作流版本出错"), SWITCH_PROCESS_DEFINITION_VERSION_NOT_EXIST_PROCESS_DEFINITION_ERROR(10152 - , "Switch process definition version error: not exists process definition, [process definition id {0}]", "切换工作流版本出错:工作流不存在,[工作流id {0}]"), + , "Switch process definition version error: not exists process definition, [process definition id {0}]", "切换工作流版本出错:工作流不存在,[工作流id {0}]"), SWITCH_PROCESS_DEFINITION_VERSION_NOT_EXIST_PROCESS_DEFINITION_VERSION_ERROR(10153 - , "Switch process definition version error: not exists process definition version, [process definition id {0}] [version number {1}]", "切换工作流版本出错:工作流版本信息不存在,[工作流id {0}] [版本号 {1}]"), + , "Switch process definition version error: not exists process definition version, [process definition id {0}] [version number {1}]", "切换工作流版本出错:工作流版本信息不存在,[工作流id {0}] [版本号 {1}]"), QUERY_PROCESS_DEFINITION_VERSIONS_ERROR(10154, "query process definition versions error", "查询工作流历史版本信息出错"), QUERY_PROCESS_DEFINITION_VERSIONS_PAGE_NO_OR_PAGE_SIZE_LESS_THAN_1_ERROR(10155 - , "query process definition versions error: [page number:{0}] < 1 or [page size:{1}] < 1", "查询工作流历史版本出错:[pageNo:{0}] < 1 或 [pageSize:{1}] < 1"), + , "query process definition versions error: [page number:{0}] < 1 or [page size:{1}] < 1", "查询工作流历史版本出错:[pageNo:{0}] < 1 或 [pageSize:{1}] < 1"), DELETE_PROCESS_DEFINITION_VERSION_ERROR(10156, "delete process definition version error", "删除工作流历史版本出错"), QUERY_USER_CREATED_PROJECT_ERROR(10157, "query user created project error error", "查询用户创建的项目错误"), @@ -278,13 +278,19 @@ public enum Status { QUEUE_COUNT_ERROR(90001, "queue count error", "查询队列数据错误"), KERBEROS_STARTUP_STATE(100001, "get kerberos startup state error", "获取kerberos启动状态错误"), + + //plugin + PLUGIN_NOT_A_UI_COMPONENT(110001, "query plugin error, this plugin has no UI component", "查询插件错误,此插件无UI组件"), + QUERY_PLUGINS_RESULT_IS_NULL(110002, "query plugins result is null", "查询插件为空"), + QUERY_PLUGINS_ERROR(110003, "query plugins error", "查询插件错误"), + QUERY_PLUGIN_DETAIL_RESULT_IS_NULL(110004, "query plugin detail result is null", "查询插件详情结果为空"), ; private final int code; private final String enMsg; private final String zhMsg; - private Status(int code, String enMsg, String zhMsg) { + Status(int code, String enMsg, String zhMsg) { this.code = code; this.enMsg = enMsg; this.zhMsg = zhMsg; diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UiPluginService.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UiPluginService.java new file mode 100644 index 0000000000..102d927673 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UiPluginService.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.service; + +import org.apache.dolphinscheduler.common.enums.PluginType; + +import java.util.Map; + +/** + * UiPluginService + */ +public interface UiPluginService { + + Map queryUiPluginsByType(PluginType pluginType); + + Map queryUiPluginDetailById(int id); + +} diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UiPluginServiceImpl.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UiPluginServiceImpl.java new file mode 100644 index 0000000000..983551d8d2 --- /dev/null +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UiPluginServiceImpl.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.service.impl; + +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.service.BaseService; +import org.apache.dolphinscheduler.api.service.UiPluginService; +import org.apache.dolphinscheduler.common.Constants; +import org.apache.dolphinscheduler.common.enums.PluginType; +import org.apache.dolphinscheduler.common.utils.CollectionUtils; +import org.apache.dolphinscheduler.dao.entity.PluginDefine; +import org.apache.dolphinscheduler.dao.mapper.PluginDefineMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * UiPluginServiceImpl + */ +@Service +public class UiPluginServiceImpl extends BaseService implements UiPluginService { + + @Autowired + PluginDefineMapper pluginDefineMapper; + + @Override + public Map queryUiPluginsByType(PluginType pluginType) { + Map result = new HashMap<>(); + if (!pluginType.getHasUi()) { + putMsg(result, Status.PLUGIN_NOT_A_UI_COMPONENT); + return result; + } + List pluginDefines = pluginDefineMapper.queryByPluginType(pluginType.getDesc()); + if (CollectionUtils.isEmpty(pluginDefines)) { + putMsg(result, Status.QUERY_PLUGINS_RESULT_IS_NULL); + return result; + } + putMsg(result, Status.SUCCESS); + result.put(Constants.DATA_LIST, pluginDefines); + return result; + } + + @Override + public Map queryUiPluginDetailById(int id) { + Map result = new HashMap<>(); + PluginDefine pluginDefine = pluginDefineMapper.queryDetailById(id); + if (null == pluginDefine) { + putMsg(result, Status.QUERY_PLUGIN_DETAIL_RESULT_IS_NULL); + return result; + } + putMsg(result, Status.SUCCESS); + result.put(Constants.DATA_LIST, pluginDefine); + return result; + } +} diff --git a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UiPluginServiceTest.java b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UiPluginServiceTest.java new file mode 100644 index 0000000000..95e38b2ab9 --- /dev/null +++ b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UiPluginServiceTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.api.service; + +import org.apache.dolphinscheduler.api.enums.Status; +import org.apache.dolphinscheduler.api.service.impl.UiPluginServiceImpl; +import org.apache.dolphinscheduler.common.enums.PluginType; +import org.apache.dolphinscheduler.dao.entity.PluginDefine; +import org.apache.dolphinscheduler.dao.mapper.PluginDefineMapper; + +import java.util.Collections; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * UiPluginServiceTest + */ +@RunWith(MockitoJUnitRunner.class) +public class UiPluginServiceTest { + + @InjectMocks + UiPluginServiceImpl uiPluginService; + + @Mock + PluginDefineMapper pluginDefineMapper; + + private PluginDefine pluginDefine; + + @Before + public void before() { + String pluginParams = "[{\"field\":\"receivers\",\"props\":null,\"type\"}]"; + pluginDefine = new PluginDefine("email-alert", "alert", pluginParams); + } + + @Test + public void testQueryPlugins1() { + Map result = uiPluginService.queryUiPluginsByType(PluginType.REGISTER); + Assert.assertEquals(Status.PLUGIN_NOT_A_UI_COMPONENT, result.get("status")); + } + + @Test + public void testQueryPlugins2() { + Map result = uiPluginService.queryUiPluginsByType(PluginType.ALERT); + Mockito.when(pluginDefineMapper.queryByPluginType(PluginType.ALERT.getDesc())).thenReturn(null); + Assert.assertEquals(Status.QUERY_PLUGINS_RESULT_IS_NULL, result.get("status")); + + Mockito.when(pluginDefineMapper.queryByPluginType(PluginType.ALERT.getDesc())).thenReturn(Collections.singletonList(pluginDefine)); + result = uiPluginService.queryUiPluginsByType(PluginType.ALERT); + Assert.assertEquals(Status.SUCCESS, result.get("status")); + } + + @Test + public void testQueryPluginDetailById() { + Mockito.when(pluginDefineMapper.queryDetailById(1)).thenReturn(null); + Map result = uiPluginService.queryUiPluginDetailById(1); + Assert.assertEquals(Status.QUERY_PLUGIN_DETAIL_RESULT_IS_NULL, result.get("status")); + + Mockito.when(pluginDefineMapper.queryDetailById(1)).thenReturn(pluginDefine); + result = uiPluginService.queryUiPluginDetailById(1); + Assert.assertEquals(Status.SUCCESS, result.get("status")); + } + +} diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/PluginType.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/PluginType.java new file mode 100644 index 0000000000..958e4852d8 --- /dev/null +++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/PluginType.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.common.enums; + +import java.util.HashMap; + +import com.baomidou.mybatisplus.annotation.EnumValue; + +/** + * PluginType + */ +public enum PluginType { + + ALERT(1, "alert", true), + REGISTER(2, "register", false); + + PluginType(int code, String desc, boolean hasUi) { + this.code = code; + this.desc = desc; + this.hasUi = hasUi; + } + + @EnumValue + private final int code; + private final String desc; + private final boolean hasUi; + + public int getCode() { + return code; + } + + public String getDesc() { + return desc; + } + + public boolean getHasUi() { + return hasUi; + } + + + private static HashMap PLUGIN_TYPE_MAP = new HashMap<>(); + + static { + for (PluginType pluginType : PluginType.values()) { + PLUGIN_TYPE_MAP.put(pluginType.getCode(), pluginType); + } + } + + public static PluginType of(int type) { + if (PLUGIN_TYPE_MAP.containsKey(type)) { + return PLUGIN_TYPE_MAP.get(type); + } + throw new IllegalArgumentException("invalid type : " + type); + } +} diff --git a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java index 14e4681c43..e2d08b5222 100644 --- a/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java +++ b/dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java @@ -42,6 +42,14 @@ public interface PluginDefineMapper extends BaseMapper { */ List queryByPluginType(@Param("pluginType") String pluginType); + /** + * query detail by id + * + * @param id id + * @return PluginDefineDetail + */ + PluginDefine queryDetailById(@Param("id") int id); + /** * query by name and type * diff --git a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml index f4a6f137d9..49abe7cb2d 100644 --- a/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml +++ b/dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml @@ -25,7 +25,7 @@ @@ -35,4 +35,11 @@ from t_ds_plugin_define where plugin_name = #{pluginName} and plugin_type = #{pluginType} + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a2aed2974e..d37492efb6 100644 --- a/pom.xml +++ b/pom.xml @@ -801,6 +801,7 @@ **/api/service/TaskInstanceServiceTest.java **/api/service/TenantServiceTest.java **/api/service/UdfFuncServiceTest.java + **/api/service/UiPluginServiceTest.java **/api/service/UserAlertGroupServiceTest.java **/api/service/UsersServiceTest.java **/api/service/WorkerGroupServiceTest.java