diff --git a/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceAdminRestfulApi.java b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceAdminRestfulApi.java new file mode 100644 index 0000000000..22254d003b --- /dev/null +++ b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceAdminRestfulApi.java @@ -0,0 +1,246 @@ +/* + * Copyright 2019 WeBank + * Licensed 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 com.webank.wedatasphere.linkis.datasourcemanager.core.restful; + +import com.webank.wedatasphere.linkis.common.exception.ErrorException; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceEnv; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceParamKeyDefinition; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.FormDataTransformerFactory; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.MultiPartFormDataTransformer; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceInfoService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceRelateService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.vo.DataSourceEnvVo; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidator; +import com.webank.wedatasphere.linkis.server.Message; +import com.webank.wedatasphere.linkis.server.security.SecurityFilter; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import javax.validation.groups.Default; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.*; + +/** + * @author liaoyt + * 2020/02/10 + */ +@Path("/data_source") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class DataSourceAdminRestfulApi { + + @Autowired + private DataSourceInfoService dataSourceInfoService; + + @Autowired + private DataSourceRelateService dataSourceRelateService; + + @Autowired + private ParameterValidator parameterValidator; + + @Autowired + private Validator beanValidator; + + private MultiPartFormDataTransformer formDataTransformer; + + @PostConstruct + public void initRestful(){ + this.formDataTransformer = FormDataTransformerFactory.buildCustom(); + } + + @POST + @Path("/env/json") + public Response insertJsonEnv(DataSourceEnv dataSourceEnv, @Context HttpServletRequest req){ + return RestfulApiHelper.doAndResponse(()->{ + String userName = SecurityFilter.getLoginUsername(req); + if(!RestfulApiHelper.isAdminUser(userName)){ + return Message.error("User '" + userName + "' is not admin user[非管理员用户]"); + } + //Bean validation + Set> result = beanValidator.validate(dataSourceEnv, Default.class); + if(result.size() > 0){ + throw new ConstraintViolationException(result); + } + dataSourceEnv.setCreateUser(userName); + insertDataSourceEnv(dataSourceEnv); + return Message.ok().data("insert_id", dataSourceEnv.getId()); + }, "/data_source/env/json","Fail to insert data source environment[新增数据源环境失败]"); + } + + @POST + @Path("/env/form") + public Response insertFormEnv(FormDataMultiPart multiPartForm, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(()->{ + String userName = SecurityFilter.getLoginUsername(request); + if(!RestfulApiHelper.isAdminUser(userName)){ + return Message.error("User '" + userName + "' is not admin user[非管理员用户]"); + } + DataSourceEnv dataSourceEnv = formDataTransformer.transformToObject(multiPartForm, DataSourceEnv.class, beanValidator); + dataSourceEnv.setCreateUser(userName); + insertDataSourceEnv(dataSourceEnv); + return Message.ok().data("insert_id", dataSourceEnv.getId()); + }, "/data_source/env/form","Fail to insert data source environment[新增数据源环境失败]"); + } + + @GET + @Path("/env_list/all/type/{type_id}") + public Response getAllEnvListByDataSourceType(@PathParam("type_id")Long typeId){ + return RestfulApiHelper.doAndResponse(()->{ + List envList = dataSourceInfoService.listDataSourceEnvByType(typeId); + return Message.ok().data("env_list", envList); + }, "/data_source/env_list/all/type/" + typeId,"Fail to get data source environment list[获取数据源环境清单失败]"); + } + + @GET + @Path("/env/{env_id}") + public Response getEnvEntityById(@PathParam("env_id")Long envId){ + return RestfulApiHelper.doAndResponse(() ->{ + DataSourceEnv dataSourceEnv = dataSourceInfoService.getDataSourceEnv(envId); + return Message.ok().data("env", dataSourceEnv); + }, "/data_source/env/" + envId,"Fail to get data source environment[获取数据源环境信息失败]"); + } + + @DELETE + @Path("/env/{env_id}") + public Response removeEnvEntity(@PathParam("env_id")Long envId, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + String userName = SecurityFilter.getLoginUsername(request); + if(!RestfulApiHelper.isAdminUser(userName)){ + return Message.error("User '" + userName + "' is not admin user[非管理员用户]"); + } + Long removeId = dataSourceInfoService.removeDataSourceEnv(envId); + if(removeId < 0){ + return Message.error("Fail to remove data source environment[删除数据源环境信息失败], [id:" + + envId + "]"); + } + return Message.ok().data("remove_id", removeId); + }, "/data_source/env/" + envId,"Fail to remove data source environment[删除数据源环境信息失败]"); + } + + @PUT + @Path("/env/{env_id}/json") + public Response updateJsonEnv(DataSourceEnv dataSourceEnv, + @PathParam("env_id")Long envId, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + String userName = SecurityFilter.getLoginUsername(request); + if(!RestfulApiHelper.isAdminUser(userName)){ + return Message.error("User '" + userName + "' is not admin user[非管理员用户]"); + } + //Bean validation + Set> result = beanValidator.validate(dataSourceEnv, Default.class); + if(result.size() > 0){ + throw new ConstraintViolationException(result); + } + dataSourceEnv.setId(envId); + dataSourceEnv.setModifyUser(userName); + dataSourceEnv.setModifyTime(Calendar.getInstance().getTime()); + DataSourceEnv storedDataSourceEnv = dataSourceInfoService.getDataSourceEnv(envId); + if(null == storedDataSourceEnv){ + return Message.error("Fail to update data source environment[更新数据源环境失败], " + "[Please check the id:'" + + envId + " is correct ']"); + } + dataSourceEnv.setCreateUser(storedDataSourceEnv.getCreateUser()); + updateDataSourceEnv(dataSourceEnv, storedDataSourceEnv); + return Message.ok().data("update_id", envId); + }, "/data_source/env/" + envId + "/json","Fail to update data source environment[更新数据源环境失败]"); + } + + @PUT + @Path("/env/{env_id}/form") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response updateFormEnv(FormDataMultiPart multiPartForm, + @PathParam("env_id")Long envId, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(()->{ + if(null != multiPartForm) { + String userName = SecurityFilter.getLoginUsername(request); + if (!RestfulApiHelper.isAdminUser(userName)) { + return Message.error("User '" + userName + "' is not admin user[非管理员用户]"); + } + DataSourceEnv dataSourceEnv = formDataTransformer.transformToObject(multiPartForm, DataSourceEnv.class, beanValidator); + dataSourceEnv.setId(envId); + dataSourceEnv.setModifyUser(userName); + dataSourceEnv.setModifyTime(Calendar.getInstance().getTime()); + DataSourceEnv storedDataSourceEnv = dataSourceInfoService.getDataSourceEnv(envId); + if (null == storedDataSourceEnv) { + return Message.error("Fail to update data source environment[更新数据源环境失败], " + "[Please check the id:'" + + envId + " is correct ']"); + } + dataSourceEnv.setCreateUser(storedDataSourceEnv.getCreateUser()); + updateDataSourceEnv(dataSourceEnv, storedDataSourceEnv); + return Message.ok().data("update_id", envId); + } + return Message.error("Empty request"); + }, "/data_source/env/" + envId + "/form","Fail to update data source environment[更新数据源环境失败]"); + } + + @GET + @Path("/env") + public Response queryDataSourceEnv(@QueryParam("name")String envName, + @QueryParam("typeId")Long dataSourceTypeId, + @QueryParam("currentPage")Integer currentPage, + @QueryParam("pageSize")Integer pageSize){ + return RestfulApiHelper.doAndResponse(() -> { + DataSourceEnvVo dataSourceEnvVo = new DataSourceEnvVo(envName, dataSourceTypeId); + dataSourceEnvVo.setCurrentPage(null != currentPage ? currentPage : 1); + dataSourceEnvVo.setPageSize(null != pageSize? pageSize : 10); + List queryList = dataSourceInfoService.queryDataSourceEnvPage(dataSourceEnvVo); + return Message.ok().data("query_list", queryList); + }, "/data_source/env","Fail to query page of data source environment[查询数据源环境失败]"); + } + + /** + * Inner method to insert data source environment + * @param dataSourceEnv data source environment entity + * @throws ErrorException + */ + private void insertDataSourceEnv(DataSourceEnv dataSourceEnv) throws ErrorException{ + //Get key definitions in environment scope + List keyDefinitionList = dataSourceRelateService + .getKeyDefinitionsByType(dataSourceEnv.getDataSourceTypeId(), DataSourceParamKeyDefinition.Scope.ENV); + dataSourceEnv.setKeyDefinitions(keyDefinitionList); + Map connectParams = dataSourceEnv.getConnectParams(); + //Validate connect parameters + parameterValidator.validate(keyDefinitionList, connectParams); + dataSourceInfoService.saveDataSourceEnv(dataSourceEnv); + } + + /** + * Inner method to update data source environment + * @param updatedOne new entity + * @param storedOne old entity + * @throws ErrorException + */ + private void updateDataSourceEnv(DataSourceEnv updatedOne, DataSourceEnv storedOne) throws ErrorException{ + //Get key definitions in environment scope + List keyDefinitionList = dataSourceRelateService + .getKeyDefinitionsByType(updatedOne.getDataSourceTypeId(), DataSourceParamKeyDefinition.Scope.ENV); + updatedOne.setKeyDefinitions(keyDefinitionList); + Map connectParams = updatedOne.getConnectParams(); + //Validate connect parameters + parameterValidator.validate(keyDefinitionList, connectParams); + dataSourceInfoService.updateDataSourceEnv(updatedOne, storedOne); + } +} diff --git a/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceCoreRestfulApi.java b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceCoreRestfulApi.java new file mode 100644 index 0000000000..425cfcc0c7 --- /dev/null +++ b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceCoreRestfulApi.java @@ -0,0 +1,294 @@ +/* + * Copyright 2019 WeBank + * Licensed 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 com.webank.wedatasphere.linkis.datasourcemanager.core.restful; + +import com.webank.wedatasphere.linkis.common.exception.ErrorException; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceType; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.FormDataTransformerFactory; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.MultiPartFormDataTransformer; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceInfoService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceRelateService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.vo.DataSourceVo; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSource; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceParamKeyDefinition; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidateException; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidator; +import com.webank.wedatasphere.linkis.server.Message; +import com.webank.wedatasphere.linkis.server.security.SecurityFilter; +import org.apache.commons.lang.StringUtils; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import javax.validation.groups.Default; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.*; + +/** + * @author liaoyt + * 2020/02/10 + */ +@Path("/data_source") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Component +public class DataSourceCoreRestfulApi { + + private static final Logger LOG = LoggerFactory.getLogger(DataSourceCoreRestfulApi.class); + @Autowired + private DataSourceInfoService dataSourceInfoService; + + @Autowired + private DataSourceRelateService dataSourceRelateService; + + @Autowired + private ParameterValidator parameterValidator; + + @Autowired + private Validator beanValidator; + + private MultiPartFormDataTransformer formDataTransformer; + + + @PostConstruct + public void initRestful(){ + this.formDataTransformer = FormDataTransformerFactory.buildCustom(); + } + + @POST + @Path("/info/json") + public Response insertJsonInfo(DataSource dataSource, @Context HttpServletRequest req) { + return RestfulApiHelper.doAndResponse(() -> { + String userName = SecurityFilter.getLoginUsername(req); + //Bean validation + Set> result = beanValidator.validate(dataSource, Default.class); + if(result.size() > 0){ + throw new ConstraintViolationException(result); + } + dataSource.setCreateUser(userName); + insertDataSourceConfig(dataSource); + return Message.ok().data("insert_id", dataSource.getId()); + }, "/data_source/info/json", "Fail to insert data source[新增数据源失败]"); + } + + @POST + @Path("/info/form") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response insertFormConfig(FormDataMultiPart multiPartForm, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + if(null != multiPartForm) { + String userName = SecurityFilter.getLoginUsername(request); + DataSource dataSource = formDataTransformer.transformToObject(multiPartForm, DataSource.class, beanValidator); + dataSource.setCreateUser(userName); + insertDataSourceConfig(dataSource); + return Message.ok().data("insert_id", dataSource.getId()); + } + return Message.error("Empty request"); + }, "/data_source/info/form", "Fail to insert data source[新增数据源失败]"); + } + + @GET + @Path("/info/{data_source_id}") + public Response getInfoByDataSourceId(@QueryParam("system")String createSystem, + @PathParam("data_source_id")Long dataSourceId, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + if(StringUtils.isBlank(createSystem)){ + return Message.error("'create system' is missing[缺少系统名]"); + } + DataSource dataSource = dataSourceInfoService.getDataSourceInfo(dataSourceId, createSystem); + //Decrypt + if(null != dataSource) { + RestfulApiHelper.decryptPasswordKey(dataSourceRelateService.getKeyDefinitionsByType(dataSource.getDataSourceTypeId()) + , dataSource.getConnectParams()); + } + return Message.ok().data("info", dataSource); + }, "/data_source/info/" + dataSourceId, "Fail to access data source[获取数据源信息失败]"); + } + + + @DELETE + @Path("/info/{data_source_id}") + public Response removeDataSource(@QueryParam("system")String createSystem, + @PathParam("data_source_id")Long dataSourceId){ + return RestfulApiHelper.doAndResponse(() -> { + if(StringUtils.isBlank(createSystem)){ + return Message.error("'create system' is missing[缺少系统名]"); + } + Long removeId = dataSourceInfoService.removeDataSourceInfo(dataSourceId, createSystem); + if(removeId < 0){ + return Message.error("Fail to remove data source[删除数据源信息失败], [id:" + dataSourceId +"]"); + } + return Message.ok().data("remove_id", removeId); + }, "/data_source/info/" + dataSourceId,"Fail to remove data source[删除数据源信息失败]"); + } + + @PUT + @Path("/info/{data_source_id}/json") + public Response updateDataSourceInJson(DataSource dataSource, + @PathParam("data_source_id")Long dataSourceId, + @Context HttpServletRequest req){ + return RestfulApiHelper.doAndResponse(() -> { + String userName = SecurityFilter.getLoginUsername(req); + //Bean validation + Set> result = beanValidator.validate(dataSource, Default.class); + if(result.size() > 0){ + throw new ConstraintViolationException(result); + } + dataSource.setId(dataSourceId); + dataSource.setModifyUser(userName); + dataSource.setModifyTime(Calendar.getInstance().getTime()); + DataSource storedDataSource = dataSourceInfoService.getDataSourceInfoBrief(dataSourceId, dataSource.getCreateSystem()); + if(null == storedDataSource){ + return Message.error("Fail to update data source[更新数据源失败], " + "[Please check the id:'" + + dataSourceId +"' and create system: '"+dataSource.getCreateSystem()+" is correct ']"); + } + dataSource.setCreateUser(storedDataSource.getCreateUser()); + updateDataSourceConfig(dataSource, storedDataSource); + return Message.ok().data("update_id", dataSourceId); + }, "/data_source/info/"+dataSourceId+"/json","Fail to update data source[更新数据源失败]"); + } + + @PUT + @Path("/info/{data_source_id}/form") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public Response updateDataSourceInForm(FormDataMultiPart multiPartForm, + @PathParam("data_source_id")Long dataSourceId, + @Context HttpServletRequest req){ + return RestfulApiHelper.doAndResponse(() -> { + String userName = SecurityFilter.getLoginUsername(req); + DataSource dataSource = formDataTransformer.transformToObject(multiPartForm, DataSource.class, beanValidator); + dataSource.setId(dataSourceId); + dataSource.setModifyUser(userName); + dataSource.setModifyTime(Calendar.getInstance().getTime()); + DataSource storedDataSource = dataSourceInfoService.getDataSourceInfoBrief(dataSourceId, dataSource.getCreateSystem()); + if(null == storedDataSource){ + return Message.error("Fail to update data source[更新数据源失败], " + + "[Please check the id:'" + dataSourceId +"' and create system: '"+dataSource.getCreateSystem()+" is correct ']"); + } + dataSource.setCreateUser(storedDataSource.getCreateUser()); + updateDataSourceConfig(dataSource, storedDataSource); + return Message.ok().data("update_id", dataSourceId); + }, "/data_source/info/" + dataSourceId + "/form", "Fail to update data source[更新数据源失败]"); + } + + @GET + @Path("/info") + public Response queryDataSource(@QueryParam("system")String createSystem, + @QueryParam("name")String dataSourceName, + @QueryParam("typeId")Long dataSourceTypeId, + @QueryParam("identifies")String identifies, + @QueryParam("currentPage")Integer currentPage, + @QueryParam("pageSize")Integer pageSize){ + return RestfulApiHelper.doAndResponse(() -> { + if(StringUtils.isBlank(createSystem)){ + return Message.error("'create system' is missing[缺少系统名]"); + } + DataSourceVo dataSourceVo = new DataSourceVo(dataSourceName, dataSourceTypeId, + identifies, createSystem); + dataSourceVo.setCurrentPage(null != currentPage ? currentPage : 1); + dataSourceVo.setPageSize(null != pageSize? pageSize : 10); + List queryList = dataSourceInfoService.queryDataSourceInfoPage(dataSourceVo); + return Message.ok().data("query_list", queryList); + }, "/data_source/info", "Fail to query page of data source[查询数据源失败]"); + } + + @GET + @Path("/key_define/type/{type_id}") + public Response getKeyDefinitionsByType(@PathParam("type_id") Long dataSourceTypeId){ + return RestfulApiHelper.doAndResponse(() -> { + List keyDefinitions = dataSourceRelateService.getKeyDefinitionsByType(dataSourceTypeId); + return Message.ok().data("key_define", keyDefinitions); + }, "/data_source/key_define/type/" + dataSourceTypeId, + "Fail to get key definitions of data source type[查询数据源参数键值对失败]"); + } + + @GET + @Path("/key_define/type/{type_id}/{scope}") + public Response getKeyDefinitionsByTypeAndScope(@PathParam("type_id") Long dataSourceTypeId, + @PathParam("scope") String scopeValue){ + return RestfulApiHelper.doAndResponse(() -> { + DataSourceParamKeyDefinition.Scope scope = DataSourceParamKeyDefinition.Scope.valueOf(scopeValue.toUpperCase()); + List keyDefinitions = dataSourceRelateService + .getKeyDefinitionsByType(dataSourceTypeId, scope); + return Message.ok().data("key_define", keyDefinitions); + }, "/data_source/key_define/type/" + dataSourceTypeId + "/" + scopeValue, + "Fail to get key definitions of data source type[查询数据源参数键值对失败]"); + } + + @GET + @Path("/type/all") + public Response getAllDataSourceTypes(){ + return RestfulApiHelper.doAndResponse(() -> { + List dataSourceTypes = dataSourceRelateService.getAllDataSourceTypes(); + return Message.ok().data("type_list", dataSourceTypes); + }, "/data_source/type/all", "Fail to get all types of data source[获取数据源类型列表失败]"); + } + + /** + * Inner method to insert data source + * @param dataSource data source entity + * @throws ParameterValidateException + */ + private void insertDataSourceConfig(DataSource dataSource) throws ErrorException { + if(null != dataSource.getDataSourceEnvId()){ + //Merge parameters + dataSourceInfoService.addEnvParamsToDataSource(dataSource.getDataSourceEnvId(), dataSource); + } + //Validate connect parameters + List keyDefinitionList = dataSourceRelateService + .getKeyDefinitionsByType(dataSource.getDataSourceTypeId()); + dataSource.setKeyDefinitions(keyDefinitionList); + Map connectParams = dataSource.getConnectParams(); + parameterValidator.validate(keyDefinitionList, connectParams); + //Encrypt password value type + RestfulApiHelper.encryptPasswordKey(keyDefinitionList, connectParams); + dataSourceInfoService.saveDataSourceInfo(dataSource); + } + + /** + * Inner method to update data source + * @param updatedOne new entity + * @param storedOne old entity + * @throws ErrorException + */ + private void updateDataSourceConfig(DataSource updatedOne, DataSource storedOne) throws ErrorException{ + if(null != updatedOne.getDataSourceEnvId()){ + //Merge parameters + dataSourceInfoService.addEnvParamsToDataSource(updatedOne.getDataSourceEnvId(), updatedOne); + } + //Validate connect parameters + List keyDefinitionList = dataSourceRelateService + .getKeyDefinitionsByType(updatedOne.getDataSourceTypeId()); + updatedOne.setKeyDefinitions(keyDefinitionList); + Map connectParams = updatedOne.getConnectParams(); + parameterValidator.validate(keyDefinitionList, connectParams); + RestfulApiHelper.encryptPasswordKey(keyDefinitionList, connectParams); + dataSourceInfoService.updateDataSourceInfo(updatedOne, storedOne); + } + + + +} diff --git a/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceOperateRestfulApi.java b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceOperateRestfulApi.java new file mode 100644 index 0000000000..4258239203 --- /dev/null +++ b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/DataSourceOperateRestfulApi.java @@ -0,0 +1,127 @@ +/* + * Copyright 2019 WeBank + * Licensed 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 com.webank.wedatasphere.linkis.datasourcemanager.core.restful; + +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSource; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceParamKeyDefinition; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceType; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.FormDataTransformerFactory; +import com.webank.wedatasphere.linkis.datasourcemanager.core.formdata.MultiPartFormDataTransformer; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceInfoService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.DataSourceRelateService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.service.MetadataOperateService; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidateException; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidator; +import com.webank.wedatasphere.linkis.metadatamanager.common.MdmConfiguration; +import com.webank.wedatasphere.linkis.server.Message; +import com.webank.wedatasphere.linkis.server.security.SecurityFilter; +import org.apache.commons.lang.StringUtils; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import javax.validation.groups.Default; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author liaoyt + * 2020/02/10 + */ +@Path("/data_source/op/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Component +public class DataSourceOperateRestfulApi { + + @Autowired + private MetadataOperateService metadataOperateService; + + @Autowired + private DataSourceRelateService dataSourceRelateService; + + @Autowired + private DataSourceInfoService dataSourceInfoService; + + @Autowired + private ParameterValidator parameterValidator; + + @Autowired + private Validator beanValidator; + + private MultiPartFormDataTransformer formDataTransformer; + + @PostConstruct + public void initRestful(){ + this.formDataTransformer = FormDataTransformerFactory.buildCustom(); + } + + @POST + @Path("/connect/json") + public Response connect(DataSource dataSource, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + String operator = SecurityFilter.getLoginUsername(request); + //Bean validation + Set> result = beanValidator.validate(dataSource, Default.class); + if(result.size() > 0){ + throw new ConstraintViolationException(result); + } + doConnect(operator, dataSource); + return Message.ok().data("ok", true); + }, "/data_source/op/connect/json",""); + } + + @POST + @Path("/connect/form") + public Response connect(FormDataMultiPart multiPartForm, + @Context HttpServletRequest request){ + return RestfulApiHelper.doAndResponse(() -> { + String operator = SecurityFilter.getLoginUsername(request); + DataSource dataSource = formDataTransformer.transformToObject(multiPartForm, DataSource.class, beanValidator); + doConnect(operator, dataSource); + return Message.ok().data("ok", true); + }, "/data_source/op/connect/form",""); + } + + /** + * Build a connection + * @param dataSource + */ + protected void doConnect(String operator, DataSource dataSource) throws ParameterValidateException { + if(null != dataSource.getDataSourceEnvId()){ + dataSourceInfoService.addEnvParamsToDataSource(dataSource.getDataSourceEnvId(), dataSource); + } + //Validate connect parameters + List keyDefinitionList = dataSourceRelateService + .getKeyDefinitionsByType(dataSource.getDataSourceTypeId()); + dataSource.setKeyDefinitions(keyDefinitionList); + Map connectParams = dataSource.getConnectParams(); + parameterValidator.validate(keyDefinitionList, connectParams); + DataSourceType dataSourceType = dataSourceRelateService.getDataSourceType(dataSource.getDataSourceTypeId()); + metadataOperateService.doRemoteConnect(MdmConfiguration.METADATA_SERVICE_APPLICATION.getValue() + + (StringUtils.isNotBlank(dataSourceType.getName())?("-" +dataSourceType.getName().toLowerCase()) : ""), + operator, dataSource.getConnectParams()); + } +} diff --git a/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/RestfulApiHelper.java b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/RestfulApiHelper.java new file mode 100644 index 0000000000..0456919506 --- /dev/null +++ b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/RestfulApiHelper.java @@ -0,0 +1,113 @@ +/* + * Copyright 2019 WeBank + * Licensed 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 com.webank.wedatasphere.linkis.datasourcemanager.core.restful; + +import com.webank.wedatasphere.linkis.common.exception.WarnException; +import com.webank.wedatasphere.linkis.datasourcemanager.common.DsmConfiguration; +import com.webank.wedatasphere.linkis.datasourcemanager.common.domain.DataSourceParamKeyDefinition; +import com.webank.wedatasphere.linkis.datasourcemanager.common.util.CryptoUtils; +import com.webank.wedatasphere.linkis.datasourcemanager.core.restful.exception.BeanValidationExceptionMapper; +import com.webank.wedatasphere.linkis.datasourcemanager.core.validate.ParameterValidateException; +import com.webank.wedatasphere.linkis.server.Message; + +import javax.validation.ConstraintViolationException; +import javax.ws.rs.core.Response; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * Helper of restful api entrance + * @author liaoyt + * 2020/02/10 + */ +public class RestfulApiHelper { + /** + * If is administrator + * @param userName user name + * @return + */ + public static boolean isAdminUser(String userName){ + List userList = Arrays.asList(DsmConfiguration.DSM_ADMIN_USER_LIST.getValue().split(",")); + return userList.contains(userName); + } + + /** + * Encrypt key of password type + * @param keyDefinitionList definition list + * @param connectParams connection parameters + */ + public static void encryptPasswordKey(List keyDefinitionList, + Map connectParams){ + keyDefinitionList.forEach(keyDefinition -> { + if(keyDefinition.getValueType() == DataSourceParamKeyDefinition.ValueType.PASSWORD){ + Object password = connectParams.get(keyDefinition.getKey()); + if(null != password){ + connectParams.put(keyDefinition.getKey(), CryptoUtils.object2String(String.valueOf(password))); + } + } + }); + } + + /** + * Encrypt key of password type + * @param keyDefinitionList definition list + * @param connectParams connection parameters + */ + public static void decryptPasswordKey(List keyDefinitionList, + Map connectParams){ + keyDefinitionList.forEach(keyDefinition -> { + if(keyDefinition.getValueType() == DataSourceParamKeyDefinition.ValueType.PASSWORD){ + Object password = connectParams.get(keyDefinition.getKey()); + if(null != password){ + connectParams.put(keyDefinition.getKey(), CryptoUtils.string2Object(String.valueOf(password))); + } + } + }); + } + + /** + * + * @param tryOperation operate function + * @param failMessage message + */ + public static Response doAndResponse(TryOperation tryOperation, String method, String failMessage){ + try{ + Message message = tryOperation.operateAndGetMessage(); + return Message.messageToResponse(setMethod(message, method)); + }catch(ParameterValidateException e){ + return Message.messageToResponse(setMethod(Message.error(e.getMessage()), method)); + }catch(ConstraintViolationException e){ + return new BeanValidationExceptionMapper().toResponse(e); + }catch(WarnException e){ + return Message.messageToResponse(setMethod(Message.warn(e.getMessage()), method)); + }catch(Exception e){ + return Message.messageToResponse(setMethod(Message.error(failMessage, e), method)); + } + } + private static Message setMethod(Message message, String method){ + message.setMethod(method); + return message; + } + + + @FunctionalInterface + public interface TryOperation { + + /** + * Operate method + */ + Message operateAndGetMessage() throws Exception; + } +} diff --git a/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/exception/BeanValidationExceptionMapper.java b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/exception/BeanValidationExceptionMapper.java new file mode 100644 index 0000000000..f176ddae13 --- /dev/null +++ b/datasource/datasourcemanager/server/src/main/java/com/webank/wedatasphere/linkis/datasourcemanager/core/restful/exception/BeanValidationExceptionMapper.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 WeBank + * Licensed 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 com.webank.wedatasphere.linkis.datasourcemanager.core.restful.exception; + +import com.webank.wedatasphere.linkis.server.Message; + +import javax.validation.ConstraintViolationException; +import javax.validation.ValidationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * Map bean validation exception to response + * @author liaoyt + * 2020/02/11 + */ +@Provider +public class BeanValidationExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(ValidationException exception) { + StringBuilder stringBuilder = new StringBuilder(); + ((ConstraintViolationException)exception) + .getConstraintViolations().forEach(constraintViolation -> stringBuilder.append(constraintViolation.getMessage()).append(";")); + Message message = Message.error("Bean validation error[实例校验出错], detail:" + stringBuilder.toString()); + return Message.messageToResponse(message); + } +}