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 2e373e51c Allow realm context resolution to execute blocking calls 
(#1591)
2e373e51c is described below

commit 2e373e51ce5434c26635535b684ff210a53b1745
Author: Alexandre Dutra <[email protected]>
AuthorDate: Thu May 15 18:43:53 2025 +0200

    Allow realm context resolution to execute blocking calls (#1591)
---
 .../service/quarkus/config/QuarkusProducers.java   |  2 +-
 .../quarkus/context/RealmContextFilter.java        | 67 ++++++++++++++++++++++
 .../quarkus/logging/QuarkusLoggingMDCFilter.java   |  2 +-
 .../quarkus/metrics/RealmIdTagContributor.java     | 38 +++++++++---
 .../quarkus/tracing/QuarkusTracingFilter.java      |  2 +-
 .../service/quarkus/admin/RealmHeaderTest.java     |  2 +-
 .../test/PolarisIntegrationTestFixture.java        |  7 ++-
 .../context/DefaultRealmContextResolver.java       | 16 ++++--
 .../service/context/RealmContextFilter.java        | 51 ----------------
 .../service/context/RealmContextResolver.java      | 33 +++++++++--
 .../service/context/TestRealmContextResolver.java  |  6 +-
 .../context/UnresolvableRealmContextException.java | 34 -----------
 .../service/exception/PolarisExceptionMapper.java  |  3 -
 .../context/DefaultRealmIdResolverTest.java        | 49 +++++++++++-----
 14 files changed, 183 insertions(+), 129 deletions(-)

diff --git 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/config/QuarkusProducers.java
 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/config/QuarkusProducers.java
index 89bf2c6fb..40b79980d 100644
--- 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/config/QuarkusProducers.java
+++ 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/config/QuarkusProducers.java
@@ -60,7 +60,6 @@ import 
org.apache.polaris.service.catalog.api.IcebergRestOAuth2ApiService;
 import org.apache.polaris.service.catalog.io.FileIOFactory;
 import org.apache.polaris.service.config.RealmEntityManagerFactory;
 import org.apache.polaris.service.context.RealmContextConfiguration;
-import org.apache.polaris.service.context.RealmContextFilter;
 import org.apache.polaris.service.context.RealmContextResolver;
 import org.apache.polaris.service.events.PolarisEventListener;
 import 
org.apache.polaris.service.quarkus.auth.QuarkusAuthenticationConfiguration;
@@ -68,6 +67,7 @@ import 
org.apache.polaris.service.quarkus.auth.QuarkusAuthenticationRealmConfigu
 import 
org.apache.polaris.service.quarkus.auth.external.tenant.OidcTenantResolver;
 import 
org.apache.polaris.service.quarkus.catalog.io.QuarkusFileIOConfiguration;
 import 
org.apache.polaris.service.quarkus.context.QuarkusRealmContextConfiguration;
+import org.apache.polaris.service.quarkus.context.RealmContextFilter;
 import 
org.apache.polaris.service.quarkus.events.QuarkusPolarisEventListenerConfiguration;
 import 
org.apache.polaris.service.quarkus.persistence.QuarkusPersistenceConfiguration;
 import 
org.apache.polaris.service.quarkus.ratelimiter.QuarkusRateLimiterFilterConfiguration;
diff --git 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/context/RealmContextFilter.java
 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/context/RealmContextFilter.java
new file mode 100644
index 000000000..7ecce49b3
--- /dev/null
+++ 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/context/RealmContextFilter.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.service.quarkus.context;
+
+import io.smallrye.common.vertx.ContextLocals;
+import io.smallrye.mutiny.Uni;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.iceberg.rest.responses.ErrorResponse;
+import org.apache.polaris.service.config.PolarisFilterPriorities;
+import org.apache.polaris.service.context.RealmContextResolver;
+import org.jboss.resteasy.reactive.server.ServerRequestFilter;
+
+public class RealmContextFilter {
+
+  public static final String REALM_CONTEXT_KEY = "realmContext";
+
+  @Inject RealmContextResolver realmContextResolver;
+
+  @ServerRequestFilter(preMatching = true, priority = 
PolarisFilterPriorities.REALM_CONTEXT_FILTER)
+  public Uni<Response> resolveRealmContext(ContainerRequestContext rc) {
+    return Uni.createFrom()
+        .completionStage(
+            () ->
+                realmContextResolver.resolveRealmContext(
+                    rc.getUriInfo().getRequestUri().toString(),
+                    rc.getMethod(),
+                    rc.getUriInfo().getPath(),
+                    rc.getHeaders()::getFirst))
+        .onItem()
+        .invoke(realmContext -> rc.setProperty(REALM_CONTEXT_KEY, 
realmContext))
+        .invoke(realmContext -> ContextLocals.put(REALM_CONTEXT_KEY, 
realmContext))
+        .onItemOrFailure()
+        .transform((realmContext, error) -> error == null ? null : 
errorResponse(error));
+  }
+
+  private static Response errorResponse(Throwable error) {
+    return Response.status(Response.Status.NOT_FOUND)
+        .type(MediaType.APPLICATION_JSON_TYPE)
+        .entity(
+            ErrorResponse.builder()
+                .responseCode(Response.Status.NOT_FOUND.getStatusCode())
+                .withMessage(
+                    error.getMessage() != null ? error.getMessage() : "Missing 
or invalid realm")
+                .withType("MissingOrInvalidRealm")
+                .build())
+        .build();
+  }
+}
diff --git 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/logging/QuarkusLoggingMDCFilter.java
 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/logging/QuarkusLoggingMDCFilter.java
index 3062fabd3..cc4e7cd45 100644
--- 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/logging/QuarkusLoggingMDCFilter.java
+++ 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/logging/QuarkusLoggingMDCFilter.java
@@ -18,7 +18,7 @@
  */
 package org.apache.polaris.service.quarkus.logging;
 
-import static 
org.apache.polaris.service.context.RealmContextFilter.REALM_CONTEXT_KEY;
+import static 
org.apache.polaris.service.quarkus.context.RealmContextFilter.REALM_CONTEXT_KEY;
 
 import jakarta.annotation.Priority;
 import jakarta.enterprise.context.ApplicationScoped;
diff --git 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/metrics/RealmIdTagContributor.java
 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/metrics/RealmIdTagContributor.java
index 8388be9eb..7dd81f95b 100644
--- 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/metrics/RealmIdTagContributor.java
+++ 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/metrics/RealmIdTagContributor.java
@@ -30,24 +30,44 @@ import 
org.apache.polaris.service.context.RealmContextResolver;
 public class RealmIdTagContributor implements HttpServerMetricsTagsContributor 
{
 
   public static final String TAG_REALM = "realm_id";
+  public static final String TAG_REALM_RESOLUTION_FAILURE = 
"realm_resolution_failure";
+
+  private static final Tags UNFINISHED_RESOLUTION_TAGS = Tags.of(TAG_REALM, 
"???");
+  private static final Tags FAILED_RESOLUTION_TAGS = Tags.of(TAG_REALM, "!!!");
 
   @Inject RealmContextResolver realmContextResolver;
 
   @Override
   public Tags contribute(Context context) {
-    // FIXME request scope does not work here, so we have to resolve the realm 
context manually
+    // FIXME retrieve the realm context from context.requestContextLocalData() 
when this PR is in:
+    // https://github.com/quarkusio/quarkus/pull/47887
     HttpServerRequest request = context.request();
     try {
-      RealmContext realmContext = resolveRealmContext(request);
-      return Tags.of(TAG_REALM, realmContext.getRealmIdentifier());
-    } catch (Exception ignored) {
-      // ignore, the RealmContextFilter will handle the error
-      return Tags.empty();
+      return realmContextResolver
+          .resolveRealmContext(
+              request.absoluteURI(),
+              request.method().name(),
+              request.path(),
+              request.headers()::get)
+          .thenApply(this::successfulResolutionTags)
+          .exceptionally(this::failedResolutionTags)
+          .toCompletableFuture()
+          // get the result of the CompletableFuture if it's already completed,
+          // otherwise return UNFINISHED_RESOLUTION_TAGS as this code is 
executed on
+          // an event loop thread, and we don't want to block it.
+          .getNow(UNFINISHED_RESOLUTION_TAGS);
+    } catch (Exception e) {
+      return failedResolutionTags(e);
     }
   }
 
-  private RealmContext resolveRealmContext(HttpServerRequest request) {
-    return realmContextResolver.resolveRealmContext(
-        request.absoluteURI(), request.method().name(), request.path(), 
request.headers()::get);
+  private Tags successfulResolutionTags(RealmContext realmContext) {
+    return Tags.of(TAG_REALM, realmContext.getRealmIdentifier());
+  }
+
+  private Tags failedResolutionTags(Throwable error) {
+    return FAILED_RESOLUTION_TAGS.and(
+        TAG_REALM_RESOLUTION_FAILURE,
+        error.getMessage() == null ? error.getClass().getSimpleName() : 
error.getMessage());
   }
 }
diff --git 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/tracing/QuarkusTracingFilter.java
 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/tracing/QuarkusTracingFilter.java
index 6035cceb4..847905a6b 100644
--- 
a/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/tracing/QuarkusTracingFilter.java
+++ 
b/quarkus/service/src/main/java/org/apache/polaris/service/quarkus/tracing/QuarkusTracingFilter.java
@@ -26,8 +26,8 @@ import jakarta.ws.rs.container.ContainerRequestFilter;
 import jakarta.ws.rs.container.PreMatching;
 import jakarta.ws.rs.ext.Provider;
 import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.service.context.RealmContextFilter;
 import org.apache.polaris.service.quarkus.config.QuarkusFilterPriorities;
+import org.apache.polaris.service.quarkus.context.RealmContextFilter;
 import org.apache.polaris.service.quarkus.logging.QuarkusLoggingMDCFilter;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
index f062f9263..eff5be116 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
@@ -90,7 +90,7 @@ public class RealmHeaderTest {
           .extracting(ErrorResponse::code, ErrorResponse::type, 
ErrorResponse::message)
           .containsExactly(
               Response.Status.NOT_FOUND.getStatusCode(),
-              "UnresolvableRealmContextException",
+              "MissingOrInvalidRealm",
               "Unknown realm: INVALID");
     }
   }
diff --git 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
index a550c98d1..259cfc648 100644
--- 
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
+++ 
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
@@ -104,8 +104,11 @@ public class PolarisIntegrationTestFixture {
     }
 
     RealmContext realmContext =
-        helper.realmContextResolver.resolveRealmContext(
-            baseUri.toString(), "GET", "/", Map.of(REALM_PROPERTY_KEY, realm));
+        helper
+            .realmContextResolver
+            .resolveRealmContext(baseUri.toString(), "GET", "/", 
Map.of(REALM_PROPERTY_KEY, realm))
+            .toCompletableFuture()
+            .join();
 
     BasePersistence metaStoreSession =
         
helper.metaStoreManagerFactory.getOrCreateSessionSupplier(realmContext).get();
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/context/DefaultRealmContextResolver.java
 
b/service/common/src/main/java/org/apache/polaris/service/context/DefaultRealmContextResolver.java
index 3318bd2f5..7d779ef85 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/context/DefaultRealmContextResolver.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/context/DefaultRealmContextResolver.java
@@ -21,6 +21,8 @@ package org.apache.polaris.service.context;
 import io.smallrye.common.annotation.Identifier;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
 import java.util.function.Function;
 import org.apache.polaris.core.context.RealmContext;
 
@@ -36,21 +38,25 @@ public class DefaultRealmContextResolver implements 
RealmContextResolver {
   }
 
   @Override
-  public RealmContext resolveRealmContext(
+  public CompletionStage<RealmContext> resolveRealmContext(
       String requestURL, String method, String path, Function<String, String> 
headers) {
-    String realm = resolveRealmIdentifier(headers);
-    return () -> realm;
+    try {
+      String realm = resolveRealmIdentifier(headers);
+      return CompletableFuture.completedFuture(() -> realm);
+    } catch (Exception e) {
+      return CompletableFuture.failedFuture(e);
+    }
   }
 
   private String resolveRealmIdentifier(Function<String, String> headers) {
     String realm = headers.apply(configuration.headerName());
     if (realm != null) {
       if (!configuration.realms().contains(realm)) {
-        throw new UnresolvableRealmContextException("Unknown realm: " + realm);
+        throw new IllegalArgumentException("Unknown realm: " + realm);
       }
     } else {
       if (configuration.requireHeader()) {
-        throw new UnresolvableRealmContextException(
+        throw new IllegalArgumentException(
             "Missing required realm header: " + configuration.headerName());
       }
       realm = configuration.defaultRealm();
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/context/RealmContextFilter.java
 
b/service/common/src/main/java/org/apache/polaris/service/context/RealmContextFilter.java
deleted file mode 100644
index 7939d05b1..000000000
--- 
a/service/common/src/main/java/org/apache/polaris/service/context/RealmContextFilter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.polaris.service.context;
-
-import jakarta.annotation.Priority;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.container.PreMatching;
-import jakarta.ws.rs.ext.Provider;
-import org.apache.polaris.core.context.RealmContext;
-import org.apache.polaris.service.config.PolarisFilterPriorities;
-
-@PreMatching
-@ApplicationScoped
-@Priority(PolarisFilterPriorities.REALM_CONTEXT_FILTER)
-@Provider
-public class RealmContextFilter implements ContainerRequestFilter {
-
-  public static final String REALM_CONTEXT_KEY = "realmContext";
-
-  @Inject RealmContextResolver realmContextResolver;
-
-  @Override
-  public void filter(ContainerRequestContext rc) {
-    RealmContext realmContext =
-        realmContextResolver.resolveRealmContext(
-            rc.getUriInfo().getRequestUri().toString(),
-            rc.getMethod(),
-            rc.getUriInfo().getPath(),
-            rc.getHeaders()::getFirst);
-    rc.setProperty(REALM_CONTEXT_KEY, realmContext);
-  }
-}
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/context/RealmContextResolver.java
 
b/service/common/src/main/java/org/apache/polaris/service/context/RealmContextResolver.java
index ae2b2dc6e..0aea6e9bd 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/context/RealmContextResolver.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/context/RealmContextResolver.java
@@ -19,22 +19,45 @@
 package org.apache.polaris.service.context;
 
 import java.util.Map;
+import java.util.concurrent.CompletionStage;
 import java.util.function.Function;
 import org.apache.commons.collections.map.CaseInsensitiveMap;
 import org.apache.polaris.core.context.RealmContext;
 
+/**
+ * An interface for resolving the realm context for a given request.
+ *
+ * <p>General implementation guidance:
+ *
+ * <p>Methods in this class should not block the calling thread. If the realm 
resolution process is
+ * blocking, it should be done in a separate thread.
+ *
+ * <p>In the case of an error during realm resolution, the {@link 
CompletionStage} should complete
+ * exceptionally; methods should not throw exceptions directly.
+ *
+ * <p>The realm resolution takes place in the very early stages of the request 
processing pipeline,
+ * and before any authentication or authorization checks are performed. 
Implementations should be
+ * careful with the use of any blocking operations, as they may lead to 
performance issues or
+ * deadlocks, especially in public environments.
+ */
 public interface RealmContextResolver {
 
   /**
-   * Resolves the realm context for the given request.
+   * Resolves the realm context for the given request, and returns a {@link 
CompletionStage} that
+   * completes with the resolved realm context.
    *
-   * @return the resolved realm context
-   * @throws UnresolvableRealmContextException if the realm context cannot be 
resolved
+   * @return a {@link CompletionStage} that completes with the resolved realm 
context
    */
-  RealmContext resolveRealmContext(
+  CompletionStage<RealmContext> resolveRealmContext(
       String requestURL, String method, String path, Function<String, String> 
headers);
 
-  default RealmContext resolveRealmContext(
+  /**
+   * Resolves the realm context for the given request, and returns a {@link 
CompletionStage} that
+   * completes with the resolved realm context.
+   *
+   * @return a {@link CompletionStage} that completes with the resolved realm 
context
+   */
+  default CompletionStage<RealmContext> resolveRealmContext(
       String requestURL, String method, String path, Map<String, String> 
headers) {
     CaseInsensitiveMap caseInsensitiveMap = new CaseInsensitiveMap(headers);
     return resolveRealmContext(
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/context/TestRealmContextResolver.java
 
b/service/common/src/main/java/org/apache/polaris/service/context/TestRealmContextResolver.java
index 1fcff6496..79a914954 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/context/TestRealmContextResolver.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/context/TestRealmContextResolver.java
@@ -24,6 +24,8 @@ import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
 import java.util.function.Function;
 import org.apache.polaris.core.context.RealmContext;
 import org.slf4j.Logger;
@@ -50,7 +52,7 @@ public class TestRealmContextResolver implements 
RealmContextResolver {
   }
 
   @Override
-  public RealmContext resolveRealmContext(
+  public CompletionStage<RealmContext> resolveRealmContext(
       String requestURL, String method, String path, Function<String, String> 
headers) {
     // Since this default resolver is strictly for use in test/dev 
environments, we'll consider
     // it safe to log all contents. Any "real" resolver used in a prod 
environment should make
@@ -72,7 +74,7 @@ public class TestRealmContextResolver implements 
RealmContextResolver {
       parsedProperties.put(REALM_PROPERTY_KEY, configuration.defaultRealm());
     }
     String realmId = parsedProperties.get(REALM_PROPERTY_KEY);
-    return () -> realmId;
+    return CompletableFuture.completedFuture(() -> realmId);
   }
 
   /**
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/context/UnresolvableRealmContextException.java
 
b/service/common/src/main/java/org/apache/polaris/service/context/UnresolvableRealmContextException.java
deleted file mode 100644
index 4456fc602..000000000
--- 
a/service/common/src/main/java/org/apache/polaris/service/context/UnresolvableRealmContextException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.polaris.service.context;
-
-import java.util.Map;
-import org.apache.polaris.core.exceptions.PolarisException;
-
-/**
- * Exception thrown when a realm context cannot be resolved.
- *
- * @see RealmContextResolver#resolveRealmContext(String, String, String, Map)
- */
-public class UnresolvableRealmContextException extends PolarisException {
-
-  public UnresolvableRealmContextException(String message) {
-    super(message);
-  }
-}
diff --git 
a/service/common/src/main/java/org/apache/polaris/service/exception/PolarisExceptionMapper.java
 
b/service/common/src/main/java/org/apache/polaris/service/exception/PolarisExceptionMapper.java
index 7eac23bd5..dfbd4f6c5 100644
--- 
a/service/common/src/main/java/org/apache/polaris/service/exception/PolarisExceptionMapper.java
+++ 
b/service/common/src/main/java/org/apache/polaris/service/exception/PolarisExceptionMapper.java
@@ -31,7 +31,6 @@ import 
org.apache.polaris.core.policy.exceptions.PolicyAttachException;
 import org.apache.polaris.core.policy.exceptions.PolicyInUseException;
 import 
org.apache.polaris.core.policy.exceptions.PolicyVersionMismatchException;
 import org.apache.polaris.core.policy.validator.InvalidPolicyException;
-import org.apache.polaris.service.context.UnresolvableRealmContextException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.event.Level;
@@ -48,8 +47,6 @@ public class PolarisExceptionMapper implements 
ExceptionMapper<PolarisException>
   private Response.Status getStatus(PolarisException exception) {
     if (exception instanceof AlreadyExistsException) {
       return Response.Status.CONFLICT;
-    } else if (exception instanceof UnresolvableRealmContextException) {
-      return Response.Status.NOT_FOUND;
     } else if (exception instanceof InvalidPolicyException) {
       return Response.Status.BAD_REQUEST;
     } else if (exception instanceof PolicyAttachException) {
diff --git 
a/service/common/src/test/java/org/apache/polaris/service/context/DefaultRealmIdResolverTest.java
 
b/service/common/src/test/java/org/apache/polaris/service/context/DefaultRealmIdResolverTest.java
index 7b114cafb..e7d1ab70d 100644
--- 
a/service/common/src/test/java/org/apache/polaris/service/context/DefaultRealmIdResolverTest.java
+++ 
b/service/common/src/test/java/org/apache/polaris/service/context/DefaultRealmIdResolverTest.java
@@ -45,12 +45,16 @@ class DefaultRealmContextResolverTest {
   void headerPresentSuccess() {
     DefaultRealmContextResolver resolver = new 
DefaultRealmContextResolver(config);
     RealmContext RealmContext1 =
-        resolver.resolveRealmContext(
-            "requestURL", "method", "path", Map.of("Polaris-Header", 
"realm1"));
+        resolver
+            .resolveRealmContext("requestURL", "method", "path", 
Map.of("Polaris-Header", "realm1"))
+            .toCompletableFuture()
+            .join();
     assertThat(RealmContext1.getRealmIdentifier()).isEqualTo("realm1");
     RealmContext RealmContext2 =
-        resolver.resolveRealmContext(
-            "requestURL", "method", "path", Map.of("Polaris-Header", 
"realm2"));
+        resolver
+            .resolveRealmContext("requestURL", "method", "path", 
Map.of("Polaris-Header", "realm2"))
+            .toCompletableFuture()
+            .join();
     assertThat(RealmContext2.getRealmIdentifier()).isEqualTo("realm2");
   }
 
@@ -59,9 +63,13 @@ class DefaultRealmContextResolverTest {
     DefaultRealmContextResolver resolver = new 
DefaultRealmContextResolver(config);
     assertThatThrownBy(
             () ->
-                resolver.resolveRealmContext(
-                    "requestURL", "method", "path", Map.of("Polaris-Header", 
"realm3")))
-        .isInstanceOf(UnresolvableRealmContextException.class)
+                resolver
+                    .resolveRealmContext(
+                        "requestURL", "method", "path", 
Map.of("Polaris-Header", "realm3"))
+                    .toCompletableFuture()
+                    .join())
+        .rootCause()
+        .isInstanceOf(IllegalArgumentException.class)
         .hasMessage("Unknown realm: realm3");
   }
 
@@ -70,7 +78,10 @@ class DefaultRealmContextResolverTest {
     when(config.requireHeader()).thenReturn(false);
     DefaultRealmContextResolver resolver = new 
DefaultRealmContextResolver(config);
     RealmContext RealmContext1 =
-        resolver.resolveRealmContext("requestURL", "method", "path", Map.of());
+        resolver
+            .resolveRealmContext("requestURL", "method", "path", Map.of())
+            .toCompletableFuture()
+            .join();
     assertThat(RealmContext1.getRealmIdentifier()).isEqualTo("realm1");
   }
 
@@ -78,8 +89,14 @@ class DefaultRealmContextResolverTest {
   void headerNotPresentFailure() {
     when(config.requireHeader()).thenReturn(true);
     DefaultRealmContextResolver resolver = new 
DefaultRealmContextResolver(config);
-    assertThatThrownBy(() -> resolver.resolveRealmContext("requestURL", 
"method", "path", Map.of()))
-        .isInstanceOf(UnresolvableRealmContextException.class)
+    assertThatThrownBy(
+            () ->
+                resolver
+                    .resolveRealmContext("requestURL", "method", "path", 
Map.of())
+                    .toCompletableFuture()
+                    .join())
+        .rootCause()
+        .isInstanceOf(IllegalArgumentException.class)
         .hasMessage("Missing required realm header: Polaris-Header");
   }
 
@@ -87,12 +104,16 @@ class DefaultRealmContextResolverTest {
   void headerCaseInsensitive() {
     DefaultRealmContextResolver resolver = new 
DefaultRealmContextResolver(config);
     RealmContext RealmContext1 =
-        resolver.resolveRealmContext(
-            "requestURL", "method", "path", Map.of("POLARIS-HEADER", 
"realm1"));
+        resolver
+            .resolveRealmContext("requestURL", "method", "path", 
Map.of("POLARIS-HEADER", "realm1"))
+            .toCompletableFuture()
+            .join();
     assertThat(RealmContext1.getRealmIdentifier()).isEqualTo("realm1");
     RealmContext RealmContext2 =
-        resolver.resolveRealmContext(
-            "requestURL", "method", "path", Map.of("polaris-header", 
"realm2"));
+        resolver
+            .resolveRealmContext("requestURL", "method", "path", 
Map.of("polaris-header", "realm2"))
+            .toCompletableFuture()
+            .join();
     assertThat(RealmContext2.getRealmIdentifier()).isEqualTo("realm2");
   }
 }

Reply via email to