gh-yzou commented on code in PR #1298: URL: https://github.com/apache/polaris/pull/1298#discussion_r2029494686
########## integration-tests/src/main/java/org/apache/polaris/service/it/env/GenericTableApi.java: ########## @@ -0,0 +1,118 @@ +/* + * 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.it.env; + +import static jakarta.ws.rs.core.Response.Status.NO_CONTENT; +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.MultivaluedHashMap; +import jakarta.ws.rs.core.Response; +import java.net.URI; +import java.util.List; +import java.util.Map; +import org.apache.iceberg.catalog.Namespace; +import org.apache.iceberg.catalog.TableIdentifier; +import org.apache.iceberg.rest.RESTUtil; +import org.apache.iceberg.rest.responses.OAuthTokenResponse; +import org.apache.polaris.service.types.CreateGenericTableRequest; +import org.apache.polaris.service.types.GenericTable; +import org.apache.polaris.service.types.ListGenericTablesResponse; +import org.apache.polaris.service.types.LoadGenericTableResponse; + +/** + * A simple, non-exhaustive set of helper methods for accessing the generic tables REST API + * + * @see PolarisClient#genericTableApi(ClientCredentials) + */ +public class GenericTableApi extends RestApi { + GenericTableApi(Client client, PolarisApiEndpoints endpoints, String authToken, URI uri) { + super(client, endpoints, authToken, uri); + } + + public String obtainToken(ClientCredentials credentials) { + try (Response response = + request("v1/oauth/tokens") + .post( + Entity.form( + new MultivaluedHashMap<>( + Map.of( + "grant_type", + "client_credentials", + "scope", + "PRINCIPAL_ROLE:ALL", + "client_id", + credentials.clientId(), + "client_secret", + credentials.clientSecret()))))) { + assertThat(response).returns(Response.Status.OK.getStatusCode(), Response::getStatus); + return response.readEntity(OAuthTokenResponse.class).token(); + } + } + + public void purge(String catalog, Namespace ns) { + listGenericTables(catalog, ns).forEach(t -> dropGenericTable(catalog, t)); + } + + public List<TableIdentifier> listGenericTables(String catalog, Namespace namespace) { + String ns = RESTUtil.encodeNamespace(namespace); + try (Response res = + request("polaris/v1/{cat}/namespaces/{ns}/generic-tables", Map.of("cat", catalog, "ns", ns)) Review Comment: you can init a PolarisResourcePaths instance with catalog and then directly call genericTables methods to get the request path, this is also how client used to generate the path also, then we don't have to hard code the path. ``` PolarisResourcePaths paths = new PolarisResourcePaths(catalog); request(paths.genericTables(ns)); ``` ########## service/common/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java: ########## @@ -366,4 +349,24 @@ protected void authorizeRenameTableLikeOperationOrThrow( initializeCatalog(); } + + /** + * Helper function for when a TABLE_LIKE entity is not found so we want to throw the appropriate + * exception. Used in Iceberg APIs, so the Iceberg messages cannot be changed. + * + * @param subType The subtype of the entity that the exception should report doesn't exist + */ + public static void throwNotFoundException( + TableIdentifier identifier, PolarisEntitySubType subType) { + switch (subType) { + case ICEBERG_TABLE: + throw new NoSuchTableException("Table does not exist: %s", identifier); + case ICEBERG_VIEW: + throw new NoSuchViewException("View does not exist: %s", identifier); + case GENERIC_TABLE: + throw new NoSuchTableException("Generic table does not exist: %s", identifier); + default: + throw new NoSuchTableException("Entity does not exist: %s", subType); Review Comment: How about update this message "Entity does not exist" -> "Table does not exist" to give a more clear message to user. Right now, seems ANY_SUBTYPE is used when we are handling table in general List.of(PolarisEntitySubType.GENERIC_TABLE, PolarisEntitySubType.ICEBERG_TABLE). Then it is clear to the user that it is the Table doesn't exist ########## service/common/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogAdapter.java: ########## @@ -19,22 +19,86 @@ package org.apache.polaris.service.catalog.generic; import jakarta.enterprise.context.RequestScoped; +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.catalog.TableIdentifier; +import org.apache.iceberg.exceptions.NotAuthorizedException; +import org.apache.polaris.core.auth.AuthenticatedPolarisPrincipal; +import org.apache.polaris.core.auth.PolarisAuthorizer; +import org.apache.polaris.core.context.CallContext; import org.apache.polaris.core.context.RealmContext; +import org.apache.polaris.core.persistence.PolarisEntityManager; +import org.apache.polaris.core.persistence.PolarisMetaStoreManager; import org.apache.polaris.service.catalog.api.PolarisCatalogGenericTableApiService; 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 { + + private static final Logger LOGGER = LoggerFactory.getLogger(GenericTableCatalogAdapter.class); + + private final CallContext callContext; + private final PolarisEntityManager entityManager; + private final PolarisMetaStoreManager metaStoreManager; + private final PolarisAuthorizer polarisAuthorizer; + + @Inject + public GenericTableCatalogAdapter( + CallContext callContext, + PolarisEntityManager entityManager, + PolarisMetaStoreManager metaStoreManager, + PolarisAuthorizer polarisAuthorizer) { + this.callContext = callContext; + this.entityManager = entityManager; + this.metaStoreManager = metaStoreManager; + this.polarisAuthorizer = polarisAuthorizer; + } + + private Namespace rawStringToNamespace(String namespace) { Review Comment: The function there is just a direct call to RESTUtil.decodeNamespace, and RESTUtil is coming from iceberg rest, so we are using the same decode methods as iceberg. if we want to make it more clear, we can directly call RESTUtil.decodeNamespace in the code, so we are consistent on how the namespace is decoded. ########## service/common/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java: ########## @@ -356,4 +348,23 @@ protected void authorizeRenameTableLikeOperationOrThrow( initializeCatalog(); } + + /** + * Helper function for when a TABLE_LIKE entity is not found & we want to throw the appropriate + * exception + * + * @param subType The subtype of the entity that the exception should report doesn't exist + */ + public static void throwNotFoundException( Review Comment: I was making this suggestion because this function is specifically designed for TableLike entities, not for NamespaceEntities or other type of Entities. The function name throwNotFoundException is very general, more sounds like for all possible entities. So I was suggesting to have *TableLike* in the name to help make the function name more clear. Another options is throwNotFoundExceptionForTabeLike etc. However, I see the restriction is stated in the comment also, so that is a nit suggestion. ########## service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java: ########## @@ -472,11 +471,7 @@ private void authorizeGrantOnTableLikeOperationOrThrow( throw new NotFoundException("Catalog not found: %s", catalogName); } else if (status.getStatus() == ResolverStatus.StatusEnum.PATH_COULD_NOT_BE_FULLY_RESOLVED) { if (status.getFailedToResolvePath().getLastEntityType() == PolarisEntityType.TABLE_LIKE) { - if (subType == PolarisEntitySubType.ICEBERG_TABLE) { - throw new NoSuchTableException("Table does not exist: %s", identifier); - } else { - throw new NoSuchViewException("View does not exist: %s", identifier); - } + CatalogHandler.throwNotFoundException(identifier, subType); Review Comment: The admin API function is our internal function, that kind of interface change seems fine to me. Made a small suggestion to make the message more clear. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@polaris.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org