From bcf03ad4d1131ffc4adba4b59185c5f0461cbe85 Mon Sep 17 00:00:00 2001 From: lenian <1468826950@qq.com> Date: Wed, 4 Jan 2023 15:00:24 +0800 Subject: [PATCH] [Feature-9467] add DAMENG DataSource (#12860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Feature-9467][DataSource] add DAMENG (达梦) data source * [Feature-9467] add DM datasource doc (Issue #9467) * [Feature-9467] add DM IDataBaseOptionKeys * [Feature-9467] add DM DataSource: DmDataSourceChannelFactoryTest remove testGetDmConnection method * [Feature-9467] modification package dm to dameng; * [Feature-9467] add Dameng DmJdbcDriver18 License * [Feature-9467] add DM DataSource: remove DruidDataSourceClient Co-authored-by: lenian --- docs/docs/en/guide/datasource/dameng.md | 22 +++ docs/docs/zh/guide/datasource/dameng.md | 17 ++ docs/img/new_ui/dev/datasource/dameng.png | Bin 0 -> 28038 bytes dolphinscheduler-bom/pom.xml | 7 + .../common/constants/DataSourceConstants.java | 3 + .../dolphinscheduler-datasource-all/pom.xml | 5 + .../pom.xml | 51 ++++++ .../dameng/DamengDataSourceChannel.java | 31 ++++ .../DamengDataSourceChannelFactory.java | 38 +++++ .../dameng/DamengDataSourceClient.java | 30 ++++ .../dameng/param/DamengConnectionParam.java | 37 +++++ .../param/DamengDataSourceParamDTO.java | 42 +++++ .../param/DamengDataSourceProcessor.java | 149 ++++++++++++++++++ .../DamengDataSourceChannelFactoryTest.java | 33 ++++ .../dameng/DamengDataSourceChannelTest.java | 40 +++++ .../param/DamengDataSourceProcessorTest.java | 91 +++++++++++ dolphinscheduler-datasource-plugin/pom.xml | 1 + dolphinscheduler-dist/release-docs/LICENSE | 2 +- dolphinscheduler-dist/release-docs/NOTICE | 10 ++ .../licenses/LICENSE-DmJdbcDriver18.txt | 13 ++ .../dolphinscheduler/spi/enums/DbType.java | 3 +- .../src/service/modules/data-source/types.ts | 2 + .../src/views/datasource/list/use-form.ts | 5 + .../components/node/fields/use-datasource.ts | 5 + tools/dependencies/known-dependencies.txt | 1 + 25 files changed, 636 insertions(+), 2 deletions(-) create mode 100644 docs/docs/en/guide/datasource/dameng.md create mode 100644 docs/docs/zh/guide/datasource/dameng.md create mode 100644 docs/img/new_ui/dev/datasource/dameng.png create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/pom.xml create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannel.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactory.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceClient.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengConnectionParam.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceParamDTO.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessor.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactoryTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelTest.java create mode 100644 dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessorTest.java create mode 100644 dolphinscheduler-dist/release-docs/licenses/LICENSE-DmJdbcDriver18.txt diff --git a/docs/docs/en/guide/datasource/dameng.md b/docs/docs/en/guide/datasource/dameng.md new file mode 100644 index 0000000000..0073a4c924 --- /dev/null +++ b/docs/docs/en/guide/datasource/dameng.md @@ -0,0 +1,22 @@ +# DAMENG + +![dameng](../../../../img/new_ui/dev/datasource/dameng.png) + +## Datasource Parameters + +| **Datasource** | **Description** | +|----------------------------|-----------------------------------------------------------| +| Datasource | Select DAMENG. | +| Datasource name | Enter the name of the DataSource. | +| Description | Enter a description of the DataSource. | +| IP/Host Name | Enter the DAMENG service IP. | +| Port | Enter the DAMENG service port. | +| Username | Set the username for DAMENG connection. | +| Password | Set the password for DAMENG connection. | +| Database name | Enter the schema name of the DAMENG connection. | +| Jdbc connection parameters | Parameter settings for DAMENG connection, in JSON format. | + +## Native Supported + +No, read section example in [datasource-setting](../howto/datasource-setting.md) `DataSource Center` section to activate this datasource. + diff --git a/docs/docs/zh/guide/datasource/dameng.md b/docs/docs/zh/guide/datasource/dameng.md new file mode 100644 index 0000000000..bc4c6a12e7 --- /dev/null +++ b/docs/docs/zh/guide/datasource/dameng.md @@ -0,0 +1,17 @@ +# DAMENG数据源 + +![dameng](../../../../img/new_ui/dev/datasource/dameng.png) + +- 数据源:选择 DAMENG +- 数据源名称:输入数据源的名称 +- 描述:输入数据源的描述 +- IP 主机名:输入连接 DAMENG 的 IP +- 端口:输入连接 DAMENG 的端口 +- 用户名:设置连接 DAMENG 的用户名 +- 密码:设置连接 DAMENG 的密码 +- 数据库名:输入连接 DAMENG 的 schema +- Jdbc 连接参数:用于 DAMENG 连接的参数设置,以 JSON 形式填写 + +## 是否原生支持 + +否,使用前需请参考 [数据源配置](../howto/datasource-setting.md) 中的 "数据源中心" 章节激活数据源。 diff --git a/docs/img/new_ui/dev/datasource/dameng.png b/docs/img/new_ui/dev/datasource/dameng.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbb80ec7b1756855e96d0ea36d3711332cbc3bf GIT binary patch literal 28038 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 J6idDR^j|0un2rDd literal 0 HcmV?d00001 diff --git a/dolphinscheduler-bom/pom.xml b/dolphinscheduler-bom/pom.xml index ec543f6a6d..4743ef0f28 100644 --- a/dolphinscheduler-bom/pom.xml +++ b/dolphinscheduler-bom/pom.xml @@ -60,6 +60,7 @@ 2.1.210 8.0.16 21.5.0.0 + 8.1.2.79 1.7.36 4.1.2 3.1.0 @@ -382,6 +383,12 @@ test + + com.dameng + DmJdbcDriver18 + ${dameng-jdbc.version} + + com.h2database h2 diff --git a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java index 4bb1296914..7400636a9d 100644 --- a/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java +++ b/dolphinscheduler-common/src/main/java/org/apache/dolphinscheduler/common/constants/DataSourceConstants.java @@ -36,6 +36,7 @@ public class DataSourceConstants { public static final String COM_REDSHIFT_JDBC_DRIVER = "com.amazon.redshift.jdbc42.Driver"; public static final String COM_ATHENA_JDBC_DRIVER = "com.simba.athena.jdbc.Driver"; public static final String COM_TRINO_JDBC_DRIVER = "io.trino.jdbc.TrinoDriver"; + public static final String COM_DAMENG_JDBC_DRIVER = "dm.jdbc.driver.DmDriver"; /** * validation Query @@ -51,6 +52,7 @@ public class DataSourceConstants { public static final String REDHIFT_VALIDATION_QUERY = "select 1"; public static final String ATHENA_VALIDATION_QUERY = "select 1"; public static final String TRINO_VALIDATION_QUERY = "select 1"; + public static final String DAMENG_VALIDATION_QUERY = "select 1"; /** * jdbc url @@ -67,6 +69,7 @@ public class DataSourceConstants { public static final String JDBC_REDSHIFT = "jdbc:redshift://"; public static final String JDBC_ATHENA = "jdbc:awsathena://"; public static final String JDBC_TRINO = "jdbc:trino://"; + public static final String JDBC_DAMENG = "jdbc:dm://"; /** * database type diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml index aa81a85b35..4030b07bd6 100644 --- a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-all/pom.xml @@ -97,5 +97,10 @@ dolphinscheduler-datasource-azure-sql ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-datasource-dameng + ${project.version} + diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/pom.xml b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/pom.xml new file mode 100644 index 0000000000..f965b1df8f --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + org.apache.dolphinscheduler + dolphinscheduler-datasource-plugin + dev-SNAPSHOT + + + dolphinscheduler-datasource-dameng + jar + ${project.artifactId} + + + + + org.apache.dolphinscheduler + dolphinscheduler-spi + provided + + + + org.apache.dolphinscheduler + dolphinscheduler-datasource-api + ${project.version} + + + + com.dameng + DmJdbcDriver18 + + + + diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannel.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannel.java new file mode 100644 index 0000000000..6fa197c3ba --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannel.java @@ -0,0 +1,31 @@ +/* + * 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.plugin.datasource.dameng; + +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; +import org.apache.dolphinscheduler.spi.datasource.DataSourceClient; +import org.apache.dolphinscheduler.spi.enums.DbType; + +public class DamengDataSourceChannel implements DataSourceChannel { + + @Override + public DataSourceClient createDataSourceClient(BaseConnectionParam baseConnectionParam, DbType dbType) { + return new DamengDataSourceClient(baseConnectionParam, dbType); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactory.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactory.java new file mode 100644 index 0000000000..945f6610c0 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactory.java @@ -0,0 +1,38 @@ +/* + * 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.plugin.datasource.dameng; + +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannelFactory; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import com.google.auto.service.AutoService; + +@AutoService(DataSourceChannelFactory.class) +public class DamengDataSourceChannelFactory implements DataSourceChannelFactory { + + @Override + public String getName() { + return DbType.DAMENG.getDescp(); + } + + @Override + public DataSourceChannel create() { + return new DamengDataSourceChannel(); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceClient.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceClient.java new file mode 100644 index 0000000000..85261afb7d --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceClient.java @@ -0,0 +1,30 @@ +/* + * 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.plugin.datasource.dameng; + +import org.apache.dolphinscheduler.plugin.datasource.api.client.CommonDataSourceClient; +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +public class DamengDataSourceClient extends CommonDataSourceClient { + + public DamengDataSourceClient(BaseConnectionParam baseConnectionParam, DbType dbType) { + super(baseConnectionParam, dbType); + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengConnectionParam.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengConnectionParam.java new file mode 100644 index 0000000000..2f03da8077 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengConnectionParam.java @@ -0,0 +1,37 @@ +/* + * 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.plugin.datasource.dameng.param; + +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; + +public class DamengConnectionParam extends BaseConnectionParam { + + @Override + public String toString() { + return "DamengConnectionParam{" + + "user='" + user + '\'' + + ", address='" + address + '\'' + + ", database='" + database + '\'' + + ", jdbcUrl='" + jdbcUrl + '\'' + + ", driverLocation='" + driverLocation + '\'' + + ", driverClassName='" + driverClassName + '\'' + + ", validationQuery='" + validationQuery + '\'' + + ", other='" + other + '\'' + + '}'; + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceParamDTO.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceParamDTO.java new file mode 100644 index 0000000000..f4dd9046fc --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceParamDTO.java @@ -0,0 +1,42 @@ +/* + * 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.plugin.datasource.dameng.param; + +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.BaseDataSourceParamDTO; +import org.apache.dolphinscheduler.spi.enums.DbType; + +public class DamengDataSourceParamDTO extends BaseDataSourceParamDTO { + + @Override + public String toString() { + return "DamengDatasourceParamDTO{" + + "name='" + name + '\'' + + ", note='" + note + '\'' + + ", host='" + host + '\'' + + ", port=" + port + + ", database='" + database + '\'' + + ", userName='" + userName + '\'' + + ", other='" + other + '\'' + + '}'; + } + + @Override + public DbType getType() { + return DbType.DAMENG; + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessor.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessor.java new file mode 100644 index 0000000000..b15345864d --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/main/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessor.java @@ -0,0 +1,149 @@ +/* + * 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.plugin.datasource.dameng.param; + +import org.apache.dolphinscheduler.common.constants.Constants; +import org.apache.dolphinscheduler.common.constants.DataSourceConstants; +import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.AbstractDataSourceProcessor; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.BaseDataSourceParamDTO; +import org.apache.dolphinscheduler.plugin.datasource.api.datasource.DataSourceProcessor; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.PasswordUtils; +import org.apache.dolphinscheduler.spi.datasource.BaseConnectionParam; +import org.apache.dolphinscheduler.spi.datasource.ConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.auto.service.AutoService; + +@AutoService(DataSourceProcessor.class) +public class DamengDataSourceProcessor extends AbstractDataSourceProcessor { + + private final Logger logger = LoggerFactory.getLogger(DamengDataSourceProcessor.class); + + @Override + public BaseDataSourceParamDTO castDatasourceParamDTO(String paramJson) { + return JSONUtils.parseObject(paramJson, DamengDataSourceParamDTO.class); + } + + @Override + public BaseDataSourceParamDTO createDatasourceParamDTO(String connectionJson) { + DamengConnectionParam connectionParams = (DamengConnectionParam) createConnectionParams(connectionJson); + DamengDataSourceParamDTO damengDatasourceParamDTO = new DamengDataSourceParamDTO(); + + damengDatasourceParamDTO.setUserName(connectionParams.getUser()); + damengDatasourceParamDTO.setDatabase(connectionParams.getDatabase()); + damengDatasourceParamDTO.setOther(connectionParams.getOther()); + + String address = connectionParams.getAddress(); + String[] hostSeperator = address.split(Constants.DOUBLE_SLASH); + String[] hostPortArray = hostSeperator[hostSeperator.length - 1].split(Constants.COMMA); + damengDatasourceParamDTO.setPort(Integer.parseInt(hostPortArray[0].split(Constants.COLON)[1])); + damengDatasourceParamDTO.setHost(hostPortArray[0].split(Constants.COLON)[0]); + + return damengDatasourceParamDTO; + } + + @Override + public BaseConnectionParam createConnectionParams(BaseDataSourceParamDTO dataSourceParam) { + DamengDataSourceParamDTO dmDatasourceParam = (DamengDataSourceParamDTO) dataSourceParam; + String address = String + .format("%s%s:%s", DataSourceConstants.JDBC_DAMENG, dmDatasourceParam.getHost(), + dmDatasourceParam.getPort()); + String jdbcUrl = StringUtils.isEmpty(dmDatasourceParam.getDatabase()) ? address + : String.format("%s/%s", address, + dmDatasourceParam.getDatabase()); + + DamengConnectionParam damengConnectionParam = new DamengConnectionParam(); + damengConnectionParam.setJdbcUrl(jdbcUrl); + damengConnectionParam.setDatabase(damengConnectionParam.getDatabase()); + damengConnectionParam.setAddress(address); + damengConnectionParam.setUser(dmDatasourceParam.getUserName()); + damengConnectionParam.setPassword(PasswordUtils.encodePassword(dmDatasourceParam.getPassword())); + damengConnectionParam.setDriverClassName(getDatasourceDriver()); + damengConnectionParam.setValidationQuery(getValidationQuery()); + damengConnectionParam.setOther(dmDatasourceParam.getOther()); + + return damengConnectionParam; + } + + @Override + public ConnectionParam createConnectionParams(String connectionJson) { + return JSONUtils.parseObject(connectionJson, DamengConnectionParam.class); + } + + @Override + public String getDatasourceDriver() { + return DataSourceConstants.COM_DAMENG_JDBC_DRIVER; + } + + @Override + public String getValidationQuery() { + return DataSourceConstants.DAMENG_VALIDATION_QUERY; + } + + @Override + public String getJdbcUrl(ConnectionParam connectionParam) { + DamengConnectionParam damengConnectionParam = (DamengConnectionParam) connectionParam; + String jdbcUrl = damengConnectionParam.getJdbcUrl(); + if (MapUtils.isNotEmpty(damengConnectionParam.getOther())) { + return String.format("%s?%s", jdbcUrl, transformOther(damengConnectionParam.getOther())); + } + return jdbcUrl; + } + + @Override + public Connection getConnection(ConnectionParam connectionParam) throws ClassNotFoundException, SQLException { + DamengConnectionParam damengConnectionParam = (DamengConnectionParam) connectionParam; + Class.forName(getDatasourceDriver()); + return DriverManager.getConnection(getJdbcUrl(damengConnectionParam), damengConnectionParam.getUser(), + PasswordUtils.decodePassword(damengConnectionParam.getPassword())); + } + + @Override + public DbType getDbType() { + return DbType.DAMENG; + } + + @Override + public DataSourceProcessor create() { + return new DamengDataSourceProcessor(); + } + + private String transformOther(Map paramMap) { + if (MapUtils.isEmpty(paramMap)) { + return null; + } + List otherList = new ArrayList<>(); + paramMap.forEach((key, value) -> otherList.add(String.format("%s=%s", key, value))); + return String.join("&", otherList); + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactoryTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactoryTest.java new file mode 100644 index 0000000000..5288fb521d --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelFactoryTest.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.plugin.datasource.dameng; + +import org.apache.dolphinscheduler.spi.datasource.DataSourceChannel; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class DamengDataSourceChannelFactoryTest { + + @Test + public void testCreate() { + DamengDataSourceChannelFactory sourceChannelFactory = new DamengDataSourceChannelFactory(); + DataSourceChannel dataSourceChannel = sourceChannelFactory.create(); + Assertions.assertNotNull(dataSourceChannel); + } +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelTest.java new file mode 100644 index 0000000000..d47b671c25 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/DamengDataSourceChannelTest.java @@ -0,0 +1,40 @@ +/* + * 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.plugin.datasource.dameng; + +import org.apache.dolphinscheduler.plugin.datasource.dameng.param.DamengConnectionParam; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class DamengDataSourceChannelTest { + + @Test + public void testCreateDataSourceClient() { + DamengDataSourceChannel sourceChannel = Mockito.mock(DamengDataSourceChannel.class); + DamengDataSourceClient dataSourceClient = Mockito.mock(DamengDataSourceClient.class); + Mockito.when(sourceChannel.createDataSourceClient(Mockito.any(), Mockito.any())).thenReturn(dataSourceClient); + Assertions.assertNotNull(sourceChannel.createDataSourceClient(new DamengConnectionParam(), DbType.DAMENG)); + } + +} diff --git a/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessorTest.java b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessorTest.java new file mode 100644 index 0000000000..b724a3c106 --- /dev/null +++ b/dolphinscheduler-datasource-plugin/dolphinscheduler-datasource-dameng/src/test/java/org/apache/dolphinscheduler/plugin/datasource/dameng/param/DamengDataSourceProcessorTest.java @@ -0,0 +1,91 @@ +/* + * 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.plugin.datasource.dameng.param; + +import org.apache.dolphinscheduler.common.constants.DataSourceConstants; +import org.apache.dolphinscheduler.plugin.datasource.api.utils.PasswordUtils; +import org.apache.dolphinscheduler.spi.enums.DbType; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class DamengDataSourceProcessorTest { + + private DamengDataSourceProcessor damengDatasourceProcessor = new DamengDataSourceProcessor(); + + @Test + public void testCreateConnectionParams() { + DamengDataSourceParamDTO damengDatasourceParamDTO = new DamengDataSourceParamDTO(); + damengDatasourceParamDTO.setUserName("SYSDBA"); + damengDatasourceParamDTO.setPassword("SYSDBA"); + damengDatasourceParamDTO.setHost("localhost"); + damengDatasourceParamDTO.setPort(5236); + damengDatasourceParamDTO.setDatabase("PERSON"); + + try (MockedStatic mockedPasswordUtils = Mockito.mockStatic(PasswordUtils.class)) { + Mockito.when(PasswordUtils.encodePassword(Mockito.anyString())).thenReturn("test"); + DamengConnectionParam connectionParams = (DamengConnectionParam) damengDatasourceProcessor + .createConnectionParams(damengDatasourceParamDTO); + Assertions.assertEquals("jdbc:dm://localhost:5236", connectionParams.getAddress()); + Assertions.assertEquals("jdbc:dm://localhost:5236/PERSON", connectionParams.getJdbcUrl()); + } + } + + @Test + public void testCreateConnectionParams2() { + String connectionJson = "{\"user\":\"SYSDBA\",\"password\":\"SYSDBA\"," + + "\"address\":\"jdbc:dm://localhost:5236\"" + + ",\"database\":\"PERSON\",\"jdbcUrl\":\"jdbc:dm://localhost:5236/PERSON\"}"; + DamengConnectionParam connectionParams = (DamengConnectionParam) damengDatasourceProcessor + .createConnectionParams(connectionJson); + Assertions.assertNotNull(connectionJson); + Assertions.assertEquals("SYSDBA", connectionParams.getUser()); + } + + @Test + public void testGetDatasourceDriver() { + Assertions.assertEquals(DataSourceConstants.COM_DAMENG_JDBC_DRIVER, + damengDatasourceProcessor.getDatasourceDriver()); + } + + @Test + public void testGetJdbcUrl() { + DamengConnectionParam damengConnectionParam = new DamengConnectionParam(); + damengConnectionParam.setJdbcUrl("jdbc:dm://localhost:5236/PERSON"); + Assertions.assertEquals( + "jdbc:dm://localhost:5236/PERSON", + damengDatasourceProcessor.getJdbcUrl(damengConnectionParam)); + } + + @Test + public void testGetDbType() { + Assertions.assertEquals(DbType.DAMENG, damengDatasourceProcessor.getDbType()); + } + + @Test + public void testGetValidationQuery() { + Assertions.assertEquals(DataSourceConstants.DAMENG_VALIDATION_QUERY, + damengDatasourceProcessor.getValidationQuery()); + } + +} diff --git a/dolphinscheduler-datasource-plugin/pom.xml b/dolphinscheduler-datasource-plugin/pom.xml index ab04eae4f9..f9f82f8736 100644 --- a/dolphinscheduler-datasource-plugin/pom.xml +++ b/dolphinscheduler-datasource-plugin/pom.xml @@ -44,6 +44,7 @@ dolphinscheduler-datasource-trino dolphinscheduler-datasource-starrocks dolphinscheduler-datasource-azure-sql + dolphinscheduler-datasource-dameng diff --git a/dolphinscheduler-dist/release-docs/LICENSE b/dolphinscheduler-dist/release-docs/LICENSE index 48f3cf5c7d..2eb79349d3 100644 --- a/dolphinscheduler-dist/release-docs/LICENSE +++ b/dolphinscheduler-dist/release-docs/LICENSE @@ -516,7 +516,7 @@ The text of each license is also included at licenses/LICENSE-[project].txt. reactor-core 3.4.22: https://mvnrepository.com/artifact/io.projectreactor/reactor-core/3.4.22, Apache 2.0 reactor-netty-core 1.0.22: https://mvnrepository.com/artifact/io.projectreactor.netty/reactor-netty-core/1.0.22, Apache 2.0 reactor-netty-http 1.0.22: https://mvnrepository.com/artifact/io.projectreactor.netty/reactor-netty-http/1.0.22, Apache 2.0 - + DmJdbcDriver18 8.1.2.79: https://mvnrepository.com/artifact/com.dameng/DmJdbcDriver18/8.1.2.79, Apache 2.0 jna-platform diff --git a/dolphinscheduler-dist/release-docs/NOTICE b/dolphinscheduler-dist/release-docs/NOTICE index 904f9098df..21c28d6dcb 100644 --- a/dolphinscheduler-dist/release-docs/NOTICE +++ b/dolphinscheduler-dist/release-docs/NOTICE @@ -2096,3 +2096,13 @@ perfmark NOTICE * agent/src/main/resources/io/perfmark/agent/third_party/asm/LICENSE (BSD style License) * HOMEPAGE: * https://asm.ow2.io/ + +======================================================================== + + +Dameng DmJdbcDriver18 NOTICE + +======================================================================== + +Dameng DmJdbcDriver18 +Copyright 2000-2022 Dameng Group Holding Ltd. diff --git a/dolphinscheduler-dist/release-docs/licenses/LICENSE-DmJdbcDriver18.txt b/dolphinscheduler-dist/release-docs/licenses/LICENSE-DmJdbcDriver18.txt new file mode 100644 index 0000000000..87efe005aa --- /dev/null +++ b/dolphinscheduler-dist/release-docs/licenses/LICENSE-DmJdbcDriver18.txt @@ -0,0 +1,13 @@ +Copyright 2000-2022 Dameng Group Holding Ltd. + +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. \ No newline at end of file diff --git a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java index 0a2a0ef5ce..c2d4977bf5 100644 --- a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java +++ b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/enums/DbType.java @@ -42,7 +42,8 @@ public enum DbType { ATHENA(11, "athena"), TRINO(12, "trino"), STARROCKS(13, "starrocks"), - AZURESQL(14, "azuresql"); + AZURESQL(14, "azuresql"), + DAMENG(15, "dameng"); private static final Map DB_TYPE_MAP = Arrays.stream(DbType.values()).collect(toMap(DbType::getCode, Functions.identity())); diff --git a/dolphinscheduler-ui/src/service/modules/data-source/types.ts b/dolphinscheduler-ui/src/service/modules/data-source/types.ts index 1ad7fb7ad1..0d0b3e8867 100644 --- a/dolphinscheduler-ui/src/service/modules/data-source/types.ts +++ b/dolphinscheduler-ui/src/service/modules/data-source/types.ts @@ -30,6 +30,7 @@ type IDataBase = | 'TRINO' | 'AZURESQL' | 'STARROCKS' + | 'DAMENG' type IDataBaseLabel = | 'MYSQL' @@ -46,6 +47,7 @@ type IDataBaseLabel = | 'TRINO' | 'AZURESQL' | 'STARROCKS' +| 'DAMENG' interface IDataSource { id?: number diff --git a/dolphinscheduler-ui/src/views/datasource/list/use-form.ts b/dolphinscheduler-ui/src/views/datasource/list/use-form.ts index 371129ea04..dcf15e766c 100644 --- a/dolphinscheduler-ui/src/views/datasource/list/use-form.ts +++ b/dolphinscheduler-ui/src/views/datasource/list/use-form.ts @@ -367,6 +367,11 @@ export const datasourceType: IDataBaseOptionKeys = { value: 'STARROCKS', label: 'STARROCKS', defaultPort: 9030 + }, + DAMENG: { + value: 'DAMENG', + label: 'DAMENG', + defaultPort: 5236 } } diff --git a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-datasource.ts b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-datasource.ts index 30cddc65cd..984ad08b69 100644 --- a/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-datasource.ts +++ b/dolphinscheduler-ui/src/views/projects/task/components/node/fields/use-datasource.ts @@ -108,6 +108,11 @@ export function useDatasource( code: 'AZURESQL', disabled: false }, + { + id: 15, + code: 'DAMENG', + disabled: false + } ] const getDatasourceTypes = async () => { diff --git a/tools/dependencies/known-dependencies.txt b/tools/dependencies/known-dependencies.txt index f3e9efc5d3..5e7b64c525 100644 --- a/tools/dependencies/known-dependencies.txt +++ b/tools/dependencies/known-dependencies.txt @@ -398,3 +398,4 @@ oauth2-oidc-sdk-9.35.jar reactor-core-3.4.22.jar reactor-netty-core-1.0.22.jar reactor-netty-http-1.0.22.jar +DmJdbcDriver18-8.1.2.79.jar