diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml
index efc139b19..201cee7e2 100644
--- a/.github/workflows/backend.yml
+++ b/.github/workflows/backend.yml
@@ -49,8 +49,14 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: true
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@v3
+ with:
+ java-version: 8
+ distribution: 'temurin'
+ cache: 'maven'
- name: Check code style
- run: ./mvnw --batch-mode --quiet --no-snapshot-updates clean checkstyle:check
+ run: ./mvnw --batch-mode --quiet --no-snapshot-updates clean spotless:check
dead-link:
if: github.repository == 'apache/incubator-seatunnel-web'
@@ -125,7 +131,7 @@ jobs:
cache: 'maven'
- name: Install
run: >-
- ./mvnw -B -q install -DskipTests
+ ./mvnw -B -q install -DskipTests -P release
-D"maven.test.skip"=true
-D"maven.javadoc.skip"=true
-D"checkstyle.skip"=true
diff --git a/.gitignore b/.gitignore
index 1197e9bdb..9bf8b904b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,7 @@ test.conf
spark-warehouse
*.flattened-pom.xml
/seatunnel-ui/package-lock.json
+/seatunnel-ui/node
+/seatunnel-ui/node/*
+/seatunnel-ui/node_modules
+/seatunnel-ui/node_modules/*
diff --git a/.licenserc.yaml b/.licenserc.yaml
index ec23eba6e..052f0bc1a 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -41,5 +41,6 @@ header:
- '**/.gitkeep'
- '**/com/typesafe/config/**'
- 'seatunnel-main-repository/**'
+ - 'seatunnel-web-dist/release-docs/**'
comment: on-failure
diff --git a/README.md b/README.md
index 304448308..6353d46df 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Apache SeaTunnel (Incubating)
+# Apache SeaTunnel
@@ -21,90 +21,128 @@ Click it if your want to know more about our design. 👉🏻[Design](https://gi
## How to start
-First, we need clone this project from Github.
+### 1 Preparing the Apache DolphinScheduler environment
-```shell
-git clone https://github.com/apache/incubator-seatunnel-web.git
-```
+#### 1.1 Install Apache DolphinScheduler
+
+If you already have Apache DolphinScheduler environment, you can skip this step and go to [Create Tenant and User for SeaTunnel Web](#1.2 Create Tenant and User for SeaTunnel Web)
+
+Because running SeaTunnel Web must rely on the DolphinScheduler, if you do not have a DS environment, you need to first install and deploy a DolphinScheduler (hereinafter referred to as DS). Taking DS version 3.1.5 as an example.
+
+Reference `https://dolphinscheduler.apache.org/zh-cn/docs/3.1.5/guide/installation/standalone` to install a standalone DS.
+
+#### 1.2 Create Tenant and User for SeaTunnel Web
+
+If you already have a DS environment and decide to use existing users and tenants for SeaTunnel Web, you can skip this step and go to [Create Project for SeaTunnel Web](#1.3 Create Project for SeaTunnel Web).
+
+Because SeaTunnel Web needs to call the interface of DS to create workflows and tasks, it is necessary to submit the projects, users, and tenants created in DS for SeaTunnel to use.
+
+1. Create Tenant
+
+"Security" -> "Tenant Manage" -> "Create Tenant"
+
+![image](docs/images/ds_create_tenant.png)
+
+2. For simplicity, use the default user admin of DS directly here
+
+#### 1.3 Create Project for SeaTunnel Web
+
+![image](docs/images/ds_create_project.png)
+
+#### 1.4 Create Token for SeaTunnel Web
+
+![image](docs/images/ds_create_token.png)
+
+### 2 Run SeaTunnel Web in IDEA
+
+If you want to deploy and run SeaTunnel Web, Please turn to [3 Run SeaTunnel Web In Server](#3 Run SeaTunnel Web In Server)
+
+#### 2.1 Init database
+
+1. Edit `whaletunnel-server/whaletunnel-app/src/main/resources/script/seatunnel_server_env.sh` file, Complete the installed database address, port, username, and password. Here is an example:
+
+ ```
+ export HOSTNAME="localhost"
+ export PORT="3306"
+ export USERNAME="root"
+ export PASSWORD="123456"
+ ```
+2. Run init shell `sh seatunnel-server/seatunnel-app/src/main/resources/script/init_sql.sh` If there are no errors during operation, it indicates successful initialization.
+
+#### 2.2 Config application and Run SeaTunnel Web Backend Server
+
+1. Edit `seatunnel-server/seatunnel-app/src/main/resources/application.yml` Fill in the database connection information and DS interface related information in the file.
+
+![image](docs/images/application_config.png)
+
+2. Run `seatunnel-server/seatunnel-app/src/main/java/org/apache/seatunnel/app/SeatunnelApplication.java` If there are no errors reported, the seatunnel web backend service is successfully started.
+
+#### 2.3 Run SeaTunnel Web Front End
-Then, setup up configuration of db and more.
-```shell
-vim seatunnel-server/seatunnel-app/src/main/resources/application.yml
```
+cd seatunnel-ui
+npm install
+npm run dev
-Notice:
-At present, we only support the following scheduler systems: dolphinscheduler, more scheduler systems will be supported in the future;
-And for easier use, we plan to build our own scheduling system in Seatunnel.
-
-Here is a sample parameter configuration for Seatunnel integration dolphinscheduler:
-```yaml
-ds:
- script:
- # The path where the script is stored
- dir: /dj
- project:
- # The default project name of dolphinscheduler
- default: test_dj
- tenant:
- # Which tenant been used to submit script
- default: default
- api:
- # The dolphinscheduler user token
- token: 12345678
- # The dolphinscheduler api prefix address
- prefix: http://127.0.0.1:12345/dolphinscheduler
```
-Now comes the crucial part, this is about your account security, please modify the Jwt secret key and algorithm.
+If there are no issues with the operation, the following information will be displayed:
-```yaml
-jwt:
- expireTime: 86400
- secretKey: https://github.com/apache/incubator-seatunnel
- algorithm: HS256
```
+ ➜ Local: http://127.0.0.1:5173/
+ ➜ Network: use --host to expose
+ ➜ press h to show help
-
-Next, execute sql to create table .(Your must create database first by yourself)
-```shell
-# Replace `username` & `dbName` with the real username and database name.
-# We will provided script in future.
-mysql -u username -p [dbName] < bin/seatunnl.sql
```
-Now, you've done all the preparatory work, launch our app.
+Accessing in a browser http://127.0.0.1:5173/login Okay, the default username and password are admin/admin.
-### Launch it in IntelliJ IDEA
+### 3 Run SeaTunnel Web In Server
-Starting the back end of St in idea is really simple, just run the main method of `SeatunnelApplication.java` in the `seatunnel-app` module.
-And the log will tell u anything you need to know.
+#### 3.1 Build Install Package From Code
-### Start it in the command line
+```
+cd incubator-seatunnel-web
+sh build.sh code
+```
-```shell
-# start backend
+Then you can find the installer package in dir `incubator-seatunnel-web/seatunnel-web-dist/target/apache-seatunnel-web-${project.version}.tar.gz`.
-# for build code
-sh build.sh code
+#### 3.2 Install
-# for build image
-sh build.sh image
-
-# and then start docker container
-docker run apache/seatunnel-web
+Copy the `apache-seatunnel-web-${project.version}.tar.gz` to your server node and unzip it.
+```shell
+tar -zxvf apache-seatunnel-web-${project.version}.tar.gz
```
-### start frontend
-You can use a Web server such as Apache HTTP Server or Nginx to start front-end applications. Deploy the built front-end code to the root directory of the Web server, start the Web server, and enter the URL of the Web server in a browser to access the application.
+#### 3.3 Init database
+
+1. Edit `apache-seatunnel-web-${project.version}/script/seatunnel_server_env.sh` file, Complete the installed database address, port, username, and password. Here is an example:
+
+ ```
+ export HOSTNAME="localhost"
+ export PORT="3306"
+ export USERNAME="root"
+ export PASSWORD="123456"
+ ```
+2. Run init shell `sh apache-seatunnel-web-${project.version}/script/init_sql.sh` If there are no errors during operation, it indicates successful initialization.
+
+#### 3.4 Config application and Run SeaTunnel Web Backend Server
+
+Edit `apache-seatunnel-web-${project.version}/config/application.yml` Fill in the database connection information and DS interface related information in the file.
+
+![image](docs/images/application_config.png)
+
+#### 3.5 Start SeaTunnel Web
-If you want start in dev mode:
```shell
-cd seatunnel-ui
-npm install
-npm run dev
+cd apache-seatunnel-web-${project.version}
+sh bin/seatunnel-backend-daemon.sh start
```
+Accessing in a browser http://127.0.0.1:8801/ui/ Okay, the default username and password are admin/admin.
+
### How to use it
After all the pre-work is done, we can open the following URL: 127.0.0.1:7890(please replace it according to your configuration) to use it.
diff --git a/build.sh b/build.sh
index d48afbf41..da4f8b1df 100644
--- a/build.sh
+++ b/build.sh
@@ -29,7 +29,7 @@ DOCKER_VERSION=1.0.0-snapshot
code() {
/bin/sh $WORKDIR/mvnw clean package -DskipTests
# mv release zip
- mv $WORKDIR/seatunnel-server/seatunnel-app/target/seatunnel-web.zip $WORKDIR/
+ mv $WORKDIR/seatunnel-web-dist/target/apache-seatunnel-web-1.0.0-SNAPSHOT.zip $WORKDIR/
}
# build image
diff --git a/docs/images/application_config.png b/docs/images/application_config.png
new file mode 100644
index 000000000..eac17bae6
Binary files /dev/null and b/docs/images/application_config.png differ
diff --git a/docs/images/ds_create_project.png b/docs/images/ds_create_project.png
new file mode 100644
index 000000000..71bb25168
Binary files /dev/null and b/docs/images/ds_create_project.png differ
diff --git a/docs/images/ds_create_tenant.png b/docs/images/ds_create_tenant.png
new file mode 100644
index 000000000..45dfe3363
Binary files /dev/null and b/docs/images/ds_create_tenant.png differ
diff --git a/docs/images/ds_create_token.png b/docs/images/ds_create_token.png
new file mode 100644
index 000000000..539c0bdf1
Binary files /dev/null and b/docs/images/ds_create_token.png differ
diff --git a/docs/images/ds_create_user.png b/docs/images/ds_create_user.png
new file mode 100644
index 000000000..5117f398b
Binary files /dev/null and b/docs/images/ds_create_user.png differ
diff --git a/pom.xml b/pom.xml
index e5195ce02..ef6b0822e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,8 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
4.0.0
@@ -26,56 +25,21 @@
org.apache.seatunnel
seatunnel-web
+ ${revision}
pom
- 1.0.0-SNAPSHOT
SeaTunnel
-
- Production ready big data processing product based on Apache Spark and Apache Flink.
-
-
- https://github.com/apache/incubator-seatunnel
-
-
-
- The Apache License, Version 2.0
- https://www.apache.org/licenses/LICENSE-2.0.txt
-
-
-
-
- scm:git:https://github.com/apache/incubator-seatunnel.git
- scm:git:https://github.com/apache/incubator-seatunnel.git
- https://github.com/apache/incubator-seatunnel
- HEAD
-
-
-
- GitHub
- https://github.com/apache/incubator-seatunnel/issues
-
-
-
-
- SeaTunnel Developer List
- dev@seatunnel.apache.org
- dev-subscribe@seatunnel.apache.org
- dev-unsubscribe@seatunnel.apache.org
-
-
- SeaTunnel Commits List
- commits@seatunnel.apache.org
- commits-subscribe@seatunnel.apache.org
- commits-unsubscribe@seatunnel.apache.org
-
-
+ Production ready big data processing product based on Apache Spark and Apache Flink.
- seatunnel-server
+ seatunnel-server
+ seatunnel-datasource
+ seatunnel-web-dist
+ 1.0.0-SNAPSHOT
${java.version}
${java.version}
1.8
@@ -87,7 +51,6 @@
2.22.2
2.22.2
2.9.1
- 3.1.2
3.10.1
3.3.0
3.2.0
@@ -95,15 +58,11 @@
1.20
1.9.5
3.1.0
- true
- 1.18.0
+ 3.3.0
false
-
- 2.1.3
- 1.2
- 1.7.25
- 2.12.7.1
+ 2.12.7.1
+ 2.12.7
8.0.16
2.1.214
5.9.0
@@ -111,82 +70,805 @@
3.4
19.0
3.10.0
- 2.17.1
4.2.0
+ 2.4.7-WS-SNAPSHOT
+ 2.1.0.9
+ 3.1.4
+ 1.11.271
+ 1.0.1
+ 1.18.24
+ true
+ 3.1.1
+ 1.3.0
+
+ 2.6.8
+ 5.3.20
+ 3.5.3.1
+ 1.2.9
+ 2.6.1
+ 1.5.10
+ 6.2.2.Final
+ 1.3.2
+ 1.14.3
+ 0.10.7
+ 9.1.6
+ 2.11.0
+ 3.0.0
+ 1.0.1
+ 2.3.1
+ 3.1.4
+ 1.11.271
+ 2.29.0
+ 1.2.11
+ 2.17.1
+ 1.2.3
+ 1.2
+ 1.2.17
+ 2.17.1
+ 1.7.25
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+ ch.qos.logback
+ logback-core
+ ${logback.version}
+
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${slf4j.version}
+
+
+
+
+
+
+
+ org.slf4j
+ log4j-over-slf4j
+ ${slf4j.version}
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j.version}
+ provided
+
+
+
+ org.apache.logging.log4j
+ log4j-to-slf4j
+ ${log4j2.version}
+
+
+
+ org.slf4j
+ slf4j-jdk14
+ ${slf4j.version}
+ provided
+
+
+
+ org.slf4j
+ slf4j-jcl
+ ${slf4j.version}
+ provided
+
+
+
+ org.slf4j
+ slf4j-nop
+ ${slf4j.version}
+ provided
+
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+ provided
+
+
+
+ org.slf4j
+ slf4j-reload4j
+ ${slf4j.version}
+ provided
+
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+ provided
+
+
+ log4j
+ log4j
+ ${log4j.version}
+ provided
+
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j2.version}
+ provided
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j2.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j2.version}
+ provided
+
+
+
+ org.apache.logging.log4j
+ log4j-1.2-api
+ ${log4j2.version}
+ provided
+
+
+
+
+
+
+ org.apache.seatunnel
+ seatunnel-common
+ ${seatunnel-framework.version}
+
+
+
+ org.apache.seatunnel
+ seatunnel-jackson
+ ${seatunnel-framework.version}
+ optional
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-properties
+
+
+
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ ${seatunnel-framework.version}
+
+
+
+ org.apache.seatunnel
+ seatunnel-engine-client
+ ${seatunnel-framework.version}
+
+
+
+ com.google.auto.service
+ auto-service
+ ${auto-service.version}
+ provided
+
+
+
+ org.apache.seatunnel
+ seatunnel-plugin-discovery
+ ${seatunnel-framework.version}
+
+
+
+ org.apache.seatunnel
+ seatunnel-transforms-v2
+ ${seatunnel-framework.version}
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-jetty
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+ ${spring-boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ ${spring-boot.version}
+ test
+
+
+ com.google.code.gson
+ gson
+ 2.8.6
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ ${druid-spring-boot-starter.version}
+
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis-plus-boot-starter.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+
+
+ org.hibernate.validator
+ hibernate-validator
+ ${hibernate.validator.version}
+
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${springfox-swagger.version}
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${springfox-swagger.version}
+
+
+ io.swagger
+ swagger-annotations
+ ${swagger-annotations.version}
+
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jwt.version}
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jwt.version}
+ runtime
+
+
+
+
+ org.jsoup
+ jsoup
+ ${jsoup.version}
+
+
+
+
+ org.apache.seatunnel
+ connector-common
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ connector-console
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ connector-fake
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ connector-jdbc
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+ org.apache.commons
+ commons-collections4
+ ${commons-collections4.version}
+
+
+ org.junit
+ junit-bom
+ ${junit.version}
+ pom
+ import
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson-databind.version}
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ org.checkerframework
+ checker-qual
+ ${checker.qual.version}
+
+
+
+ org.awaitility
+ awaitility
+ ${awaitility.version}
+ test
+
+
+
+ org.apache.seatunnel
+ seatunnel-hadoop3-3.1.4-uber
+ ${hadoop-uber.version}
+
+
+ org.apache.avro
+ avro
+
+
+
+
+ org.apache.hadoop
+ hadoop-aws
+ ${hadoop-aws.version}
+ provided
+
+
+ jdk.tools
+ jdk.tools
+
+
+
+
+ com.amazonaws
+ aws-java-sdk-bundle
+ ${aws-java-sdk-bundle.version}
+ provided
+
+
+ com.cronutils
+ cron-utils
+ ${cron-utils.version}
+
+
+ org.javassist
+ javassist
+
+
+
+
+ org.apache.seatunnel
+ seatunnel-datasource-client
+ ${project.version}
+
+
+ com.google.auto.service
+ auto-service-annotations
+ ${auto-service-annotation.version}
+ compile
+
+
+
+ org.apache.seatunnel
+ datasource-s3
+ ${project.version}
+ provided
+
+
+
+ com.google.code.findbugs
+ jsr305
+ ${jsr305.version}
+
+
+
+
+ org.apache.seatunnel
+ connector-common
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ seatunnel-transforms-v2
+ ${seatunnel-framework.version}
+
+
+
+ org.apache.seatunnel
+ connector-console
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ connector-fake
+ ${seatunnel-framework.version}
+ test
+
+
+
+ org.apache.seatunnel
+ connector-kafka
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-base
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-feishu
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-wechat
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-myhours
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-lemlist
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-klaviyo
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-onesignal
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-notion
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-jdbc
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-socket
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-clickhouse
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-pulsar
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-hive
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-file-hadoop
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-file-local
+ ${seatunnel-framework.version}
+ test
+
org.apache.seatunnel
- seatunnel-common
- ${seatunnel-common.version}
+ connector-file-oss
+ ${seatunnel-framework.version}
+ test
-
- org.projectlombok
- lombok
- ${lombok.version}
- provided
+ org.apache.seatunnel
+ connector-file-oss-jindo
+ ${seatunnel-framework.version}
+ test
-
- org.apache.commons
- commons-lang3
- ${commons-lang3.version}
+ org.apache.seatunnel
+ connector-file-ftp
+ ${seatunnel-framework.version}
+ test
- org.apache.commons
- commons-collections4
- ${commons-collections4.version}
+ org.apache.seatunnel
+ connector-file-sftp
+ ${seatunnel-framework.version}
+ test
- org.junit
- junit-bom
- ${junit.version}
- pom
- import
+ org.apache.seatunnel
+ connector-hudi
+ ${seatunnel-framework.version}
+ test
-
- com.fasterxml.jackson.core
- jackson-databind
- ${jackson.version}
+ org.apache.seatunnel
+ connector-dingtalk
+ ${seatunnel-framework.version}
+ test
-
- com.google.guava
- guava
- ${guava.version}
+ org.apache.seatunnel
+ connector-kudu
+ ${seatunnel-framework.version}
+ test
-
- org.apache.logging.log4j
- log4j-core
- ${log4j-core.version}
+ org.apache.seatunnel
+ connector-email
+ ${seatunnel-framework.version}
+ test
- org.slf4j
- slf4j-api
- ${slf4j.version}
+ org.apache.seatunnel
+ connector-elasticsearch
+ ${seatunnel-framework.version}
+ test
-
- org.slf4j
- slf4j-log4j12
- ${slf4j.version}
+ org.apache.seatunnel
+ connector-iotdb
+ ${seatunnel-framework.version}
+ test
-
- org.checkerframework
- checker-qual
- ${checker.qual.version}
+ org.apache.seatunnel
+ connector-neo4j
+ ${seatunnel-framework.version}
+ test
-
- org.awaitility
- awaitility
- ${awaitility.version}
+ org.apache.seatunnel
+ connector-redis
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-google-sheets
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-datahub
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-sentry
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-mongodb
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-iceberg
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-influxdb
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-cassandra
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-file-s3
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-amazondynamodb
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-starrocks
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-tablestore
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-slack
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-gitlab
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-http-jira
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-rabbitmq
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-openmldb
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-doris
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-maxcompute
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-cdc-mysql
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-cdc-sqlserver
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-cdc-oracle
+ ${seatunnel-framework.version}
test
@@ -194,6 +876,23 @@
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ org.apache.seatunnel
+ connector-cdc-sqlserver
+ ${seatunnel-framework.version}
+ test
+
+
+ org.apache.seatunnel
+ connector-cdc-mysql
+ ${seatunnel-framework.version}
+ test
+
org.projectlombok
lombok
@@ -201,7 +900,40 @@
org.slf4j
slf4j-api
- ${slf4j.version}
+
+
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+
+
+
+ org.slf4j
+ log4j-over-slf4j
+
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+
+ org.apache.logging.log4j
+ log4j-to-slf4j
org.junit.jupiter
@@ -242,8 +974,7 @@
${skipUT}
- ${project.build.directory}/jacoco.exec
-
+ ${project.build.directory}/jacoco.exec
**/*IT.java
@@ -251,7 +982,6 @@
-
org.apache.maven.plugins
@@ -259,51 +989,53 @@
${maven-assembly-plugin.version}
-
+
org.apache.maven.plugins
- maven-checkstyle-plugin
- ${maven-checkstyle-plugin.version}
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
-
- ${maven.multiModuleProjectDirectory}/tools/checkstyle/checkStyle.xml
-
- UTF-8
- true
- true
- ${checkstyle.fails.on.error}
-
- ${project.build.sourceDirectory}
- ${project.build.testSourceDirectory}
-
-
- **/*.properties,
- **/*.sh,
- **/*.bat,
- **/*.yml,
- **/*.yaml,
- **/*.xml
-
-
- **/.asf.yaml,
- **/.github/**
-
-
-
+ false
+ true
+
+ true
+
+
+ org.slf4j:*
+ ch.qos.logback:*
+ log4j:*
+ org.apache.logging.log4j:*
+ commons-logging:*
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
- validate
- process-sources
- check
+ shade
+ package
+
+
+
+
+
+
-
-
org.apache.maven.plugins
maven-source-plugin
@@ -339,7 +1071,6 @@
-
org.codehaus.mojo
build-helper-maven-plugin
@@ -351,7 +1082,7 @@
license-maven-plugin
${maven-license-maven-plugin}
- ${project.basedir}/seatunnel-dist/target/
+ ${project.basedir}/seatunnel-web-dist/target/
THIRD-PARTY.txt
false
false
@@ -362,6 +1093,112 @@
test,provided
+
+
+ org.codehaus.mojo
+ flatten-maven-plugin
+ ${flatten-maven-plugin.version}
+
+ true
+ resolveCiFriendliesOnly
+
+
+
+ flatten
+
+ flatten
+
+ process-resources
+
+
+ flatten.clean
+
+ clean
+
+ clean
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ ${maven-dependency-plugin.version}
+
+
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+ ${spotless.version}
+
+
+
+ 1.7
+
+
+
+
+
+ org.apache.seatunnel.shade,org.apache.seatunnel,org.apache,org,,javax,java,\#
+
+
+ Remove wildcard imports
+ import\s+(static)*\s*[^\*\s]+\*;(\r\n|\r|\n)
+ $1
+
+
+ Block powermock
+ import\s+org\.powermock\.[^\*\s]*(|\*);(\r\n|\r|\n)
+ $1
+
+
+ Block jUnit4 imports
+ import\s+org\.junit\.[^jupiter][^\*\s]*(|\*);(\r\n|\r|\n)
+ $1
+
+
+
+
+ UTF-8
+ 4
+ true
+ false
+ true
+ true
+ false
+ false
+ custom_1
+ false
+ false
+
+
+ Leading blank line
+ project
+ project
+
+
+
+
+ docs/**/*.md
+
+
+ **/.github/**/*.md
+
+
+
+
+ true
+
+
+
+
+
+ check
+
+ compile
+
+
+
+
@@ -376,6 +1213,7 @@
org.apache.maven.plugins
maven-release-plugin
+ 3.0.1
true
@{project.version}
@@ -394,10 +1232,6 @@
org.apache.maven.plugins
maven-surefire-plugin
-
- org.apache.maven.plugins
- maven-failsafe-plugin
-
org.apache.maven.plugins
@@ -408,7 +1242,48 @@
org.codehaus.mojo
license-maven-plugin
+
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+
+ https://github.com/apache/incubator-seatunnel
+
+
+
+ The Apache License, Version 2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+
+
+
+
+
+ SeaTunnel Developer List
+ dev-subscribe@seatunnel.apache.org
+ dev-unsubscribe@seatunnel.apache.org
+ dev@seatunnel.apache.org
+
+
+ SeaTunnel Commits List
+ commits-subscribe@seatunnel.apache.org
+ commits-unsubscribe@seatunnel.apache.org
+ commits@seatunnel.apache.org
+
+
+
+
+ scm:git:https://github.com/apache/incubator-seatunnel.git
+ scm:git:https://github.com/apache/incubator-seatunnel.git
+ https://github.com/apache/incubator-seatunnel
+ HEAD
+
+
+
+ GitHub
+ https://github.com/apache/incubator-seatunnel/issues
+
+
diff --git a/seatunnel-datasource/pom.xml b/seatunnel-datasource/pom.xml
new file mode 100644
index 000000000..a6fcbc7a5
--- /dev/null
+++ b/seatunnel-datasource/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-web
+ ${revision}
+
+
+ seatunnel-datasource
+ pom
+
+
+ seatunnel-datasource-client
+ seatunnel-datasource-plugins
+
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-client/pom.xml b/seatunnel-datasource/seatunnel-datasource-client/pom.xml
new file mode 100644
index 000000000..e697c6777
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource
+ ${revision}
+
+
+ seatunnel-datasource-client
+
+
+
+ org.apache.seatunnel
+ seatunnel-api
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+
+
+
+ org.apache.seatunnel
+ datasource-all
+ ${project.version}
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+ ${e2e.dependency.skip}
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/AbstractDataSourceClient.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/AbstractDataSourceClient.java
new file mode 100644
index 000000000..b9e3b4f33
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/AbstractDataSourceClient.java
@@ -0,0 +1,135 @@
+/*
+ * 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.seatunnel.datasource;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.exception.DataSourceSDKException;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.service.DataSourceService;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public abstract class AbstractDataSourceClient implements DataSourceService {
+
+ private Map supportedDataSourceInfo = new HashMap<>();
+
+ private Map supportedDataSourceIndex = new HashMap<>();
+
+ protected List supportedDataSources = new ArrayList<>();
+
+ private List dataSourceChannels = new ArrayList<>();
+
+ protected AbstractDataSourceClient() {
+ AtomicInteger dataSourceIndex = new AtomicInteger();
+ ServiceLoader.load(DataSourceFactory.class)
+ .forEach(
+ seaTunnelDataSourceFactory -> {
+ seaTunnelDataSourceFactory
+ .supportedDataSources()
+ .forEach(
+ dataSourceInfo -> {
+ supportedDataSourceInfo.put(
+ dataSourceInfo.getName().toUpperCase(),
+ dataSourceInfo);
+ supportedDataSourceIndex.put(
+ dataSourceInfo.getName().toUpperCase(),
+ dataSourceIndex.get());
+ supportedDataSources.add(dataSourceInfo);
+ });
+ dataSourceChannels.add(seaTunnelDataSourceFactory.createChannel());
+ dataSourceIndex.getAndIncrement();
+ });
+ if (supportedDataSourceInfo.isEmpty()) {
+ throw new DataSourceSDKException("No supported data source found");
+ }
+ }
+
+ @Override
+ public Boolean checkDataSourceConnectivity(
+ String pluginName, Map dataSourceParams) {
+ return getDataSourceChannel(pluginName)
+ .checkDataSourceConnectivity(pluginName, dataSourceParams);
+ }
+
+ @Override
+ public List listAllDataSources() {
+ return supportedDataSources;
+ }
+
+ protected DataSourceChannel getDataSourceChannel(String pluginName) {
+ checkNotNull(pluginName, "pluginName cannot be null");
+ Integer index = supportedDataSourceIndex.get(pluginName.toUpperCase());
+ if (index == null) {
+ throw new DataSourceSDKException(
+ "The %s plugin is not supported or plugin not exist.", pluginName);
+ }
+ return dataSourceChannels.get(index);
+ }
+
+ @Override
+ public OptionRule queryDataSourceFieldByName(String pluginName) {
+ return getDataSourceChannel(pluginName).getDataSourceOptions(pluginName);
+ }
+
+ @Override
+ public OptionRule queryMetadataFieldByName(String pluginName) {
+ return getDataSourceChannel(pluginName)
+ .getDatasourceMetadataFieldsByDataSourceName(pluginName);
+ }
+
+ @Override
+ public List getTables(
+ String pluginName, String databaseName, Map requestParams) {
+ return getDataSourceChannel(pluginName).getTables(pluginName, requestParams, databaseName);
+ }
+
+ @Override
+ public List getDatabases(String pluginName, Map requestParams) {
+ return getDataSourceChannel(pluginName).getDatabases(pluginName, requestParams);
+ }
+
+ @Override
+ public List getTableFields(
+ String pluginName,
+ Map requestParams,
+ String databaseName,
+ String tableName) {
+ return getDataSourceChannel(pluginName)
+ .getTableFields(pluginName, requestParams, databaseName, tableName);
+ }
+
+ @Override
+ public Map> getTableFields(
+ String pluginName,
+ Map requestParams,
+ String databaseName,
+ List tableNames) {
+ return getDataSourceChannel(pluginName)
+ .getTableFields(pluginName, requestParams, databaseName, tableNames);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/DataSourceClient.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/DataSourceClient.java
new file mode 100644
index 000000000..4bf46baa1
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/DataSourceClient.java
@@ -0,0 +1,28 @@
+/*
+ * 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.seatunnel.datasource;
+
+import org.apache.seatunnel.datasource.annotation.ThreadSafe;
+
+@ThreadSafe
+public class DataSourceClient extends AbstractDataSourceClient {
+
+ public DataSourceClient() {
+ super();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.java
new file mode 100644
index 000000000..55794b81c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.java
@@ -0,0 +1,29 @@
+/*
+ * 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.seatunnel.datasource.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface ThreadSafe {}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/exception/DataSourceSDKException.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/exception/DataSourceSDKException.java
new file mode 100644
index 000000000..3f90eabc1
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/exception/DataSourceSDKException.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.seatunnel.datasource.exception;
+
+public class DataSourceSDKException extends RuntimeException {
+
+ public DataSourceSDKException(String message) {
+ super(message);
+ }
+
+ public DataSourceSDKException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public DataSourceSDKException(Throwable cause) {
+ super(cause);
+ }
+
+ public DataSourceSDKException(String message, Object... args) {
+ super(String.format(message, args));
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/PageQueryRequest.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/PageQueryRequest.java
new file mode 100644
index 000000000..8b09bc355
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/PageQueryRequest.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.seatunnel.datasource.request;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+import java.util.Map;
+
+@Data
+@SuperBuilder
+public class PageQueryRequest {
+
+ private Integer pageNum;
+
+ private Integer pageSize;
+
+ private String orderBy;
+
+ private String order;
+
+ private String search;
+
+ Map fuzzySearchParamMap;
+
+ Map exactSearchParamMap;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableCreateRequest.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableCreateRequest.java
new file mode 100644
index 000000000..3d7c42208
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableCreateRequest.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.seatunnel.datasource.request;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class VirtualTableCreateRequest {
+
+ private Long id;
+
+ private Long dataSourceId;
+
+ private String description;
+
+ private String databaseName;
+
+ private String tableName;
+
+ private List fields;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableFieldRequest.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableFieldRequest.java
new file mode 100644
index 000000000..f2acb83c2
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableFieldRequest.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.seatunnel.datasource.request;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+@Builder
+public class VirtualTableFieldRequest {
+
+ private String type;
+
+ private String name;
+
+ private String comment;
+
+ private Boolean primaryKey;
+
+ private String defaultValue;
+
+ private Boolean nullable;
+
+ private Map properties;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableUpdateRequest.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableUpdateRequest.java
new file mode 100644
index 000000000..0939687c6
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/request/VirtualTableUpdateRequest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.seatunnel.datasource.request;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class VirtualTableUpdateRequest {
+
+ private String description;
+
+ private String databaseName;
+
+ private String tableName;
+
+ private List fields;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/BaseResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/BaseResponse.java
new file mode 100644
index 000000000..831a2a64a
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/BaseResponse.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.seatunnel.datasource.response;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+import java.util.Date;
+
+@Data
+@SuperBuilder
+public class BaseResponse {
+
+ /** create time */
+ private Date createTime;
+
+ /** update time */
+ private Date updateTime;
+
+ private String createUserId;
+
+ private String updateUserId;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/DataSourceDetailResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/DataSourceDetailResponse.java
new file mode 100644
index 000000000..f489ad455
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/DataSourceDetailResponse.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.seatunnel.datasource.response;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+import java.util.Map;
+
+@Data
+@SuperBuilder
+public class DataSourceDetailResponse extends BaseResponse {
+
+ private Long id;
+
+ private String dataSourceName;
+
+ private String pluginName;
+
+ private String comment;
+
+ private Map params;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageDataResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageDataResponse.java
new file mode 100644
index 000000000..24e801cce
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageDataResponse.java
@@ -0,0 +1,32 @@
+/*
+ * 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.seatunnel.datasource.response;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class PageDataResponse {
+ private Integer pageNum;
+ private Integer pageSize;
+ private Integer total;
+ private List datas;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageResultResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageResultResponse.java
new file mode 100644
index 000000000..10bab20c8
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/PageResultResponse.java
@@ -0,0 +1,36 @@
+/*
+ * 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.seatunnel.datasource.response;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PageResultResponse {
+
+ private Integer pageNum;
+
+ private Integer pageSize;
+
+ private Integer total;
+
+ private Integer pages;
+
+ private List dataList;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableDetailResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableDetailResponse.java
new file mode 100644
index 000000000..63ab5d575
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableDetailResponse.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.seatunnel.datasource.response;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+import java.util.List;
+
+@Data
+@SuperBuilder
+public class VirtualTableDetailResponse extends BaseResponse {
+
+ private Long id;
+
+ private Long dataSourceId;
+
+ private String description;
+
+ private String type;
+
+ private String databaseName;
+
+ private String tableName;
+
+ private List fields;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableFieldResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableFieldResponse.java
new file mode 100644
index 000000000..5e8583ef4
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableFieldResponse.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.seatunnel.datasource.response;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+import java.util.Map;
+
+@Data
+@SuperBuilder
+public class VirtualTableFieldResponse {
+
+ private String type;
+
+ private String name;
+
+ private String comment;
+
+ private Boolean primaryKey;
+
+ private String defaultValue;
+
+ private Boolean nullable;
+
+ private Map properties;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableResponse.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableResponse.java
new file mode 100644
index 000000000..8e061ad49
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/response/VirtualTableResponse.java
@@ -0,0 +1,36 @@
+/*
+ * 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.seatunnel.datasource.response;
+
+import lombok.Data;
+import lombok.experimental.SuperBuilder;
+
+@Data
+@SuperBuilder
+public class VirtualTableResponse extends BaseResponse {
+
+ private Long id;
+
+ private Long dataSourceId;
+
+ private String description;
+
+ private String databaseName;
+
+ private String tableName;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/service/DataSourceService.java b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/service/DataSourceService.java
new file mode 100644
index 000000000..e777d5e9c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/main/java/org/apache/seatunnel/datasource/service/DataSourceService.java
@@ -0,0 +1,116 @@
+/*
+ * 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.seatunnel.datasource.service;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+
+import java.util.List;
+import java.util.Map;
+
+public interface DataSourceService {
+
+ /**
+ * get all data source plugins
+ *
+ * @return data source plugins info
+ */
+ List listAllDataSources();
+
+ /**
+ * get data source plugin fields
+ *
+ * @param pluginName data source name
+ * @return data source plugin fields
+ */
+ OptionRule queryDataSourceFieldByName(String pluginName);
+
+ /**
+ * get data source metadata fields
+ *
+ * @param pluginName data source name
+ * @return data source metadata fields
+ */
+ OptionRule queryMetadataFieldByName(String pluginName);
+
+ /**
+ * check data source params is valid and connectable
+ *
+ * @param parameters data source params eg mysql plugin key: url // jdbc url key: username key:
+ * password other key...
+ * @return true if valid, false if invalid
+ */
+ /**
+ * we can use this method to check data source connectivity
+ *
+ * @param pluginName source params
+ * @return check result
+ */
+ Boolean checkDataSourceConnectivity(String pluginName, Map datasourceParams);
+
+ /**
+ * get data source table names by database name
+ *
+ * @param pluginName plugin name
+ * @param databaseName database name
+ * @param requestParams connection params
+ * @return table names
+ */
+ List getTables(
+ String pluginName, String databaseName, Map requestParams);
+
+ /**
+ * get data source database names
+ *
+ * @param pluginName plugin name
+ * @param requestParams connection params
+ * @return database names
+ */
+ List getDatabases(String pluginName, Map requestParams);
+
+ /**
+ * get data source table fields
+ *
+ * @param pluginName plugin name
+ * @param requestParams connection params
+ * @param databaseName database name
+ * @param tableName table name
+ * @return table fields
+ */
+ List getTableFields(
+ String pluginName,
+ Map requestParams,
+ String databaseName,
+ String tableName);
+
+ /**
+ * get data source table fields
+ *
+ * @param pluginName plugin name
+ * @param requestParams connection params
+ * @param databaseName database name
+ * @param tableNames table names
+ * @return table fields
+ */
+ Map> getTableFields(
+ String pluginName,
+ Map requestParams,
+ String databaseName,
+ List tableNames);
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/test/java/com/whaleops/datasource/s3/S3DatasourceChannelTest.java b/seatunnel-datasource/seatunnel-datasource-client/src/test/java/com/whaleops/datasource/s3/S3DatasourceChannelTest.java
new file mode 100644
index 000000000..ff13771a7
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/test/java/com/whaleops/datasource/s3/S3DatasourceChannelTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.whaleops.datasource.s3;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+@Disabled
+class S3DatasourceChannelTest {
+ // private static S3DatasourceChannel S3_DATASOURCE_CHANNEL = new S3DatasourceChannel();
+
+ @Test
+ void checkDataSourceConnectivity() {
+ Assertions.assertDoesNotThrow(
+ () -> {
+ // S3_DATASOURCE_CHANNEL.checkDataSourceConnectivity("S3",
+ // createRequestParams());
+ });
+ }
+
+ private Map createRequestParams() {
+ Map requestParams =
+ new ImmutableMap.Builder()
+ .put("bucket", "s3a://poc-kuke")
+ .put("fs.s3a.endpoint", "s3.cn-north-1.amazonaws.com.cn")
+ .put(
+ "fs.s3a.aws.credentials.provider",
+ "org.apache.hadoop.fs.s3a.SimpleAWSCredentialsProvider")
+ .put("access_key", "AKIAYYUV5DMXADXRBGTA")
+ .put("secret_key", "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")
+ .put("hadoop_s3_properties", "")
+ .build();
+ return requestParams;
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-client/src/test/java/org/apache/seatunnel/datasource/DataSourceClientTest.java b/seatunnel-datasource/seatunnel-datasource-client/src/test/java/org/apache/seatunnel/datasource/DataSourceClientTest.java
new file mode 100644
index 000000000..09d0f5fb4
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-client/src/test/java/org/apache/seatunnel/datasource/DataSourceClientTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.seatunnel.datasource;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DataSourceClientTest {
+ private static final DataSourceClient DATA_SOURCE_CLIENT = new DataSourceClient();
+
+ @Test
+ public void listAllDataSources() {
+ Assertions.assertTrue(
+ DATA_SOURCE_CLIENT.listAllDataSources().stream()
+ .anyMatch(
+ dataSourcePluginInfo ->
+ StringUtils.equalsIgnoreCase(
+ dataSourcePluginInfo.getName(), "jdbc-mysql")));
+ Assertions.assertTrue(
+ DATA_SOURCE_CLIENT.listAllDataSources().stream()
+ .anyMatch(
+ dataSourcePluginInfo ->
+ StringUtils.equalsIgnoreCase(
+ dataSourcePluginInfo.getName(), "kafka")));
+ Assertions.assertTrue(
+ DATA_SOURCE_CLIENT.listAllDataSources().stream()
+ .anyMatch(
+ dataSourcePluginInfo ->
+ StringUtils.equalsIgnoreCase(
+ dataSourcePluginInfo.getName(), "elasticsearch")));
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-all/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-all/pom.xml
new file mode 100644
index 000000000..64d904df9
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-all/pom.xml
@@ -0,0 +1,112 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-all
+
+
+
+ org.apache.seatunnel
+ datasource-jdbc-clickhouse
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-hive
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-mysql
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-oracle
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-postgresql
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-tidb
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-redshift
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-sqlserver
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-jdbc-starrocks
+ ${project.version}
+
+
+
+ org.apache.seatunnel
+ datasource-kafka
+ ${project.version}
+
+
+
+ org.apache.seatunnel
+ datasource-elasticsearch
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-s3-redshift
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-starrocks
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-mysql-cdc
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-s3
+ ${project.version}
+
+
+ org.apache.seatunnel
+ datasource-sqlserver-cdc
+ ${project.version}
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/pom.xml
new file mode 100644
index 000000000..017a221ad
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-elasticsearch
+
+
+ 7.5.1
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+ org.elasticsearch.client
+ elasticsearch-rest-client
+ ${elasticsearch-rest-client.version}
+
+
+ io.airlift
+ security
+ 206
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannel.java
new file mode 100644
index 000000000..989e45fd9
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannel.java
@@ -0,0 +1,136 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.apache.seatunnel.shade.com.typesafe.config.ConfigFactory;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.elasticsearch.client.EsRestClient;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ElasticSearchDataSourceChannel implements DataSourceChannel {
+
+ private static final String DATABASE = "default";
+
+ @Override
+ public boolean canAbleGetSchema() {
+ return true;
+ }
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return ElasticSearchOptionRule.optionRule();
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return ElasticSearchOptionRule.metadataRule();
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ databaseCheck(database);
+ try (EsRestClient client =
+ EsRestClient.createInstance(ConfigFactory.parseMap(requestParams))) {
+ return client.listIndex();
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ return DEFAULT_DATABASES;
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (EsRestClient client =
+ EsRestClient.createInstance(ConfigFactory.parseMap(requestParams))) {
+ client.getClusterInfo();
+ return true;
+ } catch (Throwable e) {
+ throw new DataSourcePluginException(
+ "check ElasticSearch connectivity failed, " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ databaseCheck(database);
+ try (EsRestClient client =
+ EsRestClient.createInstance(ConfigFactory.parseMap(requestParams))) {
+ Map fieldTypeMapping = client.getFieldTypeMapping(table);
+ List fields = new ArrayList<>();
+ fieldTypeMapping.forEach(
+ (fieldName, fieldType) ->
+ fields.add(convertToTableField(fieldName, fieldType)));
+ return fields;
+ } catch (Exception ex) {
+ throw new DataSourcePluginException("Get table fields failed", ex);
+ }
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ databaseCheck(database);
+ Map> tableFields = new HashMap<>();
+ tables.forEach(
+ table ->
+ tableFields.put(
+ table, getTableFields(pluginName, requestParams, database, table)));
+ return tableFields;
+ }
+
+ private static void databaseCheck(@NonNull String database) {
+ if (!StringUtils.equalsIgnoreCase(database, DATABASE)) {
+ throw new IllegalArgumentException("database not found: " + database);
+ }
+ }
+
+ private TableField convertToTableField(String fieldName, String fieldType) {
+ TableField tableField = new TableField();
+ tableField.setName(fieldName);
+ tableField.setType(fieldType);
+ tableField.setComment(null);
+ tableField.setNullable(true);
+ tableField.setPrimaryKey(fieldName.equals("_id"));
+ tableField.setDefaultValue(null);
+ return tableField;
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceConfig.java
new file mode 100644
index 000000000..97eec189f
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceConfig.java
@@ -0,0 +1,36 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+public class ElasticSearchDataSourceConfig {
+
+ public static final String PLUGIN_NAME = "ElasticSearch";
+
+ public static final String PLUGIN_VERSION = "1.0.0";
+
+ public static final DataSourcePluginInfo ELASTICSEARCH_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon(PLUGIN_NAME)
+ .version(PLUGIN_VERSION)
+ .type(DatasourcePluginTypeEnum.NO_STRUCTURED.getCode())
+ .build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactory.java
new file mode 100644
index 000000000..f9d01cae3
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+@AutoService(DataSourceFactory.class)
+public class ElasticSearchDataSourceFactory implements DataSourceFactory {
+
+ public static final String PLUGIN_NAME = "ElasticSearch";
+
+ @Override
+ public String factoryIdentifier() {
+ return PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(ElasticSearchDataSourceConfig.ELASTICSEARCH_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new ElasticSearchDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchOptionRule.java
new file mode 100644
index 000000000..510978797
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchOptionRule.java
@@ -0,0 +1,109 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+
+import java.util.List;
+
+public class ElasticSearchOptionRule {
+
+ public static final Option> HOSTS =
+ Options.key("hosts")
+ .listType()
+ .noDefaultValue()
+ .withDescription(
+ "Elasticsearch cluster http address, the format is host:port, allowing multiple hosts to be specified. Such as [\"host1:9200\", \"host2:9200\"]");
+
+ public static final Option INDEX =
+ Options.key("index")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("Elasticsearch index name, support * fuzzy matching");
+
+ public static final Option USERNAME =
+ Options.key("username")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("x-pack username");
+
+ public static final Option PASSWORD =
+ Options.key("password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("x-pack password");
+
+ public static final Option TLS_VERIFY_CERTIFICATE =
+ Options.key("tls_verify_certificate")
+ .booleanType()
+ .defaultValue(true)
+ .withDescription("Enable certificates validation for HTTPS endpoints");
+
+ public static final Option TLS_VERIFY_HOSTNAME =
+ Options.key("tls_verify_hostname")
+ .booleanType()
+ .defaultValue(true)
+ .withDescription("Enable hostname validation for HTTPS endpoints");
+
+ public static final Option TLS_KEY_STORE_PATH =
+ Options.key("tls_keystore_path")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "The path to the PEM or JKS key store. This file must be readable by the operating system user running SeaTunnel.");
+
+ public static final Option TLS_KEY_STORE_PASSWORD =
+ Options.key("tls_keystore_password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The key password for the key store specified");
+
+ public static final Option TLS_TRUST_STORE_PATH =
+ Options.key("tls_truststore_path")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "The path to PEM or JKS trust store. This file must be readable by the operating system user running SeaTunnel.");
+
+ public static final Option TLS_TRUST_STORE_PASSWORD =
+ Options.key("tls_truststore_password")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("The key password for the trust store specified");
+
+ public static OptionRule optionRule() {
+ return OptionRule.builder()
+ .required(HOSTS)
+ .optional(
+ USERNAME,
+ PASSWORD,
+ TLS_VERIFY_CERTIFICATE,
+ TLS_VERIFY_HOSTNAME,
+ TLS_KEY_STORE_PATH,
+ TLS_KEY_STORE_PASSWORD,
+ TLS_TRUST_STORE_PATH,
+ TLS_TRUST_STORE_PASSWORD)
+ .build();
+ }
+
+ public static OptionRule metadataRule() {
+ return OptionRule.builder().required(INDEX).build();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ElasticsearchClusterInfo.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ElasticsearchClusterInfo.java
new file mode 100644
index 000000000..f02516ce9
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ElasticsearchClusterInfo.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.seatunnel.datasource.plugin.elasticsearch.client;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@Builder
+@ToString
+public class ElasticsearchClusterInfo {
+ private String distribution;
+ private String clusterVersion;
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/EsRestClient.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/EsRestClient.java
new file mode 100644
index 000000000..4de06bf4a
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/EsRestClient.java
@@ -0,0 +1,373 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch.client;
+
+import org.apache.seatunnel.shade.com.fasterxml.jackson.databind.JsonNode;
+import org.apache.seatunnel.shade.com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.seatunnel.shade.com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.seatunnel.shade.com.typesafe.config.Config;
+
+import org.apache.seatunnel.common.utils.JsonUtils;
+import org.apache.seatunnel.datasource.plugin.elasticsearch.ElasticSearchOptionRule;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.TrustAllStrategy;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.util.EntityUtils;
+
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.net.ssl.SSLContext;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class EsRestClient implements AutoCloseable {
+
+ private static final int CONNECTION_REQUEST_TIMEOUT = 10 * 1000;
+
+ private static final int SOCKET_TIMEOUT = 5 * 60 * 1000;
+
+ private final RestClient restClient;
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private EsRestClient(RestClient restClient) {
+ this.restClient = restClient;
+ }
+
+ public static EsRestClient createInstance(Config pluginConfig) {
+ try {
+ List hosts =
+ OBJECT_MAPPER.readValue(
+ pluginConfig.getString(ElasticSearchOptionRule.HOSTS.key()),
+ List.class);
+ Optional username = Optional.empty();
+ Optional password = Optional.empty();
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.USERNAME.key())) {
+ username =
+ Optional.of(pluginConfig.getString(ElasticSearchOptionRule.USERNAME.key()));
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.PASSWORD.key())) {
+ password =
+ Optional.of(
+ pluginConfig.getString(ElasticSearchOptionRule.PASSWORD.key()));
+ }
+ }
+ Optional keystorePath = Optional.empty();
+ Optional keystorePassword = Optional.empty();
+ Optional truststorePath = Optional.empty();
+ Optional truststorePassword = Optional.empty();
+ boolean tlsVerifyCertificate =
+ ElasticSearchOptionRule.TLS_VERIFY_CERTIFICATE.defaultValue();
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_VERIFY_CERTIFICATE.key())) {
+ tlsVerifyCertificate =
+ pluginConfig.getBoolean(
+ ElasticSearchOptionRule.TLS_VERIFY_CERTIFICATE.key());
+ }
+ if (tlsVerifyCertificate) {
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_KEY_STORE_PATH.key())) {
+ keystorePath =
+ Optional.of(
+ pluginConfig.getString(
+ ElasticSearchOptionRule.TLS_KEY_STORE_PATH.key()));
+ }
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_KEY_STORE_PASSWORD.key())) {
+ keystorePassword =
+ Optional.of(
+ pluginConfig.getString(
+ ElasticSearchOptionRule.TLS_KEY_STORE_PASSWORD.key()));
+ }
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_TRUST_STORE_PATH.key())) {
+ truststorePath =
+ Optional.of(
+ pluginConfig.getString(
+ ElasticSearchOptionRule.TLS_TRUST_STORE_PATH.key()));
+ }
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_TRUST_STORE_PASSWORD.key())) {
+ truststorePassword =
+ Optional.of(
+ pluginConfig.getString(
+ ElasticSearchOptionRule.TLS_TRUST_STORE_PASSWORD
+ .key()));
+ }
+ }
+ boolean tlsVerifyHostnames = ElasticSearchOptionRule.TLS_VERIFY_HOSTNAME.defaultValue();
+ if (pluginConfig.hasPath(ElasticSearchOptionRule.TLS_VERIFY_HOSTNAME.key())) {
+ tlsVerifyHostnames =
+ pluginConfig.getBoolean(ElasticSearchOptionRule.TLS_VERIFY_HOSTNAME.key());
+ }
+ return createInstance(
+ hosts,
+ username,
+ password,
+ tlsVerifyCertificate,
+ tlsVerifyHostnames,
+ keystorePath,
+ keystorePassword,
+ truststorePath,
+ truststorePassword);
+ } catch (Exception e) {
+ throw new RuntimeException("Create EsRestClient failed", e);
+ }
+ }
+
+ public static EsRestClient createInstance(
+ List hosts,
+ Optional username,
+ Optional password,
+ boolean tlsVerifyCertificate,
+ boolean tlsVerifyHostnames,
+ Optional keystorePath,
+ Optional keystorePassword,
+ Optional truststorePath,
+ Optional truststorePassword) {
+ RestClientBuilder restClientBuilder =
+ getRestClientBuilder(
+ hosts,
+ username,
+ password,
+ tlsVerifyCertificate,
+ tlsVerifyHostnames,
+ keystorePath,
+ keystorePassword,
+ truststorePath,
+ truststorePassword);
+ return new EsRestClient(restClientBuilder.build());
+ }
+
+ private static RestClientBuilder getRestClientBuilder(
+ List hosts,
+ Optional username,
+ Optional password,
+ boolean tlsVerifyCertificate,
+ boolean tlsVerifyHostnames,
+ Optional keystorePath,
+ Optional keystorePassword,
+ Optional truststorePath,
+ Optional truststorePassword) {
+ HttpHost[] httpHosts = new HttpHost[hosts.size()];
+ for (int i = 0; i < hosts.size(); i++) {
+ httpHosts[i] = HttpHost.create(hosts.get(i));
+ }
+
+ RestClientBuilder restClientBuilder =
+ RestClient.builder(httpHosts)
+ .setRequestConfigCallback(
+ requestConfigBuilder ->
+ requestConfigBuilder
+ .setConnectionRequestTimeout(
+ CONNECTION_REQUEST_TIMEOUT)
+ .setSocketTimeout(SOCKET_TIMEOUT));
+
+ restClientBuilder.setHttpClientConfigCallback(
+ httpClientBuilder -> {
+ if (username.isPresent()) {
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+ credentialsProvider.setCredentials(
+ AuthScope.ANY,
+ new UsernamePasswordCredentials(username.get(), password.get()));
+ httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
+ }
+
+ try {
+ if (tlsVerifyCertificate) {
+ Optional sslContext =
+ SSLUtils.buildSSLContext(
+ keystorePath,
+ keystorePassword,
+ truststorePath,
+ truststorePassword);
+ sslContext.ifPresent(e -> httpClientBuilder.setSSLContext(e));
+ } else {
+ SSLContext sslContext =
+ SSLContexts.custom()
+ .loadTrustMaterial(new TrustAllStrategy())
+ .build();
+ httpClientBuilder.setSSLContext(sslContext);
+ }
+ if (!tlsVerifyHostnames) {
+ httpClientBuilder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return httpClientBuilder;
+ });
+ return restClientBuilder;
+ }
+
+ public ElasticsearchClusterInfo getClusterInfo() {
+ Request request = new Request("GET", "/");
+ try {
+ Response response = restClient.performRequest(request);
+ String result = EntityUtils.toString(response.getEntity());
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(result);
+ JsonNode versionNode = jsonNode.get("version");
+ return ElasticsearchClusterInfo.builder()
+ .clusterVersion(versionNode.get("number").asText())
+ .distribution(
+ Optional.ofNullable(versionNode.get("distribution"))
+ .map(JsonNode::asText)
+ .orElse(null))
+ .build();
+ } catch (IOException e) {
+ throw new ResponseException("fail to get elasticsearch version.", e);
+ }
+ }
+
+ public void close() {
+ try {
+ restClient.close();
+ } catch (IOException e) {
+ log.warn("close elasticsearch connection error", e);
+ }
+ }
+
+ public List listIndex() {
+ String endpoint = "/_cat/indices?format=json";
+ Request request = new Request("GET", endpoint);
+ try {
+ Response response = restClient.performRequest(request);
+ if (response == null) {
+ throw new ResponseException("GET " + endpoint + " response null");
+ }
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ String entity = EntityUtils.toString(response.getEntity());
+ return JsonUtils.toList(entity, Map.class).stream()
+ .map(map -> map.get("index").toString())
+ .collect(Collectors.toList());
+ } else {
+ throw new ResponseException(
+ String.format(
+ "GET %s response status code=%d",
+ endpoint, response.getStatusLine().getStatusCode()));
+ }
+ } catch (IOException ex) {
+ throw new ResponseException(ex);
+ }
+ }
+
+ public void dropIndex(String tableName) {
+ String endpoint = String.format("/%s", tableName);
+ Request request = new Request("DELETE", endpoint);
+ try {
+ Response response = restClient.performRequest(request);
+ if (response == null) {
+ throw new ResponseException("DELETE " + endpoint + " response null");
+ }
+ // todo: if the index doesn't exist, the response status code is 200?
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ throw new ResponseException(
+ String.format(
+ "DELETE %s response status code=%d",
+ endpoint, response.getStatusLine().getStatusCode()));
+ }
+ } catch (IOException ex) {
+ throw new ResponseException(ex);
+ }
+ }
+
+ /**
+ * get es field name and type mapping relation
+ *
+ * @param index index name
+ * @return {key-> field name,value->es type}
+ */
+ public Map getFieldTypeMapping(String index) {
+ String endpoint = String.format("/%s/_mappings", index);
+ Request request = new Request("GET", endpoint);
+ Map mapping = new HashMap<>();
+ try {
+ Response response = restClient.performRequest(request);
+ if (response == null) {
+ throw new ResponseException("GET " + endpoint + " response null");
+ }
+ if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ throw new ResponseException(
+ String.format(
+ "GET %s response status code=%d",
+ endpoint, response.getStatusLine().getStatusCode()));
+ }
+ String entity = EntityUtils.toString(response.getEntity());
+ log.info(String.format("GET %s response=%s", endpoint, entity));
+ ObjectNode responseJson = JsonUtils.parseObject(entity);
+ for (Iterator it = responseJson.elements(); it.hasNext(); ) {
+ JsonNode indexProperty = it.next();
+ JsonNode mappingsProperty = indexProperty.get("mappings");
+ if (mappingsProperty.has("mappingsProperty")) {
+ JsonNode properties = mappingsProperty.get("properties");
+ mapping = getFieldTypeMappingFromProperties(properties);
+ } else {
+ for (JsonNode typeNode : mappingsProperty) {
+ JsonNode properties;
+ if (typeNode.has("properties")) {
+ properties = typeNode.get("properties");
+ } else {
+ properties = typeNode;
+ }
+ mapping.putAll(getFieldTypeMappingFromProperties(properties));
+ }
+ }
+ }
+ } catch (IOException ex) {
+ throw new ResponseException(ex);
+ }
+ return mapping;
+ }
+
+ private static Map getFieldTypeMappingFromProperties(JsonNode properties) {
+ Map mapping = new HashMap<>();
+ for (Iterator it = properties.fieldNames(); it.hasNext(); ) {
+ String field = it.next();
+ JsonNode fieldProperty = properties.get(field);
+ if (fieldProperty == null) {
+ mapping.put(field, "text");
+ } else {
+ if (fieldProperty.has("type")) {
+ String type = fieldProperty.get("type").asText();
+ mapping.put(field, type);
+ } else {
+ log.warn(
+ String.format(
+ "fail to get elasticsearch field %s mapping type,so give a default type text",
+ field));
+ mapping.put(field, "text");
+ }
+ }
+ }
+ return mapping;
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ResponseException.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ResponseException.java
new file mode 100644
index 000000000..59417cb70
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/ResponseException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch.client;
+
+public class ResponseException extends RuntimeException {
+
+ public ResponseException() {
+ super();
+ }
+
+ public ResponseException(String message) {
+ super(message);
+ }
+
+ public ResponseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ResponseException(Throwable cause) {
+ super(cause);
+ }
+
+ protected ResponseException(
+ String message,
+ Throwable cause,
+ boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/SSLUtils.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/SSLUtils.java
new file mode 100644
index 000000000..8f3caa204
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/main/java/org/apache/seatunnel/datasource/plugin/elasticsearch/client/SSLUtils.java
@@ -0,0 +1,165 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch.client;
+
+import io.airlift.security.pem.PemReader;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.x500.X500Principal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import static java.util.Collections.list;
+
+@SuppressWarnings("MagicNumber")
+public final class SSLUtils {
+
+ public static Optional buildSSLContext(
+ Optional keyStorePath,
+ Optional keyStorePassword,
+ Optional trustStorePath,
+ Optional trustStorePassword)
+ throws GeneralSecurityException, IOException {
+ if (!keyStorePath.isPresent() && !trustStorePath.isPresent()) {
+ return Optional.empty();
+ }
+ return Optional.of(
+ createSSLContext(
+ keyStorePath, keyStorePassword, trustStorePath, trustStorePassword));
+ }
+
+ private static SSLContext createSSLContext(
+ Optional keyStorePath,
+ Optional keyStorePassword,
+ Optional trustStorePath,
+ Optional trustStorePassword)
+ throws GeneralSecurityException, IOException {
+ // load KeyStore if configured and get KeyManagers
+ KeyStore keyStore = null;
+ KeyManager[] keyManagers = null;
+ if (keyStorePath.isPresent()) {
+ File keyStoreFile = new File(keyStorePath.get());
+ char[] keyManagerPassword;
+ try {
+ // attempt to read the key store as a PEM file
+ keyStore = PemReader.loadKeyStore(keyStoreFile, keyStoreFile, keyStorePassword);
+ // for PEM encoded keys, the password is used to decrypt the specific key (and does
+ // not protect the keystore itself)
+ keyManagerPassword = new char[0];
+ } catch (IOException | GeneralSecurityException ignored) {
+ keyManagerPassword = keyStorePassword.map(String::toCharArray).orElse(null);
+
+ keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ try (InputStream in = new FileInputStream(keyStoreFile)) {
+ keyStore.load(in, keyManagerPassword);
+ }
+ }
+ validateCertificates(keyStore);
+ KeyManagerFactory keyManagerFactory =
+ KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(keyStore, keyManagerPassword);
+ keyManagers = keyManagerFactory.getKeyManagers();
+ }
+
+ // load TrustStore if configured, otherwise use KeyStore
+ KeyStore trustStore = keyStore;
+ if (trustStorePath.isPresent()) {
+ File trustStoreFile = new File(trustStorePath.get());
+ trustStore = loadTrustStore(trustStoreFile, trustStorePassword);
+ }
+
+ // create TrustManagerFactory
+ TrustManagerFactory trustManagerFactory =
+ TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(trustStore);
+
+ // get X509TrustManager
+ TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+ if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
+ throw new RuntimeException(
+ "Unexpected default trust managers:" + Arrays.toString(trustManagers));
+ }
+ // create SSLContext
+ SSLContext result = SSLContext.getInstance("SSL");
+ result.init(keyManagers, trustManagers, null);
+ return result;
+ }
+
+ private static KeyStore loadTrustStore(File trustStorePath, Optional trustStorePassword)
+ throws IOException, GeneralSecurityException {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ try {
+ // attempt to read the trust store as a PEM file
+ List certificateChain = PemReader.readCertificateChain(trustStorePath);
+ if (!certificateChain.isEmpty()) {
+ trustStore.load(null, null);
+ for (X509Certificate certificate : certificateChain) {
+ X500Principal principal = certificate.getSubjectX500Principal();
+ trustStore.setCertificateEntry(principal.getName(), certificate);
+ }
+ return trustStore;
+ }
+ } catch (IOException | GeneralSecurityException ignored) {
+ // ignored
+ }
+
+ try (InputStream in = new FileInputStream(trustStorePath)) {
+ trustStore.load(in, trustStorePassword.map(String::toCharArray).orElse(null));
+ }
+ return trustStore;
+ }
+
+ private static void validateCertificates(KeyStore keyStore) throws GeneralSecurityException {
+ for (String alias : list(keyStore.aliases())) {
+ if (!keyStore.isKeyEntry(alias)) {
+ continue;
+ }
+ Certificate certificate = keyStore.getCertificate(alias);
+ if (!(certificate instanceof X509Certificate)) {
+ continue;
+ }
+
+ try {
+ ((X509Certificate) certificate).checkValidity();
+ } catch (CertificateExpiredException e) {
+ throw new CertificateExpiredException(
+ "KeyStore certificate is expired: " + e.getMessage());
+ } catch (CertificateNotYetValidException e) {
+ throw new CertificateNotYetValidException(
+ "KeyStore certificate is not yet valid: " + e.getMessage());
+ }
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannelTest.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannelTest.java
new file mode 100644
index 000000000..b888a1ff7
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceChannelTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+import java.util.List;
+import java.util.Map;
+
+// todo: use testcontainer to create container
+@Disabled
+class ElasticSearchDataSourceChannelTest {
+ private static final Logger LOGGER =
+ LoggerFactory.getLogger(ElasticSearchDataSourceChannelTest.class);
+
+ private static final ElasticSearchDataSourceChannel ELASTIC_SEARCH_DATA_SOURCE_CHANNEL =
+ new ElasticSearchDataSourceChannel();
+
+ private static final String PLUGIN_NAME = "ElasticSearch";
+
+ private static final String DATABASE = "Default";
+
+ private static final Map REQUEST_MAP =
+ new ImmutableMap.Builder()
+ .put(ElasticSearchOptionRule.HOSTS.key(), "[\"http://localhost:9200\"]")
+ .build();
+
+ @Test
+ void canAbleGetSchema() {
+ Assertions.assertTrue(ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.canAbleGetSchema());
+ }
+
+ @Test
+ void getDataSourceOptions() {
+ Assertions.assertNotNull(
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getDataSourceOptions(PLUGIN_NAME));
+ }
+
+ @Test
+ void getDatasourceMetadataFieldsByDataSourceName() {
+ Assertions.assertNotNull(
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getDatasourceMetadataFieldsByDataSourceName(
+ PLUGIN_NAME));
+ }
+
+ @Test
+ void getTables() {
+ Assertions.assertDoesNotThrow(
+ () -> {
+ List tables =
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getTables(
+ PLUGIN_NAME, REQUEST_MAP, DATABASE);
+ LOGGER.info("{}", tables);
+ });
+ }
+
+ @Test
+ void getDatabases() {
+ Assertions.assertLinesMatch(
+ Lists.newArrayList("default"),
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getDatabases(PLUGIN_NAME, REQUEST_MAP));
+ }
+
+ @Test
+ void checkDataSourceConnectivity() {
+ Assertions.assertTrue(
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.checkDataSourceConnectivity(
+ PLUGIN_NAME, REQUEST_MAP));
+ }
+
+ @Test
+ void getTableFields() {
+ Assertions.assertDoesNotThrow(
+ () -> {
+ List tableFields =
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getTableFields(
+ PLUGIN_NAME, REQUEST_MAP, DATABASE, "");
+ LOGGER.info("{}", tableFields);
+ });
+ }
+
+ @Test
+ void testGetTableFields() {
+ Assertions.assertDoesNotThrow(
+ () -> {
+ Map> tableFields =
+ ELASTIC_SEARCH_DATA_SOURCE_CHANNEL.getTableFields(
+ PLUGIN_NAME, REQUEST_MAP, DATABASE, Lists.newArrayList(""));
+ LOGGER.info("{}", tableFields);
+ });
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactoryTest.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactoryTest.java
new file mode 100644
index 000000000..0441d7a12
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-elasticsearch/src/test/java/org/apache/seatunnel/datasource/plugin/elasticsearch/ElasticSearchDataSourceFactoryTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.seatunnel.datasource.plugin.elasticsearch;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ElasticSearchDataSourceFactoryTest {
+
+ private static final ElasticSearchDataSourceFactory ELASTIC_SEARCH_DATA_SOURCE_FACTORY =
+ new ElasticSearchDataSourceFactory();
+
+ @Test
+ void factoryIdentifier() {
+ Assertions.assertEquals(
+ "ElasticSearch", ELASTIC_SEARCH_DATA_SOURCE_FACTORY.factoryIdentifier());
+ }
+
+ @Test
+ void supportedDataSources() {
+ Assertions.assertFalse(ELASTIC_SEARCH_DATA_SOURCE_FACTORY.supportedDataSources().isEmpty());
+ }
+
+ @Test
+ void createChannel() {
+ Assertions.assertNotNull(ELASTIC_SEARCH_DATA_SOURCE_FACTORY.createChannel());
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/pom.xml
new file mode 100644
index 000000000..6537afe7c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-clickhouse
+
+
+ 0.3.2-patch11
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+
+
+ com.clickhouse
+ clickhouse-jdbc
+ ${clickhouse.version}
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseDataSourceConfig.java
new file mode 100644
index 000000000..4c5b3b2e7
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseDataSourceConfig.java
@@ -0,0 +1,59 @@
+/*
+ * 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.seatunnel.datasource.plugin.clickhouse.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class ClickhouseDataSourceConfig {
+ public static final String PLUGIN_NAME = "JDBC-ClickHouse";
+
+ public static final DataSourcePluginInfo CLICKHOUSE_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon(PLUGIN_NAME)
+ .version("1.0.0")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .supportVirtualTables(false)
+ .build();
+
+ public static final Set CLICKHOUSE_SYSTEM_DATABASES =
+ Sets.newHashSet(
+ "system",
+ "default",
+ "information_schema",
+ "mysql",
+ "performance_schema",
+ "sys");
+
+ public static final OptionRule OPTION_RULE =
+ OptionRule.builder()
+ .required(ClickhouseOptionRule.URL, ClickhouseOptionRule.DRIVER)
+ .optional(ClickhouseOptionRule.USER, ClickhouseOptionRule.PASSWORD)
+ .build();
+
+ public static final OptionRule METADATA_RULE =
+ OptionRule.builder()
+ .required(ClickhouseOptionRule.DATABASE, ClickhouseOptionRule.TABLE)
+ .build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceChannel.java
new file mode 100644
index 000000000..ef160afbc
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceChannel.java
@@ -0,0 +1,178 @@
+/*
+ * 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.seatunnel.datasource.plugin.clickhouse.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.api.utils.JdbcUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Slf4j
+public class ClickhouseJdbcDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return ClickhouseDataSourceConfig.OPTION_RULE;
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return ClickhouseDataSourceConfig.METADATA_RULE;
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ List tableNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams); ) {
+ ResultSet resultSet =
+ connection
+ .getMetaData()
+ .getTables(database, null, null, new String[] {"TABLE"});
+ while (resultSet.next()) {
+ String tableName = resultSet.getString("TABLE_NAME");
+ if (StringUtils.isNotBlank(tableName)) {
+ tableNames.add(tableName);
+ }
+ }
+ return tableNames;
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ Statement statement = connection.createStatement();
+ ResultSet re = statement.executeQuery("SHOW DATABASES;")) {
+ // filter system databases
+ while (re.next()) {
+ String dbName = re.getString("name");
+ if (StringUtils.isNotBlank(dbName)
+ && !ClickhouseDataSourceConfig.CLICKHOUSE_SYSTEM_DATABASES.contains(
+ dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ } catch (Exception ex) {
+ throw new RuntimeException("get databases failed", ex);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (Connection ignored = getConnection(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException("Check jdbc connectivity failed", e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database)) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, database, table);
+ try (ResultSet resultSet = metaData.getColumns(database, null, table, null)) {
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ tableField.setNullable(Boolean.TRUE.toString().equals(nullable.toString()));
+ tableFields.add(tableField);
+ }
+ }
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("Get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ return null;
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ private Connection getConnection(Map requestParams)
+ throws SQLException, ClassNotFoundException {
+ return getConnection(requestParams, null);
+ }
+
+ private Connection getConnection(Map requestParams, String databaseName)
+ throws SQLException, ClassNotFoundException {
+ checkNotNull(requestParams.get(ClickhouseOptionRule.DRIVER.key()));
+ checkNotNull(requestParams.get(ClickhouseOptionRule.URL.key()), "Jdbc url cannot be null");
+ String url =
+ JdbcUtils.replaceDatabase(
+ requestParams.get(ClickhouseOptionRule.URL.key()), databaseName);
+ if (requestParams.containsKey(ClickhouseOptionRule.USER.key())) {
+ String username = requestParams.get(ClickhouseOptionRule.USER.key());
+ String password = requestParams.get(ClickhouseOptionRule.PASSWORD.key());
+ return DriverManager.getConnection(url, username, password);
+ }
+ return DriverManager.getConnection(url);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceFactory.java
new file mode 100644
index 000000000..f8b979864
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseJdbcDataSourceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.seatunnel.datasource.plugin.clickhouse.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Set;
+
+@Slf4j
+@AutoService(DataSourceFactory.class)
+public class ClickhouseJdbcDataSourceFactory implements DataSourceFactory {
+
+ @Override
+ public String factoryIdentifier() {
+ return ClickhouseDataSourceConfig.PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(ClickhouseDataSourceConfig.CLICKHOUSE_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new ClickhouseJdbcDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseOptionRule.java
new file mode 100644
index 000000000..f02e6030d
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-clickhouse/src/main/java/org/apache/seatunnel/datasource/plugin/clickhouse/jdbc/ClickhouseOptionRule.java
@@ -0,0 +1,68 @@
+/*
+ * 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.seatunnel.datasource.plugin.clickhouse.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+
+public class ClickhouseOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "jdbc url, eg:"
+ + "jdbc:clickhouse://localhost:8123/test?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
+
+ public static final Option USER =
+ Options.key("user").stringType().noDefaultValue().withDescription("jdbc user");
+
+ public static final Option PASSWORD =
+ Options.key("password").stringType().noDefaultValue().withDescription("jdbc password");
+
+ public static final Option DATABASE =
+ Options.key("database").stringType().noDefaultValue().withDescription("jdbc database");
+
+ public static final Option TABLE =
+ Options.key("table").stringType().noDefaultValue().withDescription("jdbc table");
+
+ public static final Option DRIVER =
+ Options.key("driver")
+ .enumType(DriverType.class)
+ .noDefaultValue()
+ .withDescription("driver");
+
+ public enum DriverType {
+ ClickHouse("ru.yandex.clickhouse.ClickHouseDriver");
+ private final String driverClassName;
+
+ DriverType(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ @Override
+ public String toString() {
+ return driverClassName;
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/pom.xml
new file mode 100644
index 000000000..32dce470d
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/pom.xml
@@ -0,0 +1,36 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-hive
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcConstants.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcConstants.java
new file mode 100644
index 000000000..8b133ac7d
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcConstants.java
@@ -0,0 +1,29 @@
+/*
+ * 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.seatunnel.datasource.plugin.hive.jdbc;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class HiveJdbcConstants {
+
+ public static final Set HIVE_SYSTEM_DATABASES =
+ Sets.newHashSet(
+ "information_schema", "mysql", "performance_schema", "sys", "test", "hivedb");
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceChannel.java
new file mode 100644
index 000000000..62559037d
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceChannel.java
@@ -0,0 +1,216 @@
+/*
+ * 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.seatunnel.datasource.plugin.hive.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class HiveJdbcDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return HiveJdbcOptionRule.optionRule();
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return HiveJdbcOptionRule.metadataRule();
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ return getTables(pluginName, requestParams, database);
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try {
+ return getDataBaseNames(pluginName, requestParams);
+ } catch (SQLException e) {
+ log.error("Query Hive databases error, request params is {}", requestParams, e);
+ throw new DataSourcePluginException("Query Hive databases error,", e);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ return checkJdbcConnectivity(requestParams);
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ return getTableFields(requestParams, database, table);
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ Map> tableFields = new HashMap<>(tables.size());
+ for (String table : tables) {
+ tableFields.put(table, getTableFields(requestParams, database, table));
+ }
+ return tableFields;
+ }
+
+ protected boolean checkJdbcConnectivity(Map requestParams) {
+ try (Connection ignored = init(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException(
+ "check jdbc connectivity failed, " + e.getMessage(), e);
+ }
+ }
+
+ protected Connection init(Map requestParams) throws SQLException {
+ if (MapUtils.isEmpty(requestParams)) {
+ throw new DataSourcePluginException(
+ "Hive jdbc request params is null, please check your config");
+ }
+ String url = requestParams.get(HiveJdbcOptionRule.URL.key());
+ return DriverManager.getConnection(url);
+ }
+
+ protected List getDataBaseNames(String pluginName, Map requestParams)
+ throws SQLException {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = init(requestParams);
+ Statement statement = connection.createStatement(); ) {
+ ResultSet re = statement.executeQuery("SHOW DATABASES;");
+ // filter system databases
+ while (re.next()) {
+ String dbName = re.getString("database");
+ if (StringUtils.isNotBlank(dbName) && isNotSystemDatabase(pluginName, dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ }
+ }
+
+ protected List getTableNames(Map requestParams, String dbName) {
+ List tableNames = new ArrayList<>();
+ try (Connection connection = init(requestParams); ) {
+ ResultSet resultSet =
+ connection.getMetaData().getTables(dbName, null, null, new String[] {"TABLE"});
+ while (resultSet.next()) {
+ String tableName = resultSet.getString("TABLE_NAME");
+ if (StringUtils.isNotBlank(tableName)) {
+ tableNames.add(tableName);
+ }
+ }
+ return tableNames;
+ } catch (SQLException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ protected List getTableFields(
+ Map requestParams, String dbName, String tableName) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = init(requestParams); ) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, dbName, tableName);
+ ResultSet resultSet = metaData.getColumns(dbName, null, tableName, null);
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ boolean isNullable = convertToBoolean(nullable);
+ tableField.setNullable(isNullable);
+ tableFields.add(tableField);
+ }
+ } catch (SQLException e) {
+ throw new DataSourcePluginException("get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ @SuppressWarnings("checkstyle:MagicNumber")
+ private static boolean checkHostConnectable(String host, int port) {
+ try (Socket socket = new Socket()) {
+ socket.connect(new InetSocketAddress(host, port), 1000);
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ private boolean isNotSystemDatabase(String pluginName, String dbName) {
+ // FIXME,filters system databases
+ return true;
+ }
+
+ private boolean convertToBoolean(Object value) {
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+ if (value instanceof String) {
+ return value.equals("TRUE");
+ }
+ return false;
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceFactory.java
new file mode 100644
index 000000000..b149cc3b7
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcDataSourceFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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.seatunnel.datasource.plugin.hive.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class HiveJdbcDataSourceFactory implements DataSourceFactory {
+ @Override
+ public String factoryIdentifier() {
+ return "Hive-JDBC";
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ DataSourcePluginInfo dataSourcePluginInfo =
+ DataSourcePluginInfo.builder()
+ .name("Hive-JDBC")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .version("1.0.0")
+ .icon("Hive-JDBC")
+ .supportVirtualTables(false)
+ .build();
+ Set dataSourceInfos = new HashSet<>();
+ dataSourceInfos.add(dataSourcePluginInfo);
+ return dataSourceInfos;
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new HiveJdbcDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcOptionRule.java
new file mode 100644
index 000000000..fb004b69f
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-hive/src/main/java/org/apache/seatunnel/datasource/plugin/hive/jdbc/HiveJdbcOptionRule.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.seatunnel.datasource.plugin.hive.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+
+public class HiveJdbcOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "jdbc url, eg:"
+ + "jdbc:hive2://localhost:10000/default?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
+
+ public static OptionRule optionRule() {
+ return OptionRule.builder().required(URL).build();
+ }
+
+ public static OptionRule metadataRule() {
+ // todo
+ return OptionRule.builder().build();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/pom.xml
new file mode 100644
index 000000000..39a6fa462
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-mysql
+
+
+ 8.0.28
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+
+
+ mysql
+ mysql-connector-java
+ ${mysql-connector.version}
+ provided
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlDataSourceConfig.java
new file mode 100644
index 000000000..03d6d0cf3
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlDataSourceConfig.java
@@ -0,0 +1,51 @@
+/*
+ * 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.seatunnel.datasource.plugin.mysql.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class MysqlDataSourceConfig {
+
+ public static final String PLUGIN_NAME = "JDBC-Mysql";
+
+ public static final DataSourcePluginInfo MYSQL_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon(PLUGIN_NAME)
+ .version("1.0.0")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .build();
+
+ public static final Set MYSQL_SYSTEM_DATABASES =
+ Sets.newHashSet("information_schema", "mysql", "performance_schema", "sys");
+
+ public static final OptionRule OPTION_RULE =
+ OptionRule.builder()
+ .required(MysqlOptionRule.URL, MysqlOptionRule.DRIVER)
+ .optional(MysqlOptionRule.USER, MysqlOptionRule.PASSWORD)
+ .build();
+
+ public static final OptionRule METADATA_RULE =
+ OptionRule.builder().required(MysqlOptionRule.DATABASE, MysqlOptionRule.TABLE).build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceChannel.java
new file mode 100644
index 000000000..99ab042b9
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceChannel.java
@@ -0,0 +1,183 @@
+/*
+ * 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.seatunnel.datasource.plugin.mysql.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.api.utils.JdbcUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class MysqlJdbcDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return MysqlDataSourceConfig.OPTION_RULE;
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return MysqlDataSourceConfig.METADATA_RULE;
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ List tableNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ ResultSet resultSet =
+ connection
+ .getMetaData()
+ .getTables(database, null, null, new String[] {"TABLE"})) {
+ while (resultSet.next()) {
+ String tableName = resultSet.getString("TABLE_NAME");
+ if (StringUtils.isNotBlank(tableName)) {
+ tableNames.add(tableName);
+ }
+ }
+ return tableNames;
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ PreparedStatement statement = connection.prepareStatement("SHOW DATABASES;");
+ ResultSet re = statement.executeQuery()) {
+ // filter system databases
+ while (re.next()) {
+ String dbName = re.getString("database");
+ if (StringUtils.isNotBlank(dbName)
+ && !MysqlDataSourceConfig.MYSQL_SYSTEM_DATABASES.contains(dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("Get databases failed", e);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (Connection ignored = getConnection(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException("check jdbc connectivity failed", e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database)) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, database, table);
+ try (ResultSet resultSet = metaData.getColumns(database, null, table, null)) {
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ tableField.setNullable(Boolean.TRUE.toString().equals(nullable.toString()));
+ tableFields.add(tableField);
+ }
+ }
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ return tables.parallelStream()
+ .collect(
+ Collectors.toMap(
+ Function.identity(),
+ table ->
+ getTableFields(
+ pluginName, requestParams, database, table)));
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ private Connection getConnection(Map requestParams)
+ throws SQLException, ClassNotFoundException {
+ return getConnection(requestParams, null);
+ }
+
+ private Connection getConnection(Map requestParams, String databaseName)
+ throws SQLException, ClassNotFoundException {
+ checkNotNull(requestParams.get(MysqlOptionRule.DRIVER.key()));
+ checkNotNull(requestParams.get(MysqlOptionRule.URL.key()), "Jdbc url cannot be null");
+ String url =
+ JdbcUtils.replaceDatabase(
+ requestParams.get(MysqlOptionRule.URL.key()), databaseName);
+ if (requestParams.containsKey(MysqlOptionRule.USER.key())) {
+ String username = requestParams.get(MysqlOptionRule.USER.key());
+ String password = requestParams.get(MysqlOptionRule.PASSWORD.key());
+ return DriverManager.getConnection(url, username, password);
+ }
+ return DriverManager.getConnection(url);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceFactory.java
new file mode 100644
index 000000000..31f6439bf
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlJdbcDataSourceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.seatunnel.datasource.plugin.mysql.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Set;
+
+@Slf4j
+@AutoService(DataSourceFactory.class)
+public class MysqlJdbcDataSourceFactory implements DataSourceFactory {
+
+ @Override
+ public String factoryIdentifier() {
+ return MysqlDataSourceConfig.PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(MysqlDataSourceConfig.MYSQL_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new MysqlJdbcDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlOptionRule.java
new file mode 100644
index 000000000..e34696410
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-mysql/src/main/java/org/apache/seatunnel/datasource/plugin/mysql/jdbc/MysqlOptionRule.java
@@ -0,0 +1,69 @@
+/*
+ * 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.seatunnel.datasource.plugin.mysql.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+
+public class MysqlOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "jdbc url, eg:"
+ + " jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
+
+ public static final Option USER =
+ Options.key("user").stringType().noDefaultValue().withDescription("jdbc user");
+
+ public static final Option PASSWORD =
+ Options.key("password").stringType().noDefaultValue().withDescription("jdbc password");
+
+ public static final Option DATABASE =
+ Options.key("database").stringType().noDefaultValue().withDescription("jdbc database");
+
+ public static final Option TABLE =
+ Options.key("table").stringType().noDefaultValue().withDescription("jdbc table");
+
+ public static final Option DRIVER =
+ Options.key("driver")
+ .enumType(DriverType.class)
+ .defaultValue(DriverType.MYSQL)
+ .withDescription("driver");
+
+ public enum DriverType {
+ MYSQL("com.mysql.cj.jdbc.Driver"),
+ ;
+ private final String driverClassName;
+
+ DriverType(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ @Override
+ public String toString() {
+ return driverClassName;
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/pom.xml
new file mode 100644
index 000000000..9e108276c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-oracle
+
+
+ 21.5.0.0
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+
+
+ com.oracle.database.jdbc
+ ojdbc8
+ ${oracle-jdbc.version}
+ provided
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceChannel.java
new file mode 100644
index 000000000..87a04fcf6
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceChannel.java
@@ -0,0 +1,175 @@
+/*
+ * 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.seatunnel.datasource.plugin.oracle.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.api.utils.JdbcUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class OracleDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return OracleDataSourceConfig.OPTION_RULE;
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return OracleDataSourceConfig.METADATA_RULE;
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ List tableNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ ResultSet resultSet =
+ connection
+ .getMetaData()
+ .getTables(database, null, null, new String[] {"TABLE"}); ) {
+ while (resultSet.next()) {
+ String tableName = resultSet.getString("TABLE_NAME");
+ if (StringUtils.isNotBlank(tableName)) {
+ tableNames.add(tableName);
+ }
+ }
+ return tableNames;
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ PreparedStatement statement = connection.prepareStatement("SHOW DATABASES;");
+ ResultSet re = statement.executeQuery()) {
+ // filter system databases
+ while (re.next()) {
+ String dbName = re.getString("database");
+ if (StringUtils.isNotBlank(dbName)
+ && !OracleDataSourceConfig.ORACLE_SYSTEM_DATABASES.contains(dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ } catch (Exception ex) {
+ throw new RuntimeException("get databases failed", ex);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (Connection ignored = getConnection(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException("check jdbc connectivity failed", e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database)) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, database, table);
+ try (ResultSet resultSet = metaData.getColumns(database, null, table, null)) {
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ tableField.setNullable(Boolean.TRUE.toString().equals(nullable.toString()));
+ tableFields.add(tableField);
+ }
+ }
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DataSourcePluginException("get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ return null;
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ private Connection getConnection(Map requestParams)
+ throws SQLException, ClassNotFoundException {
+ return getConnection(requestParams, null);
+ }
+
+ private Connection getConnection(Map requestParams, String databaseName)
+ throws SQLException, ClassNotFoundException {
+ checkNotNull(requestParams.get(OracleOptionRule.DRIVER.key()));
+ checkNotNull(requestParams.get(OracleOptionRule.URL.key()), "Jdbc url cannot be null");
+ String url =
+ JdbcUtils.replaceDatabase(
+ requestParams.get(OracleOptionRule.URL.key()), databaseName);
+ if (requestParams.containsKey(OracleOptionRule.USER.key())) {
+ String username = requestParams.get(OracleOptionRule.USER.key());
+ String password = requestParams.get(OracleOptionRule.PASSWORD.key());
+ return DriverManager.getConnection(url, username, password);
+ }
+ return DriverManager.getConnection(url);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceConfig.java
new file mode 100644
index 000000000..83455b6d7
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleDataSourceConfig.java
@@ -0,0 +1,53 @@
+/*
+ * 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.seatunnel.datasource.plugin.oracle.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class OracleDataSourceConfig {
+
+ public static final String PLUGIN_NAME = "JDBC-Oracle";
+
+ public static final DataSourcePluginInfo ORACLE_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon(PLUGIN_NAME)
+ .version("1.0.0")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .build();
+
+ public static final Set ORACLE_SYSTEM_DATABASES =
+ Sets.newHashSet("SYS", "SYSTEM", "SYSDBA", "SYSOPER", "HR", "SCOTT");
+
+ public static final OptionRule OPTION_RULE =
+ OptionRule.builder()
+ .required(OracleOptionRule.URL, OracleOptionRule.DRIVER)
+ .optional(OracleOptionRule.USER, OracleOptionRule.PASSWORD)
+ .build();
+
+ public static final OptionRule METADATA_RULE =
+ OptionRule.builder()
+ .required(OracleOptionRule.DATABASE, OracleOptionRule.TABLE)
+ .build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleJdbcDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleJdbcDataSourceFactory.java
new file mode 100644
index 000000000..b6a0aec9c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleJdbcDataSourceFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.seatunnel.datasource.plugin.oracle.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Set;
+
+@Slf4j
+@AutoService(DataSourceFactory.class)
+public class OracleJdbcDataSourceFactory implements DataSourceFactory {
+ @Override
+ public String factoryIdentifier() {
+ return OracleDataSourceConfig.PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(OracleDataSourceConfig.ORACLE_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new OracleDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleOptionRule.java
new file mode 100644
index 000000000..f3ec40e33
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-oracle/src/main/java/org/apache/seatunnel/datasource/plugin/oracle/jdbc/OracleOptionRule.java
@@ -0,0 +1,67 @@
+/*
+ * 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.seatunnel.datasource.plugin.oracle.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+
+public class OracleOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription("jdbc url, eg:" + "jdbc:oracle:thin:@localhost:1521:XE");
+
+ public static final Option USER =
+ Options.key("user").stringType().noDefaultValue().withDescription("jdbc user");
+
+ public static final Option PASSWORD =
+ Options.key("password").stringType().noDefaultValue().withDescription("jdbc password");
+
+ public static final Option DATABASE =
+ Options.key("database").stringType().noDefaultValue().withDescription("jdbc database");
+
+ public static final Option TABLE =
+ Options.key("table").stringType().noDefaultValue().withDescription("jdbc table");
+
+ public static final Option DRIVER =
+ Options.key("driver")
+ .enumType(DriverType.class)
+ .defaultValue(DriverType.ORACLE)
+ .withDescription("driver");
+
+ public enum DriverType {
+ ORACLE("oracle.jdbc.driver.OracleDriver"),
+ ;
+ private final String driverClassName;
+
+ DriverType(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ @Override
+ public String toString() {
+ return driverClassName;
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/pom.xml
new file mode 100644
index 000000000..9b07fb21a
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-postgresql
+
+
+ 42.4.3
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ provided
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceChannel.java
new file mode 100644
index 000000000..e43939536
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceChannel.java
@@ -0,0 +1,185 @@
+/*
+ * 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.seatunnel.datasource.plugin.postgresql.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.api.utils.JdbcUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class PostgresqlDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return PostgresqlDataSourceConfig.OPTION_RULE;
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return PostgresqlDataSourceConfig.METADATA_RULE;
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ List tableNames = new ArrayList<>();
+ String query = "SELECT table_schema, table_name FROM information_schema.tables";
+ try (Connection connection = getConnection(requestParams, database)) {
+ try (Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery(query)) {
+ while (resultSet.next()) {
+ String schemaName = resultSet.getString("table_schema");
+ String tableName = resultSet.getString("table_name");
+ if (StringUtils.isNotBlank(schemaName)
+ && !PostgresqlDataSourceConfig.POSTGRESQL_SYSTEM_DATABASES.contains(
+ schemaName)) {
+ tableNames.add(schemaName + "." + tableName);
+ }
+ }
+ }
+ return tableNames;
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ PreparedStatement statement =
+ connection.prepareStatement("select datname from pg_database;");
+ ResultSet re = statement.executeQuery()) {
+ while (re.next()) {
+ String dbName = re.getString("datname");
+ if (StringUtils.isNotBlank(dbName)
+ && !PostgresqlDataSourceConfig.POSTGRESQL_SYSTEM_DATABASES.contains(
+ dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get databases failed", e);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (Connection ignored = getConnection(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException("check jdbc connectivity failed", e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database); ) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, database, table);
+ String[] split = table.split("\\.");
+ if (split.length != 2) {
+ throw new DataSourcePluginException(
+ "Postgresql tableName should composed by schemaName.tableName");
+ }
+ try (ResultSet resultSet = metaData.getColumns(database, split[0], split[1], null)) {
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ tableField.setNullable(Boolean.TRUE.toString().equals(nullable.toString()));
+ tableFields.add(tableField);
+ }
+ }
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ return null;
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ private Connection getConnection(Map requestParams)
+ throws SQLException, ClassNotFoundException {
+ return getConnection(requestParams, null);
+ }
+
+ private Connection getConnection(Map requestParams, String databaseName)
+ throws SQLException, ClassNotFoundException {
+ checkNotNull(requestParams.get(PostgresqlOptionRule.DRIVER.key()));
+ checkNotNull(requestParams.get(PostgresqlOptionRule.URL.key()), "Jdbc url cannot be null");
+ String url =
+ JdbcUtils.replaceDatabase(
+ requestParams.get(PostgresqlOptionRule.URL.key()), databaseName);
+ if (requestParams.containsKey(PostgresqlOptionRule.USER.key())) {
+ String username = requestParams.get(PostgresqlOptionRule.USER.key());
+ String password = requestParams.get(PostgresqlOptionRule.PASSWORD.key());
+ return DriverManager.getConnection(url, username, password);
+ }
+ return DriverManager.getConnection(url);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceConfig.java
new file mode 100644
index 000000000..f150ab5d0
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceConfig.java
@@ -0,0 +1,62 @@
+/*
+ * 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.seatunnel.datasource.plugin.postgresql.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class PostgresqlDataSourceConfig {
+
+ public static final String PLUGIN_NAME = "JDBC-Postgres";
+
+ public static final DataSourcePluginInfo POSTGRESQL_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon(PLUGIN_NAME)
+ .version("1.0.0")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .build();
+
+ public static final Set POSTGRESQL_SYSTEM_DATABASES =
+ Sets.newHashSet(
+ "information_schema",
+ "pg_catalog",
+ "root",
+ "pg_toast",
+ "pg_temp_1",
+ "pg_toast_temp_1",
+ "postgres",
+ "template0",
+ "template1");
+
+ public static final OptionRule OPTION_RULE =
+ OptionRule.builder()
+ .required(PostgresqlOptionRule.URL, PostgresqlOptionRule.DRIVER)
+ .optional(PostgresqlOptionRule.USER, PostgresqlOptionRule.PASSWORD)
+ .build();
+
+ public static final OptionRule METADATA_RULE =
+ OptionRule.builder()
+ .required(PostgresqlOptionRule.DATABASE, PostgresqlOptionRule.TABLE)
+ .build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceFactory.java
new file mode 100644
index 000000000..13dd7847c
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlDataSourceFactory.java
@@ -0,0 +1,46 @@
+/*
+ * 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.seatunnel.datasource.plugin.postgresql.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+@AutoService(DataSourceFactory.class)
+public class PostgresqlDataSourceFactory implements DataSourceFactory {
+
+ @Override
+ public String factoryIdentifier() {
+ return PostgresqlDataSourceConfig.PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(PostgresqlDataSourceConfig.POSTGRESQL_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new PostgresqlDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlOptionRule.java
new file mode 100644
index 000000000..748c4ea79
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-postgresql/src/main/java/org/apache/seatunnel/datasource/plugin/postgresql/jdbc/PostgresqlOptionRule.java
@@ -0,0 +1,69 @@
+/*
+ * 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.seatunnel.datasource.plugin.postgresql.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+
+public class PostgresqlOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "jdbc url, eg:"
+ + "jdbc:postgresql://localhost:5432//test?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
+
+ public static final Option USER =
+ Options.key("user").stringType().noDefaultValue().withDescription("jdbc user");
+
+ public static final Option PASSWORD =
+ Options.key("password").stringType().noDefaultValue().withDescription("jdbc password");
+
+ public static final Option DATABASE =
+ Options.key("database").stringType().noDefaultValue().withDescription("jdbc database");
+
+ public static final Option TABLE =
+ Options.key("table").stringType().noDefaultValue().withDescription("jdbc table");
+
+ public static final Option DRIVER =
+ Options.key("driver")
+ .enumType(DriverType.class)
+ .defaultValue(DriverType.POSTGRESQL)
+ .withDescription("driver");
+
+ public enum DriverType {
+ POSTGRESQL("org.postgresql.Driver"),
+ ;
+ private final String driverClassName;
+
+ DriverType(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ @Override
+ public String toString() {
+ return driverClassName;
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/pom.xml
new file mode 100644
index 000000000..440e4a451
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-redshift
+
+
+ 2.1.0.10
+
+
+
+
+ org.apache.seatunnel
+ datasource-plugins-api
+ ${project.version}
+ provided
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ com.google.auto.service
+ auto-service
+
+
+ org.apache.seatunnel
+ seatunnel-api
+ provided
+
+
+
+
+ com.amazon.redshift
+ redshift-jdbc42
+ ${redshift.version}
+ provided
+
+
+
+
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceChannel.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceChannel.java
new file mode 100644
index 000000000..0e3dfa709
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceChannel.java
@@ -0,0 +1,181 @@
+/*
+ * 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.seatunnel.datasource.plugin.redshift.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginException;
+import org.apache.seatunnel.datasource.plugin.api.model.TableField;
+import org.apache.seatunnel.datasource.plugin.api.utils.JdbcUtils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.NonNull;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class RedshiftDataSourceChannel implements DataSourceChannel {
+
+ @Override
+ public OptionRule getDataSourceOptions(@NonNull String pluginName) {
+ return RedshiftDataSourceConfig.OPTION_RULE;
+ }
+
+ @Override
+ public OptionRule getDatasourceMetadataFieldsByDataSourceName(@NonNull String pluginName) {
+ return RedshiftDataSourceConfig.METADATA_RULE;
+ }
+
+ @Override
+ public List getTables(
+ @NonNull String pluginName, Map requestParams, String database) {
+ List tableNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database);
+ ResultSet resultSet =
+ connection.getMetaData().getTables(database, null, null, null); ) {
+ while (resultSet.next()) {
+ String schemaName = resultSet.getString("TABLE_SCHEM");
+ String tableName = resultSet.getString("TABLE_NAME");
+ // todo: use isNotSystemSchemaName
+ if (StringUtils.isNotBlank(schemaName)
+ && !RedshiftDataSourceConfig.REDSHIFT_SYSTEM_TABLES.contains(schemaName)) {
+ tableNames.add(schemaName + "." + tableName);
+ }
+ }
+ return tableNames;
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get table names failed", e);
+ }
+ }
+
+ @Override
+ public List getDatabases(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ List dbNames = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams);
+ PreparedStatement statement =
+ connection.prepareStatement("select datname from pg_database;");
+ ResultSet re = statement.executeQuery()) {
+ while (re.next()) {
+ String dbName = re.getString("datname");
+ if (StringUtils.isNotBlank(dbName)
+ && !RedshiftDataSourceConfig.REDSHIFT_SYSTEM_TABLES.contains(dbName)) {
+ dbNames.add(dbName);
+ }
+ }
+ return dbNames;
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get databases failed", e);
+ }
+ }
+
+ @Override
+ public boolean checkDataSourceConnectivity(
+ @NonNull String pluginName, @NonNull Map requestParams) {
+ try (Connection ignored = getConnection(requestParams)) {
+ return true;
+ } catch (Exception e) {
+ throw new DataSourcePluginException("check jdbc connectivity failed", e);
+ }
+ }
+
+ @Override
+ public List getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull String table) {
+ List tableFields = new ArrayList<>();
+ try (Connection connection = getConnection(requestParams, database); ) {
+ DatabaseMetaData metaData = connection.getMetaData();
+ String primaryKey = getPrimaryKey(metaData, database, table);
+ String[] split = table.split("\\.");
+ if (split.length != 2) {
+ throw new DataSourcePluginException(
+ "Postgresql tableName should composed by schemaName.tableName");
+ }
+ try (ResultSet resultSet = metaData.getColumns(database, split[0], split[1], null)) {
+ while (resultSet.next()) {
+ TableField tableField = new TableField();
+ String columnName = resultSet.getString("COLUMN_NAME");
+ tableField.setPrimaryKey(false);
+ if (StringUtils.isNotBlank(primaryKey) && primaryKey.equals(columnName)) {
+ tableField.setPrimaryKey(true);
+ }
+ tableField.setName(columnName);
+ tableField.setType(resultSet.getString("TYPE_NAME"));
+ tableField.setComment(resultSet.getString("REMARKS"));
+ Object nullable = resultSet.getObject("IS_NULLABLE");
+ tableField.setNullable(Boolean.TRUE.toString().equals(nullable.toString()));
+ tableFields.add(tableField);
+ }
+ }
+ } catch (SQLException | ClassNotFoundException e) {
+ throw new DataSourcePluginException("get table fields failed", e);
+ }
+ return tableFields;
+ }
+
+ @Override
+ public Map> getTableFields(
+ @NonNull String pluginName,
+ @NonNull Map requestParams,
+ @NonNull String database,
+ @NonNull List tables) {
+ return null;
+ }
+
+ private String getPrimaryKey(DatabaseMetaData metaData, String dbName, String tableName)
+ throws SQLException {
+ ResultSet primaryKeysInfo = metaData.getPrimaryKeys(dbName, "%", tableName);
+ while (primaryKeysInfo.next()) {
+ return primaryKeysInfo.getString("COLUMN_NAME");
+ }
+ return null;
+ }
+
+ private Connection getConnection(Map requestParams)
+ throws SQLException, ClassNotFoundException {
+ return getConnection(requestParams, null);
+ }
+
+ private Connection getConnection(Map requestParams, String databaseName)
+ throws SQLException, ClassNotFoundException {
+ checkNotNull(requestParams.get(RedshiftOptionRule.DRIVER.key()));
+ checkNotNull(requestParams.get(RedshiftOptionRule.URL.key()), "Jdbc url cannot be null");
+ String url =
+ JdbcUtils.replaceDatabase(
+ requestParams.get(RedshiftOptionRule.URL.key()), databaseName);
+ if (requestParams.containsKey(RedshiftOptionRule.USER.key())) {
+ String username = requestParams.get(RedshiftOptionRule.USER.key());
+ String password = requestParams.get(RedshiftOptionRule.PASSWORD.key());
+ return DriverManager.getConnection(url, username, password);
+ }
+ return DriverManager.getConnection(url);
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceConfig.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceConfig.java
new file mode 100644
index 000000000..b5561f09e
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceConfig.java
@@ -0,0 +1,62 @@
+/*
+ * 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.seatunnel.datasource.plugin.redshift.jdbc;
+
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.plugin.api.DatasourcePluginTypeEnum;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+public class RedshiftDataSourceConfig {
+
+ public static final String PLUGIN_NAME = "JDBC-Redshift";
+
+ public static final DataSourcePluginInfo REDSHIFT_DATASOURCE_PLUGIN_INFO =
+ DataSourcePluginInfo.builder()
+ .name(PLUGIN_NAME)
+ .icon("redshift")
+ .version("1.0.0")
+ .type(DatasourcePluginTypeEnum.DATABASE.getCode())
+ .build();
+
+ public static final Set REDSHIFT_SYSTEM_TABLES =
+ Sets.newHashSet(
+ "information_schema",
+ "pg_catalog",
+ "root",
+ "pg_toast",
+ "pg_temp_1",
+ "pg_toast_temp_1",
+ "postgres",
+ "template0",
+ "template1");
+
+ public static final OptionRule OPTION_RULE =
+ OptionRule.builder()
+ .required(RedshiftOptionRule.URL, RedshiftOptionRule.DRIVER)
+ .optional(RedshiftOptionRule.USER, RedshiftOptionRule.PASSWORD)
+ .build();
+
+ public static final OptionRule METADATA_RULE =
+ OptionRule.builder()
+ .required(RedshiftOptionRule.DATABASE, RedshiftOptionRule.TABLE)
+ .build();
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceFactory.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceFactory.java
new file mode 100644
index 000000000..bf33a24c3
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftDataSourceFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.seatunnel.datasource.plugin.redshift.jdbc;
+
+import org.apache.seatunnel.datasource.plugin.api.DataSourceChannel;
+import org.apache.seatunnel.datasource.plugin.api.DataSourceFactory;
+import org.apache.seatunnel.datasource.plugin.api.DataSourcePluginInfo;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Sets;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Set;
+
+@Slf4j
+@AutoService(DataSourceFactory.class)
+public class RedshiftDataSourceFactory implements DataSourceFactory {
+
+ @Override
+ public String factoryIdentifier() {
+ return RedshiftDataSourceConfig.PLUGIN_NAME;
+ }
+
+ @Override
+ public Set supportedDataSources() {
+ return Sets.newHashSet(RedshiftDataSourceConfig.REDSHIFT_DATASOURCE_PLUGIN_INFO);
+ }
+
+ @Override
+ public DataSourceChannel createChannel() {
+ return new RedshiftDataSourceChannel();
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftOptionRule.java b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftOptionRule.java
new file mode 100644
index 000000000..c4f389545
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-redshift/src/main/java/org/apache/seatunnel/datasource/plugin/redshift/jdbc/RedshiftOptionRule.java
@@ -0,0 +1,69 @@
+/*
+ * 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.seatunnel.datasource.plugin.redshift.jdbc;
+
+import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.Options;
+
+public class RedshiftOptionRule {
+
+ public static final Option URL =
+ Options.key("url")
+ .stringType()
+ .noDefaultValue()
+ .withDescription(
+ "jdbc url, eg:"
+ + "jdbc:redshift://server.redshift.amazonaws.com:5439/test?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
+
+ public static final Option USER =
+ Options.key("user").stringType().noDefaultValue().withDescription("jdbc user");
+
+ public static final Option PASSWORD =
+ Options.key("password").stringType().noDefaultValue().withDescription("jdbc password");
+
+ public static final Option DATABASE =
+ Options.key("database").stringType().noDefaultValue().withDescription("jdbc database");
+
+ public static final Option TABLE =
+ Options.key("table").stringType().noDefaultValue().withDescription("jdbc table");
+
+ public static final Option DRIVER =
+ Options.key("driver")
+ .enumType(DriverType.class)
+ .defaultValue(DriverType.JDBC42_REDSHIFT)
+ .withDescription("driver");
+
+ public enum DriverType {
+ JDBC42_REDSHIFT("com.amazon.redshift.jdbc42.Driver"),
+ ;
+ private final String driverClassName;
+
+ DriverType(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ @Override
+ public String toString() {
+ return driverClassName;
+ }
+ }
+}
diff --git a/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-sqlserver/pom.xml b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-sqlserver/pom.xml
new file mode 100644
index 000000000..1ff5b6bca
--- /dev/null
+++ b/seatunnel-datasource/seatunnel-datasource-plugins/datasource-jdbc-sqlserver/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ org.apache.seatunnel
+ seatunnel-datasource-plugins
+ ${revision}
+
+
+ datasource-jdbc-sqlserver
+
+
+ 9.2.1.jre8
+
+
+
+
+