This is an automated email from the ASF dual-hosted git repository.
adutra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 579b271b8 Remove "giant" constructors from Handlers and Adapters
(#3669)
579b271b8 is described below
commit 579b271b8c41cd26339bccfd771c1a591ad27039
Author: Alexandre Dutra <[email protected]>
AuthorDate: Fri Feb 6 13:35:11 2026 +0100
Remove "giant" constructors from Handlers and Adapters (#3669)
This PR attempts to reduce the "giant constructor" symptoms in catalog
adapters and handlers.
* The `CatalogHandler` subtypes are now `@PolarisImmutable` objects, and
thus can leverage the generated builder to create instances without the need
for big constructors.
* The handlers are now produced by a new factory, which is a CDI
request-scoped bean with direct field injection to avoid constructor injection.
---
.../service/catalog/common/CatalogHandler.java | 141 ++++++------
.../generic/GenericTableCatalogAdapter.java | 62 +-----
.../generic/GenericTableCatalogHandler.java | 50 ++---
.../generic/GenericTableCatalogHandlerFactory.java | 55 +++++
.../catalog/iceberg/IcebergCatalogAdapter.java | 79 +------
.../catalog/iceberg/IcebergCatalogHandler.java | 246 ++++++++++-----------
.../iceberg/IcebergCatalogHandlerFactory.java | 78 +++++++
.../catalog/policy/PolicyCatalogAdapter.java | 68 ++----
.../catalog/policy/PolicyCatalogHandler.java | 80 +++----
.../policy/PolicyCatalogHandlerFactory.java | 47 ++++
...PolarisGenericTableCatalogHandlerAuthzTest.java | 31 ++-
.../AbstractIcebergCatalogHandlerAuthzTest.java | 138 ++++++------
.../iceberg/IcebergAllowedLocationTest.java | 6 +-
.../catalog/iceberg/IcebergCatalogAdapterTest.java | 2 +-
...ebergCatalogHandlerFineGrainedDisabledTest.java | 35 +--
.../policy/PolicyCatalogHandlerAuthzTest.java | 18 +-
.../org/apache/polaris/service/TestServices.java | 43 +++-
17 files changed, 583 insertions(+), 596 deletions(-)
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
index 9d5778ac2..871de1ea9 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
@@ -20,7 +20,6 @@ package org.apache.polaris.service.catalog.common;
import static
org.apache.polaris.core.entity.PolarisEntitySubType.ICEBERG_TABLE;
-import jakarta.enterprise.inject.Instance;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
@@ -31,23 +30,23 @@ import org.apache.iceberg.exceptions.AlreadyExistsException;
import org.apache.iceberg.exceptions.NoSuchNamespaceException;
import org.apache.iceberg.exceptions.NoSuchTableException;
import org.apache.iceberg.exceptions.NoSuchViewException;
-import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.CallContext;
-import org.apache.polaris.core.credentials.PolarisCredentialManager;
+import org.apache.polaris.core.context.RealmContext;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.service.types.PolicyIdentifier;
+import org.immutables.value.Value;
/**
* An ABC for catalog wrappers which provides authorize methods that should be
called before a
@@ -56,48 +55,36 @@ import org.apache.polaris.service.types.PolicyIdentifier;
*/
public abstract class CatalogHandler {
- // Initialized in the authorize methods.
- protected PolarisResolutionManifest resolutionManifest = null;
+ public abstract String catalogName();
+
+ public abstract PolarisPrincipal polarisPrincipal();
- protected final ResolutionManifestFactory resolutionManifestFactory;
- protected final String catalogName;
- protected final PolarisAuthorizer authorizer;
- protected final PolarisCredentialManager credentialManager;
- protected final Instance<ExternalCatalogFactory> externalCatalogFactories;
-
- protected final PolarisDiagnostics diagnostics;
- protected final CallContext callContext;
- protected final RealmConfig realmConfig;
- protected final PolarisPrincipal polarisPrincipal;
-
- public CatalogHandler(
- PolarisDiagnostics diagnostics,
- CallContext callContext,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisPrincipal principal,
- String catalogName,
- PolarisAuthorizer authorizer,
- PolarisCredentialManager credentialManager,
- Instance<ExternalCatalogFactory> externalCatalogFactories) {
- this.diagnostics = diagnostics;
- this.callContext = callContext;
- this.realmConfig = callContext.getRealmConfig();
- this.resolutionManifestFactory = resolutionManifestFactory;
- this.catalogName = catalogName;
- this.polarisPrincipal = principal;
- this.authorizer = authorizer;
- this.credentialManager = credentialManager;
- this.externalCatalogFactories = externalCatalogFactories;
+ public abstract CallContext callContext();
+
+ @Value.Derived
+ public RealmConfig realmConfig() {
+ return callContext().getRealmConfig();
}
- protected PolarisCredentialManager getPolarisCredentialManager() {
- return credentialManager;
+ @Value.Derived
+ public RealmContext realmContext() {
+ return callContext().getRealmContext();
}
+ public abstract PolarisMetaStoreManager metaStoreManager();
+
+ public abstract ResolutionManifestFactory resolutionManifestFactory();
+
+ public abstract PolarisAuthorizer authorizer();
+
protected PolarisResolutionManifest newResolutionManifest() {
- return
resolutionManifestFactory.createResolutionManifest(polarisPrincipal,
catalogName);
+ return
resolutionManifestFactory().createResolutionManifest(polarisPrincipal(),
catalogName());
}
+ // Initialized in the authorize methods.
+ @SuppressWarnings("immutables:incompat")
+ protected PolarisResolutionManifest resolutionManifest = null;
+
/** Initialize the catalog once authorized. Called after all `authorize...`
methods. */
protected abstract void initializeCatalog();
@@ -152,12 +139,13 @@ public abstract class CatalogHandler {
if (target == null) {
throw new NoSuchNamespaceException("Namespace does not exist: %s",
namespace);
}
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- null /* secondary */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ null /* secondary */);
initializeCatalog();
}
@@ -184,12 +172,13 @@ public abstract class CatalogHandler {
if (target == null) {
throw new NoSuchNamespaceException("Namespace does not exist: %s",
parentNamespace);
}
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- null /* secondary */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ null /* secondary */);
initializeCatalog();
}
@@ -220,12 +209,13 @@ public abstract class CatalogHandler {
if (target == null) {
throw new NoSuchNamespaceException("Namespace does not exist: %s",
namespace);
}
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- null /* secondary */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ null /* secondary */);
initializeCatalog();
}
@@ -267,12 +257,13 @@ public abstract class CatalogHandler {
}
for (PolarisAuthorizableOperation op : ops) {
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- null /* secondary */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ null /* secondary */);
}
initializeCatalog();
@@ -317,12 +308,13 @@ public abstract class CatalogHandler {
: new NoSuchViewException(
"View does not exist: %s",
identifier)))
.toList();
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- targets,
- null /* secondaries */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ targets,
+ null /* secondaries */);
initializeCatalog();
}
@@ -384,12 +376,13 @@ public abstract class CatalogHandler {
resolutionManifest.getResolvedPath(src, PolarisEntityType.TABLE_LIKE,
subType, true);
PolarisResolvedPathWrapper secondary =
resolutionManifest.getResolvedPath(dst.namespace(), true);
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- secondary);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ secondary);
initializeCatalog();
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
index ba00e21a0..d467d52a5 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java
@@ -19,23 +19,15 @@
package org.apache.polaris.service.catalog.generic;
import jakarta.enterprise.context.RequestScoped;
-import jakarta.enterprise.inject.Any;
-import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import org.apache.iceberg.catalog.TableIdentifier;
-import org.apache.polaris.core.PolarisDiagnostics;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.core.credentials.PolarisCredentialManager;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
import org.apache.polaris.service.catalog.CatalogPrefixParser;
import
org.apache.polaris.service.catalog.api.PolarisCatalogGenericTableApiService;
import org.apache.polaris.service.catalog.common.CatalogAdapter;
@@ -43,68 +35,36 @@ import org.apache.polaris.service.config.ReservedProperties;
import org.apache.polaris.service.types.CreateGenericTableRequest;
import org.apache.polaris.service.types.ListGenericTablesResponse;
import org.apache.polaris.service.types.LoadGenericTableResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@RequestScoped
public class GenericTableCatalogAdapter
implements PolarisCatalogGenericTableApiService, CatalogAdapter {
- private static final Logger LOGGER =
LoggerFactory.getLogger(GenericTableCatalogAdapter.class);
-
- private final PolarisDiagnostics diagnostics;
private final RealmContext realmContext;
private final RealmConfig realmConfig;
- private final CallContext callContext;
- private final ResolutionManifestFactory resolutionManifestFactory;
- private final PolarisMetaStoreManager metaStoreManager;
- private final PolarisAuthorizer polarisAuthorizer;
private final ReservedProperties reservedProperties;
private final CatalogPrefixParser prefixParser;
- private final PolarisCredentialManager polarisCredentialManager;
- private final Instance<ExternalCatalogFactory> externalCatalogFactories;
+ private final GenericTableCatalogHandlerFactory handlerFactory;
@Inject
public GenericTableCatalogAdapter(
- PolarisDiagnostics diagnostics,
- RealmContext realmContext,
CallContext callContext,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisAuthorizer polarisAuthorizer,
CatalogPrefixParser prefixParser,
ReservedProperties reservedProperties,
- PolarisCredentialManager polarisCredentialManager,
- @Any Instance<ExternalCatalogFactory> externalCatalogFactories) {
- this.diagnostics = diagnostics;
- this.realmContext = realmContext;
- this.callContext = callContext;
+ GenericTableCatalogHandlerFactory handlerFactory) {
+ this.realmContext = callContext.getRealmContext();
this.realmConfig = callContext.getRealmConfig();
- this.resolutionManifestFactory = resolutionManifestFactory;
- this.metaStoreManager = metaStoreManager;
- this.polarisAuthorizer = polarisAuthorizer;
this.prefixParser = prefixParser;
this.reservedProperties = reservedProperties;
- this.polarisCredentialManager = polarisCredentialManager;
- this.externalCatalogFactories = externalCatalogFactories;
+ this.handlerFactory = handlerFactory;
}
- private GenericTableCatalogHandler newHandlerWrapper(
- SecurityContext securityContext, String prefix) {
+ private GenericTableCatalogHandler newHandler(SecurityContext
securityContext, String prefix) {
FeatureConfiguration.enforceFeatureEnabledOrThrow(
realmConfig, FeatureConfiguration.ENABLE_GENERIC_TABLES);
PolarisPrincipal principal = validatePrincipal(securityContext);
-
- return new GenericTableCatalogHandler(
- diagnostics,
- callContext,
- resolutionManifestFactory,
- metaStoreManager,
- principal,
- prefixParser.prefixToCatalogName(prefix),
- polarisAuthorizer,
- polarisCredentialManager,
- externalCatalogFactories);
+ String catalogName = prefixParser.prefixToCatalogName(prefix);
+ return handlerFactory.createHandler(catalogName, principal);
}
@Override
@@ -114,7 +74,7 @@ public class GenericTableCatalogAdapter
CreateGenericTableRequest createGenericTableRequest,
RealmContext realmContext,
SecurityContext securityContext) {
- GenericTableCatalogHandler handler = newHandlerWrapper(securityContext,
prefix);
+ GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
LoadGenericTableResponse response =
handler.createGenericTable(
TableIdentifier.of(decodeNamespace(namespace),
createGenericTableRequest.getName()),
@@ -133,7 +93,7 @@ public class GenericTableCatalogAdapter
String genericTable,
RealmContext realmContext,
SecurityContext securityContext) {
- GenericTableCatalogHandler handler = newHandlerWrapper(securityContext,
prefix);
+ GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
handler.dropGenericTable(TableIdentifier.of(decodeNamespace(namespace),
genericTable));
return Response.noContent().build();
}
@@ -146,7 +106,7 @@ public class GenericTableCatalogAdapter
Integer pageSize,
RealmContext realmContext,
SecurityContext securityContext) {
- GenericTableCatalogHandler handler = newHandlerWrapper(securityContext,
prefix);
+ GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
ListGenericTablesResponse response =
handler.listGenericTables(decodeNamespace(namespace));
return Response.ok(response).build();
}
@@ -158,7 +118,7 @@ public class GenericTableCatalogAdapter
String genericTable,
RealmContext realmContext,
SecurityContext securityContext) {
- GenericTableCatalogHandler handler = newHandlerWrapper(securityContext,
prefix);
+ GenericTableCatalogHandler handler = newHandler(securityContext, prefix);
LoadGenericTableResponse response =
handler.loadGenericTable(TableIdentifier.of(decodeNamespace(namespace),
genericTable));
return Response.ok(response).build();
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
index 7cd906f9a..0acae1d31 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
@@ -24,22 +24,17 @@ import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.catalog.TableIdentifier;
-import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
-import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.catalog.GenericTableCatalog;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.connection.ConnectionConfigInfoDpo;
import org.apache.polaris.core.connection.ConnectionType;
-import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.credentials.PolarisCredentialManager;
import org.apache.polaris.core.entity.CatalogEntity;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.table.GenericTableEntity;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.immutables.PolarisImmutable;
import org.apache.polaris.service.catalog.common.CatalogHandler;
import org.apache.polaris.service.types.GenericTable;
import org.apache.polaris.service.types.ListGenericTablesResponse;
@@ -47,34 +42,16 @@ import
org.apache.polaris.service.types.LoadGenericTableResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class GenericTableCatalogHandler extends CatalogHandler {
+@PolarisImmutable
+@SuppressWarnings("immutables:incompat")
+public abstract class GenericTableCatalogHandler extends CatalogHandler {
private static final Logger LOGGER =
LoggerFactory.getLogger(GenericTableCatalogHandler.class);
- private PolarisMetaStoreManager metaStoreManager;
+ protected abstract PolarisCredentialManager credentialManager();
- private GenericTableCatalog genericTableCatalog;
+ protected abstract Instance<ExternalCatalogFactory>
externalCatalogFactories();
- public GenericTableCatalogHandler(
- PolarisDiagnostics diagnostics,
- CallContext callContext,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisPrincipal principal,
- String catalogName,
- PolarisAuthorizer authorizer,
- PolarisCredentialManager polarisCredentialManager,
- Instance<ExternalCatalogFactory> externalCatalogFactories) {
- super(
- diagnostics,
- callContext,
- resolutionManifestFactory,
- principal,
- catalogName,
- authorizer,
- polarisCredentialManager,
- externalCatalogFactories);
- this.metaStoreManager = metaStoreManager;
- }
+ private GenericTableCatalog genericTableCatalog;
@Override
protected void initializeCatalog() {
@@ -87,7 +64,7 @@ public class GenericTableCatalogHandler extends
CatalogHandler {
.addKeyValue("remoteUrl", connectionConfigInfoDpo.getUri())
.log("Initializing federated catalog");
FeatureConfiguration.enforceFeatureEnabledOrThrow(
- realmConfig, FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
+ realmConfig(), FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
GenericTableCatalog federatedCatalog;
ConnectionType connectionType =
@@ -95,8 +72,8 @@ public class GenericTableCatalogHandler extends
CatalogHandler {
// Use the unified factory pattern for all external catalog types
Instance<ExternalCatalogFactory> externalCatalogFactory =
- externalCatalogFactories.select(
- Identifier.Literal.of(connectionType.getFactoryIdentifier()));
+ externalCatalogFactories()
+
.select(Identifier.Literal.of(connectionType.getFactoryIdentifier()));
if (externalCatalogFactory.isResolvable()) {
// Pass through catalog properties (e.g., rest.client.proxy.*, timeout
settings)
Map<String, String> catalogProperties =
resolvedCatalogEntity.getPropertiesAsMap();
@@ -104,7 +81,7 @@ public class GenericTableCatalogHandler extends
CatalogHandler {
externalCatalogFactory
.get()
.createGenericCatalog(
- connectionConfigInfoDpo, getPolarisCredentialManager(),
catalogProperties);
+ connectionConfigInfoDpo, credentialManager(),
catalogProperties);
} else {
throw new UnsupportedOperationException(
"External catalog factory for type '" + connectionType + "' is
unavailable.");
@@ -113,8 +90,9 @@ public class GenericTableCatalogHandler extends
CatalogHandler {
} else {
LOGGER.atInfo().log("Initializing non-federated catalog");
this.genericTableCatalog =
- new PolarisGenericTableCatalog(metaStoreManager, callContext,
this.resolutionManifest);
- this.genericTableCatalog.initialize(catalogName, Map.of());
+ new PolarisGenericTableCatalog(
+ metaStoreManager(), callContext(), this.resolutionManifest);
+ this.genericTableCatalog.initialize(catalogName(), Map.of());
}
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandlerFactory.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandlerFactory.java
new file mode 100644
index 000000000..d0f42ca55
--- /dev/null
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandlerFactory.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.service.catalog.generic;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.inject.Any;
+import jakarta.enterprise.inject.Instance;
+import jakarta.inject.Inject;
+import org.apache.polaris.core.auth.PolarisAuthorizer;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.catalog.ExternalCatalogFactory;
+import org.apache.polaris.core.context.CallContext;
+import org.apache.polaris.core.credentials.PolarisCredentialManager;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+
+@RequestScoped
+public class GenericTableCatalogHandlerFactory {
+
+ @Inject CallContext callContext;
+ @Inject ResolutionManifestFactory resolutionManifestFactory;
+ @Inject PolarisMetaStoreManager metaStoreManager;
+ @Inject PolarisAuthorizer authorizer;
+ @Inject PolarisCredentialManager credentialManager;
+ @Inject @Any Instance<ExternalCatalogFactory> externalCatalogFactories;
+
+ public GenericTableCatalogHandler createHandler(String catalogName,
PolarisPrincipal principal) {
+ return ImmutableGenericTableCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(principal)
+ .callContext(callContext)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .authorizer(authorizer)
+ .credentialManager(credentialManager)
+ .externalCatalogFactories(externalCatalogFactories)
+ .build();
+ }
+}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
index e4582416b..a240186d0 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
@@ -24,8 +24,6 @@ import static
org.apache.polaris.service.catalog.validation.IcebergPropertiesVal
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import jakarta.enterprise.context.RequestScoped;
-import jakarta.enterprise.inject.Any;
-import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.Response;
@@ -51,27 +49,17 @@ import
org.apache.iceberg.rest.requests.UpdateNamespacePropertiesRequest;
import org.apache.iceberg.rest.requests.UpdateTableRequest;
import org.apache.iceberg.rest.responses.ImmutableLoadCredentialsResponse;
import org.apache.iceberg.rest.responses.LoadTableResponse;
-import org.apache.polaris.core.PolarisDiagnostics;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.core.credentials.PolarisCredentialManager;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
-import org.apache.polaris.core.persistence.resolver.ResolverFactory;
import org.apache.polaris.core.rest.PolarisResourcePaths;
import org.apache.polaris.service.catalog.AccessDelegationMode;
import org.apache.polaris.service.catalog.CatalogPrefixParser;
import org.apache.polaris.service.catalog.api.IcebergRestCatalogApiService;
import
org.apache.polaris.service.catalog.api.IcebergRestConfigurationApiService;
import org.apache.polaris.service.catalog.common.CatalogAdapter;
-import org.apache.polaris.service.catalog.io.StorageAccessConfigProvider;
import org.apache.polaris.service.config.ReservedProperties;
-import org.apache.polaris.service.context.catalog.CallContextCatalogFactory;
-import org.apache.polaris.service.events.EventAttributeMap;
import org.apache.polaris.service.http.IcebergHttpUtil;
import org.apache.polaris.service.http.IfNoneMatch;
import org.apache.polaris.service.reporting.PolarisMetricsReporter;
@@ -91,62 +79,29 @@ public class IcebergCatalogAdapter
private static final Logger LOGGER =
LoggerFactory.getLogger(IcebergCatalogAdapter.class);
- private final PolarisDiagnostics diagnostics;
private final RealmContext realmContext;
- private final CallContext callContext;
private final RealmConfig realmConfig;
- private final CallContextCatalogFactory catalogFactory;
- private final ResolutionManifestFactory resolutionManifestFactory;
- private final ResolverFactory resolverFactory;
- private final PolarisMetaStoreManager metaStoreManager;
- private final PolarisCredentialManager credentialManager;
- private final PolarisAuthorizer polarisAuthorizer;
private final CatalogPrefixParser prefixParser;
private final ReservedProperties reservedProperties;
- private final CatalogHandlerUtils catalogHandlerUtils;
- private final Instance<ExternalCatalogFactory> externalCatalogFactories;
- private final StorageAccessConfigProvider storageAccessConfigProvider;
private final PolarisMetricsReporter metricsReporter;
private final Clock clock;
- private final EventAttributeMap eventAttributeMap;
+ private final IcebergCatalogHandlerFactory handlerFactory;
@Inject
public IcebergCatalogAdapter(
- PolarisDiagnostics diagnostics,
- RealmContext realmContext,
CallContext callContext,
- CallContextCatalogFactory catalogFactory,
- ResolverFactory resolverFactory,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisCredentialManager credentialManager,
- PolarisAuthorizer polarisAuthorizer,
CatalogPrefixParser prefixParser,
ReservedProperties reservedProperties,
- CatalogHandlerUtils catalogHandlerUtils,
- @Any Instance<ExternalCatalogFactory> externalCatalogFactories,
- StorageAccessConfigProvider storageAccessConfigProvider,
PolarisMetricsReporter metricsReporter,
Clock clock,
- EventAttributeMap eventAttributeMap) {
- this.diagnostics = diagnostics;
- this.realmContext = realmContext;
- this.callContext = callContext;
+ IcebergCatalogHandlerFactory handlerFactory) {
+ this.realmContext = callContext.getRealmContext();
this.realmConfig = callContext.getRealmConfig();
- this.catalogFactory = catalogFactory;
- this.resolutionManifestFactory = resolutionManifestFactory;
- this.resolverFactory = resolverFactory;
- this.metaStoreManager = metaStoreManager;
- this.credentialManager = credentialManager;
- this.polarisAuthorizer = polarisAuthorizer;
this.prefixParser = prefixParser;
this.reservedProperties = reservedProperties;
- this.catalogHandlerUtils = catalogHandlerUtils;
- this.externalCatalogFactories = externalCatalogFactories;
- this.storageAccessConfigProvider = storageAccessConfigProvider;
this.metricsReporter = metricsReporter;
this.clock = clock;
- this.eventAttributeMap = eventAttributeMap;
+ this.handlerFactory = handlerFactory;
}
/**
@@ -165,7 +120,7 @@ public class IcebergCatalogAdapter
SecurityContext securityContext,
String catalogName,
Function<IcebergCatalogHandler, Response> action) {
- try (IcebergCatalogHandler wrapper = newHandlerWrapper(securityContext,
catalogName)) {
+ try (IcebergCatalogHandler wrapper = newHandler(securityContext,
catalogName)) {
return action.apply(wrapper);
} catch (RuntimeException e) {
LOGGER.debug("RuntimeException while operating on catalog. Propagating
to caller.", e);
@@ -177,26 +132,9 @@ public class IcebergCatalogAdapter
}
@VisibleForTesting
- IcebergCatalogHandler newHandlerWrapper(SecurityContext securityContext,
String catalogName) {
+ IcebergCatalogHandler newHandler(SecurityContext securityContext, String
catalogName) {
PolarisPrincipal principal = validatePrincipal(securityContext);
-
- return new IcebergCatalogHandler(
- diagnostics,
- callContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- principal,
- catalogFactory,
- catalogName,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- externalCatalogFactories,
- storageAccessConfigProvider,
- eventAttributeMap);
+ return handlerFactory.createHandler(catalogName, principal);
}
@Override
@@ -759,6 +697,9 @@ public class IcebergCatalogAdapter
@Override
public Response getConfig(
String warehouse, RealmContext realmContext, SecurityContext
securityContext) {
+ if (warehouse == null) {
+ throw new BadRequestException("Please specify a warehouse");
+ }
return withCatalogByName(
securityContext, warehouse, catalog ->
Response.ok(catalog.getConfig()).build());
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
index 3a4cbf8d3..3f70f4a72 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
@@ -84,20 +84,16 @@ import org.apache.iceberg.rest.responses.LoadViewResponse;
import org.apache.iceberg.rest.responses.UpdateNamespacePropertiesResponse;
import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
-import org.apache.polaris.core.auth.PolarisPrincipal;
import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.connection.ConnectionConfigInfoDpo;
import org.apache.polaris.core.connection.ConnectionType;
-import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.credentials.PolarisCredentialManager;
import org.apache.polaris.core.entity.CatalogEntity;
import org.apache.polaris.core.entity.PolarisEntity;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.table.IcebergTableLikeEntity;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.ResolvedPolarisEntity;
import
org.apache.polaris.core.persistence.TransactionWorkspaceMetaStoreManager;
@@ -105,7 +101,6 @@ import
org.apache.polaris.core.persistence.dao.entity.EntitiesResult;
import org.apache.polaris.core.persistence.dao.entity.EntityWithPath;
import org.apache.polaris.core.persistence.pagination.Page;
import org.apache.polaris.core.persistence.pagination.PageToken;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
import org.apache.polaris.core.persistence.resolver.Resolver;
import org.apache.polaris.core.persistence.resolver.ResolverFactory;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
@@ -113,6 +108,7 @@ import org.apache.polaris.core.rest.PolarisEndpoints;
import org.apache.polaris.core.storage.PolarisStorageActions;
import org.apache.polaris.core.storage.StorageAccessConfig;
import org.apache.polaris.core.storage.StorageUtil;
+import org.apache.polaris.immutables.PolarisImmutable;
import org.apache.polaris.service.catalog.AccessDelegationMode;
import org.apache.polaris.service.catalog.CatalogPrefixParser;
import org.apache.polaris.service.catalog.SupportsNotifications;
@@ -144,7 +140,9 @@ import org.slf4j.LoggerFactory;
* model objects used in this layer to still benefit from the shared
implementation of
* authorization-aware catalog protocols.
*/
-public class IcebergCatalogHandler extends CatalogHandler implements
AutoCloseable {
+@PolarisImmutable
+@SuppressWarnings("immutables:incompat")
+public abstract class IcebergCatalogHandler extends CatalogHandler implements
AutoCloseable {
private static final Logger LOGGER =
LoggerFactory.getLogger(IcebergCatalogHandler.class);
private static final Set<Endpoint> DEFAULT_ENDPOINTS =
@@ -178,63 +176,43 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.add(Endpoint.V1_RENAME_VIEW)
.build();
- private final CatalogPrefixParser prefixParser;
- private final ResolverFactory resolverFactory;
- private final PolarisMetaStoreManager metaStoreManager;
- private final CallContextCatalogFactory catalogFactory;
- private final ReservedProperties reservedProperties;
- private final CatalogHandlerUtils catalogHandlerUtils;
- private final StorageAccessConfigProvider storageAccessConfigProvider;
- private final EventAttributeMap eventAttributeMap;
+ protected abstract PolarisDiagnostics diagnostics();
+
+ protected abstract PolarisCredentialManager credentialManager();
+
+ protected abstract Instance<ExternalCatalogFactory>
externalCatalogFactories();
+
+ protected abstract CatalogPrefixParser prefixParser();
+
+ protected abstract ResolverFactory resolverFactory();
+
+ protected abstract CallContextCatalogFactory catalogFactory();
+
+ protected abstract ReservedProperties reservedProperties();
+
+ protected abstract CatalogHandlerUtils catalogHandlerUtils();
+
+ protected abstract StorageAccessConfigProvider storageAccessConfigProvider();
+
+ protected abstract EventAttributeMap eventAttributeMap();
// Catalog instance will be initialized after authorizing resolver
successfully resolves
// the catalog entity.
- protected Catalog baseCatalog = null;
- protected SupportsNamespaces namespaceCatalog = null;
- protected ViewCatalog viewCatalog = null;
-
- public static final String SNAPSHOTS_ALL = "all";
- public static final String SNAPSHOTS_REFS = "refs";
-
- public IcebergCatalogHandler(
- PolarisDiagnostics diagnostics,
- CallContext callContext,
- CatalogPrefixParser prefixParser,
- ResolverFactory resolverFactory,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisCredentialManager credentialManager,
- PolarisPrincipal principal,
- CallContextCatalogFactory catalogFactory,
- String catalogName,
- PolarisAuthorizer authorizer,
- ReservedProperties reservedProperties,
- CatalogHandlerUtils catalogHandlerUtils,
- Instance<ExternalCatalogFactory> externalCatalogFactories,
- StorageAccessConfigProvider storageAccessConfigProvider,
- EventAttributeMap eventAttributeMap) {
- super(
- diagnostics,
- callContext,
- resolutionManifestFactory,
- principal,
- catalogName,
- authorizer,
- credentialManager,
- externalCatalogFactories);
- this.prefixParser = prefixParser;
- this.resolverFactory = resolverFactory;
- this.metaStoreManager = metaStoreManager;
- this.catalogFactory = catalogFactory;
- this.reservedProperties = reservedProperties;
- this.catalogHandlerUtils = catalogHandlerUtils;
- this.storageAccessConfigProvider = storageAccessConfigProvider;
- this.eventAttributeMap = eventAttributeMap;
- }
+ @SuppressWarnings("immutables:incompat")
+ private Catalog baseCatalog = null;
+
+ @SuppressWarnings("immutables:incompat")
+ private SupportsNamespaces namespaceCatalog = null;
+
+ @SuppressWarnings("immutables:incompat")
+ private ViewCatalog viewCatalog = null;
+
+ private static final String SNAPSHOTS_ALL = "all";
+ private static final String SNAPSHOTS_REFS = "refs";
private CatalogEntity getResolvedCatalogEntity() {
CatalogEntity catalogEntity =
resolutionManifest.getResolvedCatalogEntity();
- diagnostics.checkNotNull(catalogEntity, "No catalog available");
+ diagnostics().checkNotNull(catalogEntity, "No catalog available");
return catalogEntity;
}
@@ -260,7 +238,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
}
private boolean shouldDecodeToken() {
- return realmConfig.getConfig(LIST_PAGINATION_ENABLED,
getResolvedCatalogEntity());
+ return realmConfig().getConfig(LIST_PAGINATION_ENABLED,
getResolvedCatalogEntity());
}
public ListNamespacesResponse listNamespaces(
@@ -276,7 +254,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.nextPageToken(results.encodedResponseToken())
.build();
} else {
- return catalogHandlerUtils.listNamespaces(namespaceCatalog, parent,
pageToken, pageSize);
+ return catalogHandlerUtils().listNamespaces(namespaceCatalog, parent,
pageToken, pageSize);
}
}
@@ -291,7 +269,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.addKeyValue("remoteUrl", connectionConfigInfoDpo.getUri())
.log("Initializing federated catalog");
FeatureConfiguration.enforceFeatureEnabledOrThrow(
- realmConfig, FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
+ realmConfig(), FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
Catalog federatedCatalog;
ConnectionType connectionType =
@@ -299,8 +277,8 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
// Use the unified factory pattern for all external catalog types
Instance<ExternalCatalogFactory> externalCatalogFactory =
- externalCatalogFactories.select(
- Identifier.Literal.of(connectionType.getFactoryIdentifier()));
+ externalCatalogFactories()
+
.select(Identifier.Literal.of(connectionType.getFactoryIdentifier()));
if (externalCatalogFactory.isResolvable()) {
// Pass through catalog properties (e.g., rest.client.proxy.*, timeout
settings)
// to the external catalog factory for configuration of the underlying
HTTP client
@@ -308,8 +286,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
federatedCatalog =
externalCatalogFactory
.get()
- .createCatalog(
- connectionConfigInfoDpo, getPolarisCredentialManager(),
catalogProperties);
+ .createCatalog(connectionConfigInfoDpo, credentialManager(),
catalogProperties);
} else {
throw new UnsupportedOperationException(
"External catalog factory for type '" + connectionType + "' is
unavailable.");
@@ -321,7 +298,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
this.baseCatalog = federatedCatalog;
} else {
LOGGER.atInfo().log("Initializing non-federated catalog");
- this.baseCatalog =
catalogFactory.createCallContextCatalog(resolutionManifest);
+ this.baseCatalog =
catalogFactory().createCallContextCatalog(resolutionManifest);
}
this.namespaceCatalog =
(baseCatalog instanceof SupportsNamespaces) ? (SupportsNamespaces)
baseCatalog : null;
@@ -332,7 +309,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
PolarisAuthorizableOperation op =
PolarisAuthorizableOperation.LIST_NAMESPACES;
authorizeBasicNamespaceOperationOrThrow(op, parent);
- return catalogHandlerUtils.listNamespaces(namespaceCatalog, parent);
+ return catalogHandlerUtils().listNamespaces(namespaceCatalog, parent);
}
public CreateNamespaceResponse createNamespace(CreateNamespaceRequest
request) {
@@ -356,19 +333,20 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
// retrieve the latest namespace metadata for the duration of the
CreateNamespace
// operation, even if the entityVersion and/or grantsVersion update in
the interim.
namespaceCatalog.createNamespace(
- namespace,
reservedProperties.removeReservedProperties(request.properties()));
+ namespace,
reservedProperties().removeReservedProperties(request.properties()));
Map<String, String> filteredProperties =
- reservedProperties.removeReservedProperties(
- resolutionManifest
- .getPassthroughResolvedPath(namespace)
- .getRawLeafEntity()
- .getPropertiesAsMap());
+ reservedProperties()
+ .removeReservedProperties(
+ resolutionManifest
+ .getPassthroughResolvedPath(namespace)
+ .getRawLeafEntity()
+ .getPropertiesAsMap());
return CreateNamespaceResponse.builder()
.withNamespace(namespace)
.setProperties(filteredProperties)
.build();
} else {
- return catalogHandlerUtils.createNamespace(namespaceCatalog, request);
+ return catalogHandlerUtils().createNamespace(namespaceCatalog, request);
}
}
@@ -376,7 +354,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
PolarisAuthorizableOperation op =
PolarisAuthorizableOperation.LOAD_NAMESPACE_METADATA;
authorizeBasicNamespaceOperationOrThrow(op, namespace);
- return catalogHandlerUtils.loadNamespace(namespaceCatalog, namespace);
+ return catalogHandlerUtils().loadNamespace(namespaceCatalog, namespace);
}
public void namespaceExists(Namespace namespace) {
@@ -391,14 +369,14 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
authorizeBasicNamespaceOperationOrThrow(op, namespace);
// TODO: Just skip CatalogHandlers for this one maybe
- catalogHandlerUtils.loadNamespace(namespaceCatalog, namespace);
+ catalogHandlerUtils().loadNamespace(namespaceCatalog, namespace);
}
public void dropNamespace(Namespace namespace) {
PolarisAuthorizableOperation op =
PolarisAuthorizableOperation.DROP_NAMESPACE;
authorizeBasicNamespaceOperationOrThrow(op, namespace);
- catalogHandlerUtils.dropNamespace(namespaceCatalog, namespace);
+ catalogHandlerUtils().dropNamespace(namespaceCatalog, namespace);
}
public UpdateNamespacePropertiesResponse updateNamespaceProperties(
@@ -406,7 +384,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
PolarisAuthorizableOperation op =
PolarisAuthorizableOperation.UPDATE_NAMESPACE_PROPERTIES;
authorizeBasicNamespaceOperationOrThrow(op, namespace);
- return catalogHandlerUtils.updateNamespaceProperties(namespaceCatalog,
namespace, request);
+ return catalogHandlerUtils().updateNamespaceProperties(namespaceCatalog,
namespace, request);
}
public ListTablesResponse listTables(Namespace namespace, String pageToken,
Integer pageSize) {
@@ -421,7 +399,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.nextPageToken(results.encodedResponseToken())
.build();
} else {
- return catalogHandlerUtils.listTables(baseCatalog, namespace, pageToken,
pageSize);
+ return catalogHandlerUtils().listTables(baseCatalog, namespace,
pageToken, pageSize);
}
}
@@ -429,7 +407,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_TABLES;
authorizeBasicNamespaceOperationOrThrow(op, namespace);
- return catalogHandlerUtils.listTables(baseCatalog, namespace);
+ return catalogHandlerUtils().listTables(baseCatalog, namespace);
}
/**
@@ -497,7 +475,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
Map<String, String> properties = Maps.newHashMap();
properties.put("created-at",
OffsetDateTime.now(ZoneOffset.UTC).toString());
-
properties.putAll(reservedProperties.removeReservedProperties(request.properties()));
+
properties.putAll(reservedProperties().removeReservedProperties(request.properties()));
Table table =
baseCatalog
@@ -538,7 +516,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
Map<String, String> properties = Maps.newHashMap();
properties.put("created-at",
OffsetDateTime.now(ZoneOffset.UTC).toString());
-
properties.putAll(reservedProperties.removeReservedProperties(request.properties()));
+
properties.putAll(reservedProperties().removeReservedProperties(request.properties()));
String location;
if (request.location() != null) {
@@ -638,7 +616,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
authorizeCreateTableLikeUnderNamespaceOperationOrThrow(
op, TableIdentifier.of(namespace, request.name()));
- return catalogHandlerUtils.registerTable(baseCatalog, namespace, request);
+ return catalogHandlerUtils().registerTable(baseCatalog, namespace,
request);
}
public boolean sendNotification(TableIdentifier identifier,
NotificationRequest request) {
@@ -854,8 +832,8 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
}
if (baseCatalog instanceof IcebergCatalog
- || realmConfig.getConfig(
- ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING,
getResolvedCatalogEntity())) {
+ || realmConfig()
+ .getConfig(ALLOW_FEDERATED_CATALOGS_CREDENTIAL_VENDING,
getResolvedCatalogEntity())) {
Set<String> tableLocations =
StorageUtil.getLocationsUsedByTable(tableMetadata);
@@ -865,12 +843,13 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
}
StorageAccessConfig storageAccessConfig =
- storageAccessConfigProvider.getStorageAccessConfig(
- tableIdentifier,
- tableLocations,
- actions,
- refreshCredentialsEndpoint,
- resolvedStoragePath);
+ storageAccessConfigProvider()
+ .getStorageAccessConfig(
+ tableIdentifier,
+ tableLocations,
+ actions,
+ refreshCredentialsEndpoint,
+ resolvedStoragePath);
Map<String, String> credentialConfig = storageAccessConfig.credentials();
if (delegationModes.contains(VENDED_CREDENTIALS)) {
if (!credentialConfig.isEmpty()) {
@@ -882,7 +861,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.build());
} else {
Boolean skipCredIndirection =
-
realmConfig.getConfig(FeatureConfiguration.SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION);
+
realmConfig().getConfig(FeatureConfiguration.SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION);
Preconditions.checkArgument(
!storageAccessConfig.supportsCredentialVending() ||
skipCredIndirection,
"Credential vending was requested for table %s, but no
credentials are available",
@@ -903,7 +882,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
try {
// Delegate to common validation logic
CatalogUtils.validateLocationsForTableLike(
- realmConfig, tableIdentifier, tableLocations, resolvedStoragePath);
+ realmConfig(), tableIdentifier, tableLocations, resolvedStoragePath);
LOGGER
.atInfo()
@@ -963,8 +942,8 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot update table on static-facade
external catalogs.");
}
- return catalogHandlerUtils.updateTable(
- baseCatalog, tableIdentifier, applyUpdateFilters(request));
+ return catalogHandlerUtils()
+ .updateTable(baseCatalog, tableIdentifier,
applyUpdateFilters(request));
}
public LoadTableResponse updateTableForStagedCreate(
@@ -976,8 +955,8 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot update table on static-facade
external catalogs.");
}
- return catalogHandlerUtils.updateTable(
- baseCatalog, tableIdentifier, applyUpdateFilters(request));
+ return catalogHandlerUtils()
+ .updateTable(baseCatalog, tableIdentifier,
applyUpdateFilters(request));
}
public void dropTableWithoutPurge(TableIdentifier tableIdentifier) {
@@ -985,7 +964,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
authorizeBasicTableLikeOperationOrThrow(
op, PolarisEntitySubType.ICEBERG_TABLE, tableIdentifier);
- catalogHandlerUtils.dropTable(baseCatalog, tableIdentifier);
+ catalogHandlerUtils().dropTable(baseCatalog, tableIdentifier);
}
public void dropTableWithPurge(TableIdentifier tableIdentifier) {
@@ -997,7 +976,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot drop table on static-facade
external catalogs.");
}
- catalogHandlerUtils.purgeTable(baseCatalog, tableIdentifier);
+ catalogHandlerUtils().purgeTable(baseCatalog, tableIdentifier);
}
public void tableExists(TableIdentifier tableIdentifier) {
@@ -1006,7 +985,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
op, PolarisEntitySubType.ICEBERG_TABLE, tableIdentifier);
// TODO: Just skip CatalogHandlers for this one maybe
- catalogHandlerUtils.loadTable(baseCatalog, tableIdentifier);
+ catalogHandlerUtils().loadTable(baseCatalog, tableIdentifier);
}
public void renameTable(RenameTableRequest request) {
@@ -1018,7 +997,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot rename table on static-facade
external catalogs.");
}
- catalogHandlerUtils.renameTable(baseCatalog, request);
+ catalogHandlerUtils().renameTable(baseCatalog, request);
}
public void commitTransaction(CommitTransactionRequest
commitTransactionRequest) {
@@ -1048,7 +1027,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
// only go into an in-memory collection that we can commit as a single
atomic unit after all
// validations.
TransactionWorkspaceMetaStoreManager transactionMetaStoreManager =
- new TransactionWorkspaceMetaStoreManager(diagnostics,
metaStoreManager);
+ new TransactionWorkspaceMetaStoreManager(diagnostics(),
metaStoreManager());
((IcebergCatalog)
baseCatalog).setMetaStoreManager(transactionMetaStoreManager);
List<TableMetadata> tableMetadataObjs = new ArrayList<>();
@@ -1083,8 +1062,9 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
// expose the concept of being able to read
uncommitted updates.
if (singleUpdate instanceof MetadataUpdate.SetLocation
setLocation) {
if
(!currentMetadata.location().equals(setLocation.location())
- && !realmConfig.getConfig(
-
FeatureConfiguration.ALLOW_NAMESPACE_LOCATION_OVERLAP)) {
+ && !realmConfig()
+ .getConfig(
+
FeatureConfiguration.ALLOW_NAMESPACE_LOCATION_OVERLAP)) {
throw new BadRequestException(
"Unsupported operation: commitTransaction
containing SetLocation"
+ " for table '%s' and new location '%s'",
@@ -1109,8 +1089,9 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
// Commit the collected updates in a single atomic operation
List<EntityWithPath> pendingUpdates =
transactionMetaStoreManager.getPendingUpdates();
EntitiesResult result =
- metaStoreManager.updateEntitiesPropertiesIfNotChanged(
- callContext.getPolarisCallContext(), pendingUpdates);
+ metaStoreManager()
+ .updateEntitiesPropertiesIfNotChanged(
+ callContext().getPolarisCallContext(), pendingUpdates);
if (!result.isSuccess()) {
// TODO: Retries and server-side cleanup on failure, review possible
exceptions
throw new CommitFailedException(
@@ -1118,7 +1099,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
result.getReturnStatus(), result.getExtraInformation());
}
- eventAttributeMap.put(EventAttributes.TABLE_METADATAS, tableMetadataObjs);
+ eventAttributeMap().put(EventAttributes.TABLE_METADATAS,
tableMetadataObjs);
}
public ListTablesResponse listViews(Namespace namespace, String pageToken,
Integer pageSize) {
@@ -1133,7 +1114,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
.nextPageToken(results.encodedResponseToken())
.build();
} else if (baseCatalog instanceof ViewCatalog viewCatalog) {
- return catalogHandlerUtils.listViews(viewCatalog, namespace, pageToken,
pageSize);
+ return catalogHandlerUtils().listViews(viewCatalog, namespace,
pageToken, pageSize);
} else {
throw new BadRequestException(
"Unsupported operation: listViews with baseCatalog type: %s",
@@ -1145,7 +1126,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_VIEWS;
authorizeBasicNamespaceOperationOrThrow(op, namespace);
- return catalogHandlerUtils.listViews(viewCatalog, namespace);
+ return catalogHandlerUtils().listViews(viewCatalog, namespace);
}
public LoadViewResponse createView(Namespace namespace, CreateViewRequest
request) {
@@ -1157,14 +1138,14 @@ public class IcebergCatalogHandler extends
CatalogHandler implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot create view on static-facade
external catalogs.");
}
- return catalogHandlerUtils.createView(viewCatalog, namespace, request);
+ return catalogHandlerUtils().createView(viewCatalog, namespace, request);
}
public LoadViewResponse loadView(TableIdentifier viewIdentifier) {
PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LOAD_VIEW;
authorizeBasicTableLikeOperationOrThrow(op,
PolarisEntitySubType.ICEBERG_VIEW, viewIdentifier);
- return catalogHandlerUtils.loadView(viewCatalog, viewIdentifier);
+ return catalogHandlerUtils().loadView(viewCatalog, viewIdentifier);
}
public LoadViewResponse replaceView(TableIdentifier viewIdentifier,
UpdateTableRequest request) {
@@ -1175,14 +1156,15 @@ public class IcebergCatalogHandler extends
CatalogHandler implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot replace view on static-facade
external catalogs.");
}
- return catalogHandlerUtils.updateView(viewCatalog, viewIdentifier,
applyUpdateFilters(request));
+ return catalogHandlerUtils()
+ .updateView(viewCatalog, viewIdentifier, applyUpdateFilters(request));
}
public void dropView(TableIdentifier viewIdentifier) {
PolarisAuthorizableOperation op = PolarisAuthorizableOperation.DROP_VIEW;
authorizeBasicTableLikeOperationOrThrow(op,
PolarisEntitySubType.ICEBERG_VIEW, viewIdentifier);
- catalogHandlerUtils.dropView(viewCatalog, viewIdentifier);
+ catalogHandlerUtils().dropView(viewCatalog, viewIdentifier);
}
public void viewExists(TableIdentifier viewIdentifier) {
@@ -1190,7 +1172,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
authorizeBasicTableLikeOperationOrThrow(op,
PolarisEntitySubType.ICEBERG_VIEW, viewIdentifier);
// TODO: Just skip CatalogHandlers for this one maybe
- catalogHandlerUtils.loadView(viewCatalog, viewIdentifier);
+ catalogHandlerUtils().loadView(viewCatalog, viewIdentifier);
}
public void renameView(RenameTableRequest request) {
@@ -1202,7 +1184,7 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
if (catalog.isStaticFacade()) {
throw new BadRequestException("Cannot rename view on static-facade
external catalogs.");
}
- catalogHandlerUtils.renameView(viewCatalog, request);
+ catalogHandlerUtils().renameView(viewCatalog, request);
}
private @Nonnull LoadTableResponse filterResponseToSnapshots(
@@ -1233,9 +1215,10 @@ public class IcebergCatalogHandler extends
CatalogHandler implements AutoCloseab
private EnumSet<PolarisAuthorizableOperation>
getUpdateTableAuthorizableOperations(
UpdateTableRequest request) {
boolean useFineGrainedOperations =
- realmConfig.getConfig(
- FeatureConfiguration.ENABLE_FINE_GRAINED_UPDATE_TABLE_PRIVILEGES,
- getResolvedCatalogEntity());
+ realmConfig()
+ .getConfig(
+
FeatureConfiguration.ENABLE_FINE_GRAINED_UPDATE_TABLE_PRIVILEGES,
+ getResolvedCatalogEntity());
if (useFineGrainedOperations) {
EnumSet<PolarisAuthorizableOperation> actions =
@@ -1308,13 +1291,15 @@ public class IcebergCatalogHandler extends
CatalogHandler implements AutoCloseab
LOGGER.info("Catalog type: {}", catalogEntity.getCatalogType());
LOGGER.info(
"allow external catalog credential vending: {}",
- realmConfig.getConfig(
- FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING,
catalogEntity));
+ realmConfig()
+ .getConfig(
+
FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, catalogEntity));
if (catalogEntity
.getCatalogType()
.equals(org.apache.polaris.core.admin.model.Catalog.TypeEnum.EXTERNAL)
- && !realmConfig.getConfig(
- FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING,
catalogEntity)) {
+ && !realmConfig()
+ .getConfig(
+
FeatureConfiguration.ALLOW_EXTERNAL_CATALOG_CREDENTIAL_VENDING, catalogEntity))
{
throw new ForbiddenException(
"Access Delegation is not enabled for this catalog. Please consult
applicable "
+ "documentation for the catalog config property '%s' to enable
this feature",
@@ -1330,25 +1315,16 @@ public class IcebergCatalogHandler extends
CatalogHandler implements AutoCloseab
}
public ConfigResponse getConfig() {
- // 'catalogName' is taken from the REST request's 'warehouse' query
parameter.
- // 'warehouse' as an output will be treated by the client as a default
catalog
- // storage base location.
- // 'prefix' as an output is the REST subpath that routes to the catalog
- // resource, which may be URL-escaped catalogName or potentially a
different
- // unique identifier for the catalog being accessed.
- if (catalogName == null) {
- throw new BadRequestException("Please specify a warehouse");
- }
- Resolver resolver = resolverFactory.createResolver(polarisPrincipal,
catalogName);
+ Resolver resolver = resolverFactory().createResolver(polarisPrincipal(),
catalogName());
ResolverStatus resolverStatus = resolver.resolveAll();
if (!resolverStatus.getStatus().equals(ResolverStatus.StatusEnum.SUCCESS))
{
- throw new NotFoundException("Unable to find warehouse %s", catalogName);
+ throw new NotFoundException("Unable to find warehouse %s",
catalogName());
}
ResolvedPolarisEntity resolvedReferenceCatalog =
resolver.getResolvedReferenceCatalog();
Map<String, String> properties =
PolarisEntity.of(resolvedReferenceCatalog.getEntity()).getPropertiesAsMap();
- String prefix = prefixParser.catalogNameToPrefix(catalogName);
+ String prefix = prefixParser().catalogNameToPrefix(catalogName());
return ConfigResponse.builder()
.withDefaults(properties) // catalog properties are defaults
.withOverrides(ImmutableMap.of("prefix", prefix))
@@ -1356,8 +1332,8 @@ public class IcebergCatalogHandler extends CatalogHandler
implements AutoCloseab
ImmutableList.<Endpoint>builder()
.addAll(DEFAULT_ENDPOINTS)
.addAll(VIEW_ENDPOINTS)
-
.addAll(PolarisEndpoints.getSupportedGenericTableEndpoints(realmConfig))
-
.addAll(PolarisEndpoints.getSupportedPolicyEndpoints(realmConfig))
+
.addAll(PolarisEndpoints.getSupportedGenericTableEndpoints(realmConfig()))
+
.addAll(PolarisEndpoints.getSupportedPolicyEndpoints(realmConfig()))
.build())
.build();
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFactory.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFactory.java
new file mode 100644
index 000000000..40f69bc4c
--- /dev/null
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFactory.java
@@ -0,0 +1,78 @@
+/*
+ * 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.polaris.service.catalog.iceberg;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.inject.Any;
+import jakarta.enterprise.inject.Instance;
+import jakarta.inject.Inject;
+import org.apache.polaris.core.PolarisDiagnostics;
+import org.apache.polaris.core.auth.PolarisAuthorizer;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.catalog.ExternalCatalogFactory;
+import org.apache.polaris.core.context.CallContext;
+import org.apache.polaris.core.credentials.PolarisCredentialManager;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.core.persistence.resolver.ResolverFactory;
+import org.apache.polaris.service.catalog.CatalogPrefixParser;
+import org.apache.polaris.service.catalog.io.StorageAccessConfigProvider;
+import org.apache.polaris.service.config.ReservedProperties;
+import org.apache.polaris.service.context.catalog.CallContextCatalogFactory;
+import org.apache.polaris.service.events.EventAttributeMap;
+
+@RequestScoped
+public class IcebergCatalogHandlerFactory {
+
+ @Inject PolarisDiagnostics diagnostics;
+ @Inject CallContext callContext;
+ @Inject CatalogPrefixParser prefixParser;
+ @Inject ResolverFactory resolverFactory;
+ @Inject ResolutionManifestFactory resolutionManifestFactory;
+ @Inject PolarisMetaStoreManager metaStoreManager;
+ @Inject PolarisCredentialManager credentialManager;
+ @Inject CallContextCatalogFactory catalogFactory;
+ @Inject PolarisAuthorizer authorizer;
+ @Inject ReservedProperties reservedProperties;
+ @Inject CatalogHandlerUtils catalogHandlerUtils;
+ @Inject @Any Instance<ExternalCatalogFactory> externalCatalogFactories;
+ @Inject StorageAccessConfigProvider storageAccessConfigProvider;
+ @Inject EventAttributeMap eventAttributeMap;
+
+ public IcebergCatalogHandler createHandler(String catalogName,
PolarisPrincipal principal) {
+ return ImmutableIcebergCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(principal)
+ .diagnostics(diagnostics)
+ .callContext(callContext)
+ .prefixParser(prefixParser)
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(catalogFactory)
+ .authorizer(authorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(externalCatalogFactories)
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
+ }
+}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogAdapter.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogAdapter.java
index 9b6ebd4e7..523107dc4 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogAdapter.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogAdapter.java
@@ -19,24 +19,16 @@
package org.apache.polaris.service.catalog.policy;
import jakarta.enterprise.context.RequestScoped;
-import jakarta.enterprise.inject.Any;
-import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.rest.RESTUtil;
-import org.apache.polaris.core.PolarisDiagnostics;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.CallContext;
import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.core.credentials.PolarisCredentialManager;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
import org.apache.polaris.core.policy.PolicyType;
import org.apache.polaris.service.catalog.CatalogPrefixParser;
import org.apache.polaris.service.catalog.api.PolarisCatalogPolicyApiService;
@@ -49,62 +41,32 @@ import
org.apache.polaris.service.types.ListPoliciesResponse;
import org.apache.polaris.service.types.LoadPolicyResponse;
import org.apache.polaris.service.types.PolicyIdentifier;
import org.apache.polaris.service.types.UpdatePolicyRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@RequestScoped
public class PolicyCatalogAdapter implements PolarisCatalogPolicyApiService,
CatalogAdapter {
- private static final Logger LOGGER =
LoggerFactory.getLogger(PolicyCatalogAdapter.class);
- private final PolarisDiagnostics diagnostics;
private final RealmContext realmContext;
private final RealmConfig realmConfig;
- private final CallContext callContext;
- private final ResolutionManifestFactory resolutionManifestFactory;
- private final PolarisMetaStoreManager metaStoreManager;
- private final PolarisAuthorizer polarisAuthorizer;
private final CatalogPrefixParser prefixParser;
- private final PolarisCredentialManager polarisCredentialManager;
- private final Instance<ExternalCatalogFactory> externalCatalogFactories;
+ private final PolicyCatalogHandlerFactory handlerFactory;
@Inject
public PolicyCatalogAdapter(
- PolarisDiagnostics diagnostics,
- RealmContext realmContext,
CallContext callContext,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisAuthorizer polarisAuthorizer,
CatalogPrefixParser prefixParser,
- PolarisCredentialManager polarisCredentialManager,
- @Any Instance<ExternalCatalogFactory> externalCatalogFactories) {
- this.diagnostics = diagnostics;
- this.realmContext = realmContext;
- this.callContext = callContext;
+ PolicyCatalogHandlerFactory handlerFactory) {
+ this.realmContext = callContext.getRealmContext();
this.realmConfig = callContext.getRealmConfig();
- this.resolutionManifestFactory = resolutionManifestFactory;
- this.metaStoreManager = metaStoreManager;
- this.polarisAuthorizer = polarisAuthorizer;
this.prefixParser = prefixParser;
- this.polarisCredentialManager = polarisCredentialManager;
- this.externalCatalogFactories = externalCatalogFactories;
+ this.handlerFactory = handlerFactory;
}
- private PolicyCatalogHandler newHandlerWrapper(SecurityContext
securityContext, String prefix) {
+ private PolicyCatalogHandler newHandler(SecurityContext securityContext,
String prefix) {
FeatureConfiguration.enforceFeatureEnabledOrThrow(
realmConfig, FeatureConfiguration.ENABLE_POLICY_STORE);
PolarisPrincipal principal = validatePrincipal(securityContext);
-
- return new PolicyCatalogHandler(
- diagnostics,
- callContext,
- resolutionManifestFactory,
- metaStoreManager,
- principal,
- prefixParser.prefixToCatalogName(prefix),
- polarisAuthorizer,
- polarisCredentialManager,
- externalCatalogFactories);
+ String catalogName = prefixParser.prefixToCatalogName(prefix);
+ return handlerFactory.createHandler(catalogName, principal);
}
@Override
@@ -115,7 +77,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
RealmContext realmContext,
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
LoadPolicyResponse response = handler.createPolicy(ns,
createPolicyRequest);
return Response.ok(response).build();
}
@@ -132,7 +94,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
Namespace ns = decodeNamespace(namespace);
PolicyType type =
policyType != null ?
PolicyType.fromName(RESTUtil.decodeString(policyType)) : null;
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
ListPoliciesResponse response = handler.listPolicies(ns, type);
return Response.ok(response).build();
}
@@ -146,7 +108,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
PolicyIdentifier identifier = new PolicyIdentifier(ns,
RESTUtil.decodeString(policyName));
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
LoadPolicyResponse response = handler.loadPolicy(identifier);
return Response.ok(response).build();
}
@@ -161,7 +123,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
PolicyIdentifier identifier = new PolicyIdentifier(ns,
RESTUtil.decodeString(policyName));
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
LoadPolicyResponse response = handler.updatePolicy(identifier,
updatePolicyRequest);
return Response.ok(response).build();
}
@@ -176,7 +138,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
PolicyIdentifier identifier = new PolicyIdentifier(ns,
RESTUtil.decodeString(policyName));
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
handler.dropPolicy(identifier, detachAll != null && detachAll);
return Response.noContent().build();
}
@@ -191,7 +153,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
PolicyIdentifier identifier = new PolicyIdentifier(ns,
RESTUtil.decodeString(policyName));
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
handler.attachPolicy(identifier, attachPolicyRequest);
return Response.noContent().build();
}
@@ -206,7 +168,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
SecurityContext securityContext) {
Namespace ns = decodeNamespace(namespace);
PolicyIdentifier identifier = new PolicyIdentifier(ns,
RESTUtil.decodeString(policyName));
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
handler.detachPolicy(identifier, detachPolicyRequest);
return Response.noContent().build();
}
@@ -225,7 +187,7 @@ public class PolicyCatalogAdapter implements
PolarisCatalogPolicyApiService, Cat
String target = targetName != null ? RESTUtil.decodeString(targetName) :
null;
PolicyType type =
policyType != null ?
PolicyType.fromName(RESTUtil.decodeString(policyType)) : null;
- PolicyCatalogHandler handler = newHandlerWrapper(securityContext, prefix);
+ PolicyCatalogHandler handler = newHandler(securityContext, prefix);
GetApplicablePoliciesResponse response = handler.getApplicablePolicies(ns,
target, type);
return Response.ok(response).build();
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
index 712193e40..85b0816d1 100644
---
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
@@ -20,7 +20,6 @@ package org.apache.polaris.service.catalog.policy;
import com.google.common.base.Strings;
import jakarta.annotation.Nullable;
-import jakarta.enterprise.inject.Instance;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -29,23 +28,16 @@ import org.apache.iceberg.catalog.TableIdentifier;
import org.apache.iceberg.exceptions.NoSuchNamespaceException;
import org.apache.iceberg.exceptions.NoSuchTableException;
import org.apache.iceberg.exceptions.NotFoundException;
-import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
-import org.apache.polaris.core.auth.PolarisAuthorizer;
-import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
-import org.apache.polaris.core.context.CallContext;
-import org.apache.polaris.core.credentials.PolarisCredentialManager;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
-import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
-import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.core.policy.PolicyType;
import org.apache.polaris.core.policy.exceptions.NoSuchPolicyException;
+import org.apache.polaris.immutables.PolarisImmutable;
import org.apache.polaris.service.catalog.common.CatalogHandler;
import org.apache.polaris.service.types.AttachPolicyRequest;
import org.apache.polaris.service.types.CreatePolicyRequest;
@@ -57,37 +49,16 @@ import
org.apache.polaris.service.types.PolicyAttachmentTarget;
import org.apache.polaris.service.types.PolicyIdentifier;
import org.apache.polaris.service.types.UpdatePolicyRequest;
-public class PolicyCatalogHandler extends CatalogHandler {
-
- private PolarisMetaStoreManager metaStoreManager;
+@PolarisImmutable
+@SuppressWarnings("immutables:incompat")
+public abstract class PolicyCatalogHandler extends CatalogHandler {
private PolicyCatalog policyCatalog;
- public PolicyCatalogHandler(
- PolarisDiagnostics diagnostics,
- CallContext callContext,
- ResolutionManifestFactory resolutionManifestFactory,
- PolarisMetaStoreManager metaStoreManager,
- PolarisPrincipal principal,
- String catalogName,
- PolarisAuthorizer authorizer,
- PolarisCredentialManager polarisCredentialManager,
- Instance<ExternalCatalogFactory> externalCatalogFactories) {
- super(
- diagnostics,
- callContext,
- resolutionManifestFactory,
- principal,
- catalogName,
- authorizer,
- polarisCredentialManager,
- externalCatalogFactories);
- this.metaStoreManager = metaStoreManager;
- }
-
@Override
protected void initializeCatalog() {
- this.policyCatalog = new PolicyCatalog(metaStoreManager, callContext,
this.resolutionManifest);
+ this.policyCatalog =
+ new PolicyCatalog(metaStoreManager(), callContext(),
this.resolutionManifest);
}
public ListPoliciesResponse listPolicies(Namespace parent, @Nullable
PolicyType policyType) {
@@ -179,12 +150,13 @@ public class PolicyCatalogHandler extends CatalogHandler {
throw new NoSuchPolicyException(String.format("Policy does not exist:
%s", identifier));
}
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- target,
- null /* secondary */);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ target,
+ null /* secondary */);
initializeCatalog();
}
@@ -221,12 +193,13 @@ public class PolicyCatalogHandler extends CatalogHandler {
if (targetCatalog == null) {
throw new NotFoundException("Catalog not found");
}
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- targetCatalog,
- null);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ targetCatalog,
+ null);
initializeCatalog();
}
@@ -278,12 +251,13 @@ public class PolicyCatalogHandler extends CatalogHandler {
PolarisAuthorizableOperation op =
determinePolicyMappingOperation(target, targetWrapper, isAttach);
- authorizer.authorizeOrThrow(
- polarisPrincipal,
- resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
- op,
- policyWrapper,
- targetWrapper);
+ authorizer()
+ .authorizeOrThrow(
+ polarisPrincipal(),
+ resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
+ op,
+ policyWrapper,
+ targetWrapper);
initializeCatalog();
}
diff --git
a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerFactory.java
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerFactory.java
new file mode 100644
index 000000000..5d8b305b4
--- /dev/null
+++
b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.service.catalog.policy;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.inject.Inject;
+import org.apache.polaris.core.auth.PolarisAuthorizer;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.context.CallContext;
+import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
+import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+
+@RequestScoped
+public class PolicyCatalogHandlerFactory {
+
+ @Inject CallContext callContext;
+ @Inject ResolutionManifestFactory resolutionManifestFactory;
+ @Inject PolarisMetaStoreManager metaStoreManager;
+ @Inject PolarisAuthorizer authorizer;
+
+ public PolicyCatalogHandler createHandler(String catalogName,
PolarisPrincipal principal) {
+ return ImmutablePolicyCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(principal)
+ .callContext(callContext)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .authorizer(authorizer)
+ .build();
+ }
+}
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
index 75067a48e..a6fc272c2 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalogHandlerAuthzTest.java
@@ -20,14 +20,17 @@ package org.apache.polaris.service.catalog.generic;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.TestProfile;
+import jakarta.enterprise.inject.Instance;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.iceberg.catalog.TableIdentifier;
import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.catalog.ExternalCatalogFactory;
import org.apache.polaris.core.entity.PolarisPrivilege;
import org.apache.polaris.service.admin.PolarisAuthzTestBase;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
@QuarkusTest
@TestProfile(PolarisAuthzTestBase.Profile.class)
@@ -41,20 +44,28 @@ public class PolarisGenericTableCatalogHandlerAuthzTest
extends PolarisAuthzTest
return newWrapper(activatedPrincipalRoles, CATALOG_NAME);
}
+ @SuppressWarnings("unchecked")
+ private static Instance<ExternalCatalogFactory>
emptyExternalCatalogFactory() {
+ Instance<ExternalCatalogFactory> mock = Mockito.mock(Instance.class);
+ Mockito.when(mock.select(Mockito.any())).thenReturn(mock);
+ Mockito.when(mock.isUnsatisfied()).thenReturn(true);
+ return mock;
+ }
+
private GenericTableCatalogHandler newWrapper(
Set<String> activatedPrincipalRoles, String catalogName) {
PolarisPrincipal authenticatedPrincipal =
PolarisPrincipal.of(principalEntity, activatedPrincipalRoles);
- return new GenericTableCatalogHandler(
- diagServices,
- callContext,
- resolutionManifestFactory,
- metaStoreManager,
- authenticatedPrincipal,
- catalogName,
- polarisAuthorizer,
- null,
- null);
+ return ImmutableGenericTableCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(authenticatedPrincipal)
+ .callContext(callContext)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .authorizer(polarisAuthorizer)
+ .externalCatalogFactories(emptyExternalCatalogFactory())
+ .build();
}
/**
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
index 76aa2e4e1..91af34e5b 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/AbstractIcebergCatalogHandlerAuthzTest.java
@@ -117,23 +117,24 @@ public abstract class
AbstractIcebergCatalogHandlerAuthzTest extends PolarisAuth
Set<String> activatedPrincipalRoles, String catalogName,
CallContextCatalogFactory factory) {
PolarisPrincipal authenticatedPrincipal =
PolarisPrincipal.of(principalEntity, activatedPrincipalRoles);
- return new IcebergCatalogHandler(
- diagServices,
- callContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authenticatedPrincipal,
- factory,
- catalogName,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- emptyExternalCatalogFactory(),
- storageAccessConfigProvider,
- eventAttributeMap);
+ return ImmutableIcebergCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(authenticatedPrincipal)
+ .diagnostics(diagServices)
+ .callContext(callContext)
+ .prefixParser(prefixParser)
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(factory)
+ .authorizer(polarisAuthorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(emptyExternalCatalogFactory())
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
}
protected void doTestInsufficientPrivileges(
@@ -258,37 +259,39 @@ public abstract class
AbstractIcebergCatalogHandlerAuthzTest extends PolarisAuth
PolarisPrincipal authenticatedPrincipal =
PolarisPrincipal.of(newPrincipal.getPrincipal(),
Set.of(PRINCIPAL_ROLE1, PRINCIPAL_ROLE2));
- IcebergCatalogHandler wrapper =
- new IcebergCatalogHandler(
- diagServices,
- callContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authenticatedPrincipal,
- callContextCatalogFactory,
- CATALOG_NAME,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- emptyExternalCatalogFactory(),
- storageAccessConfigProvider,
- eventAttributeMap);
+
+ IcebergCatalogHandler handler =
+ ImmutableIcebergCatalogHandler.builder()
+ .catalogName(CATALOG_NAME)
+ .polarisPrincipal(authenticatedPrincipal)
+ .diagnostics(diagServices)
+ .callContext(callContext)
+ .prefixParser(prefixParser)
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(callContextCatalogFactory)
+ .authorizer(polarisAuthorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(emptyExternalCatalogFactory())
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
// a variety of actions are all disallowed because the principal's
credentials must be rotated
doTestInsufficientPrivileges(
List.of(PolarisPrivilege.values()),
principalName,
- () -> wrapper.listNamespaces(Namespace.of()));
+ () -> handler.listNamespaces(Namespace.of()));
Namespace ns3 = Namespace.of("ns3");
doTestInsufficientPrivileges(
List.of(PolarisPrivilege.values()),
principalName,
- () ->
wrapper.createNamespace(CreateNamespaceRequest.builder().withNamespace(ns3).build()));
+ () ->
handler.createNamespace(CreateNamespaceRequest.builder().withNamespace(ns3).build()));
doTestInsufficientPrivileges(
- List.of(PolarisPrivilege.values()), principalName, () ->
wrapper.listTables(NS1));
+ List.of(PolarisPrivilege.values()), principalName, () ->
handler.listTables(NS1));
PrincipalWithCredentialsCredentials credentials =
new PrincipalWithCredentialsCredentials(
newPrincipal.getPrincipalSecrets().getPrincipalClientId(),
@@ -298,24 +301,13 @@ public abstract class
AbstractIcebergCatalogHandlerAuthzTest extends PolarisAuth
metaStoreManager, principalName, credentials,
callContext.getPolarisCallContext());
PolarisPrincipal authenticatedPrincipal1 =
PolarisPrincipal.of(refreshPrincipal, Set.of(PRINCIPAL_ROLE1,
PRINCIPAL_ROLE2));
+
+ @SuppressWarnings("resource")
IcebergCatalogHandler refreshedWrapper =
- new IcebergCatalogHandler(
- diagServices,
- callContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authenticatedPrincipal1,
- callContextCatalogFactory,
- CATALOG_NAME,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- emptyExternalCatalogFactory(),
- storageAccessConfigProvider,
- eventAttributeMap);
+ ImmutableIcebergCatalogHandler.builder()
+ .from(handler)
+ .polarisPrincipal(authenticatedPrincipal1)
+ .build();
doTestSufficientPrivilegeSets(
List.of(Set.of(PolarisPrivilege.NAMESPACE_LIST)),
@@ -1185,27 +1177,29 @@ public abstract class
AbstractIcebergCatalogHandlerAuthzTest extends PolarisAuth
};
// Mock the regular CallContext calls
+ Mockito.when(mockCallContext.getRealmContext()).thenReturn(() -> "test");
Mockito.when(mockCallContext.getRealmConfig()).thenReturn(customRealmConfig);
Mockito.when(mockCallContext.getPolarisCallContext())
.thenReturn(callContext.getPolarisCallContext());
- return new IcebergCatalogHandler(
- diagServices,
- mockCallContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authenticatedPrincipal,
- factory,
- catalogName,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- emptyExternalCatalogFactory(),
- storageAccessConfigProvider,
- eventAttributeMap);
+ return ImmutableIcebergCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(authenticatedPrincipal)
+ .diagnostics(diagServices)
+ .callContext(mockCallContext)
+ .prefixParser(prefixParser)
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(factory)
+ .authorizer(polarisAuthorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(emptyExternalCatalogFactory())
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
}
@Test
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java
index 825131494..d7a48e481 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergAllowedLocationTest.java
@@ -195,7 +195,7 @@ public class IcebergAllowedLocationTest {
var updateResponse =
services
.catalogAdapter()
- .newHandlerWrapper(services.securityContext(), catalog)
+ .newHandler(services.securityContext(), catalog)
.replaceView(viewId, updateRequest);
assertEquals(
updateResponse.metadata().properties().get(USER_SPECIFIED_WRITE_METADATA_LOCATION_KEY),
@@ -253,7 +253,7 @@ public class IcebergAllowedLocationTest {
() ->
services
.catalogAdapter()
- .newHandlerWrapper(services.securityContext(), catalog)
+ .newHandler(services.securityContext(), catalog)
.replaceView(viewId, updateRequest));
// Test 2: Try to create a view with location not allowed
@@ -344,7 +344,7 @@ public class IcebergAllowedLocationTest {
var updateResponse =
services
.catalogAdapter()
- .newHandlerWrapper(services.securityContext(), catalog)
+ .newHandler(services.securityContext(), catalog)
.updateTable(tableId, updateRequest);
assertThat(updateResponse.tableMetadata().properties())
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapterTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapterTest.java
index f5e6a81c3..5254f85a7 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapterTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapterTest.java
@@ -219,7 +219,7 @@ public class IcebergCatalogAdapterTest {
return wrappedHandler;
})
.when(catalogAdapter)
- .newHandlerWrapper(Mockito.any(), Mockito.any());
+ .newHandler(Mockito.any(), Mockito.any());
}
private static Stream<Arguments> paginationTestCases() {
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
index 16cb0974f..5da024ba1 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandlerFineGrainedDisabledTest.java
@@ -60,23 +60,24 @@ public class IcebergCatalogHandlerFineGrainedDisabledTest
extends PolarisAuthzTe
private IcebergCatalogHandler newWrapper() {
PolarisPrincipal authenticatedPrincipal =
PolarisPrincipal.of(principalEntity, Set.of());
- return new IcebergCatalogHandler(
- diagServices,
- callContext,
- prefixParser,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authenticatedPrincipal,
- callContextCatalogFactory,
- CATALOG_NAME,
- polarisAuthorizer,
- reservedProperties,
- catalogHandlerUtils,
- emptyExternalCatalogFactory(),
- storageAccessConfigProvider,
- eventAttributeMap);
+ return ImmutableIcebergCatalogHandler.builder()
+ .catalogName(CATALOG_NAME)
+ .polarisPrincipal(authenticatedPrincipal)
+ .diagnostics(diagServices)
+ .callContext(callContext)
+ .prefixParser(prefixParser)
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(callContextCatalogFactory)
+ .authorizer(polarisAuthorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(emptyExternalCatalogFactory())
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
}
public static class Profile extends PolarisAuthzTestBase.Profile {
diff --git
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerAuthzTest.java
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerAuthzTest.java
index 4bd6dc5c8..ea73cbe20 100644
---
a/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerAuthzTest.java
+++
b/runtime/service/src/test/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandlerAuthzTest.java
@@ -50,16 +50,14 @@ public class PolicyCatalogHandlerAuthzTest extends
PolarisAuthzTestBase {
private PolicyCatalogHandler newWrapper(Set<String> activatedPrincipalRoles,
String catalogName) {
PolarisPrincipal authenticatedPrincipal =
PolarisPrincipal.of(principalEntity, activatedPrincipalRoles);
- return new PolicyCatalogHandler(
- diagServices,
- callContext,
- resolutionManifestFactory,
- metaStoreManager,
- authenticatedPrincipal,
- catalogName,
- polarisAuthorizer,
- null,
- null);
+ return ImmutablePolicyCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(authenticatedPrincipal)
+ .callContext(callContext)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .authorizer(polarisAuthorizer)
+ .metaStoreManager(metaStoreManager)
+ .build();
}
/**
diff --git
a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
index 7b4e5c2dd..b6572b2d6 100644
---
a/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
+++
b/runtime/service/src/testFixtures/java/org/apache/polaris/service/TestServices.java
@@ -73,8 +73,11 @@ import
org.apache.polaris.service.catalog.api.IcebergRestConfigurationApi;
import
org.apache.polaris.service.catalog.api.IcebergRestConfigurationApiService;
import org.apache.polaris.service.catalog.iceberg.CatalogHandlerUtils;
import org.apache.polaris.service.catalog.iceberg.IcebergCatalogAdapter;
+import org.apache.polaris.service.catalog.iceberg.IcebergCatalogHandler;
+import org.apache.polaris.service.catalog.iceberg.IcebergCatalogHandlerFactory;
import
org.apache.polaris.service.catalog.iceberg.IcebergRestCatalogEventServiceDelegator;
import
org.apache.polaris.service.catalog.iceberg.IcebergRestConfigurationEventServiceDelegator;
+import
org.apache.polaris.service.catalog.iceberg.ImmutableIcebergCatalogHandler;
import org.apache.polaris.service.catalog.io.FileIOFactory;
import org.apache.polaris.service.catalog.io.MeasuredFileIOFactory;
import org.apache.polaris.service.catalog.io.StorageAccessConfigProvider;
@@ -336,25 +339,41 @@ public record TestServices(
Mockito.when(externalCatalogFactory.isUnsatisfied()).thenReturn(true);
EventAttributeMap eventAttributeMap = new EventAttributeMap();
+
+ IcebergCatalogHandlerFactory handlerFactory =
+ new IcebergCatalogHandlerFactory() {
+ @Override
+ public IcebergCatalogHandler createHandler(
+ String catalogName, PolarisPrincipal principal) {
+ return ImmutableIcebergCatalogHandler.builder()
+ .catalogName(catalogName)
+ .polarisPrincipal(principal)
+ .diagnostics(diagnostics)
+ .callContext(callContext)
+ .prefixParser(new DefaultCatalogPrefixParser())
+ .resolverFactory(resolverFactory)
+ .resolutionManifestFactory(resolutionManifestFactory)
+ .metaStoreManager(metaStoreManager)
+ .credentialManager(credentialManager)
+ .catalogFactory(callContextFactory)
+ .authorizer(authorizer)
+ .reservedProperties(reservedProperties)
+ .catalogHandlerUtils(catalogHandlerUtils)
+ .externalCatalogFactories(externalCatalogFactory)
+ .storageAccessConfigProvider(storageAccessConfigProvider)
+ .eventAttributeMap(eventAttributeMap)
+ .build();
+ }
+ };
+
IcebergCatalogAdapter catalogService =
new IcebergCatalogAdapter(
- diagnostics,
- realmContext,
callContext,
- callContextFactory,
- resolverFactory,
- resolutionManifestFactory,
- metaStoreManager,
- credentialManager,
- authorizer,
new DefaultCatalogPrefixParser(),
reservedProperties,
- catalogHandlerUtils,
- externalCatalogFactory,
- storageAccessConfigProvider,
new DefaultMetricsReporter(),
Clock.systemUTC(),
- eventAttributeMap);
+ handlerFactory);
// Optionally wrap with event delegator
IcebergRestCatalogApiService finalRestCatalogService = catalogService;