Skip to content

Commit 44b51da

Browse files
committed
Add UC utils and kernel-spark UC dependency
1 parent aab0082 commit 44b51da

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ lazy val sparkV1Filtered = (project in file("spark-v1-filtered"))
462462
lazy val sparkV2 = (project in file("kernel-spark"))
463463
.dependsOn(sparkV1Filtered)
464464
.dependsOn(kernelDefaults)
465+
.dependsOn(kernelUnityCatalog % "compile->compile;test->test")
465466
.dependsOn(goldenTables % "test")
466467
.settings(
467468
name := "delta-spark-v2",
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (2025) The Delta Lake Project Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.delta.kernel.spark.snapshot.unitycatalog;
17+
18+
import static java.util.Objects.requireNonNull;
19+
20+
import io.delta.kernel.spark.utils.CatalogTableUtils;
21+
import io.delta.storage.commit.uccommitcoordinator.UCCommitCoordinatorClient;
22+
import java.util.Map;
23+
import java.util.Optional;
24+
import org.apache.spark.sql.SparkSession;
25+
import org.apache.spark.sql.catalyst.catalog.CatalogTable;
26+
import org.apache.spark.sql.delta.coordinatedcommits.UCCommitCoordinatorBuilder$;
27+
28+
/**
29+
* Utility class for extracting Unity Catalog connection information from Spark catalog metadata.
30+
*
31+
* <p>This class isolates Spark dependencies, allowing {@link UnityCatalogAdapter} to be created
32+
* without Spark if connection info is provided directly via {@link UnityCatalogConnectionInfo}.
33+
*/
34+
public final class SparkUnityCatalogUtils {
35+
36+
// Utility class - no instances
37+
private SparkUnityCatalogUtils() {}
38+
39+
/**
40+
* Extracts Unity Catalog connection information from Spark catalog table metadata.
41+
*
42+
* @param catalogTable Spark catalog table metadata
43+
* @param spark SparkSession for resolving Unity Catalog configurations
44+
* @return connection info if table is UC-managed, empty otherwise
45+
* @throws IllegalArgumentException if table is UC-managed but configuration is invalid
46+
*/
47+
public static Optional<UnityCatalogConnectionInfo> extractConnectionInfo(
48+
CatalogTable catalogTable, SparkSession spark) {
49+
requireNonNull(catalogTable, "catalogTable is null");
50+
requireNonNull(spark, "spark is null");
51+
52+
if (!CatalogTableUtils.isUnityCatalogManagedTable(catalogTable)) {
53+
return Optional.empty();
54+
}
55+
56+
String tableId = extractUCTableId(catalogTable);
57+
String tablePath = extractTablePath(catalogTable);
58+
59+
// Get catalog name
60+
scala.Option<String> catalogOption = catalogTable.identifier().catalog();
61+
String catalogName =
62+
catalogOption.isDefined()
63+
? catalogOption.get()
64+
: spark.sessionState().catalogManager().currentCatalog().name();
65+
66+
// Get UC endpoint and token from Spark configs
67+
scala.collection.immutable.List<scala.Tuple3<String, String, String>> scalaConfigs =
68+
UCCommitCoordinatorBuilder$.MODULE$.getCatalogConfigs(spark);
69+
70+
Optional<scala.Tuple3<String, String, String>> configTuple =
71+
scala.jdk.javaapi.CollectionConverters.asJava(scalaConfigs).stream()
72+
.filter(tuple -> tuple._1().equals(catalogName))
73+
.findFirst();
74+
75+
if (!configTuple.isPresent()) {
76+
throw new IllegalArgumentException(
77+
"Cannot create UC client: Unity Catalog configuration not found for catalog '"
78+
+ catalogName
79+
+ "'.");
80+
}
81+
82+
scala.Tuple3<String, String, String> config = configTuple.get();
83+
String endpoint = config._2();
84+
String token = config._3();
85+
86+
return Optional.of(new UnityCatalogConnectionInfo(tableId, tablePath, endpoint, token));
87+
}
88+
89+
private static String extractUCTableId(CatalogTable catalogTable) {
90+
Map<String, String> storageProperties =
91+
scala.jdk.javaapi.CollectionConverters.asJava(catalogTable.storage().properties());
92+
93+
String ucTableId = storageProperties.get(UCCommitCoordinatorClient.UC_TABLE_ID_KEY);
94+
if (ucTableId == null || ucTableId.isEmpty()) {
95+
throw new IllegalArgumentException(
96+
"Cannot extract ucTableId from table " + catalogTable.identifier());
97+
}
98+
return ucTableId;
99+
}
100+
101+
private static String extractTablePath(CatalogTable catalogTable) {
102+
if (catalogTable.location() == null) {
103+
throw new IllegalArgumentException(
104+
"Cannot extract table path: location is null for table " + catalogTable.identifier());
105+
}
106+
return catalogTable.location().toString();
107+
}
108+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (2025) The Delta Lake Project Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.delta.kernel.spark.snapshot.unitycatalog;
17+
18+
import static java.util.Objects.requireNonNull;
19+
20+
/**
21+
* Connection information for Unity Catalog managed tables.
22+
*
23+
* <p>This POJO encapsulates all the information needed to connect to a Unity Catalog table without
24+
* requiring Spark dependencies.
25+
*/
26+
public final class UnityCatalogConnectionInfo {
27+
private final String tableId;
28+
private final String tablePath;
29+
private final String endpoint;
30+
private final String token;
31+
32+
public UnityCatalogConnectionInfo(
33+
String tableId, String tablePath, String endpoint, String token) {
34+
this.tableId = requireNonNull(tableId, "tableId is null");
35+
this.tablePath = requireNonNull(tablePath, "tablePath is null");
36+
this.endpoint = requireNonNull(endpoint, "endpoint is null");
37+
this.token = requireNonNull(token, "token is null");
38+
}
39+
40+
public String getTableId() {
41+
return tableId;
42+
}
43+
44+
public String getTablePath() {
45+
return tablePath;
46+
}
47+
48+
public String getEndpoint() {
49+
return endpoint;
50+
}
51+
52+
public String getToken() {
53+
return token;
54+
}
55+
}

0 commit comments

Comments
 (0)