This is an automated email from the ASF dual-hosted git repository.
jinsongzhou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/amoro.git
The following commit(s) were added to refs/heads/master by this push:
new a8cc843f9 [AMORO-3210] Support loading flink mixed catalog without ams
url (#3211)
a8cc843f9 is described below
commit a8cc843f98af7daadd47f80287a9c83586ab2807
Author: ZhouJinsong <[email protected]>
AuthorDate: Fri Sep 20 15:46:01 2024 +0800
[AMORO-3210] Support loading flink mixed catalog without ams url (#3211)
* Support loading flink mixed catalog without ams url
* Change some flink doc description
* Fix a spelling issue in method name
* Fix a style error
---
.../java/org/apache/amoro/utils/CatalogUtil.java | 2 +-
.../java/org/apache/amoro/mixed/CatalogLoader.java | 6 +-
.../apache/amoro/utils/MixedFormatCatalogUtil.java | 173 -------
.../amoro/catalog/BasicCatalogTestHelper.java | 4 +-
.../apache/amoro/catalog/BasicMixedCatalog.java | 3 +-
.../org/apache/amoro/catalog/TableTestBase.java | 4 +-
.../formats/IcebergHadoopCatalogTestHelper.java | 5 +-
.../MixedIcebergHadoopCatalogTestHelper.java | 6 +-
.../apache/amoro/flink/InternalCatalogBuilder.java | 87 +++-
.../amoro/flink/catalog/FlinkUnifiedCatalog.java | 7 +-
.../apache/amoro/flink/catalog/MixedCatalog.java | 6 +-
.../catalog/factories/CatalogFactoryOptions.java | 47 --
.../factories/FlinkUnifiedCatalogFactory.java | 64 ++-
.../factories/mixed/MixedCatalogFactory.java | 55 +-
.../flink/table/KafkaConnectorOptionsUtil.java | 567 ---------------------
...eFactory.java => MixedDynamicTableFactory.java} | 26 +-
.../org/apache/amoro/flink/table/OptionsUtil.java | 64 +++
...actory.java => UnifiedDynamicTableFactory.java} | 8 +-
.../org.apache.flink.table.factories.Factory | 2 +-
.../amoro/flink/catalog/TestMixedCatalog.java | 10 +-
.../org.apache.flink.table.factories.Factory | 2 +-
docs/engines/flink/flink-ddl.md | 13 +-
22 files changed, 250 insertions(+), 911 deletions(-)
diff --git a/amoro-common/src/main/java/org/apache/amoro/utils/CatalogUtil.java
b/amoro-common/src/main/java/org/apache/amoro/utils/CatalogUtil.java
index 89d3e7fdf..bd49ea931 100644
--- a/amoro-common/src/main/java/org/apache/amoro/utils/CatalogUtil.java
+++ b/amoro-common/src/main/java/org/apache/amoro/utils/CatalogUtil.java
@@ -197,7 +197,7 @@ public class CatalogUtil {
tableMeta.getTableIdentifier().getTableName());
}
- public static org.apache.amoro.api.TableIdentifier amsTaleId(TableIdentifier
tableIdentifier) {
+ public static org.apache.amoro.api.TableIdentifier
amsTableId(TableIdentifier tableIdentifier) {
return new org.apache.amoro.api.TableIdentifier(
tableIdentifier.getCatalog(),
tableIdentifier.getDatabase(),
diff --git
a/amoro-format-iceberg/src/main/java/org/apache/amoro/mixed/CatalogLoader.java
b/amoro-format-iceberg/src/main/java/org/apache/amoro/mixed/CatalogLoader.java
index 3842e8e6a..b285fec01 100644
---
a/amoro-format-iceberg/src/main/java/org/apache/amoro/mixed/CatalogLoader.java
+++
b/amoro-format-iceberg/src/main/java/org/apache/amoro/mixed/CatalogLoader.java
@@ -31,6 +31,7 @@ import org.apache.amoro.properties.CatalogMetaProperties;
import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
import org.apache.amoro.shade.thrift.org.apache.thrift.TException;
import org.apache.amoro.table.TableMetaStore;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.amoro.utils.MixedFormatCatalogUtil;
import org.apache.iceberg.common.DynConstructors;
@@ -86,8 +87,7 @@ public class CatalogLoader {
catalogImpl = MIXED_ICEBERG_CATALOG_IMP;
break;
case CatalogMetaProperties.CATALOG_TYPE_HIVE:
- Set<TableFormat> tableFormats =
- MixedFormatCatalogUtil.tableFormats(metastoreType,
catalogProperties);
+ Set<TableFormat> tableFormats =
CatalogUtil.tableFormats(metastoreType, catalogProperties);
if (tableFormats.contains(TableFormat.MIXED_HIVE)) {
catalogImpl = HIVE_CATALOG_IMPL;
} else {
@@ -142,7 +142,7 @@ public class CatalogLoader {
catalogName,
type,
catalogMeta.getCatalogProperties(),
- MixedFormatCatalogUtil.buildMetaStore(catalogMeta));
+ CatalogUtil.buildMetaStore(catalogMeta));
} catch (NoSuchObjectException e1) {
throw new IllegalArgumentException("catalog not found, please check
catalog name", e1);
} catch (Exception e) {
diff --git
a/amoro-format-iceberg/src/main/java/org/apache/amoro/utils/MixedFormatCatalogUtil.java
b/amoro-format-iceberg/src/main/java/org/apache/amoro/utils/MixedFormatCatalogUtil.java
index ba3a5e2e1..3508bfefc 100644
---
a/amoro-format-iceberg/src/main/java/org/apache/amoro/utils/MixedFormatCatalogUtil.java
+++
b/amoro-format-iceberg/src/main/java/org/apache/amoro/utils/MixedFormatCatalogUtil.java
@@ -18,20 +18,14 @@
package org.apache.amoro.utils;
-import org.apache.amoro.TableFormat;
import org.apache.amoro.api.CatalogMeta;
-import org.apache.amoro.api.TableMeta;
import org.apache.amoro.io.AuthenticatedFileIO;
import org.apache.amoro.op.MixedHadoopTableOperations;
import org.apache.amoro.op.MixedTableOperations;
import org.apache.amoro.properties.CatalogMetaProperties;
import org.apache.amoro.shade.guava32.com.google.common.base.Preconditions;
import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
-import org.apache.amoro.shade.guava32.com.google.common.collect.Sets;
-import org.apache.amoro.table.TableIdentifier;
-import org.apache.amoro.table.TableMetaStore;
import org.apache.amoro.table.TableProperties;
-import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.iceberg.BaseTable;
@@ -46,49 +40,13 @@ import org.apache.iceberg.util.PropertyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Arrays;
-import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.stream.Collectors;
public class MixedFormatCatalogUtil {
private static final Logger LOG =
LoggerFactory.getLogger(MixedFormatCatalogUtil.class);
- /** Return table format set catalog supported. */
- public static Set<TableFormat> tableFormats(CatalogMeta meta) {
- return tableFormats(meta.getCatalogType(), meta.getCatalogProperties());
- }
-
- /** Return table format set catalog supported. */
- public static Set<TableFormat> tableFormats(
- String metastoreType, Map<String, String> catalogProperties) {
- if (catalogProperties != null
- && catalogProperties.containsKey(CatalogMetaProperties.TABLE_FORMATS))
{
- String tableFormatsProperty =
catalogProperties.get(CatalogMetaProperties.TABLE_FORMATS);
- return Arrays.stream(tableFormatsProperty.split(","))
- .map(
- tableFormatString ->
-
TableFormat.valueOf(tableFormatString.trim().toUpperCase(Locale.ROOT)))
- .collect(Collectors.toSet());
- } else {
- // Generate table format from catalog type for compatibility with older
versions
- switch (metastoreType) {
- case CatalogMetaProperties.CATALOG_TYPE_AMS:
- return Sets.newHashSet(TableFormat.MIXED_ICEBERG);
- case CatalogMetaProperties.CATALOG_TYPE_CUSTOM:
- case CatalogMetaProperties.CATALOG_TYPE_HADOOP:
- case CatalogMetaProperties.CATALOG_TYPE_GLUE:
- return Sets.newHashSet(TableFormat.ICEBERG);
- case CatalogMetaProperties.CATALOG_TYPE_HIVE:
- return Sets.newHashSet(TableFormat.MIXED_HIVE);
- default:
- throw new IllegalArgumentException("Unsupported catalog type:" +
metastoreType);
- }
- }
- }
-
/** Merge catalog properties in client side into catalog meta. */
public static void mergeCatalogProperties(CatalogMeta meta, Map<String,
String> properties) {
if (meta.getCatalogProperties() == null) {
@@ -135,90 +93,6 @@ public class MixedFormatCatalogUtil {
return icebergCatalogProperties;
}
- /** Build {@link TableMetaStore} from catalog meta. */
- public static TableMetaStore buildMetaStore(CatalogMeta catalogMeta) {
- // load storage configs
- TableMetaStore.Builder builder = TableMetaStore.builder();
- if (catalogMeta.getStorageConfigs() != null) {
- Map<String, String> storageConfigs = catalogMeta.getStorageConfigs();
- if
(CatalogMetaProperties.STORAGE_CONFIGS_VALUE_TYPE_HADOOP.equalsIgnoreCase(
- MixedFormatCatalogUtil.getCompatibleStorageType(storageConfigs))) {
- String coreSite =
storageConfigs.get(CatalogMetaProperties.STORAGE_CONFIGS_KEY_CORE_SITE);
- String hdfsSite =
storageConfigs.get(CatalogMetaProperties.STORAGE_CONFIGS_KEY_HDFS_SITE);
- String hiveSite =
storageConfigs.get(CatalogMetaProperties.STORAGE_CONFIGS_KEY_HIVE_SITE);
- builder
- .withBase64CoreSite(coreSite)
- .withBase64MetaStoreSite(hiveSite)
- .withBase64HdfsSite(hdfsSite);
- }
- }
-
- boolean loadAuthFromAMS =
- PropertyUtil.propertyAsBoolean(
- catalogMeta.getCatalogProperties(),
- CatalogMetaProperties.LOAD_AUTH_FROM_AMS,
- CatalogMetaProperties.LOAD_AUTH_FROM_AMS_DEFAULT);
- // load auth configs from ams
- if (loadAuthFromAMS) {
- if (catalogMeta.getAuthConfigs() != null) {
- Map<String, String> authConfigs = catalogMeta.getAuthConfigs();
- String authType =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_TYPE);
- LOG.info("TableMetaStore use auth config in catalog meta, authType is
{}", authType);
- if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_SIMPLE.equalsIgnoreCase(authType))
{
- String hadoopUsername =
-
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_HADOOP_USERNAME);
- builder.withSimpleAuth(hadoopUsername);
- } else if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_KERBEROS.equalsIgnoreCase(
- authType)) {
- String krb5 =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_KRB5);
- String keytab =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_KEYTAB);
- String principal =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_PRINCIPAL);
- builder.withBase64KrbAuth(keytab, krb5, principal);
- } else if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_AK_SK.equalsIgnoreCase(authType))
{
- String accessKey =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_ACCESS_KEY);
- String secretKey =
authConfigs.get(CatalogMetaProperties.AUTH_CONFIGS_KEY_SECRET_KEY);
- builder.withAkSkAuth(accessKey, secretKey);
- }
- }
- }
-
- // cover auth configs from ams with auth configs in properties
- String authType =
-
catalogMeta.getCatalogProperties().get(CatalogMetaProperties.AUTH_CONFIGS_KEY_TYPE);
- if (StringUtils.isNotEmpty(authType)) {
- LOG.info("TableMetaStore use auth config in properties, authType is {}",
authType);
- if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_SIMPLE.equalsIgnoreCase(authType))
{
- String hadoopUsername =
- catalogMeta
- .getCatalogProperties()
- .get(CatalogMetaProperties.AUTH_CONFIGS_KEY_HADOOP_USERNAME);
- builder.withSimpleAuth(hadoopUsername);
- } else if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_KERBEROS.equalsIgnoreCase(
- authType)) {
- String krb5 =
-
catalogMeta.getCatalogProperties().get(CatalogMetaProperties.AUTH_CONFIGS_KEY_KRB5);
- String keytab =
-
catalogMeta.getCatalogProperties().get(CatalogMetaProperties.AUTH_CONFIGS_KEY_KEYTAB);
- String principal =
- catalogMeta
- .getCatalogProperties()
- .get(CatalogMetaProperties.AUTH_CONFIGS_KEY_PRINCIPAL);
- builder.withBase64KrbAuth(keytab, krb5, principal);
- } else if
(CatalogMetaProperties.AUTH_CONFIGS_VALUE_TYPE_AK_SK.equalsIgnoreCase(authType))
{
- String accessKey =
- catalogMeta
- .getCatalogProperties()
- .get(CatalogMetaProperties.AUTH_CONFIGS_KEY_ACCESS_KEY);
- String secretKey =
- catalogMeta
- .getCatalogProperties()
- .get(CatalogMetaProperties.AUTH_CONFIGS_KEY_SECRET_KEY);
- builder.withAkSkAuth(accessKey, secretKey);
- }
- }
- return builder.build();
- }
-
/** Wrap table operation with authorization logic for {@link Table}. */
public static Table useMixedTableOperations(
Table table,
@@ -295,53 +169,6 @@ public class MixedFormatCatalogUtil {
return mergedProperties;
}
- public static TableIdentifier tableId(TableMeta tableMeta) {
- return TableIdentifier.of(
- tableMeta.getTableIdentifier().getCatalog(),
- tableMeta.getTableIdentifier().getDatabase(),
- tableMeta.getTableIdentifier().getTableName());
- }
-
- public static org.apache.amoro.api.TableIdentifier amsTaleId(TableIdentifier
tableIdentifier) {
- return new org.apache.amoro.api.TableIdentifier(
- tableIdentifier.getCatalog(),
- tableIdentifier.getDatabase(),
- tableIdentifier.getTableName());
- }
-
- /**
- * Get storage type compatible with history storage type `hdfs`, which is
`Hadoop` now.
- *
- * @param conf - configurations containing `storage.type`
- * @return storage type, return `Hadoop` if `storage.type` is `hdfs`, return
null if
- * `storage.type` not exist.
- */
- public static String getCompatibleStorageType(Map<String, String> conf) {
- if (CatalogMetaProperties.STORAGE_CONFIGS_VALUE_TYPE_HDFS_LEGACY.equals(
- conf.get(CatalogMetaProperties.STORAGE_CONFIGS_KEY_TYPE))) {
- return CatalogMetaProperties.STORAGE_CONFIGS_VALUE_TYPE_HADOOP;
- }
- return conf.get(CatalogMetaProperties.STORAGE_CONFIGS_KEY_TYPE);
- }
-
- /**
- * Copy property from source properties to target properties, support
changing the key name.
- *
- * @param fromProperties - from these properties
- * @param toProperties - to these properties
- * @param fromKey - from key
- * @param toKey - to key
- */
- public static <T> void copyProperty(
- Map<String, String> fromProperties,
- Map<String, T> toProperties,
- String fromKey,
- String toKey) {
- if (StringUtils.isNotEmpty(fromProperties.get(fromKey))) {
- toProperties.put(toKey, (T) fromProperties.get(fromKey));
- }
- }
-
/**
* Build cache catalog.
*
diff --git
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicCatalogTestHelper.java
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicCatalogTestHelper.java
index 599cfffd3..054864f99 100644
---
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicCatalogTestHelper.java
+++
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicCatalogTestHelper.java
@@ -25,7 +25,6 @@ import org.apache.amoro.api.CatalogMeta;
import org.apache.amoro.properties.CatalogMetaProperties;
import org.apache.amoro.shade.guava32.com.google.common.base.Preconditions;
import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
-import org.apache.amoro.utils.MixedFormatCatalogUtil;
import org.apache.hadoop.conf.Configuration;
import org.apache.iceberg.CatalogUtil;
import org.apache.iceberg.catalog.Catalog;
@@ -100,7 +99,8 @@ public class BasicCatalogTestHelper implements
CatalogTestHelper {
"Cannot build mixed-tables for table format:" + tableFormat);
}
return new MixedTables(
- catalogMeta.getCatalogProperties(),
MixedFormatCatalogUtil.buildMetaStore(catalogMeta));
+ catalogMeta.getCatalogProperties(),
+ org.apache.amoro.utils.CatalogUtil.buildMetaStore(catalogMeta));
}
@Override
diff --git
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicMixedCatalog.java
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicMixedCatalog.java
index 9717db05f..16b7c0afa 100644
---
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicMixedCatalog.java
+++
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/BasicMixedCatalog.java
@@ -47,6 +47,7 @@ import org.apache.amoro.table.TableMetaStore;
import org.apache.amoro.table.TableProperties;
import org.apache.amoro.table.blocker.BasicTableBlockerManager;
import org.apache.amoro.table.blocker.TableBlockerManager;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.amoro.utils.CompatiblePropertyUtil;
import org.apache.amoro.utils.ConvertStructUtil;
import org.apache.amoro.utils.MixedFormatCatalogUtil;
@@ -214,7 +215,7 @@ public class BasicMixedCatalog implements
MixedFormatCatalog {
protected TableMeta getMixedTableMeta(TableIdentifier identifier) {
TableMeta tableMeta;
try {
- tableMeta =
getClient().getTable(MixedFormatCatalogUtil.amsTaleId(identifier));
+ tableMeta = getClient().getTable(CatalogUtil.amsTableId(identifier));
return tableMeta;
} catch (NoSuchObjectException e) {
throw new NoSuchTableException(e, "load table failed %s.", identifier);
diff --git
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/TableTestBase.java
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/TableTestBase.java
index 2dc49c9d9..7e6419256 100644
---
a/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/TableTestBase.java
+++
b/amoro-format-iceberg/src/test/java/org/apache/amoro/catalog/TableTestBase.java
@@ -23,7 +23,7 @@ import org.apache.amoro.table.MixedTable;
import org.apache.amoro.table.TableBuilder;
import org.apache.amoro.table.TableMetaStore;
import org.apache.amoro.table.UnkeyedTable;
-import org.apache.amoro.utils.MixedFormatCatalogUtil;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.amoro.utils.MixedTableUtil;
import org.junit.After;
import org.junit.Before;
@@ -41,7 +41,7 @@ public abstract class TableTestBase extends CatalogTestBase {
@Before
public void setupTable() {
- this.tableMetaStore =
MixedFormatCatalogUtil.buildMetaStore(getCatalogMeta());
+ this.tableMetaStore = CatalogUtil.buildMetaStore(getCatalogMeta());
getUnifiedCatalog().createDatabase(TableTestHelper.TEST_DB_NAME);
switch (getTestFormat()) {
diff --git
a/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/IcebergHadoopCatalogTestHelper.java
b/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/IcebergHadoopCatalogTestHelper.java
index 6fad3b3c7..34625cc2d 100644
---
a/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/IcebergHadoopCatalogTestHelper.java
+++
b/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/IcebergHadoopCatalogTestHelper.java
@@ -24,6 +24,7 @@ import org.apache.amoro.formats.iceberg.IcebergCatalogFactory;
import org.apache.amoro.shade.guava32.com.google.common.collect.Lists;
import org.apache.amoro.shade.guava32.com.google.common.collect.Sets;
import org.apache.amoro.table.TableMetaStore;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.amoro.utils.MixedFormatCatalogUtil;
import org.apache.hadoop.conf.Configuration;
import org.apache.iceberg.PartitionSpec;
@@ -73,7 +74,7 @@ public class IcebergHadoopCatalogTestHelper extends
AbstractFormatCatalogTestHel
@Override
public AmoroCatalog amoroCatalog() {
IcebergCatalogFactory icebergCatalogFactory = new IcebergCatalogFactory();
- TableMetaStore metaStore =
MixedFormatCatalogUtil.buildMetaStore(getCatalogMeta());
+ TableMetaStore metaStore = CatalogUtil.buildMetaStore(getCatalogMeta());
Map<String, String> properties =
icebergCatalogFactory.convertCatalogProperties(
catalogName, getMetastoreType(), catalogProperties);
@@ -85,7 +86,7 @@ public class IcebergHadoopCatalogTestHelper extends
AbstractFormatCatalogTestHel
Map<String, String> props =
MixedFormatCatalogUtil.withIcebergCatalogInitializeProperties(
catalogName, getMetastoreType(), catalogProperties);
- TableMetaStore metaStore =
MixedFormatCatalogUtil.buildMetaStore(getCatalogMeta());
+ TableMetaStore metaStore = CatalogUtil.buildMetaStore(getCatalogMeta());
return org.apache.iceberg.CatalogUtil.buildIcebergCatalog(
catalogName, props, metaStore.getConfiguration());
}
diff --git
a/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/MixedIcebergHadoopCatalogTestHelper.java
b/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/MixedIcebergHadoopCatalogTestHelper.java
index da7b00c9d..ceb5642bd 100644
---
a/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/MixedIcebergHadoopCatalogTestHelper.java
+++
b/amoro-format-iceberg/src/test/java/org/apache/amoro/formats/MixedIcebergHadoopCatalogTestHelper.java
@@ -28,7 +28,7 @@ import
org.apache.amoro.shade.guava32.com.google.common.collect.Lists;
import org.apache.amoro.shade.guava32.com.google.common.collect.Sets;
import org.apache.amoro.table.TableIdentifier;
import org.apache.amoro.table.TableMetaStore;
-import org.apache.amoro.utils.MixedFormatCatalogUtil;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.iceberg.PartitionSpec;
import org.apache.iceberg.Schema;
import org.apache.iceberg.types.Types;
@@ -63,7 +63,7 @@ public class MixedIcebergHadoopCatalogTestHelper
@Override
public AmoroCatalog amoroCatalog() {
MixedIcebergCatalogFactory mixedIcebergCatalogFactory = new
MixedIcebergCatalogFactory();
- TableMetaStore metaStore =
MixedFormatCatalogUtil.buildMetaStore(getCatalogMeta());
+ TableMetaStore metaStore = CatalogUtil.buildMetaStore(getCatalogMeta());
Map<String, String> properties =
mixedIcebergCatalogFactory.convertCatalogProperties(
catalogName, getMetastoreType(), catalogProperties);
@@ -74,7 +74,7 @@ public class MixedIcebergHadoopCatalogTestHelper
@Override
public MixedFormatCatalog originalCatalog() {
CatalogMeta meta = getCatalogMeta();
- TableMetaStore metaStore = MixedFormatCatalogUtil.buildMetaStore(meta);
+ TableMetaStore metaStore = CatalogUtil.buildMetaStore(meta);
return CatalogLoader.createCatalog(
catalogName(), meta.getCatalogType(), meta.getCatalogProperties(),
metaStore);
}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/InternalCatalogBuilder.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/InternalCatalogBuilder.java
index b286defac..089255df5 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/InternalCatalogBuilder.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/InternalCatalogBuilder.java
@@ -18,18 +18,31 @@
package org.apache.amoro.flink;
+import static org.apache.iceberg.CatalogUtil.ICEBERG_CATALOG_TYPE_HIVE;
+import static org.apache.iceberg.flink.FlinkCatalogFactory.HADOOP_CONF_DIR;
+import static org.apache.iceberg.flink.FlinkCatalogFactory.HIVE_CONF_DIR;
+
import org.apache.amoro.mixed.CatalogLoader;
import org.apache.amoro.mixed.MixedFormatCatalog;
import org.apache.amoro.properties.CatalogMetaProperties;
+import org.apache.amoro.shade.guava32.com.google.common.base.Strings;
+import org.apache.amoro.table.TableMetaStore;
import org.apache.amoro.utils.ConfigurationFileUtil;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.flink.configuration.GlobalConfiguration;
+import org.apache.flink.runtime.util.HadoopUtils;
import org.apache.flink.table.catalog.exceptions.CatalogException;
import org.apache.flink.util.Preconditions;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.iceberg.flink.FlinkCatalogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.Serializable;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@@ -39,12 +52,68 @@ public class InternalCatalogBuilder implements Serializable
{
private String metastoreUrl;
private Map<String, String> properties = new HashMap<>(0);
+ private String catalogName;
private MixedFormatCatalog createMixedFormatCatalog() {
- Preconditions.checkArgument(
- StringUtils.isNotBlank(metastoreUrl),
- "metastoreUrl can not be empty. e.g:
thrift://127.0.0.1:port/catalogName");
- return CatalogLoader.load(metastoreUrl, properties);
+ if (metastoreUrl != null) {
+ return CatalogLoader.load(metastoreUrl, properties);
+ } else {
+ Preconditions.checkArgument(catalogName != null, "Catalog name cannot be
empty");
+ String metastoreType =
properties.get(FlinkCatalogFactory.ICEBERG_CATALOG_TYPE);
+ Preconditions.checkArgument(metastoreType != null, "Catalog type cannot
be empty");
+ TableMetaStore tableMetaStore =
+ TableMetaStore.builder()
+ .withConfiguration(clusterHadoopConf(metastoreType, properties))
+ .build();
+ return CatalogLoader.createCatalog(catalogName, metastoreType,
properties, tableMetaStore);
+ }
+ }
+
+ public static Configuration clusterHadoopConf(
+ String metastoreType, Map<String, String> properties) {
+ Configuration configuration =
+
HadoopUtils.getHadoopConfiguration(GlobalConfiguration.loadConfiguration());
+ if (ICEBERG_CATALOG_TYPE_HIVE.equals(metastoreType)) {
+ String hiveConfDir = properties.get(HIVE_CONF_DIR);
+ String hadoopConfDir = properties.get(HADOOP_CONF_DIR);
+ configuration = mergeHiveConf(configuration, hiveConfDir, hadoopConfDir);
+ }
+ return configuration;
+ }
+
+ private static Configuration mergeHiveConf(
+ Configuration hadoopConf, String hiveConfDir, String hadoopConfDir) {
+ Configuration newConf = new Configuration(hadoopConf);
+ if (!Strings.isNullOrEmpty(hiveConfDir)) {
+ Preconditions.checkState(
+ Files.exists(Paths.get(hiveConfDir, "hive-site.xml")),
+ "There should be a hive-site.xml file under the directory %s",
+ hiveConfDir);
+ newConf.addResource(new Path(hiveConfDir, "hive-site.xml"));
+ } else {
+ // If don't provide the hive-site.xml path explicitly, it will try to
load resource from
+ // classpath. If still
+ // couldn't load the configuration file, then it will throw exception in
HiveCatalog.
+ URL configFile =
InternalCatalogBuilder.class.getClassLoader().getResource("hive-site.xml");
+ if (configFile != null) {
+ newConf.addResource(configFile);
+ }
+ }
+
+ if (!Strings.isNullOrEmpty(hadoopConfDir)) {
+ Preconditions.checkState(
+ Files.exists(Paths.get(hadoopConfDir, "hdfs-site.xml")),
+ "Failed to load Hadoop configuration: missing %s",
+ Paths.get(hadoopConfDir, "hdfs-site.xml"));
+ newConf.addResource(new Path(hadoopConfDir, "hdfs-site.xml"));
+ Preconditions.checkState(
+ Files.exists(Paths.get(hadoopConfDir, "core-site.xml")),
+ "Failed to load Hadoop configuration: missing %s",
+ Paths.get(hadoopConfDir, "core-site.xml"));
+ newConf.addResource(new Path(hadoopConfDir, "core-site.xml"));
+ }
+
+ return newConf;
}
public String getMetastoreUrl() {
@@ -66,9 +135,6 @@ public class InternalCatalogBuilder implements Serializable {
}
public InternalCatalogBuilder metastoreUrl(String metastoreUrl) {
- Preconditions.checkArgument(
- StringUtils.isNotBlank(metastoreUrl),
- "metastore url can not be empty e.g:
thrift://127.0.0.1:port/catalogName");
this.metastoreUrl = metastoreUrl;
return this;
}
@@ -113,4 +179,9 @@ public class InternalCatalogBuilder implements Serializable
{
this.properties = finalProperties;
return this;
}
+
+ public InternalCatalogBuilder catalogName(String catalogName) {
+ this.catalogName = catalogName;
+ return this;
+ }
}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/FlinkUnifiedCatalog.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/FlinkUnifiedCatalog.java
index 1ce6aff3b..3d944adb7 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/FlinkUnifiedCatalog.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/FlinkUnifiedCatalog.java
@@ -33,7 +33,7 @@ import
org.apache.amoro.flink.catalog.factories.FlinkUnifiedCatalogFactory;
import
org.apache.amoro.flink.catalog.factories.iceberg.IcebergFlinkCatalogFactory;
import org.apache.amoro.flink.catalog.factories.mixed.MixedCatalogFactory;
import
org.apache.amoro.flink.catalog.factories.paimon.PaimonFlinkCatalogFactory;
-import org.apache.amoro.flink.table.AmoroDynamicTableFactory;
+import org.apache.amoro.flink.table.UnifiedDynamicTableFactory;
import org.apache.amoro.shade.guava32.com.google.common.base.Preconditions;
import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
import org.apache.amoro.table.TableIdentifier;
@@ -62,8 +62,6 @@ import
org.apache.flink.table.catalog.stats.CatalogTableStatistics;
import org.apache.flink.table.expressions.Expression;
import org.apache.flink.table.factories.CatalogFactory;
import org.apache.flink.table.factories.Factory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
@@ -72,7 +70,6 @@ import java.util.Optional;
/** This is a Flink catalog wrap a unified catalog. */
public class FlinkUnifiedCatalog extends AbstractCatalog {
- private static final Logger LOG =
LoggerFactory.getLogger(FlinkUnifiedCatalog.class);
private final UnifiedCatalog unifiedCatalog;
private final String amsUri;
@@ -329,7 +326,7 @@ public class FlinkUnifiedCatalog extends AbstractCatalog {
@Override
public Optional<Factory> getFactory() {
- return Optional.of(new AmoroDynamicTableFactory(availableCatalogs));
+ return Optional.of(new UnifiedDynamicTableFactory(availableCatalogs));
}
@Override
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/MixedCatalog.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/MixedCatalog.java
index d43d9a1f0..d8dba8a50 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/MixedCatalog.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/MixedCatalog.java
@@ -27,7 +27,7 @@ import static
org.apache.flink.util.Preconditions.checkNotNull;
import org.apache.amoro.NoSuchDatabaseException;
import org.apache.amoro.flink.InternalCatalogBuilder;
import org.apache.amoro.flink.catalog.factories.CatalogFactoryOptions;
-import org.apache.amoro.flink.table.DynamicTableFactory;
+import org.apache.amoro.flink.table.MixedDynamicTableFactory;
import org.apache.amoro.flink.table.descriptors.MixedFormatValidator;
import org.apache.amoro.flink.util.MixedFormatUtils;
import org.apache.amoro.mixed.MixedFormatCatalog;
@@ -237,7 +237,7 @@ public class MixedCatalog extends AbstractCatalog {
return;
}
- properties.put(CONNECTOR.key(), DynamicTableFactory.IDENTIFIER);
+ properties.put(CONNECTOR.key(), MixedDynamicTableFactory.IDENTIFIER);
properties.put(MixedFormatValidator.MIXED_FORMAT_CATALOG.key(),
tableIdentifier.getCatalog());
properties.put(MixedFormatValidator.MIXED_FORMAT_TABLE.key(),
tableIdentifier.getTableName());
properties.put(MixedFormatValidator.MIXED_FORMAT_DATABASE.key(),
tableIdentifier.getDatabase());
@@ -611,7 +611,7 @@ public class MixedCatalog extends AbstractCatalog {
@Override
public Optional<Factory> getFactory() {
- return Optional.of(new DynamicTableFactory(this));
+ return Optional.of(new MixedDynamicTableFactory(this));
}
public InternalCatalogBuilder catalogBuilder() {
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/CatalogFactoryOptions.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/CatalogFactoryOptions.java
index 75f57737a..464e32eb0 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/CatalogFactoryOptions.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/CatalogFactoryOptions.java
@@ -18,16 +18,13 @@
package org.apache.amoro.flink.catalog.factories;
-import static org.apache.amoro.flink.catalog.MixedCatalog.DEFAULT_DB;
import static org.apache.amoro.properties.CatalogMetaProperties.TABLE_FORMATS;
import org.apache.amoro.flink.catalog.FlinkUnifiedCatalog;
import org.apache.amoro.flink.catalog.MixedCatalog;
-import org.apache.amoro.properties.CatalogMetaProperties;
import org.apache.flink.annotation.Internal;
import org.apache.flink.configuration.ConfigOption;
import org.apache.flink.configuration.ConfigOptions;
-import org.apache.flink.table.catalog.CommonCatalogOptions;
/** {@link ConfigOption}s for {@link MixedCatalog} and {@link
FlinkUnifiedCatalog}. */
@Internal
@@ -37,53 +34,9 @@ public class CatalogFactoryOptions {
@Deprecated public static final String LEGACY_MIXED_IDENTIFIER = "arctic";
public static final String UNIFIED_IDENTIFIER = "unified";
- public static final ConfigOption<String> DEFAULT_DATABASE =
- ConfigOptions.key(CommonCatalogOptions.DEFAULT_DATABASE_KEY)
- .stringType()
- .defaultValue(DEFAULT_DB);
-
- public static final String PROPERTIES_PREFIX = "properties";
-
public static final ConfigOption<String> METASTORE_URL =
ConfigOptions.key("metastore.url").stringType().noDefaultValue();
- // authorization configs
- public static final ConfigOption<String> AUTH_AMS_CONFIGS_DISABLE =
- ConfigOptions.key(PROPERTIES_PREFIX + "." +
CatalogMetaProperties.LOAD_AUTH_FROM_AMS)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> AUTH_METHOD =
- ConfigOptions.key(PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_TYPE)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> SIMPLE_USER_NAME =
- ConfigOptions.key(
- PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_HADOOP_USERNAME)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> KEYTAB_LOGIN_USER =
- ConfigOptions.key(PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_PRINCIPAL)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> KRB5_CONF_PATH =
- ConfigOptions.key(PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_KRB_PATH)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> KRB5_CONF_ENCODE =
- ConfigOptions.key(PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_KRB_ENCODE)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> KEYTAB_PATH =
- ConfigOptions.key(
- PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_KEYTAB_PATH)
- .stringType()
- .noDefaultValue();
- public static final ConfigOption<String> KEYTAB_ENCODE =
- ConfigOptions.key(
- PROPERTIES_PREFIX + "." +
CatalogMetaProperties.AUTH_CONFIGS_KEY_KEYTAB_ENCODE)
- .stringType()
- .noDefaultValue();
-
public static final ConfigOption<String> FLINK_TABLE_FORMATS =
ConfigOptions.key(TABLE_FORMATS)
.stringType()
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/FlinkUnifiedCatalogFactory.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/FlinkUnifiedCatalogFactory.java
index 8c7fc50ff..5b1cfcf86 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/FlinkUnifiedCatalogFactory.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/FlinkUnifiedCatalogFactory.java
@@ -19,25 +19,30 @@
package org.apache.amoro.flink.catalog.factories;
import static org.apache.amoro.Constants.THRIFT_TABLE_SERVICE_NAME;
-import static
org.apache.amoro.flink.catalog.factories.CatalogFactoryOptions.DEFAULT_DATABASE;
+import static org.apache.amoro.flink.table.OptionsUtil.getCatalogProperties;
import static org.apache.amoro.properties.CatalogMetaProperties.TABLE_FORMATS;
-import static org.apache.flink.table.factories.FactoryUtil.PROPERTY_VERSION;
+import org.apache.amoro.CommonUnifiedCatalog;
import org.apache.amoro.TableFormat;
import org.apache.amoro.UnifiedCatalog;
import org.apache.amoro.UnifiedCatalogLoader;
import org.apache.amoro.client.AmsThriftUrl;
+import org.apache.amoro.flink.InternalCatalogBuilder;
import org.apache.amoro.flink.catalog.FlinkUnifiedCatalog;
-import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
+import org.apache.amoro.flink.catalog.MixedCatalog;
import org.apache.amoro.shade.guava32.com.google.common.collect.Sets;
-import org.apache.amoro.utils.MixedFormatCatalogUtil;
+import org.apache.amoro.table.TableMetaStore;
+import org.apache.amoro.utils.CatalogUtil;
import org.apache.flink.configuration.ConfigOption;
import org.apache.flink.table.catalog.Catalog;
+import org.apache.flink.table.catalog.CommonCatalogOptions;
import org.apache.flink.table.factories.CatalogFactory;
-import org.apache.flink.table.factories.FactoryUtil;
+import org.apache.flink.util.Preconditions;
import org.apache.hadoop.conf.Configuration;
+import org.apache.iceberg.flink.FlinkCatalogFactory;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.Map;
import java.util.Set;
/** Factory for {@link FlinkUnifiedCatalog}. */
@@ -57,37 +62,46 @@ public class FlinkUnifiedCatalogFactory implements
CatalogFactory {
@Override
public Set<ConfigOption<?>> requiredOptions() {
- Set<ConfigOption<?>> requiredOptions = new HashSet<>();
- requiredOptions.add(CatalogFactoryOptions.METASTORE_URL);
- return requiredOptions;
+ return Collections.emptySet();
}
@Override
public Set<ConfigOption<?>> optionalOptions() {
- final Set<ConfigOption<?>> options = new HashSet<>();
- options.add(PROPERTY_VERSION);
- options.add(DEFAULT_DATABASE);
- return options;
+ return Collections.emptySet();
}
@Override
public Catalog createCatalog(Context context) {
- final FactoryUtil.CatalogFactoryHelper helper =
- FactoryUtil.createCatalogFactoryHelper(this, context);
- helper.validate();
- final String defaultDatabase = helper.getOptions().get(DEFAULT_DATABASE);
- String metastoreUrl =
helper.getOptions().get(CatalogFactoryOptions.METASTORE_URL);
+ final String defaultDatabase =
+ context
+ .getOptions()
+ .getOrDefault(CommonCatalogOptions.DEFAULT_DATABASE_KEY,
MixedCatalog.DEFAULT_DB);
+ final String metastoreUrl =
context.getOptions().get(CatalogFactoryOptions.METASTORE_URL.key());
+ final Map<String, String> catalogProperties =
getCatalogProperties(context.getOptions());
- String amoroCatalogName =
- AmsThriftUrl.parse(metastoreUrl,
THRIFT_TABLE_SERVICE_NAME).catalogName();
- UnifiedCatalog unifiedCatalog =
- UnifiedCatalogLoader.loadUnifiedCatalog(metastoreUrl,
amoroCatalogName, Maps.newHashMap());
+ UnifiedCatalog unifiedCatalog;
+ if (metastoreUrl != null) {
+ String amoroCatalogName =
+ AmsThriftUrl.parse(metastoreUrl,
THRIFT_TABLE_SERVICE_NAME).catalogName();
+ unifiedCatalog =
+ UnifiedCatalogLoader.loadUnifiedCatalog(
+ metastoreUrl, amoroCatalogName, catalogProperties);
+ } else {
+ String metastoreType =
catalogProperties.get(FlinkCatalogFactory.ICEBERG_CATALOG_TYPE);
+ Preconditions.checkArgument(metastoreType != null, "Catalog type cannot
be empty");
+ TableMetaStore tableMetaStore =
+ TableMetaStore.builder()
+ .withConfiguration(
+ InternalCatalogBuilder.clusterHadoopConf(metastoreType,
catalogProperties))
+ .build();
+ unifiedCatalog =
+ new CommonUnifiedCatalog(
+ context.getName(), metastoreType, catalogProperties,
tableMetaStore);
+ }
Configuration hadoopConf =
unifiedCatalog.authenticationContext().getConfiguration();
-
Set<TableFormat> tableFormats =
- MixedFormatCatalogUtil.tableFormats(
- unifiedCatalog.metastoreType(), unifiedCatalog.properties());
+ CatalogUtil.tableFormats(unifiedCatalog.metastoreType(),
unifiedCatalog.properties());
validate(tableFormats);
return new FlinkUnifiedCatalog(
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/mixed/MixedCatalogFactory.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/mixed/MixedCatalogFactory.java
index fd586e4d6..2298c859b 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/mixed/MixedCatalogFactory.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/catalog/factories/mixed/MixedCatalogFactory.java
@@ -18,22 +18,18 @@
package org.apache.amoro.flink.catalog.factories.mixed;
-import static
org.apache.amoro.flink.table.KafkaConnectorOptionsUtil.getKafkaParams;
-import static org.apache.flink.table.factories.FactoryUtil.PROPERTY_VERSION;
+import static org.apache.amoro.flink.table.OptionsUtil.getCatalogProperties;
import org.apache.amoro.flink.InternalCatalogBuilder;
import org.apache.amoro.flink.catalog.MixedCatalog;
import org.apache.amoro.flink.catalog.factories.CatalogFactoryOptions;
-import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
import org.apache.flink.configuration.ConfigOption;
import org.apache.flink.table.catalog.Catalog;
+import org.apache.flink.table.catalog.CommonCatalogOptions;
import org.apache.flink.table.factories.CatalogFactory;
-import org.apache.flink.table.factories.FactoryUtil;
import java.util.Collections;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
/** Factory for {@link MixedCatalog} */
@@ -47,25 +43,20 @@ public class MixedCatalogFactory implements CatalogFactory {
@Override
public Catalog createCatalog(Context context) {
- final FactoryUtil.CatalogFactoryHelper helper =
- FactoryUtil.createCatalogFactoryHelper(this, context);
- helper.validate();
+ final String defaultDatabase =
+ context
+ .getOptions()
+ .getOrDefault(CommonCatalogOptions.DEFAULT_DATABASE_KEY,
MixedCatalog.DEFAULT_DB);
+ final String metastoreUrl =
context.getOptions().get(CatalogFactoryOptions.METASTORE_URL.key());
+ final Map<String, String> catalogProperties =
getCatalogProperties(context.getOptions());
- final String defaultDatabase =
helper.getOptions().get(CatalogFactoryOptions.DEFAULT_DATABASE);
- String metastoreUrl =
helper.getOptions().get(CatalogFactoryOptions.METASTORE_URL);
- final Map<String, String> mixedCatalogProperties =
getKafkaParams(context.getOptions());
- final Map<String, String> catalogProperties =
Maps.newHashMap(mixedCatalogProperties);
+ final InternalCatalogBuilder catalogBuilder =
+ InternalCatalogBuilder.builder()
+ .metastoreUrl(metastoreUrl)
+ .catalogName(context.getName())
+ .properties(catalogProperties);
- Optional<String> tableFormatsOptional =
-
helper.getOptions().getOptional(CatalogFactoryOptions.FLINK_TABLE_FORMATS);
- tableFormatsOptional.ifPresent(
- tableFormats ->
-
catalogProperties.put(CatalogFactoryOptions.FLINK_TABLE_FORMATS.key(),
tableFormats));
-
- return new MixedCatalog(
- context.getName(),
- defaultDatabase,
-
InternalCatalogBuilder.builder().metastoreUrl(metastoreUrl).properties(catalogProperties));
+ return new MixedCatalog(context.getName(), defaultDatabase,
catalogBuilder);
}
@Override
@@ -75,22 +66,6 @@ public class MixedCatalogFactory implements CatalogFactory {
@Override
public Set<ConfigOption<?>> optionalOptions() {
- final Set<ConfigOption<?>> options = new HashSet<>();
- options.add(PROPERTY_VERSION);
- options.add(CatalogFactoryOptions.METASTORE_URL);
- options.add(CatalogFactoryOptions.DEFAULT_DATABASE);
-
- // authorization config
- options.add(CatalogFactoryOptions.AUTH_AMS_CONFIGS_DISABLE);
- options.add(CatalogFactoryOptions.AUTH_METHOD);
- options.add(CatalogFactoryOptions.SIMPLE_USER_NAME);
- options.add(CatalogFactoryOptions.KEYTAB_LOGIN_USER);
- options.add(CatalogFactoryOptions.KRB5_CONF_PATH);
- options.add(CatalogFactoryOptions.KRB5_CONF_ENCODE);
- options.add(CatalogFactoryOptions.KEYTAB_PATH);
- options.add(CatalogFactoryOptions.KEYTAB_ENCODE);
-
- options.add(CatalogFactoryOptions.FLINK_TABLE_FORMATS);
- return options;
+ return Collections.emptySet();
}
}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/KafkaConnectorOptionsUtil.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/KafkaConnectorOptionsUtil.java
deleted file mode 100644
index 0cab7037a..000000000
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/KafkaConnectorOptionsUtil.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * 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.amoro.flink.table;
-
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.DELIVERY_GUARANTEE;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.KEY_FIELDS;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.KEY_FIELDS_PREFIX;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.KEY_FORMAT;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.SCAN_STARTUP_MODE;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.SCAN_STARTUP_SPECIFIC_OFFSETS;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.SCAN_STARTUP_TIMESTAMP_MILLIS;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.SINK_PARTITIONER;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.TOPIC;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.TOPIC_PATTERN;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.TRANSACTIONAL_ID_PREFIX;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.VALUE_FIELDS_INCLUDE;
-import static
org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions.VALUE_FORMAT;
-import static org.apache.flink.table.factories.FactoryUtil.FORMAT;
-
-import org.apache.flink.configuration.ConfigOption;
-import org.apache.flink.configuration.ConfigOptions;
-import org.apache.flink.configuration.Configuration;
-import org.apache.flink.configuration.ReadableConfig;
-import org.apache.flink.connector.base.DeliveryGuarantee;
-import org.apache.flink.streaming.connectors.kafka.config.StartupMode;
-import
org.apache.flink.streaming.connectors.kafka.internals.KafkaTopicPartition;
-import
org.apache.flink.streaming.connectors.kafka.partitioner.FlinkFixedPartitioner;
-import
org.apache.flink.streaming.connectors.kafka.partitioner.FlinkKafkaPartitioner;
-import org.apache.flink.streaming.connectors.kafka.table.KafkaConnectorOptions;
-import org.apache.flink.table.api.TableException;
-import org.apache.flink.table.api.ValidationException;
-import org.apache.flink.table.data.RowData;
-import org.apache.flink.table.factories.DynamicTableFactory;
-import org.apache.flink.table.factories.FactoryUtil;
-import org.apache.flink.table.types.DataType;
-import org.apache.flink.table.types.logical.LogicalType;
-import org.apache.flink.table.types.logical.LogicalTypeRoot;
-import org.apache.flink.table.types.logical.utils.LogicalTypeChecks;
-import org.apache.flink.util.FlinkException;
-import org.apache.flink.util.InstantiationUtil;
-import org.apache.flink.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-public class KafkaConnectorOptionsUtil {
-
- private static final ConfigOption<String> SCHEMA_REGISTRY_SUBJECT =
-
ConfigOptions.key("schema-registry.subject").stringType().noDefaultValue();
-
- //
--------------------------------------------------------------------------------------------
- // Option enumerations
- //
--------------------------------------------------------------------------------------------
-
- // Sink partitioner.
- public static final String SINK_PARTITIONER_VALUE_DEFAULT = "default";
- public static final String SINK_PARTITIONER_VALUE_FIXED = "fixed";
- public static final String SINK_PARTITIONER_VALUE_ROUND_ROBIN =
"round-robin";
-
- // Prefix for Kafka specific properties.
- public static final String PROPERTIES_PREFIX = "properties.";
-
- // Other keywords.
- private static final String PARTITION = "partition";
- private static final String OFFSET = "offset";
- protected static final String AVRO_CONFLUENT = "avro-confluent";
- protected static final String DEBEZIUM_AVRO_CONFLUENT =
"debezium-avro-confluent";
- private static final List<String> SCHEMA_REGISTRY_FORMATS =
- Arrays.asList(AVRO_CONFLUENT, DEBEZIUM_AVRO_CONFLUENT);
-
- //
--------------------------------------------------------------------------------------------
- // Validation
- //
--------------------------------------------------------------------------------------------
-
- public static void validateTableSourceOptions(ReadableConfig tableOptions) {
- validateSourceTopic(tableOptions);
- validateScanStartupMode(tableOptions);
- }
-
- public static void validateTableSinkOptions(ReadableConfig tableOptions) {
- validateSinkTopic(tableOptions);
- validateSinkPartitioner(tableOptions);
- }
-
- public static void validateSourceTopic(ReadableConfig tableOptions) {
- Optional<List<String>> topic = tableOptions.getOptional(TOPIC);
- Optional<String> pattern = tableOptions.getOptional(TOPIC_PATTERN);
-
- if (topic.isPresent() && pattern.isPresent()) {
- throw new ValidationException(
- "Option 'topic' and 'topic-pattern' shouldn't be set together.");
- }
-
- if (!topic.isPresent() && !pattern.isPresent()) {
- throw new ValidationException("Either 'topic' or 'topic-pattern' must be
set.");
- }
- }
-
- public static void validateSinkTopic(ReadableConfig tableOptions) {
- String errorMessageTemp =
- "Flink Kafka sink currently only supports single topic, but got %s:
%s.";
- if (!isSingleTopic(tableOptions)) {
- if (tableOptions.getOptional(TOPIC_PATTERN).isPresent()) {
- throw new ValidationException(
- String.format(errorMessageTemp, "'topic-pattern'",
tableOptions.get(TOPIC_PATTERN)));
- } else {
- throw new ValidationException(
- String.format(errorMessageTemp, "'topic'",
tableOptions.get(TOPIC)));
- }
- }
- }
-
- private static void validateScanStartupMode(ReadableConfig tableOptions) {
- tableOptions
- .getOptional(SCAN_STARTUP_MODE)
- .ifPresent(
- mode -> {
- switch (mode) {
- case TIMESTAMP:
- if
(!tableOptions.getOptional(SCAN_STARTUP_TIMESTAMP_MILLIS).isPresent()) {
- throw new ValidationException(
- String.format(
- "'%s' is required in '%s' startup mode" + " but
missing.",
- SCAN_STARTUP_TIMESTAMP_MILLIS.key(),
- KafkaConnectorOptions.ScanStartupMode.TIMESTAMP));
- }
-
- break;
- case SPECIFIC_OFFSETS:
- if
(!tableOptions.getOptional(SCAN_STARTUP_SPECIFIC_OFFSETS).isPresent()) {
- throw new ValidationException(
- String.format(
- "'%s' is required in '%s' startup mode" + " but
missing.",
- SCAN_STARTUP_SPECIFIC_OFFSETS.key(),
-
KafkaConnectorOptions.ScanStartupMode.SPECIFIC_OFFSETS));
- }
- if (!isSingleTopic(tableOptions)) {
- throw new ValidationException(
- "Currently Kafka source only supports specific offset
for single topic.");
- }
- String specificOffsets =
tableOptions.get(SCAN_STARTUP_SPECIFIC_OFFSETS);
- parseSpecificOffsets(specificOffsets,
SCAN_STARTUP_SPECIFIC_OFFSETS.key());
-
- break;
- }
- });
- }
-
- private static void validateSinkPartitioner(ReadableConfig tableOptions) {
- tableOptions
- .getOptional(SINK_PARTITIONER)
- .ifPresent(
- partitioner -> {
- if (partitioner.equals(SINK_PARTITIONER_VALUE_ROUND_ROBIN)
- && tableOptions.getOptional(KEY_FIELDS).isPresent()) {
- throw new ValidationException(
- "Currently 'round-robin' partitioner only works when
option 'key.fields' is not specified.");
- } else if (partitioner.isEmpty()) {
- throw new ValidationException(
- String.format(
- "Option '%s' should be a non-empty string.",
SINK_PARTITIONER.key()));
- }
- });
- }
-
- //
--------------------------------------------------------------------------------------------
- // Utilities
- //
--------------------------------------------------------------------------------------------
-
- public static List<String> getSourceTopics(ReadableConfig tableOptions) {
- return tableOptions.getOptional(TOPIC).orElse(null);
- }
-
- public static Pattern getSourceTopicPattern(ReadableConfig tableOptions) {
- return
tableOptions.getOptional(TOPIC_PATTERN).map(Pattern::compile).orElse(null);
- }
-
- private static boolean isSingleTopic(ReadableConfig tableOptions) {
- // Option 'topic-pattern' is regarded as multi-topics.
- return tableOptions.getOptional(TOPIC).map(t -> t.size() ==
1).orElse(false);
- }
-
- public static StartupOptions getStartupOptions(ReadableConfig tableOptions) {
- final Map<KafkaTopicPartition, Long> specificOffsets = new HashMap<>();
- final StartupMode startupMode =
- tableOptions
- .getOptional(SCAN_STARTUP_MODE)
- .map(KafkaConnectorOptionsUtil::fromOption)
- .orElse(StartupMode.GROUP_OFFSETS);
- if (startupMode == StartupMode.SPECIFIC_OFFSETS) {
- // It will be refactored after support specific offset for multiple
topics in
- // FLINK-18602. We have already checked tableOptions.get(TOPIC) contains
one topic in
- // validateScanStartupMode().
- buildSpecificOffsets(tableOptions, tableOptions.get(TOPIC).get(0),
specificOffsets);
- }
-
- final StartupOptions options = new StartupOptions();
- options.startupMode = startupMode;
- options.specificOffsets = specificOffsets;
- if (startupMode == StartupMode.TIMESTAMP) {
- options.startupTimestampMillis =
tableOptions.get(SCAN_STARTUP_TIMESTAMP_MILLIS);
- }
- return options;
- }
-
- private static void buildSpecificOffsets(
- ReadableConfig tableOptions, String topic, Map<KafkaTopicPartition,
Long> specificOffsets) {
- String specificOffsetsStrOpt =
tableOptions.get(SCAN_STARTUP_SPECIFIC_OFFSETS);
- final Map<Integer, Long> offsetMap =
- parseSpecificOffsets(specificOffsetsStrOpt,
SCAN_STARTUP_SPECIFIC_OFFSETS.key());
- offsetMap.forEach(
- (partition, offset) -> {
- final KafkaTopicPartition topicPartition = new
KafkaTopicPartition(topic, partition);
- specificOffsets.put(topicPartition, offset);
- });
- }
-
- /**
- * Returns the {@link StartupMode} of Kafka Consumer by passed-in
table-specific {@link
- * KafkaConnectorOptions.ScanStartupMode}.
- */
- private static StartupMode fromOption(KafkaConnectorOptions.ScanStartupMode
scanStartupMode) {
- switch (scanStartupMode) {
- case EARLIEST_OFFSET:
- return StartupMode.EARLIEST;
- case LATEST_OFFSET:
- return StartupMode.LATEST;
- case GROUP_OFFSETS:
- return StartupMode.GROUP_OFFSETS;
- case SPECIFIC_OFFSETS:
- return StartupMode.SPECIFIC_OFFSETS;
- case TIMESTAMP:
- return StartupMode.TIMESTAMP;
-
- default:
- throw new TableException("Unsupported startup mode. Validator should
have checked that.");
- }
- }
-
- public static Properties getKafkaProperties(Map<String, String>
tableOptions) {
- final Properties kafkaProperties = new Properties();
-
- if (hasKafkaClientProperties(tableOptions)) {
- tableOptions.keySet().stream()
- .filter(key -> key.startsWith(PROPERTIES_PREFIX))
- .forEach(
- key -> {
- final String value = tableOptions.get(key);
- final String subKey =
key.substring((PROPERTIES_PREFIX).length());
- kafkaProperties.put(subKey, value);
- });
- }
- return kafkaProperties;
- }
-
- public static Map<String, String> getKafkaParams(Map<String, String>
tableOptions) {
- if (hasKafkaClientProperties(tableOptions)) {
- return tableOptions.entrySet().stream()
- .filter(e -> e.getKey().startsWith(PROPERTIES_PREFIX))
- .collect(
- Collectors.toMap(
- e -> e.getKey().substring(PROPERTIES_PREFIX.length()),
Map.Entry::getValue));
- }
- return Collections.emptyMap();
- }
-
- /**
- * The partitioner can be either "fixed", "round-robin" or a customized
partitioner full class
- * name.
- */
- public static Optional<FlinkKafkaPartitioner<RowData>>
getFlinkKafkaPartitioner(
- ReadableConfig tableOptions, ClassLoader classLoader) {
- return tableOptions
- .getOptional(SINK_PARTITIONER)
- .flatMap(
- (String partitioner) -> {
- switch (partitioner) {
- case SINK_PARTITIONER_VALUE_FIXED:
- return Optional.of(new FlinkFixedPartitioner<>());
- case SINK_PARTITIONER_VALUE_DEFAULT:
- case SINK_PARTITIONER_VALUE_ROUND_ROBIN:
- return Optional.empty();
- // Default fallback to full class name of the partitioner.
- default:
- return Optional.of(initializePartitioner(partitioner,
classLoader));
- }
- });
- }
-
- /**
- * Parses SpecificOffsets String to Map.
- *
- * <p>SpecificOffsets String format was given as following:
- *
- * <pre>
- * scan.startup.specific-offsets =
partition:0,offset:42;partition:1,offset:300
- * </pre>
- *
- * @return SpecificOffsets with Map format, key is partition, and value is
offset
- */
- public static Map<Integer, Long> parseSpecificOffsets(
- String specificOffsetsStr, String optionKey) {
- final Map<Integer, Long> offsetMap = new HashMap<>();
- final String[] pairs = specificOffsetsStr.split(";");
- final String validationExceptionMessage =
- String.format(
- "Invalid properties '%s' should follow the format "
- + "'partition:0,offset:42;partition:1,offset:300', but is
'%s'.",
- optionKey, specificOffsetsStr);
-
- if (pairs.length == 0) {
- throw new ValidationException(validationExceptionMessage);
- }
-
- for (String pair : pairs) {
- if (null == pair || pair.length() == 0 || !pair.contains(",")) {
- throw new ValidationException(validationExceptionMessage);
- }
-
- final String[] kv = pair.split(",");
- if (kv.length != 2 || !kv[0].startsWith(PARTITION + ':') ||
!kv[1].startsWith(OFFSET + ':')) {
- throw new ValidationException(validationExceptionMessage);
- }
-
- String partitionValue = kv[0].substring(kv[0].indexOf(":") + 1);
- String offsetValue = kv[1].substring(kv[1].indexOf(":") + 1);
- try {
- final Integer partition = Integer.valueOf(partitionValue);
- final Long offset = Long.valueOf(offsetValue);
- offsetMap.put(partition, offset);
- } catch (NumberFormatException e) {
- throw new ValidationException(validationExceptionMessage, e);
- }
- }
- return offsetMap;
- }
-
- /**
- * Decides if the table options contains Kafka client properties that start
with prefix
- * 'properties'.
- */
- private static boolean hasKafkaClientProperties(Map<String, String>
tableOptions) {
- return tableOptions.keySet().stream().anyMatch(k ->
k.startsWith(PROPERTIES_PREFIX));
- }
-
- /** Returns a class value with the given class name. */
- private static <T> FlinkKafkaPartitioner<T> initializePartitioner(
- String name, ClassLoader classLoader) {
- try {
- Class<?> clazz = Class.forName(name, true, classLoader);
- if (!FlinkKafkaPartitioner.class.isAssignableFrom(clazz)) {
- throw new ValidationException(
- String.format(
- "Sink partitioner class '%s' should extend from the required
class %s",
- name, FlinkKafkaPartitioner.class.getName()));
- }
- @SuppressWarnings("unchecked")
- final FlinkKafkaPartitioner<T> kafkaPartitioner =
- InstantiationUtil.instantiate(name, FlinkKafkaPartitioner.class,
classLoader);
-
- return kafkaPartitioner;
- } catch (ClassNotFoundException | FlinkException e) {
- throw new ValidationException(
- String.format("Could not find and instantiate partitioner class
'%s'", name), e);
- }
- }
-
- /**
- * Creates an array of indices that determine which physical fields of the
table schema to include
- * in the key format and the order that those fields have in the key format.
- *
- * <p>See {@link KafkaConnectorOptions#KEY_FORMAT}, {@link
KafkaConnectorOptions#KEY_FIELDS}, and
- * {@link KafkaConnectorOptions#KEY_FIELDS_PREFIX} for more information.
- */
- public static int[] createKeyFormatProjection(ReadableConfig options,
DataType physicalDataType) {
- final LogicalType physicalType = physicalDataType.getLogicalType();
- Preconditions.checkArgument(physicalType.is(LogicalTypeRoot.ROW), "Row
data type expected.");
- final Optional<String> optionalKeyFormat = options.getOptional(KEY_FORMAT);
- final Optional<List<String>> optionalKeyFields =
options.getOptional(KEY_FIELDS);
-
- if (!optionalKeyFormat.isPresent() && optionalKeyFields.isPresent()) {
- throw new ValidationException(
- String.format(
- "The option '%s' can only be declared if a key format is defined
using '%s'.",
- KEY_FIELDS.key(), KEY_FORMAT.key()));
- } else if (optionalKeyFormat.isPresent()
- && (!optionalKeyFields.isPresent() || optionalKeyFields.get().size()
== 0)) {
- throw new ValidationException(
- String.format(
- "A key format '%s' requires the declaration of one or more of
key fields using '%s'.",
- KEY_FORMAT.key(), KEY_FIELDS.key()));
- }
-
- if (!optionalKeyFormat.isPresent()) {
- return new int[0];
- }
-
- final String keyPrefix = options.getOptional(KEY_FIELDS_PREFIX).orElse("");
-
- final List<String> keyFields = optionalKeyFields.get();
- final List<String> physicalFields =
LogicalTypeChecks.getFieldNames(physicalType);
- return keyFields.stream()
- .mapToInt(
- keyField -> {
- final int pos = physicalFields.indexOf(keyField);
- // check that field name exists
- if (pos < 0) {
- throw new ValidationException(
- String.format(
- "Could not find the field '%s' in the table schema for
usage in the key format. "
- + "A key field must be a regular, physical column.
"
- + "The following columns can be selected in the
'%s' option:\n"
- + "%s",
- keyField, KEY_FIELDS.key(), physicalFields));
- }
- // check that field name is prefixed correctly
- if (!keyField.startsWith(keyPrefix)) {
- throw new ValidationException(
- String.format(
- "All fields in '%s' must be prefixed with '%s' when
option '%s' "
- + "is set but field '%s' is not prefixed.",
- KEY_FIELDS.key(), keyPrefix, KEY_FIELDS_PREFIX.key(),
keyField));
- }
- return pos;
- })
- .toArray();
- }
-
- /**
- * Creates an array of indices that determine which physical fields of the
table schema to include
- * in the value format.
- *
- * <p>See {@link KafkaConnectorOptions#VALUE_FORMAT}, {@link
- * KafkaConnectorOptions#VALUE_FIELDS_INCLUDE}, and {@link
- * KafkaConnectorOptions#KEY_FIELDS_PREFIX} for more information.
- */
- public static int[] createValueFormatProjection(
- ReadableConfig options, DataType physicalDataType) {
- final LogicalType physicalType = physicalDataType.getLogicalType();
- Preconditions.checkArgument(physicalType.is(LogicalTypeRoot.ROW), "Row
data type expected.");
- final int physicalFieldCount =
LogicalTypeChecks.getFieldCount(physicalType);
- final IntStream physicalFields = IntStream.range(0, physicalFieldCount);
-
- final String keyPrefix = options.getOptional(KEY_FIELDS_PREFIX).orElse("");
-
- final KafkaConnectorOptions.ValueFieldsStrategy strategy =
options.get(VALUE_FIELDS_INCLUDE);
- if (strategy == KafkaConnectorOptions.ValueFieldsStrategy.ALL) {
- if (keyPrefix.length() > 0) {
- throw new ValidationException(
- String.format(
- "A key prefix is not allowed when option '%s' is set to '%s'. "
- + "Set it to '%s' instead to avoid field overlaps.",
- VALUE_FIELDS_INCLUDE.key(),
- KafkaConnectorOptions.ValueFieldsStrategy.ALL,
- KafkaConnectorOptions.ValueFieldsStrategy.EXCEPT_KEY));
- }
- return physicalFields.toArray();
- } else if (strategy ==
KafkaConnectorOptions.ValueFieldsStrategy.EXCEPT_KEY) {
- final int[] keyProjection = createKeyFormatProjection(options,
physicalDataType);
- return physicalFields
- .filter(pos -> IntStream.of(keyProjection).noneMatch(k -> k == pos))
- .toArray();
- }
- throw new TableException("Unknown value fields strategy:" + strategy);
- }
-
- /**
- * Returns a new table context with a default schema registry subject value
in the options if the
- * format is a schema registry format (e.g. 'avro-confluent') and the
subject is not defined.
- */
- public static DynamicTableFactory.Context autoCompleteSchemaRegistrySubject(
- DynamicTableFactory.Context context) {
- Map<String, String> tableOptions = context.getCatalogTable().getOptions();
- Map<String, String> newOptions =
autoCompleteSchemaRegistrySubject(tableOptions);
- if (newOptions.size() > tableOptions.size()) {
- // build a new context
- return new FactoryUtil.DefaultDynamicTableContext(
- context.getObjectIdentifier(),
- context.getCatalogTable().copy(newOptions),
- context.getEnrichmentOptions(),
- context.getConfiguration(),
- context.getClassLoader(),
- context.isTemporary());
- } else {
- return context;
- }
- }
-
- private static Map<String, String> autoCompleteSchemaRegistrySubject(
- Map<String, String> options) {
- Configuration configuration = Configuration.fromMap(options);
- // the subject autoComplete should only be used in sink, check the topic
first
- validateSinkTopic(configuration);
- final Optional<String> valueFormat =
configuration.getOptional(VALUE_FORMAT);
- final Optional<String> keyFormat = configuration.getOptional(KEY_FORMAT);
- final Optional<String> format = configuration.getOptional(FORMAT);
- final String topic = configuration.get(TOPIC).get(0);
-
- if (format.isPresent() && SCHEMA_REGISTRY_FORMATS.contains(format.get())) {
- autoCompleteSubject(configuration, format.get(), topic + "-value");
- } else if (valueFormat.isPresent() &&
SCHEMA_REGISTRY_FORMATS.contains(valueFormat.get())) {
- autoCompleteSubject(configuration, "value." + valueFormat.get(), topic +
"-value");
- }
-
- if (keyFormat.isPresent() &&
SCHEMA_REGISTRY_FORMATS.contains(keyFormat.get())) {
- autoCompleteSubject(configuration, "key." + keyFormat.get(), topic +
"-key");
- }
- return configuration.toMap();
- }
-
- private static void autoCompleteSubject(
- Configuration configuration, String format, String subject) {
- ConfigOption<String> subjectOption =
- ConfigOptions.key(format + "." + SCHEMA_REGISTRY_SUBJECT.key())
- .stringType()
- .noDefaultValue();
- if (!configuration.getOptional(subjectOption).isPresent()) {
- configuration.setString(subjectOption, subject);
- }
- }
-
- static void validateDeliveryGuarantee(ReadableConfig tableOptions) {
- if (tableOptions.get(DELIVERY_GUARANTEE) == DeliveryGuarantee.EXACTLY_ONCE
- && !tableOptions.getOptional(TRANSACTIONAL_ID_PREFIX).isPresent()) {
- throw new ValidationException(
- TRANSACTIONAL_ID_PREFIX.key()
- + " must be specified when using
DeliveryGuarantee.EXACTLY_ONCE.");
- }
- }
-
- //
--------------------------------------------------------------------------------------------
- // Inner classes
- //
--------------------------------------------------------------------------------------------
-
- /** Kafka startup options. * */
- public static class StartupOptions {
- public StartupMode startupMode;
- public Map<KafkaTopicPartition, Long> specificOffsets;
- public long startupTimestampMillis;
- }
-
- private KafkaConnectorOptionsUtil() {}
-}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/DynamicTableFactory.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/MixedDynamicTableFactory.java
similarity index 94%
rename from
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/DynamicTableFactory.java
rename to
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/MixedDynamicTableFactory.java
index 6e62b83d5..60f8f05a6 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/DynamicTableFactory.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/MixedDynamicTableFactory.java
@@ -61,6 +61,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
@@ -68,18 +69,19 @@ import java.util.Properties;
import java.util.Set;
/** A factory generates {@link MixedFormatDynamicSource} and {@link
MixedFormatDynamicSink} */
-public class DynamicTableFactory implements DynamicTableSourceFactory,
DynamicTableSinkFactory {
- private static final Logger LOG =
LoggerFactory.getLogger(DynamicTableFactory.class);
+public class MixedDynamicTableFactory
+ implements DynamicTableSourceFactory, DynamicTableSinkFactory {
+ private static final Logger LOG =
LoggerFactory.getLogger(MixedDynamicTableFactory.class);
public static final String IDENTIFIER = "mixed-format";
private InternalCatalogBuilder internalCatalogBuilder;
private String internalCatalogName;
- public DynamicTableFactory(MixedCatalog mixedCatalog) {
+ public MixedDynamicTableFactory(MixedCatalog mixedCatalog) {
this.internalCatalogBuilder = mixedCatalog.catalogBuilder();
this.internalCatalogName = mixedCatalog.amsCatalogName();
}
- public DynamicTableFactory() {}
+ public MixedDynamicTableFactory() {}
@Override
public DynamicTableSource createDynamicTableSource(Context context) {
@@ -95,15 +97,16 @@ public class DynamicTableFactory implements
DynamicTableSourceFactory, DynamicTa
// It denotes create table by ddl 'connector' option, not through
catalog.db.tableName
if (actualBuilder == null || actualCatalogName == null) {
- String metastoreUrl = options.get(CatalogFactoryOptions.METASTORE_URL);
- Preconditions.checkNotNull(
- metastoreUrl, String.format("%s should be set",
CatalogFactoryOptions.METASTORE_URL));
- actualBuilder =
InternalCatalogBuilder.builder().metastoreUrl(metastoreUrl);
-
actualCatalogName =
options.get(MixedFormatValidator.MIXED_FORMAT_CATALOG);
Preconditions.checkNotNull(
actualCatalogName,
String.format("%s should be set",
MixedFormatValidator.MIXED_FORMAT_CATALOG.key()));
+ String metastoreUrl = options.get(CatalogFactoryOptions.METASTORE_URL);
+ actualBuilder =
+ InternalCatalogBuilder.builder()
+ .metastoreUrl(metastoreUrl)
+ .catalogName(actualCatalogName)
+ .properties(options.toMap());
}
if (options.containsKey(MixedFormatValidator.MIXED_FORMAT_DATABASE.key())
@@ -211,7 +214,7 @@ public class DynamicTableFactory implements
DynamicTableSourceFactory, DynamicTa
@Override
public Set<ConfigOption<?>> requiredOptions() {
- return new HashSet<>();
+ return Collections.emptySet();
}
@Override
@@ -247,8 +250,7 @@ public class DynamicTableFactory implements
DynamicTableSourceFactory, DynamicTa
TableSchema physicalSchema =
TableSchemaUtils.getPhysicalSchema(catalogTable.getSchema());
Schema schema = FlinkSchemaUtil.convert(physicalSchema);
- final Properties properties =
- KafkaConnectorOptionsUtil.getKafkaProperties(mixedTable.properties());
+ final Properties properties =
OptionsUtil.getKafkaProperties(mixedTable.properties());
// add topic-partition discovery
final Optional<Long> partitionDiscoveryInterval =
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/OptionsUtil.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/OptionsUtil.java
new file mode 100644
index 000000000..38ef34666
--- /dev/null
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/OptionsUtil.java
@@ -0,0 +1,64 @@
+/*
+ * 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.amoro.flink.table;
+
+import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.Properties;
+
+public class OptionsUtil {
+
+ // Prefix for specific properties.
+ public static final String PROPERTIES_PREFIX = "properties.";
+
+ public static Properties getKafkaProperties(Map<String, String>
tableOptions) {
+ final Properties kafkaProperties = new Properties();
+
+ if (hasProperties(tableOptions)) {
+ tableOptions.keySet().stream()
+ .filter(key -> key.startsWith(PROPERTIES_PREFIX))
+ .forEach(
+ key -> {
+ final String value = tableOptions.get(key);
+ final String subKey =
key.substring((PROPERTIES_PREFIX).length());
+ kafkaProperties.put(subKey, value);
+ });
+ }
+ return kafkaProperties;
+ }
+
+ public static Map<String, String> getCatalogProperties(Map<String, String>
options) {
+ Map<String, String> catalogProperties = Maps.newHashMap();
+ options.forEach(
+ (key, value) -> {
+ if (key.startsWith(PROPERTIES_PREFIX)) {
+ catalogProperties.put(key.substring((PROPERTIES_PREFIX).length()),
value);
+ } else {
+ catalogProperties.put(key, value);
+ }
+ });
+ return catalogProperties;
+ }
+
+ /** Decides if the table options contains table properties that start with
prefix 'properties'. */
+ private static boolean hasProperties(Map<String, String> tableOptions) {
+ return tableOptions.keySet().stream().anyMatch(k ->
k.startsWith(PROPERTIES_PREFIX));
+ }
+}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/AmoroDynamicTableFactory.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/UnifiedDynamicTableFactory.java
similarity index 94%
rename from
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/AmoroDynamicTableFactory.java
rename to
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/UnifiedDynamicTableFactory.java
index b929d1ddd..203a823f7 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/AmoroDynamicTableFactory.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/table/UnifiedDynamicTableFactory.java
@@ -39,15 +39,15 @@ import java.util.Optional;
import java.util.Set;
/**
- * AmoroDynamicTableFactory is a factory for creating dynamic table sources
and sinks. It implements
- * both DynamicTableSourceFactory and DynamicTableSinkFactory interfaces.
+ * UnifiedDynamicTableFactory is a factory for creating dynamic table sources
and sinks. It
+ * implements both DynamicTableSourceFactory and DynamicTableSinkFactory
interfaces.
*/
-public class AmoroDynamicTableFactory
+public class UnifiedDynamicTableFactory
implements DynamicTableSourceFactory, DynamicTableSinkFactory {
private final Map<TableFormat, AbstractCatalog> availableCatalogs;
- public AmoroDynamicTableFactory(Map<TableFormat, AbstractCatalog>
availableCatalogs) {
+ public UnifiedDynamicTableFactory(Map<TableFormat, AbstractCatalog>
availableCatalogs) {
this.availableCatalogs =
Preconditions.checkNotNull(availableCatalogs, "availableCatalogs
cannot be null");
}
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory
index 0572d04b7..3125d8dfa 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory
@@ -20,4 +20,4 @@
org.apache.amoro.flink.catalog.factories.mixed.MixedIcebergCatalogFactory
org.apache.amoro.flink.catalog.factories.mixed.MixedHiveCatalogFactory
org.apache.amoro.flink.catalog.factories.mixed.MixedCatalogFactory
org.apache.amoro.flink.catalog.factories.FlinkUnifiedCatalogFactory
-org.apache.amoro.flink.table.DynamicTableFactory
+org.apache.amoro.flink.table.MixedDynamicTableFactory
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/java/org/apache/amoro/flink/catalog/TestMixedCatalog.java
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/java/org/apache/amoro/flink/catalog/TestMixedCatalog.java
index 3c415a4cd..b9195a2e5 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/java/org/apache/amoro/flink/catalog/TestMixedCatalog.java
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/java/org/apache/amoro/flink/catalog/TestMixedCatalog.java
@@ -34,7 +34,7 @@ import org.apache.amoro.TableTestHelper;
import org.apache.amoro.catalog.BasicCatalogTestHelper;
import org.apache.amoro.catalog.CatalogTestBase;
import org.apache.amoro.flink.catalog.factories.CatalogFactoryOptions;
-import org.apache.amoro.flink.table.DynamicTableFactory;
+import org.apache.amoro.flink.table.MixedDynamicTableFactory;
import org.apache.amoro.shade.guava32.com.google.common.collect.Lists;
import org.apache.amoro.shade.guava32.com.google.common.collect.Maps;
import org.apache.amoro.table.MixedTable;
@@ -406,11 +406,11 @@ public class TestMixedCatalog extends CatalogTestBase {
// create Table with compute columns under default catalog
props = Maps.newHashMap();
- props.put("connector", DynamicTableFactory.IDENTIFIER);
+ props.put("connector", MixedDynamicTableFactory.IDENTIFIER);
props.put(CatalogFactoryOptions.METASTORE_URL.key(), getCatalogUrl());
- props.put(DynamicTableFactory.IDENTIFIER + ".catalog", catalogName);
- props.put(DynamicTableFactory.IDENTIFIER + ".database", DB);
- props.put(DynamicTableFactory.IDENTIFIER + ".table", TABLE);
+ props.put(MixedDynamicTableFactory.IDENTIFIER + ".catalog", catalogName);
+ props.put(MixedDynamicTableFactory.IDENTIFIER + ".database", DB);
+ props.put(MixedDynamicTableFactory.IDENTIFIER + ".table", TABLE);
sql(
"CREATE TABLE default_catalog.default_database."
diff --git
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/resources/META-INF/services/org.apache.flink.table.factories.Factory
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/resources/META-INF/services/org.apache.flink.table.factories.Factory
index 9911642b8..2a8b595d8 100644
---
a/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/resources/META-INF/services/org.apache.flink.table.factories.Factory
+++
b/amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/test/resources/META-INF/services/org.apache.flink.table.factories.Factory
@@ -17,4 +17,4 @@
#
org.apache.amoro.flink.catalog.factories.mixed.MixedCatalogFactory
-org.apache.amoro.flink.table.DynamicTableFactory
\ No newline at end of file
+org.apache.amoro.flink.table.MixedDynamicTableFactory
\ No newline at end of file
diff --git a/docs/engines/flink/flink-ddl.md b/docs/engines/flink/flink-ddl.md
index f7bd199cd..3978e417a 100644
--- a/docs/engines/flink/flink-ddl.md
+++ b/docs/engines/flink/flink-ddl.md
@@ -40,12 +40,13 @@ CREATE CATALOG <catalog_name> WITH (
Where `<catalog_name>` is the user-defined name of the Flink catalog, and
`<config_key>`=`<config_value>` has the following configurations:
-| Key | Default Value | Type | Required |
Description
|
-|----------------------------------|---------------|---------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| type | N/A | String | Yes |
Catalog type, validate values are mixed_iceberg and mixed_hive
|
-| metastore.url | (none) | String | Yes | The
URL for Amoro Metastore is
thrift://`<ip>`:`<port>`/`<catalog_name_in_metastore>`.<br>If high availability
is enabled for AMS, it can also be specified in the form of
zookeeper://{zookeeper-server}/{cluster-name}/{catalog-name}. |
-| default-database<img width=100/> | default | String | No | The
default database to use
|
-| property-version | 1 | Integer | No |
Catalog properties version, this option is for future backward compatibility
|
+| Key | Default Value | Type | Required | Description
|
+|------------------|---------------|---------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| type | N/A | String | Yes | Catalog type,
validate values are mixed_iceberg and mixed_hive
|
+| metastore.url | (none) | String | No | The URL for Amoro
Metastore is thrift://`<ip>`:`<port>`/`<catalog_name_in_metastore>`.<br>If high
availability is enabled for AMS, it can also be specified in the form of
zookeeper://{zookeeper-server}/{cluster-name}/{catalog-name}. |
+| default-database | default | String | No | The default database
to use
|
+| property-version | 1 | Integer | No | Catalog properties
version, this option is for future backward compatibility
|
+| catalog-type | N/A | String | No | Metastore type of
the catalog, validate values are hadoop, hive, rest, custom
|
The authentication information of AMS catalog can upload configuration files
on AMS website,
or specify the authentication information and configuration file paths when
creating catalogs with Flink DDL