Browse Source

[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
pull/3/MERGE
Kirs 4 years ago committed by GitHub
parent
commit
17d44216a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      dolphinscheduler-alert/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java
  2. 93
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/controller/UiPluginController.java
  3. 14
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/enums/Status.java
  4. 33
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/UiPluginService.java
  5. 74
      dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/UiPluginServiceImpl.java
  6. 86
      dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/UiPluginServiceTest.java
  7. 70
      dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/enums/PluginType.java
  8. 8
      dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java
  9. 9
      dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml
  10. 1
      pom.xml

3
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 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.dao.entity.PluginDefine;
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin;
import org.apache.dolphinscheduler.spi.alert.AlertChannel; import org.apache.dolphinscheduler.spi.alert.AlertChannel;
@ -91,7 +92,7 @@ public class AlertPluginManager extends AbstractDolphinPluginManager {
String nameEn = alertChannelFactory.getName(); String nameEn = alertChannelFactory.getName();
String paramsJson = PluginParamsTransfer.transferParamsToJson(params); String paramsJson = PluginParamsTransfer.transferParamsToJson(params);
PluginDefine pluginDefine = new PluginDefine(nameEn, "alert", paramsJson); PluginDefine pluginDefine = new PluginDefine(nameEn, PluginType.ALERT.getDesc(), paramsJson);
pluginDao.addOrUpdatePluginDefine(pluginDefine); pluginDao.addOrUpdatePluginDefine(pluginDefine);
} }
} }

93
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<String, Object> 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<String, Object> result = uiPluginService.queryUiPluginDetailById(pluginId);
return returnDataList(result);
}
}

14
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}"), 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_ERROR(10151, "Switch process definition version error", "切换工作流版本出错"),
SWITCH_PROCESS_DEFINITION_VERSION_NOT_EXIST_PROCESS_DEFINITION_ERROR(10152 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_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_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_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", "删除工作流历史版本出错"), DELETE_PROCESS_DEFINITION_VERSION_ERROR(10156, "delete process definition version error", "删除工作流历史版本出错"),
QUERY_USER_CREATED_PROJECT_ERROR(10157, "query user created project error 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", "查询队列数据错误"), QUEUE_COUNT_ERROR(90001, "queue count error", "查询队列数据错误"),
KERBEROS_STARTUP_STATE(100001, "get kerberos startup state error", "获取kerberos启动状态错误"), 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 int code;
private final String enMsg; private final String enMsg;
private final String zhMsg; private final String zhMsg;
private Status(int code, String enMsg, String zhMsg) { Status(int code, String enMsg, String zhMsg) {
this.code = code; this.code = code;
this.enMsg = enMsg; this.enMsg = enMsg;
this.zhMsg = zhMsg; this.zhMsg = zhMsg;

33
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<String, Object> queryUiPluginsByType(PluginType pluginType);
Map<String, Object> queryUiPluginDetailById(int id);
}

74
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<String, Object> queryUiPluginsByType(PluginType pluginType) {
Map<String, Object> result = new HashMap<>();
if (!pluginType.getHasUi()) {
putMsg(result, Status.PLUGIN_NOT_A_UI_COMPONENT);
return result;
}
List<PluginDefine> 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<String, Object> queryUiPluginDetailById(int id) {
Map<String, Object> 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;
}
}

86
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<String, Object> result = uiPluginService.queryUiPluginsByType(PluginType.REGISTER);
Assert.assertEquals(Status.PLUGIN_NOT_A_UI_COMPONENT, result.get("status"));
}
@Test
public void testQueryPlugins2() {
Map<String, Object> 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<String, Object> 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"));
}
}

70
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<Integer, PluginType> 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);
}
}

8
dolphinscheduler-dao/src/main/java/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.java

@ -42,6 +42,14 @@ public interface PluginDefineMapper extends BaseMapper<PluginDefine> {
*/ */
List<PluginDefine> queryByPluginType(@Param("pluginType") String pluginType); List<PluginDefine> 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 * query by name and type
* *

9
dolphinscheduler-dao/src/main/resources/org/apache/dolphinscheduler/dao/mapper/PluginDefineMapper.xml

@ -25,7 +25,7 @@
</select> </select>
<select id="queryByPluginType" resultType="org.apache.dolphinscheduler.dao.entity.PluginDefine"> <select id="queryByPluginType" resultType="org.apache.dolphinscheduler.dao.entity.PluginDefine">
select * select id,plugin_name,plugin_type,create_time,update_time
from t_ds_plugin_define from t_ds_plugin_define
where plugin_type = #{pluginType} where plugin_type = #{pluginType}
</select> </select>
@ -35,4 +35,11 @@
from t_ds_plugin_define from t_ds_plugin_define
where plugin_name = #{pluginName} and plugin_type = #{pluginType} where plugin_name = #{pluginName} and plugin_type = #{pluginType}
</select> </select>
<select id="queryDetailById" resultType="org.apache.dolphinscheduler.dao.entity.PluginDefine">
select id,plugin_name,plugin_type,plugin_params,create_time,update_time
from t_ds_plugin_define
where id = #{id}
</select>
</mapper> </mapper>

1
pom.xml

@ -801,6 +801,7 @@
<include>**/api/service/TaskInstanceServiceTest.java</include> <include>**/api/service/TaskInstanceServiceTest.java</include>
<include>**/api/service/TenantServiceTest.java</include> <include>**/api/service/TenantServiceTest.java</include>
<include>**/api/service/UdfFuncServiceTest.java</include> <include>**/api/service/UdfFuncServiceTest.java</include>
<include>**/api/service/UiPluginServiceTest.java</include>
<include>**/api/service/UserAlertGroupServiceTest.java</include> <include>**/api/service/UserAlertGroupServiceTest.java</include>
<include>**/api/service/UsersServiceTest.java</include> <include>**/api/service/UsersServiceTest.java</include>
<include>**/api/service/WorkerGroupServiceTest.java</include> <include>**/api/service/WorkerGroupServiceTest.java</include>

Loading…
Cancel
Save