diff --git a/extension/persistence/eclipselink/src/test/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreManagerTest.java b/extension/persistence/eclipselink/src/test/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreManagerTest.java index 9415696dae..e8374989a5 100644 --- a/extension/persistence/eclipselink/src/test/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreManagerTest.java +++ b/extension/persistence/eclipselink/src/test/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreManagerTest.java @@ -42,7 +42,7 @@ import org.apache.polaris.core.entity.PolarisPrincipalSecrets; import org.apache.polaris.core.persistence.BasePolarisMetaStoreManagerTest; import org.apache.polaris.core.persistence.PolarisTestMetaStoreManager; -import org.apache.polaris.core.persistence.transactional.PolarisMetaStoreManagerImpl; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.jpa.models.ModelPrincipalSecrets; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; @@ -104,7 +104,11 @@ protected PolarisTestMetaStoreManager createPolarisTestMetaStoreManager() { new PolarisEclipseLinkMetaStoreSessionImpl( store, Mockito.mock(), () -> "realm", null, "polaris", RANDOM_SECRETS); return new PolarisTestMetaStoreManager( - new PolarisMetaStoreManagerImpl(), + // TODO: Currently, EclipseLinkMetaStoreManager resides within a persistence implementation + // layer, below the DAO layer, and ideally shouldn't directly invoke DAO classes. The change + // is temporarily for refactor verification purposes. + // We should identify a cleaner testing strategy moving forward. + new PolarisDaoManager(), new PolarisCallContext( session, diagServices, diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java index ff2eaaf131..cc4f376690 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java @@ -36,9 +36,9 @@ import org.apache.polaris.core.entity.PolarisPrincipalSecrets; import org.apache.polaris.core.persistence.bootstrap.RootCredentialsSet; import org.apache.polaris.core.persistence.cache.EntityCache; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.core.persistence.dao.entity.BaseResult; import org.apache.polaris.core.persistence.dao.entity.EntityResult; -import org.apache.polaris.core.persistence.transactional.PolarisMetaStoreManagerImpl; import org.apache.polaris.core.persistence.transactional.TransactionalPersistence; import org.apache.polaris.core.storage.cache.StorageCredentialCache; import org.slf4j.Logger; @@ -94,7 +94,7 @@ private void initializeForRealm( realmContext.getRealmIdentifier(), () -> createMetaStoreSession(backingStore, realmContext, rootCredentialsSet, diagnostics)); - PolarisMetaStoreManager metaStoreManager = new PolarisMetaStoreManagerImpl(); + PolarisMetaStoreManager metaStoreManager = new PolarisDaoManager(); metaStoreManagerMap.put(realmContext.getRealmIdentifier(), metaStoreManager); } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogDao.java new file mode 100644 index 0000000000..c49c938c65 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogDao.java @@ -0,0 +1,74 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.CreateCatalogResult; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface CatalogDao { + CreateCatalogResult createCatalog( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisBaseEntity catalog, + @Nonnull List principalRoles); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); + + // TODO this should return a type-specific entity result, e.g., CatalogEntityResult + @Nonnull + EntityResult readEntityByName(@Nonnull PolarisCallContext callCtx, @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityId); + + @Nonnull + ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById(@Nonnull PolarisCallContext callCtx, long entityId); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String entityName); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityId); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogRoleDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogRoleDao.java new file mode 100644 index 0000000000..2d88fc0266 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CatalogRoleDao.java @@ -0,0 +1,85 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface CatalogRoleDao { + @Nonnull + EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, @Nullable List catalogPath); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId); + + @Nonnull + EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CommonDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CommonDao.java new file mode 100644 index 0000000000..0a524c87a1 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CommonDao.java @@ -0,0 +1,93 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import java.util.List; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisEntityId; +import org.apache.polaris.core.persistence.dao.entity.BaseResult; +import org.apache.polaris.core.persistence.dao.entity.ChangeTrackingResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.GenerateEntityIdResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface CommonDao { + /** + * Generate a new unique id that can be used by the Polaris client when it needs to create a new + * entity + * + * @param callCtx call context + * @return the newly created id, not expected to fail + */ + @Nonnull + GenerateEntityIdResult generateNewEntityId(@Nonnull PolarisCallContext callCtx); + + /** + * Bootstrap the Polaris service, creating the root catalog, root principal, and associated + * service admin role. Will fail if the service has already been bootstrapped. + * + * @param callCtx call context + * @return the result of the bootstrap attempt + */ + @Nonnull + BaseResult bootstrapPolarisService(@Nonnull PolarisCallContext callCtx); + + /** + * Purge all metadata associated with the Polaris service, resetting the metastore to the state it + * was in prior to bootstrapping. + * + *

*************************** WARNING ************************ + * + *

This will destroy whatever Polaris metadata exists in the metastore + * + * @param callCtx call context + * @return always success or unexpected error + */ + @Nonnull + BaseResult purge(@Nonnull PolarisCallContext callCtx); + + /** For ROOT only */ + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName); + + @Nonnull + ChangeTrackingResult loadEntitiesChangeTracking( + @Nonnull PolarisCallContext callCtx, @Nonnull List entityIds); + + /** For ROOT only */ + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId); + + /** + * only for NULL_TYPE, looks like this is only used by Tests. We could remove this method if it is + * only used by tests. + */ + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CredentialVendorDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CredentialVendorDao.java new file mode 100644 index 0000000000..920fdc05df --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/CredentialVendorDao.java @@ -0,0 +1,94 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import java.util.Set; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisEntityType; +import org.apache.polaris.core.storage.PolarisCredentialVendor; +import org.apache.polaris.core.storage.PolarisStorageActions; + +/** This seems not necessarily to be a DAO, keep it here for future refactor */ +public interface CredentialVendorDao { + /** + * Get a sub-scoped credentials for an entity against the provided allowed read and write + * locations. + * + * @param callCtx the polaris call context + * @param catalogId the catalog id + * @param entityId the entity id + * @param allowListOperation whether to allow LIST operation on the allowedReadLocations and + * allowedWriteLocations + * @param allowedReadLocations a set of allowed to read locations + * @param allowedWriteLocations a set of allowed to write locations + * @return an enum map containing the scoped credentials + */ + @Nonnull + PolarisCredentialVendor.ScopedCredentialsResult getSubscopedCredsForEntity( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + boolean allowListOperation, + @Nonnull Set allowedReadLocations, + @Nonnull Set allowedWriteLocations); + + /** + * Validate whether the entity has access to the locations with the provided target operations + * + * @param callCtx the polaris call context + * @param catalogId the catalog id + * @param entityId the entity id + * @param actions a set of operation actions: READ/WRITE/LIST/DELETE/ALL + * @param locations a set of locations to verify + * @return a Map of {@code }, a validate result value looks like this + *

+   * {
+   *   "status" : "failure",
+   *   "actions" : {
+   *     "READ" : {
+   *       "message" : "The specified file was not found",
+   *       "status" : "failure"
+   *     },
+   *     "DELETE" : {
+   *       "message" : "One or more objects could not be deleted (Status Code: 200; Error Code: null)",
+   *       "status" : "failure"
+   *     },
+   *     "LIST" : {
+   *       "status" : "success"
+   *     },
+   *     "WRITE" : {
+   *       "message" : "Access Denied (Status Code: 403; Error Code: AccessDenied)",
+   *       "status" : "failure"
+   *     }
+   *   },
+   *   "message" : "Some of the integration checks failed. Check the Polaris documentation for more information."
+   * }
+   * 
+ */ + @Nonnull + PolarisCredentialVendor.ValidateAccessResult validateAccessToLocations( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + @Nonnull Set actions, + @Nonnull Set locations); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/GrantRecordDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/GrantRecordDao.java new file mode 100644 index 0000000000..a7b409e34e --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/GrantRecordDao.java @@ -0,0 +1,167 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.auth.PolarisGrantManager; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.entity.PolarisPrivilege; + +/** This will replace the class PolarisGrantManager. */ +public interface GrantRecordDao { + /** + * Grant usage on a role to a grantee, for example granting usage on a catalog role to a principal + * role or granting a principal role to a principal. + * + * @param callCtx call context + * @param catalog if the role is a catalog role, the caller needs to pass-in the catalog entity + * which was used to resolve that granted. Else null. + * @param role resolved catalog or principal role + * @param grantee principal role or principal as resolved by the caller + * @return the grant record we created for this grant. Will return ENTITY_NOT_FOUND if the + * specified role couldn't be found. Should be retried in that case + */ + @Nonnull + PolarisGrantManager.PrivilegeResult grantUsageOnRoleToGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee); + + /** + * Revoke usage on a role (a catalog or a principal role) from a grantee (e.g. a principal role or + * a principal). + * + * @param callCtx call context + * @param catalog if the granted is a catalog role, the caller needs to pass-in the catalog entity + * which was used to resolve that role. Else null should be passed-in. + * @param role a catalog/principal role as resolved by the caller + * @param grantee resolved principal role or principal + * @return the result. Will return ENTITY_NOT_FOUND if the * specified role couldn't be found. + * Should be retried in that case. Will return GRANT_NOT_FOUND if the grant to revoke cannot + * be found + */ + @Nonnull + PolarisGrantManager.PrivilegeResult revokeUsageOnRoleFromGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee); + + /** + * Grant a privilege on a catalog securable to a grantee. + * + * @param callCtx call context + * @param grantee resolved role, the grantee + * @param catalogPath path to that entity, cannot be null or empty unless securable is top-level + * @param securable securable entity, must have been resolved by the client. Can be the catalog + * itself + * @param privilege privilege to grant + * @return the grant record we created for this grant. Will return ENTITY_NOT_FOUND if the + * specified role couldn't be found. Should be retried in that case + */ + @Nonnull + PolarisGrantManager.PrivilegeResult grantPrivilegeOnSecurableToRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege); + + /** + * Revoke a privilege on a catalog securable from a grantee. + * + * @param callCtx call context + * @param grantee resolved role, the grantee + * @param catalogPath path to that entity, cannot be null or empty unless securable is top-level + * @param securable securable entity, must have been resolved by the client. Can be the catalog + * itself. + * @param privilege privilege to revoke + * @return the result. Will return ENTITY_NOT_FOUND if the * specified role couldn't be found. + * Should be retried in that case. Will return GRANT_NOT_FOUND if the grant to revoke cannot + * be found + */ + @Nonnull + PolarisGrantManager.PrivilegeResult revokePrivilegeOnSecurableFromRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege); + + /** + * This method should be used by the Polaris app to cache all grant records on a securable. + * + * @param callCtx call context + * @param securable the securable entity + * @return the list of grants and the version of the grant records. We will return + * ENTITY_NOT_FOUND if the securable cannot be found + */ + @Nonnull + default PolarisGrantManager.LoadGrantsResult loadGrantsOnSecurable( + @Nonnull PolarisCallContext callCtx, PolarisBaseEntity securable) { + return loadGrantsOnSecurable(callCtx, securable.getCatalogId(), securable.getId()); + } + + /** + * This method should be used by the Polaris app to cache all grant records on a securable. + * + * @param callCtx call context + * @param securableCatalogId id of the catalog this securable belongs to + * @param securableId id of the securable + * @return the list of grants and the version of the grant records. We will return + * ENTITY_NOT_FOUND if the securable cannot be found + */ + @Nonnull + PolarisGrantManager.LoadGrantsResult loadGrantsOnSecurable( + @Nonnull PolarisCallContext callCtx, long securableCatalogId, long securableId); + + /** + * This method should be used by the Polaris app to load all grants made to a grantee, either a + * role or a principal. + * + * @param callCtx call context + * @param grantee the grantee entity + * @return the list of grants and the version of the grant records. We will return NULL if the + * grantee does not exist + */ + @Nonnull + default PolarisGrantManager.LoadGrantsResult loadGrantsToGrantee( + @Nonnull PolarisCallContext callCtx, PolarisBaseEntity grantee) { + return loadGrantsToGrantee(callCtx, grantee.getCatalogId(), grantee.getId()); + } + + /** + * This method should be used by the Polaris app to load all grants made to a grantee, either a + * role or a principal. + * + * @param callCtx call context + * @param granteeCatalogId id of the catalog this grantee belongs to + * @param granteeId id of the grantee + * @return the list of grants and the version of the grant records. We will return NULL if the + * grantee does not exist + */ + @Nonnull + PolarisGrantManager.LoadGrantsResult loadGrantsToGrantee( + PolarisCallContext callCtx, long granteeCatalogId, long granteeId); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/NamespaceDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/NamespaceDao.java new file mode 100644 index 0000000000..97c9a19281 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/NamespaceDao.java @@ -0,0 +1,86 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface NamespaceDao { + // TODO this should return a type-specific entity result + @Nonnull + EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, @Nonnull List catalogPath); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId); + + @Nonnull + EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PolarisDaoManager.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PolarisDaoManager.java new file mode 100644 index 0000000000..1101069c41 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PolarisDaoManager.java @@ -0,0 +1,567 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.entity.PolarisEntityId; +import org.apache.polaris.core.entity.PolarisEntitySubType; +import org.apache.polaris.core.entity.PolarisEntityType; +import org.apache.polaris.core.entity.PolarisPrivilege; +import org.apache.polaris.core.persistence.PolarisMetaStoreManager; +import org.apache.polaris.core.persistence.dao.entity.BaseResult; +import org.apache.polaris.core.persistence.dao.entity.ChangeTrackingResult; +import org.apache.polaris.core.persistence.dao.entity.CreateCatalogResult; +import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityWithPath; +import org.apache.polaris.core.persistence.dao.entity.GenerateEntityIdResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; +import org.apache.polaris.core.persistence.transactional.DelegatingCatalogDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingCatalogRoleDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingCommonDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingCredentialVendorDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingGrantRecordDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingNamespaceDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingPrincipalDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingPrincipalRoleDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingPrincipalSecretsDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingTableLikeDaoImpl; +import org.apache.polaris.core.persistence.transactional.DelegatingTaskDaoImpl; +import org.apache.polaris.core.storage.PolarisStorageActions; + +/** + * This class acts as a temporary bridge to defer refactoring of business logic. It currently + * implements PolarisMetaStoreManager, but it is no longer be necessary after refactoring. + * Post-refactor, callers can directly interact with individual DAO objects as needed. + */ +public class PolarisDaoManager implements PolarisMetaStoreManager { + // TODO, using factory or CDI to create following instances, so that the implementation can be + // injected. + private final CatalogDao catalogDao = new DelegatingCatalogDaoImpl(); + private final NamespaceDao namespaceDao = new DelegatingNamespaceDaoImpl(); + private final TableLikeDao tableLikeDao = new DelegatingTableLikeDaoImpl(); + private final CatalogRoleDao catalogRoleDao = new DelegatingCatalogRoleDaoImpl(); + private final PrincipalRoleDao principalRoleDao = new DelegatingPrincipalRoleDaoImpl(); + private final PrincipalDao principalDao = new DelegatingPrincipalDaoImpl(); + private final TaskDao taskDao = new DelegatingTaskDaoImpl(); + private final PrincipalSecretsDao principalSecretsDao = new DelegatingPrincipalSecretsDaoImpl(); + private final GrantRecordDao grantRecordDao = new DelegatingGrantRecordDaoImpl(); + private final CommonDao commonDao = new DelegatingCommonDaoImpl(); + private final CredentialVendorDao credentialVendorDao = new DelegatingCredentialVendorDaoImpl(); + + public CatalogDao getCatalogDao() { + return catalogDao; + } + + public NamespaceDao getNamespaceDao() { + return namespaceDao; + } + + public TableLikeDao getTableLikeDao() { + return tableLikeDao; + } + + public CatalogRoleDao getCatalogRoleDao() { + return catalogRoleDao; + } + + public PrincipalRoleDao getPrincipalRoleDao() { + return principalRoleDao; + } + + public PrincipalDao getPrincipalDao() { + return principalDao; + } + + public TaskDao getTaskDao() { + return taskDao; + } + + public PrincipalSecretsDao getPrincipalSecretsDao() { + return principalSecretsDao; + } + + public GrantRecordDao getGrantRecordDao() { + return grantRecordDao; + } + + public CommonDao getCommonDao() { + return commonDao; + } + + public CredentialVendorDao getCredentialVendorDao() { + return credentialVendorDao; + } + + // TODO, we can remove all following methods once we finished the business logic refactor. + @Nonnull + @Override + public BaseResult bootstrapPolarisService(@Nonnull PolarisCallContext callCtx) { + return commonDao.bootstrapPolarisService(callCtx); + } + + @Nonnull + @Override + public BaseResult purge(@Nonnull PolarisCallContext callCtx) { + return commonDao.purge(callCtx); + } + + @Nonnull + @Override + public EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityType entityType, + @Nonnull PolarisEntitySubType entitySubType, + @Nonnull String name) { + switch (entityType) { + case CATALOG: + return catalogDao.readEntityByName(callCtx, name); + case NAMESPACE: + return namespaceDao.readEntityByName(callCtx, catalogPath, name); + case TABLE_LIKE: + return tableLikeDao.readEntityByName(callCtx, catalogPath, entitySubType, name); + case CATALOG_ROLE: + return catalogRoleDao.readEntityByName(callCtx, catalogPath, name); + case PRINCIPAL: + return principalDao.readEntityByName(callCtx, name); + case PRINCIPAL_ROLE: + return principalRoleDao.readEntityByName(callCtx, name); + case TASK: + return taskDao.readEntityByName(callCtx, name); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityType entityType, + @Nonnull PolarisEntitySubType entitySubType) { + switch (entityType) { + case CATALOG: + return catalogDao.listEntities(callCtx); + case NAMESPACE: + return namespaceDao.listEntities(callCtx, catalogPath); + case TABLE_LIKE: + return tableLikeDao.listEntities(callCtx, catalogPath, entitySubType); + case CATALOG_ROLE: + return catalogRoleDao.listEntities(callCtx, catalogPath); + case PRINCIPAL: + return principalDao.listEntities(callCtx); + case PRINCIPAL_ROLE: + return principalRoleDao.listEntities(callCtx); + case TASK: + return taskDao.listEntities(callCtx); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public GenerateEntityIdResult generateNewEntityId(@Nonnull PolarisCallContext callCtx) { + return commonDao.generateNewEntityId(callCtx); + } + + @Nonnull + @Override + public CreatePrincipalResult createPrincipal( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity principal) { + return principalDao.createPrincipal(callCtx, principal); + } + + @Nonnull + @Override + public CreateCatalogResult createCatalog( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisBaseEntity catalog, + @Nonnull List principalRoles) { + return catalogDao.createCatalog(callCtx, catalog, principalRoles); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + switch (entity.getType()) { + case NAMESPACE: + return namespaceDao.createEntityIfNotExists(callCtx, catalogPath, entity); + case TABLE_LIKE: + return tableLikeDao.createEntityIfNotExists(callCtx, catalogPath, entity); + case CATALOG_ROLE: + return catalogRoleDao.createEntityIfNotExists(callCtx, catalogPath, entity); + case PRINCIPAL_ROLE: + return principalRoleDao.createEntityIfNotExists(callCtx, entity); + case TASK: + return taskDao.createEntityIfNotExists(callCtx, entity); + default: + throw new IllegalArgumentException("Unknown entity type: " + entity.getType()); + } + } + + @Nonnull + @Override + public EntitiesResult createEntitiesIfNotExist( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull List entities) { + // only for tasks + return taskDao.createTasksIfNotExist(callCtx, entities); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + switch (entity.getType()) { + case CATALOG: + return catalogDao.updateEntityPropertiesIfNotChanged(callCtx, entity); + case NAMESPACE: + return namespaceDao.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + case TABLE_LIKE: + return tableLikeDao.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + case CATALOG_ROLE: + return catalogRoleDao.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + case PRINCIPAL: + return principalDao.updateEntityPropertiesIfNotChanged(callCtx, entity); + case PRINCIPAL_ROLE: + return principalRoleDao.updateEntityPropertiesIfNotChanged(callCtx, entity); + default: + throw new IllegalArgumentException("Unknown entity type: " + entity.getType()); + } + } + + @Nonnull + @Override + public EntitiesResult updateEntitiesPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull List entities) { + // only for multi-table transactions + return tableLikeDao.updateEntitiesPropertiesIfNotChanged(callCtx, entities); + } + + @Nonnull + @Override + public EntityResult renameEntity( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToRename, + @Nullable List newCatalogPath, + @Nonnull PolarisEntity renamedEntity) { + // only tableLike is supported + return tableLikeDao.renameEntity( + callCtx, catalogPath, entityToRename, newCatalogPath, renamedEntity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + switch (entityToDrop.getType()) { + case CATALOG: + return catalogDao.dropEntityIfExists(callCtx, entityToDrop, cleanupProperties, cleanup); + case NAMESPACE: + return namespaceDao.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + case TABLE_LIKE: + return tableLikeDao.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + case CATALOG_ROLE: + return catalogRoleDao.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + case PRINCIPAL: + return principalDao.dropEntityIfExists(callCtx, entityToDrop, cleanupProperties, cleanup); + case PRINCIPAL_ROLE: + return principalRoleDao.dropEntityIfExists( + callCtx, entityToDrop, cleanupProperties, cleanup); + case TASK: + return taskDao.dropEntityIfExists(callCtx, entityToDrop, cleanupProperties, cleanup); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityToDrop.getType()); + } + } + + @Nonnull + @Override + public EntityResult loadEntity( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long entityId, + @Nonnull PolarisEntityType entityType) { + switch (entityType) { + case CATALOG: + return catalogDao.loadEntity(callCtx, entityId); + case NAMESPACE: + return namespaceDao.loadEntity(callCtx, entityCatalogId, entityId); + case TABLE_LIKE: + return tableLikeDao.loadEntity(callCtx, entityCatalogId, entityId); + case CATALOG_ROLE: + return catalogRoleDao.loadEntity(callCtx, entityCatalogId, entityId); + case PRINCIPAL: + return principalDao.loadEntity(callCtx, entityId); + case PRINCIPAL_ROLE: + return principalRoleDao.loadEntity(callCtx, entityId); + case TASK: + return taskDao.loadEntity(callCtx, entityId); + case NULL_TYPE: + return commonDao.loadEntity(callCtx, entityCatalogId, entityId); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public EntitiesResult loadTasks( + @Nonnull PolarisCallContext callCtx, String executorId, int limit) { + return taskDao.loadTasks(callCtx, executorId, limit); + } + + @Nonnull + @Override + public ChangeTrackingResult loadEntitiesChangeTracking( + @Nonnull PolarisCallContext callCtx, @Nonnull List entityIds) { + // todo we need to figure out how to handle type-specific one later + return commonDao.loadEntitiesChangeTracking(callCtx, entityIds); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long entityId, + PolarisEntityType entityType) { + switch (entityType) { + case CATALOG: + return catalogDao.loadResolvedEntityById(callCtx, entityId); + case NAMESPACE: + return namespaceDao.loadResolvedEntityById(callCtx, entityCatalogId, entityId); + case TABLE_LIKE: + return tableLikeDao.loadResolvedEntityById(callCtx, entityCatalogId, entityId); + case PRINCIPAL: + return principalDao.loadResolvedEntityById(callCtx, entityId); + case PRINCIPAL_ROLE: + return principalRoleDao.loadResolvedEntityById(callCtx, entityId); + case CATALOG_ROLE: + return catalogRoleDao.loadResolvedEntityById(callCtx, entityCatalogId, entityId); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull PolarisEntityType entityType, + @Nonnull String entityName) { + switch (entityType) { + case NAMESPACE: + return namespaceDao.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, entityName); + case TABLE_LIKE: + return tableLikeDao.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, entityName); + case PRINCIPAL: + return principalDao.loadResolvedEntityByName(callCtx, parentId, entityName); + case PRINCIPAL_ROLE: + return principalRoleDao.loadResolvedEntityByName(callCtx, parentId, entityName); + case ROOT: + return commonDao.loadResolvedEntityByName(callCtx, entityCatalogId, parentId, entityName); + case CATALOG: + return catalogDao.loadResolvedEntityByName(callCtx, parentId, entityName); + case CATALOG_ROLE: + return catalogRoleDao.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, entityName); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + @Nonnull PolarisEntityType entityType, + long entityCatalogId, + long entityId) { + switch (entityType) { + case CATALOG: + return catalogDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityId); + case NAMESPACE: + return namespaceDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityCatalogId, entityId); + case TABLE_LIKE: + return tableLikeDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityCatalogId, entityId); + case PRINCIPAL: + return principalDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityId); + case PRINCIPAL_ROLE: + return principalRoleDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityId); + case CATALOG_ROLE: + return catalogRoleDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityCatalogId, entityId); + case ROOT: + return commonDao.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, entityCatalogId, entityId); + default: + throw new IllegalArgumentException("Unknown entity type: " + entityType); + } + } + + @Nonnull + @Override + public PrivilegeResult grantUsageOnRoleToGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee) { + return grantRecordDao.grantUsageOnRoleToGrantee(callCtx, catalog, role, grantee); + } + + @Nonnull + @Override + public PrivilegeResult revokeUsageOnRoleFromGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee) { + return grantRecordDao.revokeUsageOnRoleFromGrantee(callCtx, catalog, role, grantee); + } + + @Nonnull + @Override + public PrivilegeResult grantPrivilegeOnSecurableToRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege) { + return grantRecordDao.grantPrivilegeOnSecurableToRole( + callCtx, grantee, catalogPath, securable, privilege); + } + + @Nonnull + @Override + public PrivilegeResult revokePrivilegeOnSecurableFromRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege) { + return grantRecordDao.revokePrivilegeOnSecurableFromRole( + callCtx, grantee, catalogPath, securable, privilege); + } + + @Nonnull + @Override + public LoadGrantsResult loadGrantsOnSecurable( + @Nonnull PolarisCallContext callCtx, long securableCatalogId, long securableId) { + return grantRecordDao.loadGrantsOnSecurable(callCtx, securableCatalogId, securableId); + } + + @Nonnull + @Override + public LoadGrantsResult loadGrantsToGrantee( + PolarisCallContext callCtx, long granteeCatalogId, long granteeId) { + return grantRecordDao.loadGrantsToGrantee(callCtx, granteeCatalogId, granteeId); + } + + @Nonnull + @Override + public PrincipalSecretsResult loadPrincipalSecrets( + @Nonnull PolarisCallContext callCtx, @Nonnull String clientId) { + return principalSecretsDao.loadPrincipalSecrets(callCtx, clientId); + } + + @Nonnull + @Override + public PrincipalSecretsResult rotatePrincipalSecrets( + @Nonnull PolarisCallContext callCtx, + @Nonnull String clientId, + long principalId, + boolean reset, + @Nonnull String oldSecretHash) { + return principalSecretsDao.rotatePrincipalSecrets( + callCtx, clientId, principalId, reset, oldSecretHash); + } + + @Nonnull + @Override + public ScopedCredentialsResult getSubscopedCredsForEntity( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + boolean allowListOperation, + @Nonnull Set allowedReadLocations, + @Nonnull Set allowedWriteLocations) { + return credentialVendorDao.getSubscopedCredsForEntity( + callCtx, + catalogId, + entityId, + entityType, + allowListOperation, + allowedReadLocations, + allowedWriteLocations); + } + + @Nonnull + @Override + public ValidateAccessResult validateAccessToLocations( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + @Nonnull Set actions, + @Nonnull Set locations) { + return credentialVendorDao.validateAccessToLocations( + callCtx, catalogId, entityId, entityType, actions, locations); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalDao.java new file mode 100644 index 0000000000..23a53fd8d2 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalDao.java @@ -0,0 +1,70 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface PrincipalDao { + @Nonnull + EntityResult readEntityByName(@Nonnull PolarisCallContext callCtx, @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long id); + + @Nonnull + ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx); + + CreatePrincipalResult createPrincipal( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity principal); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById(@Nonnull PolarisCallContext callCtx, long id); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String name); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long id); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalRoleDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalRoleDao.java new file mode 100644 index 0000000000..8dd1799334 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalRoleDao.java @@ -0,0 +1,70 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface PrincipalRoleDao { + @Nonnull + ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx); + + @Nonnull + EntityResult readEntityByName(@Nonnull PolarisCallContext callCtx, @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long id); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById(@Nonnull PolarisCallContext callCtx, long id); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String entityName); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityId); + + @Nonnull + EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalSecretsDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalSecretsDao.java new file mode 100644 index 0000000000..bd9890389a --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/PrincipalSecretsDao.java @@ -0,0 +1,57 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.auth.PolarisSecretsManager; + +/** This can be used to replace the class PolarisSecretsManager */ +public interface PrincipalSecretsDao { + /** + * Load the principal secrets given the client_id. + * + * @param callCtx call context + * @param clientId principal client id + * @return the secrets associated to that principal, including the entity id of the principal + */ + @Nonnull + PolarisSecretsManager.PrincipalSecretsResult loadPrincipalSecrets( + @Nonnull PolarisCallContext callCtx, @Nonnull String clientId); + + /** + * Rotate secrets + * + * @param callCtx call context + * @param clientId principal client id + * @param principalId id of the principal + * @param reset true if the principal's secrets should be disabled and replaced with a one-time + * password. if the principal's secret is already a one-time password, this flag is + * automatically true + * @param oldSecretHash main secret hash for the principal + * @return the secrets associated to that principal amd the id of the principal + */ + @Nonnull + PolarisSecretsManager.PrincipalSecretsResult rotatePrincipalSecrets( + @Nonnull PolarisCallContext callCtx, + @Nonnull String clientId, + long principalId, + boolean reset, + @Nonnull String oldSecretHash); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TableLikeDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TableLikeDao.java new file mode 100644 index 0000000000..f41a883ef4 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TableLikeDao.java @@ -0,0 +1,113 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.entity.PolarisEntitySubType; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityWithPath; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public interface TableLikeDao { + @Nonnull + EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntitySubType entitySubType, + @Nonnull String name); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, + @Nonnull List catalogPath, + @Nonnull PolarisEntitySubType entitySubType); + + @Nonnull + EntityResult renameEntity( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToRename, + @Nullable List newCatalogPath, + @Nonnull PolarisEntity renamedEntity); + + @Nonnull + ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId); + + @Nonnull + ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName); + + @Nonnull + ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId); + + @Nonnull + EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); + + /** + * This allows to operate on multiple tables at once. Just loop through the list, calling each + * entity update and return null if any of those fail. + * + * @param callCtx call context + * @param entities the set of entities to update + * @return list of all entities we updated or null if the client should retry because one update + * failed + */ + @Nonnull + EntitiesResult updateEntitiesPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull List entities); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TaskDao.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TaskDao.java new file mode 100644 index 0000000000..364f773eef --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/TaskDao.java @@ -0,0 +1,60 @@ +/* + * 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.core.persistence.dao; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; + +public interface TaskDao { + @Nonnull + EntityResult readEntityByName(@Nonnull PolarisCallContext callCtx, @Nonnull String name); + + @Nonnull + ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx); + + @Nonnull + EntitiesResult loadTasks(@Nonnull PolarisCallContext callCtx, String executorId, int limit); + + @Nonnull + EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long id); + + @Nonnull + EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity); + + @Nonnull + EntitiesResult createTasksIfNotExist( + @Nonnull PolarisCallContext callCtx, @Nonnull List entities); + + @Nonnull + DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup); +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogDaoImpl.java new file mode 100644 index 0000000000..82d719dcc1 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogDaoImpl.java @@ -0,0 +1,110 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.ANY_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.CATALOG; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.CatalogDao; +import org.apache.polaris.core.persistence.dao.entity.CreateCatalogResult; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingCatalogDaoImpl implements CatalogDao { + // TODO we need a map to cache the PolarisMetaStoreManagerImpl as well + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public CreateCatalogResult createCatalog( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisBaseEntity catalog, + @Nonnull List principalRoles) { + return metaStoreManager.createCatalog(callCtx, catalog, principalRoles); + } + + @Nonnull + @Override + public EntityResult readEntityByName(@Nonnull PolarisCallContext callCtx, @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, null, CATALOG, ANY_SUBTYPE, name); + } + + @Nonnull + @Override + public EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityId) { + return metaStoreManager.loadEntity(callCtx, 0L, entityId, CATALOG); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.listEntities(callCtx, null, CATALOG, ANY_SUBTYPE); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, null, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, null, entityToDrop, cleanupProperties, cleanup); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityId) { + return metaStoreManager.loadResolvedEntityById(callCtx, 0L, entityId, CATALOG); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName(callCtx, 0L, parentId, CATALOG, entityName); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityId) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, CATALOG, 0L, entityId); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogRoleDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogRoleDaoImpl.java new file mode 100644 index 0000000000..276c3c4d4a --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCatalogRoleDaoImpl.java @@ -0,0 +1,123 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.ANY_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntitySubType.NULL_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.CATALOG_ROLE; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.CatalogRoleDao; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingCatalogRoleDaoImpl implements CatalogRoleDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, catalogPath, CATALOG_ROLE, ANY_SUBTYPE, name); + } + + @Nonnull + @Override + public EntityResult loadEntity( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadEntity(callCtx, entityCatalogId, entityId, CATALOG_ROLE); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, @Nullable List catalogPath) { + return metaStoreManager.listEntities(callCtx, catalogPath, CATALOG_ROLE, NULL_SUBTYPE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadResolvedEntityById( + callCtx, entityCatalogId, entityId, CATALOG_ROLE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, CATALOG_ROLE, entityName); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, CATALOG_ROLE, entityCatalogId, entityId); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.createEntityIfNotExists(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCommonDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCommonDaoImpl.java new file mode 100644 index 0000000000..fd92a6bbaf --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCommonDaoImpl.java @@ -0,0 +1,92 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntityType.NULL_TYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.ROOT; + +import jakarta.annotation.Nonnull; +import java.util.List; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisEntityId; +import org.apache.polaris.core.persistence.dao.CommonDao; +import org.apache.polaris.core.persistence.dao.entity.BaseResult; +import org.apache.polaris.core.persistence.dao.entity.ChangeTrackingResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.GenerateEntityIdResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingCommonDaoImpl implements CommonDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Nonnull + @Override + public GenerateEntityIdResult generateNewEntityId(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.generateNewEntityId(callCtx); + } + + @Nonnull + @Override + public BaseResult bootstrapPolarisService(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.bootstrapPolarisService(callCtx); + } + + @Nonnull + @Override + public BaseResult purge(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.purge(callCtx); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, ROOT, entityName); + } + + @Nonnull + @Override + public ChangeTrackingResult loadEntitiesChangeTracking( + @Nonnull PolarisCallContext callCtx, @Nonnull List entityIds) { + return metaStoreManager.loadEntitiesChangeTracking(callCtx, entityIds); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, ROOT, entityCatalogId, entityId); + } + + @Nonnull + @Override + public EntityResult loadEntity( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadEntity(callCtx, entityCatalogId, entityId, NULL_TYPE); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCredentialVendorDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCredentialVendorDaoImpl.java new file mode 100644 index 0000000000..f97c1daec0 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingCredentialVendorDaoImpl.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.core.persistence.transactional; + +import jakarta.annotation.Nonnull; +import java.util.Set; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisEntityType; +import org.apache.polaris.core.persistence.dao.CredentialVendorDao; +import org.apache.polaris.core.storage.PolarisCredentialVendor; +import org.apache.polaris.core.storage.PolarisStorageActions; + +public class DelegatingCredentialVendorDaoImpl implements CredentialVendorDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Nonnull + @Override + public PolarisCredentialVendor.ScopedCredentialsResult getSubscopedCredsForEntity( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + boolean allowListOperation, + @Nonnull Set allowedReadLocations, + @Nonnull Set allowedWriteLocations) { + return metaStoreManager.getSubscopedCredsForEntity( + callCtx, + catalogId, + entityId, + entityType, + allowListOperation, + allowedReadLocations, + allowedWriteLocations); + } + + @Nonnull + @Override + public PolarisCredentialVendor.ValidateAccessResult validateAccessToLocations( + @Nonnull PolarisCallContext callCtx, + long catalogId, + long entityId, + PolarisEntityType entityType, + @Nonnull Set actions, + @Nonnull Set locations) { + return metaStoreManager.validateAccessToLocations( + callCtx, catalogId, entityId, entityType, actions, locations); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingGrantRecordDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingGrantRecordDaoImpl.java new file mode 100644 index 0000000000..5c812d54e2 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingGrantRecordDaoImpl.java @@ -0,0 +1,90 @@ +/* + * 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.core.persistence.transactional; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.auth.PolarisGrantManager; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.entity.PolarisPrivilege; +import org.apache.polaris.core.persistence.dao.GrantRecordDao; + +public class DelegatingGrantRecordDaoImpl implements GrantRecordDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Nonnull + @Override + public PolarisGrantManager.PrivilegeResult grantUsageOnRoleToGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee) { + return metaStoreManager.grantUsageOnRoleToGrantee(callCtx, catalog, role, grantee); + } + + @Nonnull + @Override + public PolarisGrantManager.PrivilegeResult revokeUsageOnRoleFromGrantee( + @Nonnull PolarisCallContext callCtx, + @Nullable PolarisEntityCore catalog, + @Nonnull PolarisEntityCore role, + @Nonnull PolarisEntityCore grantee) { + return metaStoreManager.revokeUsageOnRoleFromGrantee(callCtx, catalog, role, grantee); + } + + @Nonnull + @Override + public PolarisGrantManager.PrivilegeResult grantPrivilegeOnSecurableToRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege) { + return metaStoreManager.grantPrivilegeOnSecurableToRole( + callCtx, grantee, catalogPath, securable, privilege); + } + + @Nonnull + @Override + public PolarisGrantManager.PrivilegeResult revokePrivilegeOnSecurableFromRole( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore grantee, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore securable, + @Nonnull PolarisPrivilege privilege) { + return metaStoreManager.revokePrivilegeOnSecurableFromRole( + callCtx, grantee, catalogPath, securable, privilege); + } + + @Nonnull + @Override + public PolarisGrantManager.LoadGrantsResult loadGrantsOnSecurable( + @Nonnull PolarisCallContext callCtx, long securableCatalogId, long securableId) { + return metaStoreManager.loadGrantsOnSecurable(callCtx, securableCatalogId, securableId); + } + + @Nonnull + @Override + public PolarisGrantManager.LoadGrantsResult loadGrantsToGrantee( + PolarisCallContext callCtx, long granteeCatalogId, long granteeId) { + return metaStoreManager.loadGrantsToGrantee(callCtx, granteeCatalogId, granteeId); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingNamespaceDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingNamespaceDaoImpl.java new file mode 100644 index 0000000000..b627da98fd --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingNamespaceDaoImpl.java @@ -0,0 +1,121 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.ANY_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.NAMESPACE; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.NamespaceDao; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingNamespaceDaoImpl implements NamespaceDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, catalogPath, NAMESPACE, ANY_SUBTYPE, name); + } + + @Nonnull + @Override + public EntityResult loadEntity( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadEntity(callCtx, entityCatalogId, entityId, NAMESPACE); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, @Nonnull List catalogPath) { + return metaStoreManager.listEntities(callCtx, catalogPath, NAMESPACE, ANY_SUBTYPE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadResolvedEntityById(callCtx, entityCatalogId, entityId, NAMESPACE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, NAMESPACE, entityName); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, NAMESPACE, entityCatalogId, entityId); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.createEntityIfNotExists(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalDaoImpl.java new file mode 100644 index 0000000000..25269ea47d --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalDaoImpl.java @@ -0,0 +1,105 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.NULL_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.PRINCIPAL; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.PrincipalDao; +import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingPrincipalDaoImpl implements PrincipalDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, null, PRINCIPAL, NULL_SUBTYPE, name); + } + + @Nonnull + @Override + public EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long id) { + return metaStoreManager.loadEntity(callCtx, 0L, id, PRINCIPAL); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.listEntities(callCtx, null, PRINCIPAL, NULL_SUBTYPE); + } + + @Override + public CreatePrincipalResult createPrincipal( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity principal) { + return metaStoreManager.createPrincipal(callCtx, principal); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById(@Nonnull PolarisCallContext callCtx, long id) { + return metaStoreManager.loadResolvedEntityById(callCtx, 0L, id, PRINCIPAL); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String name) { + return metaStoreManager.loadResolvedEntityByName(callCtx, 0L, parentId, PRINCIPAL, name); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long id) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, PRINCIPAL, 0L, id); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, null, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, null, entityToDrop, cleanupProperties, cleanup); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalRoleDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalRoleDaoImpl.java new file mode 100644 index 0000000000..b6cb41e493 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalRoleDaoImpl.java @@ -0,0 +1,106 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.NULL_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.PRINCIPAL_ROLE; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.PrincipalRoleDao; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingPrincipalRoleDaoImpl implements PrincipalRoleDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Nonnull + @Override + public ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.listEntities(callCtx, null, PRINCIPAL_ROLE, NULL_SUBTYPE); + } + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, null, PRINCIPAL_ROLE, NULL_SUBTYPE, name); + } + + @Nonnull + @Override + public EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long id) { + return metaStoreManager.loadEntity(callCtx, 0L, id, PRINCIPAL_ROLE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById(@Nonnull PolarisCallContext callCtx, long id) { + return metaStoreManager.loadResolvedEntityById(callCtx, 0L, id, PRINCIPAL_ROLE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, long parentId, @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName( + callCtx, 0L, parentId, PRINCIPAL_ROLE, entityName); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long id) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, PRINCIPAL_ROLE, 0L, id); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.createEntityIfNotExists(callCtx, null, entity); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, null, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, null, entityToDrop, cleanupProperties, cleanup); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalSecretsDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalSecretsDaoImpl.java new file mode 100644 index 0000000000..e79016a029 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingPrincipalSecretsDaoImpl.java @@ -0,0 +1,46 @@ +/* + * 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.core.persistence.transactional; + +import jakarta.annotation.Nonnull; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.auth.PolarisSecretsManager; +import org.apache.polaris.core.persistence.dao.PrincipalSecretsDao; + +public class DelegatingPrincipalSecretsDaoImpl implements PrincipalSecretsDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Nonnull + @Override + public PolarisSecretsManager.PrincipalSecretsResult loadPrincipalSecrets( + @Nonnull PolarisCallContext callCtx, @Nonnull String clientId) { + return metaStoreManager.loadPrincipalSecrets(callCtx, clientId); + } + + @Override + public @Nonnull PolarisSecretsManager.PrincipalSecretsResult rotatePrincipalSecrets( + @Nonnull PolarisCallContext callCtx, + @Nonnull String clientId, + long principalId, + boolean reset, + @Nonnull String oldSecretHash) { + return metaStoreManager.rotatePrincipalSecrets( + callCtx, clientId, principalId, reset, oldSecretHash); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTableLikeDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTableLikeDaoImpl.java new file mode 100644 index 0000000000..138e5ca4ac --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTableLikeDaoImpl.java @@ -0,0 +1,146 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntityType.TABLE_LIKE; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.entity.PolarisEntitySubType; +import org.apache.polaris.core.persistence.dao.TableLikeDao; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntityWithPath; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; + +public class DelegatingTableLikeDaoImpl implements TableLikeDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntitySubType entitySubType, + @Nonnull String name) { + return metaStoreManager.readEntityByName(callCtx, catalogPath, TABLE_LIKE, entitySubType, name); + } + + @Nonnull + @Override + public EntityResult loadEntity( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadEntity(callCtx, entityCatalogId, entityId, TABLE_LIKE); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities( + @Nonnull PolarisCallContext callCtx, + @Nonnull List catalogPath, + @Nonnull PolarisEntitySubType entitySubType) { + return metaStoreManager.listEntities(callCtx, catalogPath, TABLE_LIKE, entitySubType); + } + + @Nonnull + @Override + public EntityResult renameEntity( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToRename, + @Nullable List newCatalogPath, + @Nonnull PolarisEntity renamedEntity) { + return metaStoreManager.renameEntity( + callCtx, catalogPath, entityToRename, newCatalogPath, renamedEntity); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityById( + @Nonnull PolarisCallContext callCtx, long entityCatalogId, long entityId) { + return metaStoreManager.loadResolvedEntityById(callCtx, entityCatalogId, entityId, TABLE_LIKE); + } + + @Nonnull + @Override + public ResolvedEntityResult loadResolvedEntityByName( + @Nonnull PolarisCallContext callCtx, + long entityCatalogId, + long parentId, + @Nonnull String entityName) { + return metaStoreManager.loadResolvedEntityByName( + callCtx, entityCatalogId, parentId, TABLE_LIKE, entityName); + } + + @Nonnull + @Override + public ResolvedEntityResult refreshResolvedEntity( + @Nonnull PolarisCallContext callCtx, + int entityVersion, + int entityGrantRecordsVersion, + long entityCatalogId, + long entityId) { + return metaStoreManager.refreshResolvedEntity( + callCtx, entityVersion, entityGrantRecordsVersion, TABLE_LIKE, entityCatalogId, entityId); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.createEntityIfNotExists(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public EntityResult updateEntityPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, catalogPath, entity); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nullable List catalogPath, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, catalogPath, entityToDrop, cleanupProperties, cleanup); + } + + @Nonnull + @Override + public EntitiesResult updateEntitiesPropertiesIfNotChanged( + @Nonnull PolarisCallContext callCtx, @Nonnull List entities) { + return metaStoreManager.updateEntitiesPropertiesIfNotChanged(callCtx, entities); + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTaskDaoImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTaskDaoImpl.java new file mode 100644 index 0000000000..94b29bc1ce --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/DelegatingTaskDaoImpl.java @@ -0,0 +1,90 @@ +/* + * 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.core.persistence.transactional; + +import static org.apache.polaris.core.entity.PolarisEntitySubType.ANY_SUBTYPE; +import static org.apache.polaris.core.entity.PolarisEntityType.TASK; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.PolarisCallContext; +import org.apache.polaris.core.entity.PolarisBaseEntity; +import org.apache.polaris.core.entity.PolarisEntityCore; +import org.apache.polaris.core.persistence.dao.TaskDao; +import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; +import org.apache.polaris.core.persistence.dao.entity.EntitiesResult; +import org.apache.polaris.core.persistence.dao.entity.EntityResult; +import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult; + +public class DelegatingTaskDaoImpl implements TaskDao { + PolarisMetaStoreManagerImpl metaStoreManager = new PolarisMetaStoreManagerImpl(); + + @Override + public @Nonnull EntityResult readEntityByName( + @Nonnull PolarisCallContext callCtx, @Nonnull String name) { + // Task shouldn't have a catalog path and subtype + return metaStoreManager.readEntityByName(callCtx, null, TASK, ANY_SUBTYPE, name); + } + + @Nonnull + @Override + public ListEntitiesResult listEntities(@Nonnull PolarisCallContext callCtx) { + return metaStoreManager.listEntities(callCtx, null, TASK, ANY_SUBTYPE); + } + + @Nonnull + @Override + public EntitiesResult loadTasks( + @Nonnull PolarisCallContext callCtx, String executorId, int limit) { + return metaStoreManager.loadTasks(callCtx, executorId, limit); + } + + @Nonnull + @Override + public EntityResult createEntityIfNotExists( + @Nonnull PolarisCallContext callCtx, @Nonnull PolarisBaseEntity entity) { + return metaStoreManager.createEntityIfNotExists(callCtx, null, entity); + } + + @Nonnull + @Override + public EntitiesResult createTasksIfNotExist( + @Nonnull PolarisCallContext callCtx, @Nonnull List entities) { + return metaStoreManager.createEntitiesIfNotExist(callCtx, null, entities); + } + + @Nonnull + @Override + public DropEntityResult dropEntityIfExists( + @Nonnull PolarisCallContext callCtx, + @Nonnull PolarisEntityCore entityToDrop, + @Nullable Map cleanupProperties, + boolean cleanup) { + return metaStoreManager.dropEntityIfExists( + callCtx, null, entityToDrop, cleanupProperties, cleanup); + } + + @Nonnull + @Override + public EntityResult loadEntity(@Nonnull PolarisCallContext callCtx, long entityId) { + return metaStoreManager.loadEntity(callCtx, 0L, entityId, TASK); + } +} diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/EntityCacheTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/EntityCacheTest.java index 0a3986357c..03a9cfa6de 100644 --- a/polaris-core/src/test/java/org/apache/polaris/core/persistence/EntityCacheTest.java +++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/EntityCacheTest.java @@ -33,7 +33,7 @@ import org.apache.polaris.core.persistence.cache.EntityCache; import org.apache.polaris.core.persistence.cache.EntityCacheByNameKey; import org.apache.polaris.core.persistence.cache.EntityCacheLookupResult; -import org.apache.polaris.core.persistence.transactional.PolarisMetaStoreManagerImpl; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapMetaStoreSessionImpl; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapStore; import org.apache.polaris.core.persistence.transactional.TransactionalPersistence; @@ -89,7 +89,7 @@ public EntityCacheTest() { store = new PolarisTreeMapStore(diagServices); metaStore = new PolarisTreeMapMetaStoreSessionImpl(store, Mockito.mock(), RANDOM_SECRETS); callCtx = new PolarisCallContext(metaStore, diagServices); - metaStoreManager = new PolarisMetaStoreManagerImpl(); + metaStoreManager = new PolarisDaoManager(); // bootstrap the mata store with our test schema tm = new PolarisTestMetaStoreManager(metaStoreManager, callCtx); diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisTreeMapMetaStoreManagerTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisTreeMapMetaStoreManagerTest.java index 65f8080d91..6a015948d3 100644 --- a/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisTreeMapMetaStoreManagerTest.java +++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisTreeMapMetaStoreManagerTest.java @@ -25,7 +25,7 @@ import org.apache.polaris.core.PolarisConfigurationStore; import org.apache.polaris.core.PolarisDefaultDiagServiceImpl; import org.apache.polaris.core.PolarisDiagnostics; -import org.apache.polaris.core.persistence.transactional.PolarisMetaStoreManagerImpl; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapMetaStoreSessionImpl; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapStore; import org.mockito.Mockito; @@ -42,6 +42,10 @@ public PolarisTestMetaStoreManager createPolarisTestMetaStoreManager() { new PolarisConfigurationStore() {}, timeSource.withZone(ZoneId.systemDefault())); - return new PolarisTestMetaStoreManager(new PolarisMetaStoreManagerImpl(), callCtx); + // TODO: PolarisTreeMapMetaStoreSessionImpl now resides within a persistence implementation + // layer, below the DAO layer, and ideally shouldn't directly invoke DAO classes. The change + // is temporarily for refactor verification purposes. We should identify a cleaner testing + // strategy moving forward. + return new PolarisTestMetaStoreManager(new PolarisDaoManager(), callCtx); } } diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java index fbcb2f9c94..d367b6a4e5 100644 --- a/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java +++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java @@ -45,12 +45,12 @@ import org.apache.polaris.core.entity.PrincipalEntity; import org.apache.polaris.core.entity.PrincipalRoleEntity; import org.apache.polaris.core.persistence.cache.EntityCache; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.core.persistence.dao.entity.EntityResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; import org.apache.polaris.core.persistence.resolver.Resolver; import org.apache.polaris.core.persistence.resolver.ResolverPath; import org.apache.polaris.core.persistence.resolver.ResolverStatus; -import org.apache.polaris.core.persistence.transactional.PolarisMetaStoreManagerImpl; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapMetaStoreSessionImpl; import org.apache.polaris.core.persistence.transactional.PolarisTreeMapStore; import org.apache.polaris.core.persistence.transactional.TransactionalPersistence; @@ -118,7 +118,7 @@ public ResolverTest() { store = new PolarisTreeMapStore(diagServices); metaStore = new PolarisTreeMapMetaStoreSessionImpl(store, Mockito.mock(), RANDOM_SECRETS); callCtx = new PolarisCallContext(metaStore, diagServices); - metaStoreManager = new PolarisMetaStoreManagerImpl(); + metaStoreManager = new PolarisDaoManager(); // bootstrap the mata store with our test schema tm = new PolarisTestMetaStoreManager(metaStoreManager, callCtx); diff --git a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java index c05a6b2a3d..017d5027a4 100644 --- a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java +++ b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java @@ -84,6 +84,7 @@ import org.apache.polaris.core.persistence.PolarisEntityManager; import org.apache.polaris.core.persistence.PolarisMetaStoreManager; import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper; +import org.apache.polaris.core.persistence.dao.PolarisDaoManager; import org.apache.polaris.core.persistence.dao.entity.CreateCatalogResult; import org.apache.polaris.core.persistence.dao.entity.CreatePrincipalResult; import org.apache.polaris.core.persistence.dao.entity.DropEntityResult; @@ -116,7 +117,7 @@ public class PolarisAdminService { private final SecurityContext securityContext; private final AuthenticatedPolarisPrincipal authenticatedPrincipal; private final PolarisAuthorizer authorizer; - private final PolarisMetaStoreManager metaStoreManager; + private final PolarisDaoManager daoManager; // Initialized in the authorize methods. private PolarisResolutionManifest resolutionManifest = null; @@ -129,7 +130,8 @@ public PolarisAdminService( @NotNull PolarisAuthorizer authorizer) { this.callContext = callContext; this.entityManager = entityManager; - this.metaStoreManager = metaStoreManager; + // TODO remove the casting in a followup PR + this.daoManager = (PolarisDaoManager) metaStoreManager; this.securityContext = securityContext; PolarisDiagnostics diagServices = callContext.getPolarisCallContext().getDiagServices(); diagServices.checkNotNull(securityContext, "null_security_context"); @@ -573,11 +575,14 @@ public PolarisEntity createCatalog(PolarisEntity entity) { PolarisEntity polarisEntity = new PolarisEntity.Builder(entity) - .setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId()) + .setId( + daoManager.getCommonDao().generateNewEntityId(getCurrentPolarisContext()).getId()) .setCreateTimestamp(System.currentTimeMillis()) .build(); CreateCatalogResult catalogResult = - metaStoreManager.createCatalog(getCurrentPolarisContext(), polarisEntity, List.of()); + daoManager + .getCatalogDao() + .createCatalog(getCurrentPolarisContext(), polarisEntity, List.of()); if (catalogResult.alreadyExists()) { throw new AlreadyExistsException( "Cannot create Catalog %s. Catalog already exists or resolution failed", @@ -600,8 +605,9 @@ public void deleteCatalog(String name) { .getConfigurationStore() .getConfiguration(polarisCallContext, PolarisConfiguration.CLEANUP_ON_CATALOG_DROP); DropEntityResult dropEntityResult = - metaStoreManager.dropEntityIfExists( - getCurrentPolarisContext(), null, entity, Map.of(), cleanup); + daoManager + .getCatalogDao() + .dropEntityIfExists(getCurrentPolarisContext(), entity, Map.of(), cleanup); // at least some handling of error if (!dropEntityResult.isSuccess()) { @@ -730,8 +736,10 @@ private void validateUpdateCatalogDiffOrThrow( Optional.ofNullable( CatalogEntity.of( PolarisEntity.of( - metaStoreManager.updateEntityPropertiesIfNotChanged( - getCurrentPolarisContext(), null, updatedEntity)))) + daoManager + .getCatalogDao() + .updateEntityPropertiesIfNotChanged( + getCurrentPolarisContext(), updatedEntity)))) .orElseThrow( () -> new CommitFailedException( @@ -751,19 +759,17 @@ public List listCatalogs() { * process before it could be loaded. */ private List listCatalogsUnsafe() { - return metaStoreManager - .listEntities( - getCurrentPolarisContext(), - null, - PolarisEntityType.CATALOG, - PolarisEntitySubType.ANY_SUBTYPE) + return daoManager + .getCatalogDao() + .listEntities(getCurrentPolarisContext()) .getEntities() .stream() .map( nameAndId -> PolarisEntity.of( - metaStoreManager.loadEntity( - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) + daoManager + .getCatalogDao() + .loadEntity(getCurrentPolarisContext(), nameAndId.getId()))) .toList(); } @@ -774,12 +780,18 @@ public PrincipalWithCredentials createPrincipal(PolarisEntity entity) { checkArgument(entity.getId() == -1, "Entity to be created must have no ID assigned"); CreatePrincipalResult principalResult = - metaStoreManager.createPrincipal( - getCurrentPolarisContext(), - new PolarisEntity.Builder(entity) - .setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId()) - .setCreateTimestamp(System.currentTimeMillis()) - .build()); + daoManager + .getPrincipalDao() + .createPrincipal( + getCurrentPolarisContext(), + new PolarisEntity.Builder(entity) + .setId( + daoManager + .getCommonDao() + .generateNewEntityId(getCurrentPolarisContext()) + .getId()) + .setCreateTimestamp(System.currentTimeMillis()) + .build()); if (principalResult.alreadyExists()) { throw new AlreadyExistsException( "Cannot create Principal %s. Principal already exists or resolution failed", @@ -801,8 +813,9 @@ public void deletePrincipal(String name) { .orElseThrow(() -> new NotFoundException("Principal %s not found", name)); // TODO: Handle return value in case of concurrent modification DropEntityResult dropEntityResult = - metaStoreManager.dropEntityIfExists( - getCurrentPolarisContext(), null, entity, Map.of(), false); + daoManager + .getPrincipalDao() + .dropEntityIfExists(getCurrentPolarisContext(), entity, Map.of(), false); // at least some handling of error if (!dropEntityResult.isSuccess()) { @@ -848,8 +861,10 @@ public void deletePrincipal(String name) { Optional.ofNullable( PrincipalEntity.of( PolarisEntity.of( - metaStoreManager.updateEntityPropertiesIfNotChanged( - getCurrentPolarisContext(), null, updatedEntity)))) + daoManager + .getPrincipalDao() + .updateEntityPropertiesIfNotChanged( + getCurrentPolarisContext(), updatedEntity)))) .orElseThrow( () -> new CommitFailedException( @@ -864,7 +879,8 @@ public void deletePrincipal(String name) { .orElseThrow(() -> new NotFoundException("Principal %s not found", principalName)); PolarisPrincipalSecrets currentSecrets = - metaStoreManager + daoManager + .getPrincipalSecretsDao() .loadPrincipalSecrets(getCurrentPolarisContext(), currentPrincipalEntity.getClientId()) .getPrincipalSecrets(); if (currentSecrets == null) { @@ -872,7 +888,8 @@ public void deletePrincipal(String name) { String.format("Failed to load current secrets for principal '%s'", principalName)); } PolarisPrincipalSecrets newSecrets = - metaStoreManager + daoManager + .getPrincipalSecretsDao() .rotatePrincipalSecrets( getCurrentPolarisContext(), currentPrincipalEntity.getClientId(), @@ -888,11 +905,9 @@ public void deletePrincipal(String name) { } PolarisEntity newPrincipal = PolarisEntity.of( - metaStoreManager.loadEntity( - getCurrentPolarisContext(), - 0L, - currentPrincipalEntity.getId(), - currentPrincipalEntity.getType())); + daoManager + .getPrincipalDao() + .loadEntity(getCurrentPolarisContext(), currentPrincipalEntity.getId())); return new PrincipalWithCredentials( PrincipalEntity.of(newPrincipal).asPrincipal(), new PrincipalWithCredentialsCredentials( @@ -917,19 +932,17 @@ public List listPrincipals() { PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_PRINCIPALS; authorizeBasicRootOperationOrThrow(op); - return metaStoreManager - .listEntities( - getCurrentPolarisContext(), - null, - PolarisEntityType.PRINCIPAL, - PolarisEntitySubType.NULL_SUBTYPE) + return daoManager + .getPrincipalDao() + .listEntities(getCurrentPolarisContext()) .getEntities() .stream() .map( nameAndId -> PolarisEntity.of( - metaStoreManager.loadEntity( - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) + daoManager + .getPrincipalDao() + .loadEntity(getCurrentPolarisContext(), nameAndId.getId()))) .toList(); } @@ -941,13 +954,18 @@ public PolarisEntity createPrincipalRole(PolarisEntity entity) { PolarisEntity returnedEntity = PolarisEntity.of( - metaStoreManager.createEntityIfNotExists( - getCurrentPolarisContext(), - null, - new PolarisEntity.Builder(entity) - .setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId()) - .setCreateTimestamp(System.currentTimeMillis()) - .build())); + daoManager + .getPrincipalRoleDao() + .createEntityIfNotExists( + getCurrentPolarisContext(), + new PolarisEntity.Builder(entity) + .setId( + daoManager + .getCommonDao() + .generateNewEntityId(getCurrentPolarisContext()) + .getId()) + .setCreateTimestamp(System.currentTimeMillis()) + .build())); if (returnedEntity == null) { throw new AlreadyExistsException( "Cannot create PrincipalRole %s. PrincipalRole already exists or resolution failed", @@ -965,8 +983,10 @@ public void deletePrincipalRole(String name) { .orElseThrow(() -> new NotFoundException("PrincipalRole %s not found", name)); // TODO: Handle return value in case of concurrent modification DropEntityResult dropEntityResult = - metaStoreManager.dropEntityIfExists( - getCurrentPolarisContext(), null, entity, Map.of(), true); // cleanup grants + daoManager + .getPrincipalRoleDao() + .dropEntityIfExists( + getCurrentPolarisContext(), entity, Map.of(), true); // cleanup grants // at least some handling of error if (!dropEntityResult.isSuccess()) { @@ -1013,8 +1033,10 @@ public void deletePrincipalRole(String name) { Optional.ofNullable( PrincipalRoleEntity.of( PolarisEntity.of( - metaStoreManager.updateEntityPropertiesIfNotChanged( - getCurrentPolarisContext(), null, updatedEntity)))) + daoManager + .getPrincipalRoleDao() + .updateEntityPropertiesIfNotChanged( + getCurrentPolarisContext(), updatedEntity)))) .orElseThrow( () -> new CommitFailedException( @@ -1026,19 +1048,17 @@ public List listPrincipalRoles() { PolarisAuthorizableOperation op = PolarisAuthorizableOperation.LIST_PRINCIPAL_ROLES; authorizeBasicRootOperationOrThrow(op); - return metaStoreManager - .listEntities( - getCurrentPolarisContext(), - null, - PolarisEntityType.PRINCIPAL_ROLE, - PolarisEntitySubType.NULL_SUBTYPE) + return daoManager + .getPrincipalRoleDao() + .listEntities(getCurrentPolarisContext()) .getEntities() .stream() .map( nameAndId -> PolarisEntity.of( - metaStoreManager.loadEntity( - getCurrentPolarisContext(), 0, nameAndId.getId(), nameAndId.getType()))) + daoManager + .getPrincipalRoleDao() + .loadEntity(getCurrentPolarisContext(), nameAndId.getId()))) .toList(); } @@ -1054,15 +1074,21 @@ public PolarisEntity createCatalogRole(String catalogName, PolarisEntity entity) PolarisEntity returnedEntity = PolarisEntity.of( - metaStoreManager.createEntityIfNotExists( - getCurrentPolarisContext(), - PolarisEntity.toCoreList(List.of(catalogEntity)), - new PolarisEntity.Builder(entity) - .setId(metaStoreManager.generateNewEntityId(getCurrentPolarisContext()).getId()) - .setCatalogId(catalogEntity.getId()) - .setParentId(catalogEntity.getId()) - .setCreateTimestamp(System.currentTimeMillis()) - .build())); + daoManager + .getCatalogRoleDao() + .createEntityIfNotExists( + getCurrentPolarisContext(), + PolarisEntity.toCoreList(List.of(catalogEntity)), + new PolarisEntity.Builder(entity) + .setId( + daoManager + .getCommonDao() + .generateNewEntityId(getCurrentPolarisContext()) + .getId()) + .setCatalogId(catalogEntity.getId()) + .setParentId(catalogEntity.getId()) + .setCreateTimestamp(System.currentTimeMillis()) + .build())); if (returnedEntity == null) { throw new AlreadyExistsException( "Cannot create CatalogRole %s in %s. CatalogRole already exists or resolution failed", @@ -1081,12 +1107,14 @@ public void deleteCatalogRole(String catalogName, String name) { } // TODO: Handle return value in case of concurrent modification DropEntityResult dropEntityResult = - metaStoreManager.dropEntityIfExists( - getCurrentPolarisContext(), - PolarisEntity.toCoreList(resolvedCatalogRoleEntity.getRawParentPath()), - resolvedCatalogRoleEntity.getRawLeafEntity(), - Map.of(), - true); // cleanup grants + daoManager + .getCatalogRoleDao() + .dropEntityIfExists( + getCurrentPolarisContext(), + PolarisEntity.toCoreList(resolvedCatalogRoleEntity.getRawParentPath()), + resolvedCatalogRoleEntity.getRawLeafEntity(), + Map.of(), + true); // cleanup grants // at least some handling of error if (!dropEntityResult.isSuccess()) { @@ -1136,10 +1164,12 @@ public void deleteCatalogRole(String catalogName, String name) { Optional.ofNullable( CatalogRoleEntity.of( PolarisEntity.of( - metaStoreManager.updateEntityPropertiesIfNotChanged( - getCurrentPolarisContext(), - PolarisEntity.toCoreList(List.of(catalogEntity)), - updatedEntity)))) + daoManager + .getCatalogRoleDao() + .updateEntityPropertiesIfNotChanged( + getCurrentPolarisContext(), + PolarisEntity.toCoreList(List.of(catalogEntity)), + updatedEntity)))) .orElseThrow( () -> new CommitFailedException( @@ -1154,22 +1184,18 @@ public List listCatalogRoles(String catalogName) { PolarisEntity catalogEntity = findCatalogByName(catalogName) .orElseThrow(() -> new NotFoundException("Parent catalog %s not found", catalogName)); - return metaStoreManager - .listEntities( - getCurrentPolarisContext(), - PolarisEntity.toCoreList(List.of(catalogEntity)), - PolarisEntityType.CATALOG_ROLE, - PolarisEntitySubType.NULL_SUBTYPE) + return daoManager + .getCatalogRoleDao() + .listEntities(getCurrentPolarisContext(), PolarisEntity.toCoreList(List.of(catalogEntity))) .getEntities() .stream() .map( nameAndId -> PolarisEntity.of( - metaStoreManager.loadEntity( - getCurrentPolarisContext(), - catalogEntity.getId(), - nameAndId.getId(), - nameAndId.getType()))) + daoManager + .getCatalogRoleDao() + .loadEntity( + getCurrentPolarisContext(), catalogEntity.getId(), nameAndId.getId()))) .toList(); } @@ -1185,7 +1211,8 @@ public boolean assignPrincipalRole(String principalName, String principalRoleNam .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantUsageOnRoleToGrantee( getCurrentPolarisContext(), null, principalRoleEntity, principalEntity) .isSuccess(); @@ -1202,7 +1229,8 @@ public boolean revokePrincipalRole(String principalName, String principalRoleNam findPrincipalRoleByName(principalRoleName) .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokeUsageOnRoleFromGrantee( getCurrentPolarisContext(), null, principalRoleEntity, principalEntity) .isSuccess(); @@ -1217,8 +1245,12 @@ public List listPrincipalRolesAssigned(String principalName) { findPrincipalByName(principalName) .orElseThrow(() -> new NotFoundException("Principal %s not found", principalName)); LoadGrantsResult grantList = - metaStoreManager.loadGrantsToGrantee( - getCurrentPolarisContext(), principalEntity.getCatalogId(), principalEntity.getId()); + daoManager + .getGrantRecordDao() + .loadGrantsToGrantee( + getCurrentPolarisContext(), + principalEntity.getCatalogId(), + principalEntity.getId()); return buildEntitiesFromGrantResults(grantList, false, PolarisEntityType.PRINCIPAL_ROLE, null); } @@ -1240,7 +1272,8 @@ public boolean assignCatalogRoleToPrincipalRole( findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantUsageOnRoleToGrantee( getCurrentPolarisContext(), catalogEntity, catalogRoleEntity, principalRoleEntity) .isSuccess(); @@ -1263,7 +1296,8 @@ public boolean revokeCatalogRoleFromPrincipalRole( PolarisEntity catalogRoleEntity = findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokeUsageOnRoleFromGrantee( getCurrentPolarisContext(), catalogEntity, catalogRoleEntity, principalRoleEntity) .isSuccess(); @@ -1281,10 +1315,12 @@ public List listAssigneePrincipalsForPrincipalRole(String princip .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); LoadGrantsResult grantList = - metaStoreManager.loadGrantsOnSecurable( - getCurrentPolarisContext(), - principalRoleEntity.getCatalogId(), - principalRoleEntity.getId()); + daoManager + .getGrantRecordDao() + .loadGrantsOnSecurable( + getCurrentPolarisContext(), + principalRoleEntity.getCatalogId(), + principalRoleEntity.getId()); return buildEntitiesFromGrantResults(grantList, true, PolarisEntityType.PRINCIPAL, null); } @@ -1336,10 +1372,12 @@ public List listCatalogRolesForPrincipalRole( .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); LoadGrantsResult grantList = - metaStoreManager.loadGrantsToGrantee( - getCurrentPolarisContext(), - principalRoleEntity.getCatalogId(), - principalRoleEntity.getId()); + daoManager + .getGrantRecordDao() + .loadGrantsToGrantee( + getCurrentPolarisContext(), + principalRoleEntity.getCatalogId(), + principalRoleEntity.getId()); return buildEntitiesFromGrantResults( grantList, false, @@ -1360,7 +1398,8 @@ public boolean grantPrivilegeOnRootContainerToPrincipalRole( .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantPrivilegeOnSecurableToRole( getCurrentPolarisContext(), principalRoleEntity, null, rootContainerEntity, privilege) .isSuccess(); @@ -1380,7 +1419,8 @@ public boolean revokePrivilegeOnRootContainerFromPrincipalRole( .orElseThrow( () -> new NotFoundException("PrincipalRole %s not found", principalRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokePrivilegeOnSecurableFromRole( getCurrentPolarisContext(), principalRoleEntity, null, rootContainerEntity, privilege) .isSuccess(); @@ -1404,7 +1444,8 @@ public boolean grantPrivilegeOnCatalogToRole( findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantPrivilegeOnSecurableToRole( getCurrentPolarisContext(), catalogRoleEntity, @@ -1428,7 +1469,8 @@ public boolean revokePrivilegeOnCatalogFromRole( findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokePrivilegeOnSecurableFromRole( getCurrentPolarisContext(), catalogRoleEntity, @@ -1456,7 +1498,8 @@ public boolean grantPrivilegeOnNamespaceToRole( List catalogPath = resolvedPathWrapper.getRawParentPath(); PolarisEntity namespaceEntity = resolvedPathWrapper.getRawLeafEntity(); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantPrivilegeOnSecurableToRole( getCurrentPolarisContext(), catalogRoleEntity, @@ -1484,7 +1527,8 @@ public boolean revokePrivilegeOnNamespaceFromRole( List catalogPath = resolvedPathWrapper.getRawParentPath(); PolarisEntity namespaceEntity = resolvedPathWrapper.getRawLeafEntity(); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokePrivilegeOnSecurableFromRole( getCurrentPolarisContext(), catalogRoleEntity, @@ -1565,10 +1609,12 @@ public List listAssigneePrincipalRolesForCatalogRole( findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); LoadGrantsResult grantList = - metaStoreManager.loadGrantsOnSecurable( - getCurrentPolarisContext(), - catalogRoleEntity.getCatalogId(), - catalogRoleEntity.getId()); + daoManager + .getGrantRecordDao() + .loadGrantsOnSecurable( + getCurrentPolarisContext(), + catalogRoleEntity.getCatalogId(), + catalogRoleEntity.getId()); return buildEntitiesFromGrantResults(grantList, true, PolarisEntityType.PRINCIPAL_ROLE, null); } @@ -1584,10 +1630,12 @@ public List listGrantsForCatalogRole(String catalogName, String c findCatalogRoleByName(catalogName, catalogRoleName) .orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName)); LoadGrantsResult grantList = - metaStoreManager.loadGrantsToGrantee( - getCurrentPolarisContext(), - catalogRoleEntity.getCatalogId(), - catalogRoleEntity.getId()); + daoManager + .getGrantRecordDao() + .loadGrantsToGrantee( + getCurrentPolarisContext(), + catalogRoleEntity.getCatalogId(), + catalogRoleEntity.getId()); List catalogGrants = new ArrayList<>(); List namespaceGrants = new ArrayList<>(); List tableGrants = new ArrayList<>(); @@ -1673,7 +1721,7 @@ public List listGrantsForCatalogRole(String catalogName, String c long id, PolarisEntityType entityType) { return (entitiesMap == null) - ? metaStoreManager + ? daoManager // TODO use type-specific DAO here .loadEntity(getCurrentPolarisContext(), catalogId, id, entityType) .getEntity() : entitiesMap.get(id); @@ -1687,7 +1735,8 @@ public List listGrantsForCatalogRole(String catalogName, String c for (PolarisEntityType type : PolarisEntityType.values()) { EntityResult entityResult = - metaStoreManager.loadEntity( + // TODO use type-specific DAO here + daoManager.loadEntity( getCurrentPolarisContext(), record.getSecurableCatalogId(), record.getSecurableId(), @@ -1726,7 +1775,8 @@ private boolean grantPrivilegeOnTableLikeToRole( List catalogPath = resolvedPathWrapper.getRawParentPath(); PolarisEntity tableLikeEntity = resolvedPathWrapper.getRawLeafEntity(); - return metaStoreManager + return daoManager + .getGrantRecordDao() .grantPrivilegeOnSecurableToRole( getCurrentPolarisContext(), catalogRoleEntity, @@ -1764,7 +1814,8 @@ private boolean revokePrivilegeOnTableLikeFromRole( List catalogPath = resolvedPathWrapper.getRawParentPath(); PolarisEntity tableLikeEntity = resolvedPathWrapper.getRawLeafEntity(); - return metaStoreManager + return daoManager + .getGrantRecordDao() .revokePrivilegeOnSecurableFromRole( getCurrentPolarisContext(), catalogRoleEntity,