Add datasource base api and checkstyle (#3)

* Add datasource base api and checkstyle

* Update ThreadSafe.java

* Update pom.xml
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index aa1e4df..9cf4836 100644
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -17,3 +17,4 @@
 
 distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
 wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
+
diff --git a/datasource-client/pom.xml b/datasource-client/pom.xml
index 7eb4466..c621a0d 100644
--- a/datasource-client/pom.xml
+++ b/datasource-client/pom.xml
@@ -1,4 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -10,5 +24,27 @@
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>datasource-client</artifactId>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-properties</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+    </dependencies>
 
-</project>
\ No newline at end of file
+</project>
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.java
new file mode 100644
index 0000000..e7e9072
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/annotation/ThreadSafe.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.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/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/AbstractSeaTunnelDataSourceClient.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/AbstractSeaTunnelDataSourceClient.java
new file mode 100644
index 0000000..97a6a47
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/AbstractSeaTunnelDataSourceClient.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.client;
+
+import org.apache.seatunnel.datasource.service.SeaTunnelDataSourceService;
+
+import javax.sql.DataSource;
+
+public abstract class AbstractSeaTunnelDataSourceClient implements SeaTunnelDataSourceService {
+
+    protected DataSource dataSource;
+
+    public AbstractSeaTunnelDataSourceClient(DataSource dataSource) {
+        this.dataSource = dataSource;
+        // need init all plugins?
+        initPlugins();
+    }
+
+    private void initPlugins() {
+        // init all plugins
+    }
+
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSource.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSource.java
index 46123e4..278a26c 100644
--- a/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSource.java
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSource.java
@@ -1,4 +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.client;
 
-public interface SeaTunnelDataSource {
+import org.apache.seatunnel.datasource.service.SeaTunnelAutoTableService;
+import org.apache.seatunnel.datasource.service.SeaTunnelDataSourceService;
+
+import javax.sql.DataSource;
+
+import java.util.concurrent.ConcurrentMap;
+
+public abstract class SeaTunnelDataSource implements SeaTunnelDataSourceService, SeaTunnelAutoTableService {
+
+    /**
+     * The data source. we use this to get the connection.
+     * if you want to use the connection pool, you can use the connection pool to get the connection.
+     */
+    protected DataSource dataSource;
+
+    // do not need to init all plugins?
+    protected ConcurrentMap<String, SeaTunnelAutoTableService> dataSourceMetaDataServicePluginMap;
+
 }
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSourceClient.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSourceClient.java
new file mode 100644
index 0000000..46dd654
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SeaTunnelDataSourceClient.java
@@ -0,0 +1,130 @@
+/*
+ * 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.client;
+
+import org.apache.seatunnel.datasource.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.model.DataSource;
+import org.apache.seatunnel.datasource.model.DataSourcePluginInfo;
+import org.apache.seatunnel.datasource.model.Table;
+import org.apache.seatunnel.datasource.service.SeaTunnelAutoTableService;
+import org.apache.seatunnel.datasource.service.SeaTunnelTableService;
+
+import java.util.List;
+import java.util.Map;
+
+public class SeaTunnelDataSourceClient extends AbstractSeaTunnelDataSourceClient implements SeaTunnelTableService, SeaTunnelAutoTableService {
+
+    public SeaTunnelDataSourceClient(javax.sql.DataSource dataSource) {
+        super(dataSource);
+    }
+
+    @Override
+    public List<DataSourcePluginInfo> listAllDataSources() {
+        return null;
+    }
+
+    @Override
+    public OptionRule queryDataSourceFieldByName(String dataSourceName) {
+        return null;
+    }
+
+    @Override
+    public Boolean checkDataSourceFields(Map<String, Object> parameters) {
+        return null;
+    }
+
+    @Override
+    public DataSource queryDataSourceById(Long dataSourceId) {
+        return null;
+    }
+
+    @Override
+    public Boolean saveDataSource(String dataSourceName, String comment, String pluginName, Map<String, Object> parameters) {
+        return false;
+    }
+
+    @Override
+    public Boolean deleteDataSource(Long id) {
+        return false;
+    }
+
+    @Override
+    public Boolean updateDataSource(Long dataSourceId, String dataSourceName, String comment, Map<String, Object> parameters) {
+        return false;
+    }
+
+    @Override
+    public Boolean checkDataSourceConnectivity(Map<String, Object> dataSourceParams) {
+        return null;
+    }
+
+    @Override
+    public OptionRule getDataSourceMetadataFieldsByDataSourceName(String dataSourceName) {
+        return null;
+    }
+
+    @Override
+    public OptionRule getDataSourceMetadataFieldsByDataSourceId(String dataSourceId) {
+        return null;
+    }
+
+    @Override
+    public List<String> getTables(String dataSourceId, Map<String, Object> requestParams) {
+        return null;
+    }
+
+    @Override
+    public List<String> getDatabases(String dataSourceId, Map<String, Object> requestParams) {
+        return null;
+    }
+
+    @Override
+    public Table getTable(String dataSourceId, Map<String, Object> requestParams) {
+        return null;
+    }
+
+    @Override
+    public Boolean createTable(Long datasourceId, String databaseName, String tableName, Map<String, String> tableFields, String description) {
+        return null;
+    }
+
+    @Override
+    public Boolean dropSchema(String schemaId) {
+        return null;
+    }
+
+    @Override
+    public Table getTable(Long datasourceId, String databaseName, String tableName) {
+        return null;
+    }
+
+    @Override
+    public List<String> getTableNames(Long datasourceId, String databaseName) {
+        return null;
+    }
+
+    @Override
+    public List<String> getDatabaseNames(Long datasourceId) {
+        return null;
+    }
+
+    @Override
+    public List<Table> getTables(String datasourceId, String databaseName) {
+        return null;
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SimpleSeaTunnelDataSourceClient.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SimpleSeaTunnelDataSourceClient.java
new file mode 100644
index 0000000..6e1689f
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/client/SimpleSeaTunnelDataSourceClient.java
@@ -0,0 +1,75 @@
+/*
+ * 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.client;
+
+import org.apache.seatunnel.datasource.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.model.DataSource;
+import org.apache.seatunnel.datasource.model.DataSourcePluginInfo;
+
+import java.util.List;
+import java.util.Map;
+
+public class SimpleSeaTunnelDataSourceClient extends AbstractSeaTunnelDataSourceClient {
+
+    /**
+     * init datasource pool
+     */
+    public SimpleSeaTunnelDataSourceClient(javax.sql.DataSource dataSource) {
+        super(dataSource);
+    }
+
+    @Override
+    public List<DataSourcePluginInfo> listAllDataSources() {
+        return null;
+    }
+
+    @Override
+    public OptionRule queryDataSourceFieldByName(String dataSourceName) {
+        return null;
+    }
+
+    @Override
+    public Boolean checkDataSourceFields(Map<String, Object> parameters) {
+        return null;
+    }
+
+    @Override
+    public DataSource queryDataSourceById(Long dataSourceId) {
+        return null;
+    }
+
+    @Override
+    public Boolean saveDataSource(String dataSourceName, String comment, String pluginName, Map<String, Object> parameters) {
+        return false;
+    }
+
+    @Override
+    public Boolean deleteDataSource(Long id) {
+        return false;
+    }
+
+    @Override
+    public Boolean updateDataSource(Long dataSourceId, String dataSourceName, String comment, Map<String, Object> parameters) {
+        return false;
+    }
+
+    @Override
+    public Boolean checkDataSourceConnectivity(Map<String, Object> dataSourceParams) {
+        return null;
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Option.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Option.java
new file mode 100644
index 0000000..cfe22cb
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Option.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.datasource.configuration;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+import java.util.Objects;
+
+public class Option<T> {
+    /**
+     * The current key for that config option.
+     */
+    private final String key;
+
+    /**
+     * Type of the value that this Option describes.
+     */
+    private final TypeReference<T> typeReference;
+
+    /**
+     * The default value for this option.
+     */
+    private final T defaultValue;
+
+    /**
+     * The description for this option.
+     */
+    String description = "";
+
+    public Option(String key, TypeReference<T> typeReference, T defaultValue) {
+        this.key = key;
+        this.typeReference = typeReference;
+        this.defaultValue = defaultValue;
+    }
+
+    public String key() {
+        return key;
+    }
+
+    public TypeReference<T> typeReference() {
+        return typeReference;
+    }
+
+    public T defaultValue() {
+        return defaultValue;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Option<T> withDescription(String description) {
+        this.description = description;
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Option)) {
+            return false;
+        }
+        Option<?> that = (Option<?>) obj;
+        return Objects.equals(this.key, that.key) && Objects.equals(this.defaultValue, that.defaultValue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.key, this.defaultValue);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Key: '%s', default: %s", key, defaultValue);
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Options.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Options.java
new file mode 100644
index 0000000..89e8cee
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/Options.java
@@ -0,0 +1,208 @@
+/*
+ * 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.configuration;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Type;
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+public class Options {
+
+    /**
+     * Starts building a new {@link Option}.
+     *
+     * @param key The key for the config option.
+     * @return The builder for the config option with the given key.
+     */
+    public static OptionBuilder key(String key) {
+        checkArgument(StringUtils.isNotBlank(key), "Option's key not be null.");
+        return new OptionBuilder(key);
+    }
+
+    /**
+     * The option builder is used to create a {@link Option}. It is instantiated via {@link
+     * Options#key(String)}.
+     */
+    public static final class OptionBuilder {
+        private final String key;
+
+        /**
+         * Creates a new OptionBuilder.
+         *
+         * @param key The key for the config option
+         */
+        OptionBuilder(String key) {
+            this.key = key;
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Boolean} type.
+         */
+        public TypedOptionBuilder<Boolean> booleanType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Boolean>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Integer} type.
+         */
+        public TypedOptionBuilder<Integer> intType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Integer>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Long} type.
+         */
+        public TypedOptionBuilder<Long> longType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Long>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Float} type.
+         */
+        public TypedOptionBuilder<Float> floatType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Float>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Double} type.
+         */
+        public TypedOptionBuilder<Double> doubleType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Double>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link String} type.
+         */
+        public TypedOptionBuilder<String> stringType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<String>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Duration} type.
+         */
+        public TypedOptionBuilder<Duration> durationType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Duration>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be of {@link Enum} type.
+         *
+         * @param enumClass Concrete type of the expected enum.
+         */
+        public <T extends Enum<T>> TypedOptionBuilder<T> enumType(Class<T> enumClass) {
+            return new TypedOptionBuilder<>(key, new TypeReference<T>() {
+                @Override
+                public Type getType() {
+                    return enumClass;
+                }
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be a set of properties, which can be
+         * represented as {@code Map<String, String>}.
+         */
+        public TypedOptionBuilder<Map<String, String>> mapType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<Map<String, String>>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be a list of properties, which can be
+         * represented as {@code List<String>}.
+         */
+        public TypedOptionBuilder<List<String>> listType() {
+            return new TypedOptionBuilder<>(key, new TypeReference<List<String>>() {
+            });
+        }
+
+        /**
+         * Defines that the value of the option should be a list of properties, which can be
+         * represented as {@code List<T>}.
+         */
+        public <T> TypedOptionBuilder<List<T>> listType(Class<T> option) {
+            return new TypedOptionBuilder<>(key, new TypeReference<List<T>>() {
+            });
+        }
+
+        public <T> TypedOptionBuilder<T> objectType(Class<T> option) {
+            return new TypedOptionBuilder<>(key, new TypeReference<T>() {
+                @Override
+                public Type getType() {
+                    return option;
+                }
+            });
+        }
+
+        /**
+         * The value of the definition option should be represented as T.
+         *
+         * @param typeReference complex type reference
+         */
+        public <T> TypedOptionBuilder<T> type(TypeReference<T> typeReference) {
+            return new TypedOptionBuilder<>(key, typeReference);
+        }
+    }
+
+    /**
+     * Builder for {@link Option} with a defined atomic type.
+     *
+     * @param <T> atomic type of the option
+     */
+    public static class TypedOptionBuilder<T> {
+        private final String key;
+        private final TypeReference<T> typeReference;
+
+        TypedOptionBuilder(String key, TypeReference<T> typeReference) {
+            this.key = key;
+            this.typeReference = typeReference;
+        }
+
+        /**
+         * Creates a Option with the given default value.
+         *
+         * @param value The default value for the config option
+         * @return The config option with the default value.
+         */
+        public Option<T> defaultValue(T value) {
+            return new Option<>(key, typeReference, value);
+        }
+
+        /**
+         * Creates a Option without a default value.
+         *
+         * @return The config option without a default value.
+         */
+        public Option<T> noDefaultValue() {
+            return new Option<>(key, typeReference, null);
+        }
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/ReadonlyConfig.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/ReadonlyConfig.java
new file mode 100644
index 0000000..6d15148
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/ReadonlyConfig.java
@@ -0,0 +1,123 @@
+/*
+ * 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.configuration;
+
+import static org.apache.seatunnel.datasource.configuration.util.ConfigUtil.convertToJsonString;
+import static org.apache.seatunnel.datasource.configuration.util.ConfigUtil.convertValue;
+import static org.apache.seatunnel.datasource.configuration.util.ConfigUtil.flatteningMap;
+import static org.apache.seatunnel.datasource.configuration.util.ConfigUtil.treeMap;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class ReadonlyConfig implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private static final ObjectMapper JACKSON_MAPPER = new ObjectMapper();
+
+    /**
+     * Stores the concrete key/value pairs of this configuration object.
+     */
+    protected final Map<String, Object> confData;
+
+    private ReadonlyConfig(Map<String, Object> confData) {
+        this.confData = confData;
+    }
+
+    public static ReadonlyConfig fromMap(Map<String, Object> map) {
+        return new ReadonlyConfig(treeMap(map));
+    }
+
+    public <T> T get(Option<T> option) {
+        return getOptional(option).orElseGet(option::defaultValue);
+    }
+
+    public Map<String, String> toMap() {
+        if (confData.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, String> result = new HashMap<>();
+        toMap(result);
+        return result;
+    }
+
+    public void toMap(Map<String, String> result) {
+        if (confData.isEmpty()) {
+            return;
+        }
+        Map<String, Object> flatteningMap = flatteningMap(confData);
+        for (Map.Entry<String, Object> entry : flatteningMap.entrySet()) {
+            result.put(entry.getKey(), convertToJsonString(entry.getValue()));
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> Optional<T> getOptional(Option<T> option) {
+        if (option == null) {
+            throw new NullPointerException("Option not be null.");
+        }
+        String[] keys = option.key().split("\\.");
+        Map<String, Object> data = this.confData;
+        Object value = null;
+        for (int i = 0; i < keys.length; i++) {
+            value = data.get(keys[i]);
+            if (i < keys.length - 1) {
+                if (!(value instanceof Map)) {
+                    return Optional.empty();
+                } else {
+                    data = (Map<String, Object>) value;
+                }
+            }
+        }
+        if (value == null) {
+            return Optional.empty();
+        }
+        return Optional.of(convertValue(value, option.typeReference()));
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 0;
+        for (String s : this.confData.keySet()) {
+            hash ^= s.hashCode();
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof ReadonlyConfig)) {
+            return false;
+        }
+        Map<String, Object> otherConf = ((ReadonlyConfig) obj).confData;
+        return this.confData.equals(otherConf);
+    }
+
+    @Override
+    public String toString() {
+        return convertToJsonString(this.confData);
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Condition.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Condition.java
new file mode 100644
index 0000000..42832ea
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Condition.java
@@ -0,0 +1,142 @@
+/*
+ * 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.configuration.util;
+
+import org.apache.seatunnel.datasource.configuration.Option;
+
+import java.util.Objects;
+
+public class Condition<T> {
+    private final Option<T> option;
+    private final T expectValue;
+    private Boolean and = null;
+    private Condition<?> next = null;
+
+    Condition(Option<T> option, T expectValue) {
+        this.option = option;
+        this.expectValue = expectValue;
+    }
+
+    public static <T> Condition<T> of(Option<T> option, T expectValue) {
+        return new Condition<>(option, expectValue);
+    }
+
+    public <E> Condition<T> and(Option<E> option, E expectValue) {
+        return and(of(option, expectValue));
+    }
+
+    public <E> Condition<T> or(Option<E> option, E expectValue) {
+        return or(of(option, expectValue));
+    }
+
+    public Condition<T> and(Condition<?> next) {
+        addCondition(true, next);
+        return this;
+    }
+
+    public Condition<T> or(Condition<?> next) {
+        addCondition(false, next);
+        return this;
+    }
+
+    private void addCondition(boolean and, Condition<?> next) {
+        Condition<?> tail = getTailCondition();
+        tail.and = and;
+        tail.next = next;
+    }
+
+    protected int getCount() {
+        int i = 1;
+        Condition<?> cur = this;
+        while (cur.hasNext()) {
+            i++;
+            cur = cur.next;
+        }
+        return i;
+    }
+
+    Condition<?> getTailCondition() {
+        return hasNext() ? this.next.getTailCondition() : this;
+    }
+
+    public boolean hasNext() {
+        return this.next != null;
+    }
+
+    public Condition<?> getNext() {
+        return this.next;
+    }
+
+    public Option<T> getOption() {
+        return option;
+    }
+
+    public T getExpectValue() {
+        return expectValue;
+    }
+
+    public Boolean and() {
+        return this.and;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Condition)) {
+            return false;
+        }
+        Condition<?> that = (Condition<?>) obj;
+        return Objects.equals(this.option, that.option)
+            && Objects.equals(this.expectValue, that.expectValue)
+            && Objects.equals(this.and, that.and)
+            && Objects.equals(this.next, that.next);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.option, this.expectValue, this.and, this.next);
+    }
+
+    @Override
+    public String toString() {
+        Condition<?> cur = this;
+        StringBuilder builder = new StringBuilder();
+        boolean bracket = false;
+        do {
+            builder.append("'")
+                .append(cur.option.key())
+                // TODO: support another condition
+                .append("' == ")
+                .append(cur.expectValue);
+            if (bracket) {
+                builder = new StringBuilder(String.format("(%s)", builder));
+                bracket = false;
+            }
+            if (cur.hasNext()) {
+                if (cur.next.hasNext() && !cur.and.equals(cur.next.and)) {
+                    bracket = true;
+                }
+                builder.append(cur.and ? " && " : " || ");
+            }
+            cur = cur.next;
+        } while (cur != null);
+        return builder.toString();
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/ConfigUtil.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/ConfigUtil.java
new file mode 100644
index 0000000..cfbf331
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/ConfigUtil.java
@@ -0,0 +1,174 @@
+/*
+ * 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.configuration.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class ConfigUtil {
+    private static final JavaPropsMapper PROPERTIES_MAPPER = new JavaPropsMapper();
+    private static final ObjectMapper JACKSON_MAPPER = new ObjectMapper();
+
+    /**
+     * <pre>
+     * poll.timeout = 1000
+     *                      ==>>  poll : {timeout = 1000, interval = 500}
+     * poll.interval = 500
+     * </pre>
+     */
+    public static Map<String, Object> treeMap(Object rawMap) {
+        try {
+            return PROPERTIES_MAPPER.readValue(PROPERTIES_MAPPER.writeValueAsString(rawMap), new TypeReference<Map<String, Object>>() {
+            });
+        } catch (JsonProcessingException e) {
+            throw new IllegalArgumentException("Json parsing exception.");
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static Object flatteningMap(Object rawValue, Map<String, Object> newMap, List<String> keys, boolean nestedMap) {
+        if (rawValue == null) {
+            return null;
+        }
+        if (!(rawValue instanceof List) && !(rawValue instanceof Map)) {
+            if (newMap == null) {
+                return rawValue;
+            }
+            newMap.put(String.join(".", keys), rawValue);
+            return newMap;
+        }
+
+        if (rawValue instanceof List) {
+            List<Object> rawList = (List<Object>) rawValue;
+            rawList.replaceAll(value -> flatteningMap(value, null, null, false));
+            if (newMap != null) {
+                newMap.put(String.join(".", keys), rawList);
+                return newMap;
+            }
+            return rawList;
+        } else {
+            Map<String, Object> rawMap = (Map<String, Object>) rawValue;
+            if (!nestedMap) {
+                keys = new ArrayList<>();
+                newMap = new HashMap<>(rawMap.size());
+            }
+            for (Map.Entry<String, Object> entry : rawMap.entrySet()) {
+                keys.add(entry.getKey());
+                flatteningMap(entry.getValue(), newMap, keys, true);
+                keys.remove(keys.size() - 1);
+            }
+            return newMap;
+        }
+    }
+
+    /**
+     * <pre>
+     *                                                  poll.timeout = 1000
+     * poll : {timeout = 1000, interval = 500}  ==>>
+     *                                                  poll.interval = 500
+     * </pre>
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> flatteningMap(Map<String, Object> treeMap) {
+        return (Map<String, Object>) flatteningMapWithObject(treeMap);
+    }
+
+    static Object flatteningMapWithObject(Object rawValue) {
+        return flatteningMap(rawValue, null, null, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T convertValue(Object rawValue, TypeReference<T> typeReference) {
+        rawValue = flatteningMapWithObject(rawValue);
+        if (typeReference.getType() instanceof Class) {
+            // simple type
+            Class<T> clazz = (Class<T>) typeReference.getType();
+            if (clazz.equals(rawValue.getClass())) {
+                return (T) rawValue;
+            }
+            try {
+                return convertValue(rawValue, clazz);
+            } catch (IllegalArgumentException e) {
+                // Continue with Jackson parsing
+            }
+        }
+        try {
+            // complex type && untreated type
+            return JACKSON_MAPPER.readValue(convertToJsonString(rawValue), typeReference);
+        } catch (JsonProcessingException e) {
+            throw new IllegalArgumentException(String.format("Json parsing exception, value '%s', and expected type '%s'", rawValue, typeReference.getType().getTypeName()), e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T> T convertValue(Object rawValue, Class<T> clazz) {
+        if (Boolean.class.equals(clazz)) {
+            return (T) convertToBoolean(rawValue);
+        } else if (clazz.isEnum()) {
+            return (T) convertToEnum(rawValue, (Class<? extends Enum<?>>) clazz);
+        } else if (String.class.equals(clazz)) {
+            return (T) convertToJsonString(rawValue);
+        }
+        throw new IllegalArgumentException("Unsupported type: " + clazz);
+    }
+
+    static Boolean convertToBoolean(Object o) {
+        switch (o.toString().toUpperCase()) {
+            case "TRUE":
+                return true;
+            case "FALSE":
+                return false;
+            default:
+                throw new IllegalArgumentException(
+                    String.format(
+                        "Unrecognized option for boolean: %s. Expected either true or false(case insensitive)",
+                        o));
+        }
+    }
+
+    static <E extends Enum<?>> E convertToEnum(Object o, Class<E> clazz) {
+        return Arrays.stream(clazz.getEnumConstants())
+            .filter(e -> e.toString()
+                .toUpperCase(Locale.ROOT)
+                .equals(o.toString().toUpperCase(Locale.ROOT)))
+            .findAny()
+            .orElseThrow(() -> new IllegalArgumentException(String.format(
+                "Could not parse value for enum %s. Expected one of: [%s]",
+                clazz, Arrays.toString(clazz.getEnumConstants()))));
+    }
+
+    public static String convertToJsonString(Object o) {
+        if (o instanceof String) {
+            return (String) o;
+        }
+        try {
+            return JACKSON_MAPPER.writeValueAsString(o);
+        } catch (JsonProcessingException e) {
+            throw new IllegalArgumentException(String.format("Could not parse json, value: %s", o));
+        }
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Expression.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Expression.java
new file mode 100644
index 0000000..a735bf8
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/Expression.java
@@ -0,0 +1,123 @@
+/*
+ * 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.configuration.util;
+
+import org.apache.seatunnel.datasource.configuration.Option;
+
+import java.util.Objects;
+
+public class Expression {
+    private final Condition<?> condition;
+    private Boolean and = null;
+    private Expression next = null;
+
+    Expression(Condition<?> condition) {
+        this.condition = condition;
+    }
+
+    public static <T> Expression of(Option<T> option, T expectValue) {
+        return new Expression(Condition.of(option, expectValue));
+    }
+
+    public static Expression of(Condition<?> condition) {
+        return new Expression(condition);
+    }
+
+    public Expression and(Expression next) {
+        addExpression(true, next);
+        return this;
+    }
+
+    public Expression or(Expression next) {
+        addExpression(false, next);
+        return this;
+    }
+
+    private void addExpression(boolean and, Expression next) {
+        Expression tail = getTailExpression();
+        tail.and = and;
+        tail.next = next;
+    }
+
+    private Expression getTailExpression() {
+        return hasNext() ? this.next.getTailExpression() : this;
+    }
+
+    public Condition<?> getCondition() {
+        return condition;
+    }
+
+    public boolean hasNext() {
+        return this.next != null;
+    }
+
+    public Expression getNext() {
+        return this.next;
+    }
+
+    public Boolean and() {
+        return this.and;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Expression)) {
+            return false;
+        }
+        Expression that = (Expression) obj;
+        return Objects.equals(this.condition, that.condition)
+            && Objects.equals(this.and, that.and)
+            && Objects.equals(this.next, that.next);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.condition, this.and, this.next);
+    }
+
+    @Override
+    public String toString() {
+        Expression cur = this;
+        StringBuilder builder = new StringBuilder();
+        boolean bracket = false;
+        do {
+            if (cur.condition.getCount() > 1) {
+                builder.append("(")
+                    .append(cur.condition)
+                    .append(")");
+            } else {
+                builder.append(cur.condition);
+            }
+            if (bracket) {
+                builder = new StringBuilder(String.format("(%s)", builder));
+                bracket = false;
+            }
+            if (cur.hasNext()) {
+                if (cur.next.hasNext() && !cur.and.equals(cur.next.and)) {
+                    bracket = true;
+                }
+                builder.append(cur.and ? " && " : " || ");
+            }
+            cur = cur.next;
+        } while (cur != null);
+        return builder.toString();
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionMark.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionMark.java
new file mode 100644
index 0000000..ff90309
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionMark.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.configuration.util;
+
+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;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target(ElementType.FIELD)
+public @interface OptionMark {
+
+    /**
+     * The key of the option, if not configured, we will default convert `lowerCamelCase` to `under_score_case` and provide it to users
+     */
+    String name() default "";
+
+    /**
+     * The description of the option
+     */
+    String description() default "";
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionRule.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionRule.java
new file mode 100644
index 0000000..6ae5b3c
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionRule.java
@@ -0,0 +1,265 @@
+/*
+ * 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.configuration.util;
+
+import org.apache.seatunnel.datasource.configuration.Option;
+
+import lombok.NonNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Validation rule for {@link Option}.
+ * <p>
+ * The option rule is typically built in one of the following pattern:
+ *
+ * <pre>{@code
+ * // simple rule
+ * OptionRule simpleRule = OptionRule.builder()
+ *     .optional(POLL_TIMEOUT, POLL_INTERVAL)
+ *     .required(CLIENT_SERVICE_URL)
+ *     .build();
+ *
+ * // basic full rule
+ * OptionRule fullRule = OptionRule.builder()
+ *     .optional(POLL_TIMEOUT, POLL_INTERVAL, CURSOR_STARTUP_MODE)
+ *     .required(CLIENT_SERVICE_URL, ADMIN_SERVICE_URL)
+ *     .exclusive(TOPIC_PATTERN, TOPIC)
+ *     .conditional(CURSOR_STARTUP_MODE, StartMode.TIMESTAMP, CURSOR_STARTUP_TIMESTAMP)
+ *     .build();
+ *
+ * // complex conditional rule
+ * // moot expression
+ * Expression expression = Expression.of(TOPIC_DISCOVERY_INTERVAL, 200)
+ *     .and(Expression.of(Condition.of(CURSOR_STARTUP_MODE, StartMode.EARLIEST)
+ *         .or(CURSOR_STARTUP_MODE, StartMode.LATEST)))
+ *     .or(Expression.of(Condition.of(TOPIC_DISCOVERY_INTERVAL, 100)))
+ *
+ * OptionRule complexRule = OptionRule.builder()
+ *     .optional(POLL_TIMEOUT, POLL_INTERVAL, CURSOR_STARTUP_MODE)
+ *     .required(CLIENT_SERVICE_URL, ADMIN_SERVICE_URL)
+ *     .exclusive(TOPIC_PATTERN, TOPIC)
+ *     .conditional(expression, CURSOR_RESET_MODE)
+ *     .build();
+ * }</pre>
+ */
+public class OptionRule {
+
+    /**
+     * Optional options with default value.
+     *
+     * <p> This options will not be validated.
+     * <p> This is used by the web-UI to show what options are available.
+     */
+    private final List<Option<?>> optionalOptions;
+
+    /**
+     * Required options with no default value.
+     *
+     * <p> Verify that the option is valid through the defined rules.
+     */
+    private final List<RequiredOption> requiredOptions;
+
+    OptionRule(List<Option<?>> optionalOptions, List<RequiredOption> requiredOptions) {
+        this.optionalOptions = optionalOptions;
+        this.requiredOptions = requiredOptions;
+    }
+
+    public List<Option<?>> getOptionalOptions() {
+        return optionalOptions;
+    }
+
+    public List<RequiredOption> getRequiredOptions() {
+        return requiredOptions;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof OptionRule)) {
+            return false;
+        }
+        OptionRule that = (OptionRule) o;
+        return Objects.equals(optionalOptions, that.optionalOptions)
+            && Objects.equals(requiredOptions, that.requiredOptions);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(optionalOptions, requiredOptions);
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link OptionRule}.
+     */
+    public static class Builder {
+        private final List<Option<?>> optionalOptions = new ArrayList<>();
+        private final List<RequiredOption> requiredOptions = new ArrayList<>();
+
+        private Builder() {
+        }
+
+        /**
+         * Optional options
+         *
+         * <p> This options will not be validated.
+         * <p> This is used by the web-UI to show what options are available.
+         */
+        public Builder optional(@NonNull Option<?>... options) {
+            for (Option<?> option : options) {
+                verifyDuplicate(option, "OptionsOption");
+            }
+            this.optionalOptions.addAll(Arrays.asList(options));
+            return this;
+        }
+
+        /**
+         * Absolutely required options without any constraints.
+         */
+        public Builder required(@NonNull Option<?>... options) {
+            for (Option<?> option : options) {
+                verifyDuplicate(option, "RequiredOption");
+                verifyRequiredOptionDefaultValue(option);
+            }
+            this.requiredOptions.add(RequiredOption.AbsolutelyRequiredOptions.of(options));
+            return this;
+        }
+
+        /**
+         * Exclusive options, only one of the options needs to be configured.
+         */
+        public Builder exclusive(@NonNull Option<?>... options) {
+            if (options.length <= 1) {
+                throw new OptionValidationException("The number of exclusive options must be greater than 1.");
+            }
+            for (Option<?> option : options) {
+                verifyDuplicate(option, "ExclusiveOption");
+                verifyRequiredOptionDefaultValue(option);
+            }
+            this.requiredOptions.add(RequiredOption.ExclusiveRequiredOptions.of(options));
+            return this;
+        }
+
+        public <T> Builder conditional(@NonNull Option<T> conditionalOption, @NonNull List<T> expectValues, @NonNull Option<?>... requiredOptions) {
+            for (Option<?> o : requiredOptions) {
+                verifyDuplicate(o, "ConditionalOption");
+                verifyRequiredOptionDefaultValue(o);
+            }
+
+            verifyConditionalExists(conditionalOption);
+
+            if (expectValues.size() == 0) {
+                throw new OptionValidationException(
+                    String.format("conditional option '%s' must have expect values .", conditionalOption.key()));
+            }
+
+            /**
+             * Each parameter can only be controlled by one other parameter
+             */
+            Expression expression = Expression.of(Condition.of(conditionalOption, expectValues.get(0)));
+            for (int i = 0; i < expectValues.size(); i++) {
+                if (i != 0) {
+                    expression = expression.or(Expression.of(Condition.of(conditionalOption, expectValues.get(i))));
+                }
+            }
+
+            this.requiredOptions.add(RequiredOption.ConditionalRequiredOptions.of(expression,
+                new ArrayList<>(Arrays.asList(requiredOptions))));
+            return this;
+        }
+
+        public <T> Builder conditional(@NonNull Option<T> conditionalOption, @NonNull T expectValue, @NonNull Option<?>... requiredOptions) {
+            for (Option<?> o : requiredOptions) {
+                verifyDuplicate(o, "ConditionalOption");
+                verifyRequiredOptionDefaultValue(o);
+            }
+
+            verifyConditionalExists(conditionalOption);
+
+            /**
+             * Each parameter can only be controlled by one other parameter
+             */
+            Expression expression = Expression.of(Condition.of(conditionalOption, expectValue));
+
+            this.requiredOptions.add(RequiredOption.ConditionalRequiredOptions.of(expression,
+                new ArrayList<>(Arrays.asList(requiredOptions))));
+            return this;
+        }
+
+        /**
+         * Bundled options, must be present or absent together.
+         */
+        public Builder bundled(@NonNull Option<?>... requiredOptions) {
+            for (Option<?> option : requiredOptions) {
+                verifyDuplicate(option, "BundledOption");
+            }
+            this.requiredOptions.add(RequiredOption.BundledRequiredOptions.of(requiredOptions));
+            return this;
+        }
+
+        public OptionRule build() {
+            return new OptionRule(optionalOptions, requiredOptions);
+        }
+
+        private void verifyRequiredOptionDefaultValue(@NonNull Option<?> option) {
+            if (option.defaultValue() != null) {
+                throw new OptionValidationException(
+                    String.format("Required option '%s' should have no default value.", option.key()));
+            }
+        }
+
+        private void verifyDuplicate(@NonNull Option<?> option, @NonNull String currentOptionType) {
+            if (optionalOptions.contains(option)) {
+                throw new OptionValidationException(
+                    String.format("%s '%s' duplicate in option options.", currentOptionType, option.key()));
+            }
+
+            requiredOptions.forEach(requiredOption -> {
+                if (requiredOption.getOptions().contains(option)) {
+                    throw new OptionValidationException(
+                        String.format("%s '%s' duplicate in '%s'.", currentOptionType, option.key(), requiredOption.getClass().getName()));
+                }
+            });
+        }
+
+        private void verifyConditionalExists(@NonNull Option<?> option) {
+            boolean inOptions = optionalOptions.contains(option);
+            AtomicBoolean inRequired = new AtomicBoolean(false);
+            requiredOptions.forEach(requiredOption -> {
+                if (requiredOption.getOptions().contains(option)) {
+                    inRequired.set(true);
+                }
+            });
+
+            if (!inOptions && !inRequired.get()) {
+                throw new OptionValidationException(
+                    String.format("Conditional '%s' not found in options.", option.key()));
+            }
+        }
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionUtil.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionUtil.java
new file mode 100644
index 0000000..efb5c2f
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionUtil.java
@@ -0,0 +1,103 @@
+/*
+ * 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.configuration.util;
+
+import org.apache.seatunnel.datasource.configuration.Option;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class OptionUtil {
+
+    private OptionUtil() {
+    }
+
+    public static String getOptionKeys(List<Option<?>> options) {
+        StringBuilder builder = new StringBuilder();
+        boolean flag = false;
+        for (Option<?> option : options) {
+            if (flag) {
+                builder.append(", ");
+            }
+            builder.append("'")
+                .append(option.key())
+                .append("'");
+            flag = true;
+        }
+        return builder.toString();
+    }
+
+    public static String getOptionKeys(List<Option<?>> options,
+                                       List<RequiredOption.BundledRequiredOptions> bundledOptions) {
+        List<List<Option<?>>> optionList = new ArrayList<>();
+        for (Option<?> option : options) {
+            optionList.add(Collections.singletonList(option));
+        }
+        for (RequiredOption.BundledRequiredOptions bundledOption : bundledOptions) {
+            optionList.add(bundledOption.getRequiredOption());
+        }
+        boolean flag = false;
+        StringBuilder builder = new StringBuilder();
+        for (List<Option<?>> optionSet : optionList) {
+            if (flag) {
+                builder.append(", ");
+            }
+            builder.append("[")
+                .append(getOptionKeys(optionSet))
+                .append("]");
+            flag = true;
+        }
+        return builder.toString();
+    }
+
+    public static List<Option<?>> getOptions(Class<?> clazz) throws InstantiationException, IllegalAccessException {
+        Field[] fields = clazz.getDeclaredFields();
+        List<Option<?>> options = new ArrayList<>();
+        Object object = clazz.newInstance();
+        for (Field field : fields) {
+            field.setAccessible(true);
+            OptionMark option = field.getAnnotation(OptionMark.class);
+            if (option != null) {
+                options.add(new Option<>(
+                    !StringUtils.isNotBlank(option.name()) ? formatUnderScoreCase(field.getName()) : option.name(),
+                    new TypeReference<Object>() {
+                        @Override
+                        public Type getType() {
+                            return field.getType();
+                        }
+                    }, field.get(object)).withDescription(option.description()));
+            }
+        }
+        return options;
+    }
+
+    private static String formatUnderScoreCase(String camel) {
+        StringBuilder underScore = new StringBuilder(String.valueOf(Character.toLowerCase(camel.charAt(0))));
+        for (int i = 1; i < camel.length(); i++) {
+            char c = camel.charAt(i);
+            underScore.append(Character.isLowerCase(c) ? c : "_" + Character.toLowerCase(c));
+        }
+        return underScore.toString();
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionValidationException.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionValidationException.java
new file mode 100644
index 0000000..13140b5
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/OptionValidationException.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.configuration.util;
+
+/**
+ * Exception for all errors occurring during option validation phase.
+ */
+public class OptionValidationException extends RuntimeException {
+
+    public OptionValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public OptionValidationException(String message) {
+        super(message);
+    }
+
+    public OptionValidationException(String formatMessage, Object... args) {
+        super(String.format(formatMessage, args));
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/RequiredOption.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/RequiredOption.java
new file mode 100644
index 0000000..bc199f8
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/configuration/util/RequiredOption.java
@@ -0,0 +1,224 @@
+/*
+ * 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.configuration.util;
+
+import static org.apache.seatunnel.datasource.configuration.util.OptionUtil.getOptionKeys;
+
+import org.apache.seatunnel.datasource.configuration.Option;
+
+import lombok.Getter;
+import lombok.NonNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public interface RequiredOption {
+
+    List<Option<?>> getOptions();
+
+    /**
+     * These options are mutually exclusive, allowing only one set of options to be configured.
+     */
+    @Getter
+    class ExclusiveRequiredOptions implements RequiredOption {
+        private final List<Option<?>> exclusiveOptions;
+
+        public ExclusiveRequiredOptions(@NonNull List<Option<?>> exclusiveOptions) {
+            this.exclusiveOptions = exclusiveOptions;
+        }
+
+        public static ExclusiveRequiredOptions of(Option<?>... options) {
+            return new ExclusiveRequiredOptions(new ArrayList<>(Arrays.asList(options)));
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof ExclusiveRequiredOptions)) {
+                return false;
+            }
+            ExclusiveRequiredOptions that = (ExclusiveRequiredOptions) obj;
+            return Objects.equals(this.exclusiveOptions, that.exclusiveOptions);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(exclusiveOptions);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Exclusive required set options: %s", getOptionKeys(exclusiveOptions));
+        }
+
+        @Override
+        public List<Option<?>> getOptions() {
+            return exclusiveOptions;
+        }
+    }
+
+    /**
+     * The option is required.
+     */
+    class AbsolutelyRequiredOptions implements RequiredOption {
+        @Getter
+        private final List<Option<?>> requiredOption;
+
+        AbsolutelyRequiredOptions(List<Option<?>> requiredOption) {
+            this.requiredOption = requiredOption;
+        }
+
+        public static AbsolutelyRequiredOptions of(Option<?>... requiredOption) {
+            return new AbsolutelyRequiredOptions(new ArrayList<>(Arrays.asList(requiredOption)));
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof AbsolutelyRequiredOptions)) {
+                return false;
+            }
+            AbsolutelyRequiredOptions that = (AbsolutelyRequiredOptions) obj;
+            return Objects.equals(this.requiredOption, that.requiredOption);
+        }
+
+        @Override
+        public int hashCode() {
+            return this.requiredOption.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Absolutely required options: '%s'", getOptionKeys(requiredOption));
+        }
+
+        @Override
+        public List<Option<?>> getOptions() {
+            return requiredOption;
+        }
+    }
+
+    class ConditionalRequiredOptions implements RequiredOption {
+        private final Expression expression;
+        private final List<Option<?>> requiredOption;
+
+        ConditionalRequiredOptions(Expression expression, List<Option<?>> requiredOption) {
+            this.expression = expression;
+            this.requiredOption = requiredOption;
+        }
+
+        public static ConditionalRequiredOptions of(Expression expression, List<Option<?>> requiredOption) {
+            return new ConditionalRequiredOptions(expression, requiredOption);
+        }
+
+        public static ConditionalRequiredOptions of(Condition<?> condition, List<Option<?>> requiredOption) {
+            return new ConditionalRequiredOptions(Expression.of(condition), requiredOption);
+        }
+
+        public Expression getExpression() {
+            return expression;
+        }
+
+        public List<Option<?>> getRequiredOption() {
+            return requiredOption;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof ConditionalRequiredOptions)) {
+                return false;
+            }
+            ConditionalRequiredOptions that = (ConditionalRequiredOptions) obj;
+            return Objects.equals(this.expression, that.expression) && Objects.equals(this.requiredOption, that.requiredOption);
+        }
+
+        @Override
+        public int hashCode() {
+            return this.requiredOption.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Condition expression: %s, Required options: %s", expression, getOptionKeys(requiredOption));
+        }
+
+        @Override
+        public List<Option<?>> getOptions() {
+            return requiredOption;
+        }
+    }
+
+    /**
+     * These options are bundled, must be present or absent together.
+     */
+    class BundledRequiredOptions implements RequiredOption {
+        private final List<Option<?>> requiredOption;
+
+        BundledRequiredOptions(List<Option<?>> requiredOption) {
+            this.requiredOption = requiredOption;
+        }
+
+        public static BundledRequiredOptions of(Option<?>... requiredOption) {
+            return new BundledRequiredOptions(new ArrayList<>(Arrays.asList(requiredOption)));
+        }
+
+        public static BundledRequiredOptions of(List<Option<?>> requiredOption) {
+            return new BundledRequiredOptions(requiredOption);
+        }
+
+        public List<Option<?>> getRequiredOption() {
+            return requiredOption;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof BundledRequiredOptions)) {
+                return false;
+            }
+            BundledRequiredOptions that = (BundledRequiredOptions) obj;
+            return Objects.equals(this.requiredOption, that.requiredOption);
+        }
+
+        @Override
+        public int hashCode() {
+            return this.requiredOption.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return String.format("Bundled Required options: %s", getOptionKeys(requiredOption));
+        }
+
+        @Override
+        public List<Option<?>> getOptions() {
+            return requiredOption;
+        }
+    }
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/BaseModel.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/BaseModel.java
new file mode 100644
index 0000000..09b8258
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/BaseModel.java
@@ -0,0 +1,27 @@
+/*
+ * 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.model;
+
+public class BaseModel {
+
+    private Long createdTime;
+
+    private Long updatedTime;
+
+    private Boolean deleted;
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSource.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSource.java
new file mode 100644
index 0000000..856f05a
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSource.java
@@ -0,0 +1,34 @@
+/*
+ * 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.model;
+
+import java.util.Map;
+
+public class DataSource extends BaseModel {
+
+    private Long id;
+
+    private String dataSourceName;
+
+    private String pluginName;
+
+    private String comment;
+
+    private Map<String, Object> params;
+
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSourcePluginInfo.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSourcePluginInfo.java
new file mode 100644
index 0000000..db8abb9
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/DataSourcePluginInfo.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.model;
+
+public class DataSourcePluginInfo {
+
+    public String name;
+
+    public String icon;
+
+    public String version;
+
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/Table.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/Table.java
new file mode 100644
index 0000000..f6d8846
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/Table.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.model;
+
+import java.util.Set;
+
+public class Table {
+
+    private Long id;
+
+    private Long dataSourceId;
+
+    private String description;
+
+    private String type;
+
+    private String databaseName;
+
+    private String tableName;
+
+    private Set<TableField> fields;
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/TableField.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/TableField.java
new file mode 100644
index 0000000..ba04f71
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/model/TableField.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.model;
+
+import java.util.Set;
+
+public class TableField {
+    private String type;
+
+    private String name;
+
+    private String comment;
+
+    private Boolean primaryKey;
+
+    private String defaultValue;
+
+    private Boolean nullable;
+
+    private Set<String> labels;
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/plugin/DataSourceMetedata.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/plugin/DataSourceMetedata.java
new file mode 100644
index 0000000..ec2ab4e
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/plugin/DataSourceMetedata.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;
+
+import org.apache.seatunnel.datasource.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.model.Table;
+
+import java.util.List;
+import java.util.Map;
+
+public interface DataSourceMetedata {
+
+    Boolean checkDataSourceConnectivity(Map<String, Object> dataSourceParams);
+
+    default Boolean capableGetSchema() {
+        return false;
+    }
+
+    OptionRule getDataSourceFields();
+
+    Table getTable(Map<String, Object> requestParams);
+
+    List<String> getTables(Map<String, Object> requestParams);
+
+    List<String> getDatabases(Map<String, Object> requestParams);
+
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelAutoTableService.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelAutoTableService.java
new file mode 100644
index 0000000..dd0bc70
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelAutoTableService.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.service;
+
+import org.apache.seatunnel.datasource.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.model.Table;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SeaTunnelAutoTableService {
+
+    OptionRule getDataSourceMetadataFieldsByDataSourceName(String dataSourceName);
+
+    OptionRule getDataSourceMetadataFieldsByDataSourceId(String dataSourceId);
+
+    List<String> getTables(String dataSourceId, Map<String, Object> requestParams);
+
+    List<String> getDatabases(String dataSourceId, Map<String, Object> requestParams);
+
+    Table getTable(String dataSourceId, Map<String, Object> requestParams);
+
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelDataSourceService.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelDataSourceService.java
new file mode 100644
index 0000000..9b2db50
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelDataSourceService.java
@@ -0,0 +1,44 @@
+/*
+ * 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.datasource.configuration.util.OptionRule;
+import org.apache.seatunnel.datasource.model.DataSource;
+import org.apache.seatunnel.datasource.model.DataSourcePluginInfo;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SeaTunnelDataSourceService {
+
+    List<DataSourcePluginInfo> listAllDataSources();
+
+    OptionRule queryDataSourceFieldByName(String dataSourceName);
+
+    Boolean checkDataSourceFields(Map<String, Object> parameters);
+
+    DataSource queryDataSourceById(Long dataSourceId);
+
+    Boolean saveDataSource(String dataSourceName, String comment, String pluginName, Map<String, Object> parameters);
+
+    Boolean deleteDataSource(Long id);
+
+    Boolean updateDataSource(Long dataSourceId, String dataSourceName, String comment, Map<String, Object> parameters);
+
+    Boolean checkDataSourceConnectivity(Map<String, Object> dataSourceParams);
+}
diff --git a/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelTableService.java b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelTableService.java
new file mode 100644
index 0000000..cccf0ca
--- /dev/null
+++ b/datasource-client/src/main/java/org/apache/seatunnel/datasource/service/SeaTunnelTableService.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.service;
+
+import org.apache.seatunnel.datasource.model.Table;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SeaTunnelTableService {
+    Boolean createTable(Long datasourceId, String databaseName, String tableName, Map<String, String> tableFields, String description);
+
+    Boolean dropSchema(String schemaId);
+
+    Table getTable(Long datasourceId, String databaseName, String tableName);
+
+    List<String> getTableNames(Long datasourceId, String databaseName);
+
+    List<String> getDatabaseNames(Long datasourceId);
+
+    List<Table> getTables(String datasourceId, String databaseName);
+
+}
diff --git a/pom.xml b/pom.xml
index 3678bd9..5b2ca6d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,7 +44,8 @@
 
     <scm>
         <connection>scm:git:https://github.com/apache/incubator-seatunnel-datasource-sdk.git</connection>
-        <developerConnection>scm:git:https://github.com/apache/incubator-seatunnel-datasource-sdk.git</developerConnection>
+        <developerConnection>scm:git:https://github.com/apache/incubator-seatunnel-datasource-sdk.git
+        </developerConnection>
         <url>https://github.com/apache/incubator-seatunnel-datasource-sdk</url>
         <tag>HEAD</tag>
     </scm>
@@ -72,4 +73,95 @@
     <modules>
         <module>datasource-client</module>
     </modules>
+
+    <properties>
+        <!--dependency version-->
+        <jackson.version>2.14.0</jackson.version>
+        <lombok.version>1.18.24</lombok.version>
+        <!--maven plugin version-->
+        <maven-checkstyle-plugin.version>3.2.0</maven-checkstyle-plugin.version>
+        <checkstyle.fails.on.error>true</checkstyle.fails.on.error>
+    </properties>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.fasterxml.jackson.dataformat</groupId>
+                <artifactId>jackson-dataformat-properties</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+                <scope>provided</scope>
+            </dependency>
+            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version>3.12.0</version>
+            </dependency>
+
+        </dependencies>
+
+
+    </dependencyManagement>
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <!-- checkstyle (Start) -->
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <version>${maven-checkstyle-plugin.version}</version>
+                    <configuration>
+                        <!--suppress UnresolvedMavenProperty -->
+                        <configLocation>${maven.multiModuleProjectDirectory}/tools/checkstyle/checkStyle.xml</configLocation>
+                        <consoleOutput>true</consoleOutput>
+                        <includeTestSourceDirectory>true</includeTestSourceDirectory>
+                        <failOnViolation>${checkstyle.fails.on.error}</failOnViolation>
+                        <sourceDirectories>
+                            <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
+                            <sourceDirectory>${project.build.testSourceDirectory}</sourceDirectory>
+                        </sourceDirectories>
+                        <resourceIncludes>
+                            **/*.properties,
+                            **/*.sh,
+                            **/*.bat,
+                            **/*.yml,
+                            **/*.yaml,
+                            **/*.xml
+                        </resourceIncludes>
+                        <resourceExcludes>
+                            **/.asf.yaml,
+                            **/.github/**
+                        </resourceExcludes>
+                    </configuration>
+                    <executions>
+                        <execution>
+                            <id>validate</id>
+                            <phase>process-sources</phase>
+                            <goals>
+                                <goal>check</goal>
+                            </goals>
+                        </execution>
+                    </executions>
+                </plugin>
+                <!-- checkstyle (End) -->
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
 </project>
\ No newline at end of file
diff --git a/tools/checkstyle/checkStyle.xml b/tools/checkstyle/checkStyle.xml
new file mode 100755
index 0000000..56150c0
--- /dev/null
+++ b/tools/checkstyle/checkStyle.xml
@@ -0,0 +1,546 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+        "http://checkstyle.org/dtds/configuration_1_3.dtd">
+<module name="Checker">
+
+    <property name="charset" value="UTF-8"/>
+
+    <property name="severity" value="error"/>
+
+    <property name="fileExtensions" value="java, properties, xml"/>
+
+    <module name="NewlineAtEndOfFile">
+        <!-- windows can use \r\n vs \n, so enforce the most used one ie UNIx style -->
+        <property name="lineSeparator" value="lf"/>
+    </module>
+
+    <property name="localeLanguage" value="en"/>
+
+    <module name="FileTabCharacter">
+        <property name="eachLine" value="true"/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <property name="format" value="System\.out\.println"/>
+        <property name="message" value="Prohibit invoking System.out.println in source code !"/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <property name="format" value="^\s*\*\s*@author"/>
+        <property name="minimum" value="0"/>
+        <property name="maximum" value="0"/>
+        <property name="message" value="ASF project doesn't allow @author copyright."/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <property name="format"
+                  value=".*[\u3400-\u4DB5\u4E00-\u9FA5\u9FA6-\u9FBB\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFF00-\uFFEF\u2E80-\u2EFF\u3000-\u303F\u31C0-\u31EF]+.*"/>
+        <property name="message" value="Not allow chinese character !"/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <!-- Checks that TODOs don't have stuff in parenthesis, e.g., username. -->
+        <property name="format" value="((//.*)|(\*.*))TODO\("/>
+        <property name="message" value="TODO comments must not include usernames."/>
+        <property name="severity" value="error"/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <!-- \s matches whitespace character, $ matches end of line. -->
+        <property name="format" value="\s+$"/>
+        <property name="severity" value="error"/>
+        <property name="message" value="No trailing whitespace allowed."/>
+    </module>
+
+    <module name="RegexpSingleline">
+        <property name="format" value="Throwables.propagate\("/>
+        <property name="message" value="Throwables.propagate is deprecated"/>
+        <property name="severity" value="error"/>
+    </module>
+
+    <module name="FileLength">
+        <property name="max" value="3000"/>
+    </module>
+
+    <module name="LineLength">
+        <property name="max" value="500"/>
+        <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
+    </module>
+
+    <module name="SuppressionSingleFilter">
+        <property name="files" value=".*(IT|Test).java"/>
+        <property name="checks" value="MagicNumber"/>
+    </module>
+
+    <module name="SuppressWarningsFilter"/>
+    <module name="TreeWalker">
+        <module name="SuppressWarningsHolder"/>
+        <module name="ImportOrder">
+            <property name="severity" value="error"/>
+            <property name="staticGroups" value="org.apache.seatunnel,org.apache.seatunnel.shade,*,javax,java,scala"/>
+            <property name="groups" value="org.apache.seatunnel,org.apache.seatunnel.shade,*,javax,java,scala"/>
+            <property name="separated" value="true"/>
+            <property name="sortStaticImportsAlphabetically" value="true"/>
+            <property name="option" value="top"/>
+            <property name="tokens" value="STATIC_IMPORT, IMPORT"/>
+            <message key="import.ordering" value="Import {0} appears after other imports that it should precede"/>
+        </module>
+
+        <module name="SuppressionCommentFilter"/>
+
+        <!-- Prohibit T.getT() methods for standard boxed types -->
+        <module name="Regexp">
+            <property name="format" value="Boolean\.getBoolean"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Use System.getProperties() to get system properties."/>
+        </module>
+
+        <module name="Regexp">
+            <property name="format" value="Integer\.getInteger"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Use System.getProperties() to get system properties."/>
+        </module>
+
+        <module name="Regexp">
+            <property name="format" value="Long\.getLong"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Use System.getProperties() to get system properties."/>
+        </module>
+
+        <!-- IllegalImport cannot blacklist classes so we have to fall back to Regexp. -->
+        <!-- forbid use of commons lang validate -->
+        <module name="Regexp">
+            <property name="format" value="org\.apache\.commons\.lang3\.Validate"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message"
+                      value="Use Guava Checks instead of Commons Validate. Please refer to the coding guidelines."/>
+        </module>
+
+        <module name="Regexp">
+            <property name="format" value="org\.apache\.commons\.lang\."/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Use commons-lang3 instead of commons-lang."/>
+        </module>
+
+        <module name="Regexp">
+            <property name="format" value="org\.codehaus\.jettison"/>
+            <property name="illegalPattern" value="true"/>
+            <property name="message" value="Use com.fasterxml.jackson instead of jettison."/>
+        </module>
+
+        <module name="IllegalImport">
+            <property name="regexp" value="true"/>
+            <property name="illegalPkgs"
+                      value="^com\.google\.api\.client\.repackaged,
+                      ^avro\.shaded, ^org\.apache\.hadoop\.hbase\.shaded,
+                      ^org\.apache\.hadoop\.shaded,
+                      ^javax\.ws\.rs\.ext,
+                      ^cc\.concurrent\.mango\.util\.concurrent,
+                      ^org\.apache\.curator-test\.shaded,
+                      ^com\.sun\.istack,
+                      ^org\.jetbrains\.annotations,
+                      ^jline\.internal,
+                      ^com\.cronutils\.utils,
+                      ^javax\.ws\.rs\.ext,
+                      ^org\.jboss\.netty\.util\.internal,
+                      ^com\.sun\.javafx,
+                      ^io\.reactivex\.annotations"/>
+            <property name="illegalClasses"
+                      value="^java\.util\.logging\.Logging,
+                      ^sun\.misc\.BASE64Encoder,
+                      ^sun\.misc\.BASE64Decoder,
+                      ^jdk\.internal\.jline\.internal\.Nullable,
+                      ^org\.junit\.(?!(jupiter|platform)\.).+"/>
+        </module>
+
+        <module name="OuterTypeFilename">
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="OneTopLevelClass">
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="NoLineWrap">
+            <property name="severity" value="error"/>
+        </module>
+
+        <!-- Checks for braces around if and else blocks -->
+        <module name="NeedBraces">
+            <property name="severity" value="error"/>
+            <property name="tokens" value="LITERAL_IF, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO"/>
+        </module>
+
+        <module name="LeftCurly">
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="InnerTypeLast"/>
+        <module name="IllegalTokenText">
+            <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
+            <property name="format"
+                      value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
+            <property name="message"
+                      value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
+        </module>
+
+        <module name="AvoidEscapedUnicodeCharacters">
+            <property name="allowEscapesForControlCharacters" value="true"/>
+            <property name="allowByTailComment" value="true"/>
+            <property name="allowNonPrintableEscapes" value="true"/>
+        </module>
+
+        <module name="EmptyBlock">
+            <property name="option" value="TEXT"/>
+            <property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
+        </module>
+
+        <module name="OneStatementPerLine"/>
+
+        <module name="MagicNumber">
+            <property name="ignoreHashCodeMethod" value="true"/>
+        </module>
+
+        <module name="MultipleVariableDeclarations"/>
+
+        <module name="ArrayTypeStyle"/>
+
+        <module name="MissingSwitchDefault"/>
+
+        <module name="FallThrough">
+            <!-- Warn about falling through to the next case statement.  Similar to
+            javac -Xlint:fallthrough, but the check is suppressed if a single-line comment
+            on the last non-blank line preceding the fallen-into case contains 'fall through' (or
+            some other variants that we don't publicized to promote consistency).
+            -->
+            <property name="reliefPattern"
+                      value="fall through|Fall through|fallthru|Fallthru|falls through|Falls through|fallthrough|Fallthrough|No break|NO break|no break|continue on"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <!-- MODIFIERS CHECKS -->
+        <module name="ModifierOrder">
+            <!-- Warn if modifier order is inconsistent with JLS3 8.1.1, 8.3.1, and
+                 8.4.3.  The prescribed order is:
+                 public, protected, private, abstract, static, final, transient, volatile,
+                 synchronized, native, strictfp
+              -->
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="SeparatorWrap">
+            <property name="tokens" value="DOT"/>
+            <property name="option" value="nl"/>
+        </module>
+
+        <module name="SeparatorWrap">
+            <property name="tokens" value="COMMA"/>
+            <property name="option" value="EOL"/>
+        </module>
+
+        <module name="UnusedImports">
+            <property name="severity" value="error"/>
+            <property name="processJavadoc" value="true"/>
+            <message key="import.unused" value="Unused import: {0}."/>
+        </module>
+
+        <module name="RedundantImport">
+            <!-- Checks for redundant import statements. -->
+            <property name="severity" value="error"/>
+            <message key="import.redundancy" value="Redundant import {0}."/>
+        </module>
+
+        <!-- Require static importing from Preconditions. -->
+        <module name="RegexpSinglelineJava">
+            <property name="format" value="^import com.google.common.base.Preconditions;$"/>
+            <property name="message" value="Static import functions from Guava Preconditions"/>
+        </module>
+
+        <!-- Detect multiple consecutive semicolons (e.g. ";;"). -->
+        <module name="RegexpSinglelineJava">
+            <property name="format" value=";{2,}"/>
+            <property name="message" value="Use one semicolon"/>
+            <property name="ignoreComments" value="true"/>
+        </module>
+
+        <module name="RegexpSinglelineJava">
+            <property name="format" value="throw new \w+Error\("/>
+            <property name="message" value="Avoid throwing error in application code."/>
+        </module>
+
+        <module name="RegexpSinglelineJava">
+            <property name="format" value="Objects\.toStringHelper"/>
+            <property name="message" value="Avoid using Object.toStringHelper. Use ToStringBuilder instead."/>
+        </module>
+
+        <module name="JavadocStyle">
+            <property name="severity" value="error"/>
+            <property name="checkHtml" value="true"/>
+            <property name="endOfSentenceFormat" value=""/>
+        </module>
+
+        <module name="RedundantModifier">
+            <!-- Checks for redundant modifiers on various symbol definitions.
+              See: http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier
+
+              We exclude METHOD_DEF to allow final methods in final classes to make them more future-proof.
+            -->
+            <property name="tokens" value="VARIABLE_DEF, ANNOTATION_FIELD_DEF, INTERFACE_DEF, CLASS_DEF, ENUM_DEF"/>
+        </module>
+
+        <module name="AvoidStarImport"/>
+
+        <module name="NonEmptyAtclauseDescription"/>
+
+        <!--Checks that classes that override equals() also override hashCode()-->
+        <module name="EqualsHashCode"/>
+        <!--Checks for over-complicated boolean expressions. Currently finds code like if (topic == true), topic || true, !false, etc.-->
+        <module name="SimplifyBooleanExpression"/>
+        <module name="OneStatementPerLine"/>
+        <module name="UnnecessaryParentheses"/>
+        <!--Checks for over-complicated boolean return statements. For example the following code-->
+        <module name="SimplifyBooleanReturn"/>
+
+        <!--Check that the default is after all the cases in producerGroup switch statement-->
+        <module name="DefaultComesLast"/>
+        <!--Detects empty statements (standalone ";" semicolon)-->
+        <module name="EmptyStatement">
+            <property name="severity" value="error"/>
+        </module>
+
+        <!--Checks that long constants are defined with an upper ell-->
+        <module name="UpperEll">
+            <!-- Checks that long constants are defined with an upper ell.-->
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="ConstantName">
+            <property name="format" value="(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
+        </module>
+        <!--Checks that local, non-final variable names conform to producerGroup format specified by the format property-->
+        <module name="LocalVariableName">
+            <!-- Validates identifiers for local variables against the expression "^[a-z][a-zA-Z0-9]*$". -->
+            <property name="tokens" value="VARIABLE_DEF"/>
+            <property name="format" value="^[a-z]([a-zA-Z0-9]*)?$"/>
+            <property name="severity" value="error"/>
+            <message key="name.invalidPattern" value="Local variable name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <!--Validates identifiers for local, final variables, including catch parameters-->
+        <module name="LocalFinalVariableName">
+            <!-- Validates identifiers for local final variables against the expression "^[a-z][a-zA-Z0-9]*$". -->
+            <property name="severity" value="error"/>
+        </module>
+
+        <!--Validates identifiers for non-static fields-->
+        <module name="MemberName">
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <message key="name.invalidPattern" value="Member name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <!--Validates identifiers for class type parameters-->
+        <module name="ClassTypeParameterName">
+            <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+            <message key="name.invalidPattern" value="Class type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <module name="PackageName">
+            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]{1,})*$"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="ConstantNameCheck">
+            <!-- Validates non-private, static, final fields against the supplied public/package final fields "^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$". -->
+            <metadata name="altname" value="ConstantName"/>
+            <property name="applyToPublic" value="true"/>
+            <property name="applyToProtected" value="true"/>
+            <property name="applyToPackage" value="true"/>
+            <property name="applyToPrivate" value="false"/>
+            <property name="format" value="^([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|FLAG_.*)$"/>
+            <message key="name.invalidPattern"
+                     value="Variable ''{0}'' should be in ALL_CAPS (if it is a constant) or be private (otherwise)."/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="MemberNameCheck">
+            <!-- Validates non-static members against the supplied expression. -->
+            <metadata name="altname" value="MemberName"/>
+            <property name="applyToPublic" value="true"/>
+            <property name="applyToProtected" value="true"/>
+            <property name="applyToPackage" value="true"/>
+            <property name="applyToPrivate" value="true"/>
+            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="MethodNameCheck">
+            <!-- Validates identifiers for method names. -->
+            <metadata name="altname" value="MethodName"/>
+            <property name="format" value="^[a-z][a-zA-Z0-9]*(_[a-zA-Z0-9]+)*$"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="MethodName">
+            <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
+            <message key="name.invalidPattern" value="Method name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <module name="EmptyCatchBlock">
+            <property name="exceptionVariableName" value="expected"/>
+        </module>
+
+        <module name="CommentsIndentation"/>
+
+        <module name="ParameterName">
+            <!-- Validates identifiers for method parameters against the expression "^[a-z][a-zA-Z0-9]*$". -->
+            <property name="format" value="^[a-z]([a-zA-Z0-9]*)?$"/>
+            <property name="severity" value="error"/>
+            <message key="name.invalidPattern" value="Parameter name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <module name="CatchParameterName">
+            <property name="format" value="^[a-z]([a-zA-Z0-9]*)?$"/>
+            <message key="name.invalidPattern" value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+
+        <module name="StaticVariableNameCheck">
+            <!-- Validates static, non-final fields against the supplied expression "^[a-z][a-zA-Z0-9]*_?$". -->
+            <metadata name="altname" value="StaticVariableName"/>
+            <property name="applyToPublic" value="true"/>
+            <property name="applyToProtected" value="true"/>
+            <property name="applyToPackage" value="true"/>
+            <property name="applyToPrivate" value="true"/>
+            <property name="format" value="(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="TypeNameCheck">
+            <!-- Validates static, final fields against the expression "^[A-Z][a-zA-Z0-9]*$". -->
+            <metadata name="altname" value="TypeName"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="TypeName">
+            <property name="format" value="(^[A-Z][a-zA-Z0-9]*$)|(^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$)"/>
+            <message key="name.invalidPattern" value="Type name ''{0}'' must match pattern ''{1}''."/>
+        </module>
+        <module name="MissingOverride"/>
+
+        <!--whitespace-->
+        <module name="GenericWhitespace">
+            <message key="ws.followed" value="GenericWhitespace ''{0}'' is followed by whitespace."/>
+            <message key="ws.preceded" value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
+            <message key="ws.illegalFollow" value="GenericWhitespace ''{0}'' should followed by whitespace."/>
+            <message key="ws.notPreceded" value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
+        </module>
+
+        <module name="Indentation">
+            <property name="basicOffset" value="4"/>
+            <property name="braceAdjustment" value="0"/>
+            <property name="caseIndent" value="4"/>
+            <property name="throwsIndent" value="2"/>
+            <property name="lineWrappingIndentation" value="4"/>
+            <property name="arrayInitIndent" value="4"/>
+        </module>
+
+        <module name="NoFinalizer"/>
+
+        <module name="NoWhitespaceAfter">
+            <!-- Checks that there is no whitespace after various unary operators.
+                 Linebreaks are allowed.
+            -->
+            <property name="tokens" value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/>
+            <property name="allowLineBreaks" value="true"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="WhitespaceAfter">
+            <!-- Checks that commas, semicolons and typecasts are followed by
+                 whitespace.
+            -->
+            <property name="tokens" value="COMMA, SEMI, TYPECAST"/>
+        </module>
+
+        <module name="WhitespaceAround">
+            <!-- Checks that various tokens are surrounded by whitespace.
+                 This includes most binary operators and keywords followed
+                 by regular or curly braces.
+            -->
+            <property name="allowEmptyConstructors" value="true"/>
+            <property name="allowEmptyMethods" value="true"/>
+            <property name="allowEmptyTypes" value="true"/>
+            <property name="allowEmptyLoops" value="true"/>
+            <property name="severity" value="error"/>
+            <property name="tokens" value="ASSIGN, BAND, BAND_ASSIGN, BOR,
+        BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN,
+        EQUAL, GE, GT, LAMBDA, LAND, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
+        LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
+        LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS,
+        MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION,
+        SL, SL_ASSIGN, SR_ASSIGN, STAR, STAR_ASSIGN, TYPE_EXTENSION_AND"/>
+            <message key="ws.notFollowed"
+                     value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
+            <message key="ws.notPreceded" value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
+        </module>
+
+        <module name="MethodParamPad"/>
+        <module name="ParenPad">
+            <!-- Checks that there is no whitespace before close parens or after open parens. -->
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="NoWhitespaceBefore">
+            <!-- Checks that there is no whitespace before various unary operators. Linebreaks are allowed. -->
+            <property name="tokens" value="COMMA, SEMI, DOT, POST_DEC, POST_INC, ELLIPSIS, METHOD_REF"/>
+            <property name="allowLineBreaks" value="true"/>
+            <property name="severity" value="error"/>
+        </module>
+
+        <module name="OperatorWrap">
+            <!-- Checks that assignment operators are at the end of the line. -->
+            <property name="option" value="eol"/>
+            <property name="tokens"
+                      value="ASSIGN, BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LE, LITERAL_INSTANCEOF, LT, MINUS, MOD, NOT_EQUAL, QUESTION, SL, SR, STAR, METHOD_REF"/>
+        </module>
+
+        <module name="AnnotationLocation">
+            <property name="allowSamelineMultipleAnnotations" value="false"/>
+            <property name="allowSamelineSingleParameterlessAnnotation" value="false"/>
+            <property name="allowSamelineParameterizedAnnotation" value="true"/>
+            <property name="tokens" value="METHOD_DEF, CTOR_DEF, VARIABLE_DEF, CLASS_DEF, INTERFACE_DEF, ENUM_DEF"/>
+        </module>
+
+        <module name="TypecastParenPad"/>
+
+        <module name="EmptyLineSeparator">
+            <!-- Checks for empty line separator between tokens. The only
+                 excluded token is VARIABLE_DEF, allowing class fields to
+                 be declared on consecutive lines.
+            -->
+            <property name="allowNoEmptyLineBetweenFields" value="true"/>
+            <property name="allowMultipleEmptyLines" value="false"/>
+            <property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
+            <property name="tokens"
+                      value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF, STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF"/>
+        </module>
+    </module>
+    
+</module>