This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 3c0997b95 [#5237][#5240] fix(metalake): fix list metalakes missing 
in-use property (#5241)
3c0997b95 is described below

commit 3c0997b95efc1c248c5a73ce71c74c135a6ade13
Author: mchades <[email protected]>
AuthorDate: Fri Oct 25 11:00:05 2024 +0800

    [#5237][#5240] fix(metalake): fix list metalakes missing in-use property 
(#5241)
    
    ### What changes were proposed in this pull request?
    
     - fix list metalakes missing in-use property
     - fix NPE when null properties
    
    ### Why are the changes needed?
    
    list metalakes will show metalake details by default so need put in-use
    property in it
    
    Fix: #5240
    Fix: #5237
    
    ### Does this PR introduce _any_ user-facing change?
    
    no
    
    ### How was this patch tested?
    
    tests added
---
 ...xception.java => NonEmptyCatalogException.java} |  19 +--
 ...ception.java => NonEmptyMetalakeException.java} |  19 +--
 .../exceptions/NonEmptySchemaException.java        |   2 +-
 .../org/apache/gravitino/client/ErrorHandlers.java |  11 ++
 .../apache/gravitino/client/GravitinoMetalake.java |   2 +-
 .../client/integration/test/MetalakeIT.java        | 132 ++++++++++++++++++++-
 .../gravitino/dto/requests/MetalakeSetRequest.java |   2 +
 .../apache/gravitino/catalog/CatalogManager.java   |   6 +-
 .../apache/gravitino/metalake/MetalakeManager.java |  35 +++++-
 .../metalake/MetalakeNormalizeDispatcher.java      |  23 +---
 .../gravitino/metalake/TestMetalakeManager.java    |   6 +-
 .../server/web/rest/ExceptionHandlers.java         |   8 ++
 12 files changed, 197 insertions(+), 68 deletions(-)

diff --git 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptyCatalogException.java
similarity index 67%
copy from 
api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
copy to 
api/src/main/java/org/apache/gravitino/exceptions/NonEmptyCatalogException.java
index 846fd541e..30c62a8fd 100644
--- 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
+++ 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptyCatalogException.java
@@ -21,8 +21,9 @@ package org.apache.gravitino.exceptions;
 import com.google.errorprone.annotations.FormatMethod;
 import com.google.errorprone.annotations.FormatString;
 
-/** Exception thrown when a namespace is not empty. */
-public class NonEmptySchemaException extends GravitinoRuntimeException {
+/** Exception thrown when a catalog is not empty. */
+public class NonEmptyCatalogException extends GravitinoRuntimeException {
+
   /**
    * Constructs a new exception with the specified detail message.
    *
@@ -30,19 +31,7 @@ public class NonEmptySchemaException extends 
GravitinoRuntimeException {
    * @param args the arguments to the message.
    */
   @FormatMethod
-  public NonEmptySchemaException(@FormatString String message, Object... args) 
{
+  public NonEmptyCatalogException(@FormatString String message, Object... 
args) {
     super(message, args);
   }
-
-  /**
-   * Constructs a new exception with the specified detail message and cause.
-   *
-   * @param cause the cause.
-   * @param message the detail message.
-   * @param args the arguments to the message.
-   */
-  @FormatMethod
-  public NonEmptySchemaException(Throwable cause, @FormatString String 
message, Object... args) {
-    super(cause, message, args);
-  }
 }
diff --git 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptyMetalakeException.java
similarity index 67%
copy from 
api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
copy to 
api/src/main/java/org/apache/gravitino/exceptions/NonEmptyMetalakeException.java
index 846fd541e..4e9cf8cf9 100644
--- 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
+++ 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptyMetalakeException.java
@@ -21,8 +21,9 @@ package org.apache.gravitino.exceptions;
 import com.google.errorprone.annotations.FormatMethod;
 import com.google.errorprone.annotations.FormatString;
 
-/** Exception thrown when a namespace is not empty. */
-public class NonEmptySchemaException extends GravitinoRuntimeException {
+/** Exception thrown when a metalake is not empty. */
+public class NonEmptyMetalakeException extends GravitinoRuntimeException {
+
   /**
    * Constructs a new exception with the specified detail message.
    *
@@ -30,19 +31,7 @@ public class NonEmptySchemaException extends 
GravitinoRuntimeException {
    * @param args the arguments to the message.
    */
   @FormatMethod
-  public NonEmptySchemaException(@FormatString String message, Object... args) 
{
+  public NonEmptyMetalakeException(@FormatString String message, Object... 
args) {
     super(message, args);
   }
-
-  /**
-   * Constructs a new exception with the specified detail message and cause.
-   *
-   * @param cause the cause.
-   * @param message the detail message.
-   * @param args the arguments to the message.
-   */
-  @FormatMethod
-  public NonEmptySchemaException(Throwable cause, @FormatString String 
message, Object... args) {
-    super(cause, message, args);
-  }
 }
diff --git 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
index 846fd541e..c1f8c29e5 100644
--- 
a/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
+++ 
b/api/src/main/java/org/apache/gravitino/exceptions/NonEmptySchemaException.java
@@ -21,7 +21,7 @@ package org.apache.gravitino.exceptions;
 import com.google.errorprone.annotations.FormatMethod;
 import com.google.errorprone.annotations.FormatString;
 
-/** Exception thrown when a namespace is not empty. */
+/** Exception thrown when a schema is not empty. */
 public class NonEmptySchemaException extends GravitinoRuntimeException {
   /**
    * Constructs a new exception with the specified detail message.
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
index 3cc8df1d2..3dcf6672a 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
@@ -53,6 +53,8 @@ import org.apache.gravitino.exceptions.NoSuchTableException;
 import org.apache.gravitino.exceptions.NoSuchTagException;
 import org.apache.gravitino.exceptions.NoSuchTopicException;
 import org.apache.gravitino.exceptions.NoSuchUserException;
+import org.apache.gravitino.exceptions.NonEmptyCatalogException;
+import org.apache.gravitino.exceptions.NonEmptyMetalakeException;
 import org.apache.gravitino.exceptions.NonEmptySchemaException;
 import org.apache.gravitino.exceptions.NotFoundException;
 import org.apache.gravitino.exceptions.NotInUseException;
@@ -465,6 +467,9 @@ public class ErrorHandlers {
             throw new NotInUseException(errorMessage);
           }
 
+        case ErrorConstants.NON_EMPTY_CODE:
+          throw new NonEmptyCatalogException(errorMessage);
+
         default:
           super.accept(errorResponse);
       }
@@ -496,6 +501,12 @@ public class ErrorHandlers {
         case ErrorConstants.IN_USE_CODE:
           throw new MetalakeInUseException(errorMessage);
 
+        case ErrorConstants.NOT_IN_USE_CODE:
+          throw new MetalakeNotInUseException(errorMessage);
+
+        case ErrorConstants.NON_EMPTY_CODE:
+          throw new NonEmptyMetalakeException(errorMessage);
+
         default:
           super.accept(errorResponse);
       }
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
index 47f42d3ad..1e0f7c63f 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GravitinoMetalake.java
@@ -383,7 +383,7 @@ public class GravitinoMetalake extends MetalakeDTO
     return this;
   }
 
-  /*
+  /**
    * List all the tag names under a metalake.
    *
    * @return A list of the tag names under the current metalake.
diff --git 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/MetalakeIT.java
 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/MetalakeIT.java
index 2922154f3..3a6506464 100644
--- 
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/MetalakeIT.java
+++ 
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/MetalakeIT.java
@@ -18,44 +18,54 @@
  */
 package org.apache.gravitino.client.integration.test;
 
+import static org.apache.gravitino.Metalake.PROPERTY_IN_USE;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Map;
+import org.apache.gravitino.Catalog;
+import org.apache.gravitino.CatalogChange;
 import org.apache.gravitino.MetalakeChange;
 import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.SchemaChange;
+import org.apache.gravitino.SupportsSchemas;
 import org.apache.gravitino.auth.AuthConstants;
 import org.apache.gravitino.client.GravitinoMetalake;
 import org.apache.gravitino.exceptions.IllegalNameIdentifierException;
 import org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
+import org.apache.gravitino.exceptions.MetalakeInUseException;
+import org.apache.gravitino.exceptions.MetalakeNotInUseException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NonEmptyMetalakeException;
+import org.apache.gravitino.file.FilesetCatalog;
+import org.apache.gravitino.file.FilesetChange;
 import org.apache.gravitino.integration.test.util.BaseIT;
+import org.apache.gravitino.integration.test.util.GravitinoITUtils;
 import org.apache.gravitino.utils.RandomNameUtils;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.MethodOrderer;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
 
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 public class MetalakeIT extends BaseIT {
   public static String metalakeNameA = 
RandomNameUtils.genRandomName("metalakeA");
   public static String metalakeNameB = 
RandomNameUtils.genRandomName("metalakeB");
 
   @BeforeEach
-  private void start() {
+  public void start() {
     // Just in case clean up is needed due to a test failure
     dropMetalakes();
   }
 
   @AfterEach
-  private void stop() {
+  public void stop() {
     dropMetalakes();
   }
 
@@ -88,6 +98,7 @@ public class MetalakeIT extends BaseIT {
     client.createMetalake(metalakeNameA, "metalake A comment", 
Collections.emptyMap());
     GravitinoMetalake metaLakeA = client.loadMetalake(metalakeNameA);
     assertEquals(metaLakeA.name(), metalakeNameA);
+    assertEquals("true", metaLakeA.properties().get(PROPERTY_IN_USE));
 
     // metalake does not exist
     NameIdentifier noexist = NameIdentifier.of(metalakeNameB);
@@ -150,6 +161,7 @@ public class MetalakeIT extends BaseIT {
     assertEquals(metalakeNameA, metalake.name());
     assertEquals("metalake A comment", metalake.comment());
     assertEquals(AuthConstants.ANONYMOUS_USER, metalake.auditInfo().creator());
+    assertEquals("true", metalake.properties().get(PROPERTY_IN_USE));
 
     // Test metalake name already exists
     Map<String, String> emptyMap = Collections.emptyMap();
@@ -210,11 +222,119 @@ public class MetalakeIT extends BaseIT {
     assertTrue(client.dropMetalake(metalakeNameA, true));
   }
 
+  @Test
+  public void testMetalakeAvailable() {
+    String metalakeName = RandomNameUtils.genRandomName("test_metalake");
+    client.createMetalake(metalakeName, null, null);
+    // test load metalake
+    GravitinoMetalake metalake = client.loadMetalake(metalakeName);
+    Assertions.assertEquals(metalakeName, metalake.name());
+    Assertions.assertEquals("true", 
metalake.properties().get(PROPERTY_IN_USE));
+
+    // test list metalakes
+    GravitinoMetalake[] metalakes = client.listMetalakes();
+    Assertions.assertEquals(1, metalakes.length);
+    Assertions.assertEquals(metalakeName, metalakes[0].name());
+    Assertions.assertEquals("true", 
metalakes[0].properties().get(PROPERTY_IN_USE));
+
+    Exception exception =
+        assertThrows(MetalakeInUseException.class, () -> 
client.dropMetalake(metalakeName));
+    Assertions.assertTrue(exception.getMessage().contains("please disable it 
first"));
+
+    // create a catalog under the metalake
+    String catalogName = GravitinoITUtils.genRandomName("test_catalog");
+    Catalog catalog =
+        metalake.createCatalog(
+            catalogName, Catalog.Type.FILESET, "hadoop", "catalog comment", 
ImmutableMap.of());
+    Assertions.assertEquals("true", 
catalog.properties().get(Catalog.PROPERTY_IN_USE));
+
+    Assertions.assertDoesNotThrow(() -> client.disableMetalake(metalakeName));
+    GravitinoMetalake loadedMetalake = client.loadMetalake(metalakeName);
+    Assertions.assertEquals("false", 
loadedMetalake.properties().get(PROPERTY_IN_USE));
+
+    exception =
+        assertThrows(
+            MetalakeNotInUseException.class,
+            () -> client.alterMetalake(metalakeName, 
MetalakeChange.updateComment("new comment")));
+    Assertions.assertTrue(exception.getMessage().contains("please enable it 
first"));
+
+    // test catalog operations under non-in-use metalake
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () ->
+            loadedMetalake.createCatalog(
+                catalogName, Catalog.Type.FILESET, "dummy", null, 
Collections.emptyMap()));
+    Assertions.assertThrows(MetalakeNotInUseException.class, 
loadedMetalake::listCatalogs);
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
loadedMetalake.loadCatalog(catalogName));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
loadedMetalake.dropCatalog(catalogName));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () -> loadedMetalake.alterCatalog(catalogName, 
CatalogChange.rename("dummy")));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
loadedMetalake.disableCatalog(catalogName));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
loadedMetalake.enableCatalog(catalogName));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () ->
+            loadedMetalake.testConnection(
+                catalogName, Catalog.Type.FILESET, "dummy", null, 
Collections.emptyMap()));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
loadedMetalake.catalogExists(catalogName));
+
+    // test schema operations under non-in-use metalake
+    SupportsSchemas schemaOps = catalog.asSchemas();
+    Assertions.assertThrows(MetalakeNotInUseException.class, 
schemaOps::listSchemas);
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> schemaOps.createSchema("dummy", 
null, null));
+    Assertions.assertThrows(MetalakeNotInUseException.class, () -> 
schemaOps.loadSchema("dummy"));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () -> schemaOps.alterSchema("dummy", 
SchemaChange.removeProperty("dummy")));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> schemaOps.dropSchema("dummy", 
false));
+
+    // test fileset operations under non-in-use catalog
+    FilesetCatalog filesetOps = catalog.asFilesetCatalog();
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class, () -> 
filesetOps.listFilesets(Namespace.of("dummy")));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () -> filesetOps.loadFileset(NameIdentifier.of("dummy", "dummy")));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () ->
+            filesetOps.createFileset(NameIdentifier.of("dummy", "dummy"), 
null, null, null, null));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () -> filesetOps.dropFileset(NameIdentifier.of("dummy", "dummy")));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () -> filesetOps.getFileLocation(NameIdentifier.of("dummy", "dummy"), 
"dummy"));
+    Assertions.assertThrows(
+        MetalakeNotInUseException.class,
+        () ->
+            filesetOps.alterFileset(
+                NameIdentifier.of("dummy", "dummy"), 
FilesetChange.removeComment()));
+
+    Assertions.assertThrows(
+        NonEmptyMetalakeException.class, () -> 
client.dropMetalake(metalakeName));
+
+    Assertions.assertDoesNotThrow(() -> client.enableMetalake(metalakeName));
+    Assertions.assertTrue(loadedMetalake.dropCatalog(catalogName, true));
+
+    Assertions.assertDoesNotThrow(() -> client.disableMetalake(metalakeName));
+    Assertions.assertTrue(client.dropMetalake(metalakeName));
+    Assertions.assertFalse(client.dropMetalake(metalakeName));
+  }
+
   public void dropMetalakes() {
     GravitinoMetalake[] metaLakes = client.listMetalakes();
     for (GravitinoMetalake metalake : metaLakes) {
       assertDoesNotThrow(() -> client.disableMetalake(metalake.name()));
-      assertTrue(client.dropMetalake(metalake.name()));
+      assertTrue(client.dropMetalake(metalake.name(), true));
     }
 
     // Reload metadata from backend to check if the drop operations are applied
diff --git 
a/common/src/main/java/org/apache/gravitino/dto/requests/MetalakeSetRequest.java
 
b/common/src/main/java/org/apache/gravitino/dto/requests/MetalakeSetRequest.java
index be75b2d4a..f87abef25 100644
--- 
a/common/src/main/java/org/apache/gravitino/dto/requests/MetalakeSetRequest.java
+++ 
b/common/src/main/java/org/apache/gravitino/dto/requests/MetalakeSetRequest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.gravitino.dto.requests;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.ToString;
@@ -29,6 +30,7 @@ import org.apache.gravitino.rest.RESTRequest;
 @ToString
 public class MetalakeSetRequest implements RESTRequest {
 
+  @JsonProperty("inUse")
   private final boolean inUse;
 
   /** Default constructor for MetalakeSetRequest. */
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java 
b/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
index 6af759c61..ed300e45c 100644
--- a/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
+++ b/core/src/main/java/org/apache/gravitino/catalog/CatalogManager.java
@@ -87,6 +87,7 @@ import 
org.apache.gravitino.exceptions.MetalakeNotInUseException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NonEmptyCatalogException;
 import org.apache.gravitino.exceptions.NonEmptyEntityException;
 import org.apache.gravitino.file.FilesetCatalog;
 import org.apache.gravitino.messaging.TopicCatalog;
@@ -629,6 +630,9 @@ public class CatalogManager implements CatalogDispatcher, 
Closeable {
   @Override
   public boolean dropCatalog(NameIdentifier ident, boolean force)
       throws NonEmptyEntityException, CatalogInUseException {
+    NameIdentifier metalakeIdent = 
NameIdentifier.of(ident.namespace().levels());
+    checkMetalake(metalakeIdent, store);
+
     try {
       boolean catalogInUse = catalogInUse(store, ident);
       if (catalogInUse && !force) {
@@ -646,7 +650,7 @@ public class CatalogManager implements CatalogDispatcher, 
Closeable {
       if (!schemas.isEmpty() && !force) {
         // the Kafka catalog is special, it includes a default schema
         if (!catalogEntity.getProvider().equals("kafka") || schemas.size() > 
1) {
-          throw new NonEmptyEntityException(
+          throw new NonEmptyCatalogException(
               "Catalog %s has schemas, please drop them first or use force 
option", ident);
         }
       }
diff --git 
a/core/src/main/java/org/apache/gravitino/metalake/MetalakeManager.java 
b/core/src/main/java/org/apache/gravitino/metalake/MetalakeManager.java
index b8c9f77f1..0239526e5 100644
--- a/core/src/main/java/org/apache/gravitino/metalake/MetalakeManager.java
+++ b/core/src/main/java/org/apache/gravitino/metalake/MetalakeManager.java
@@ -23,6 +23,7 @@ import static org.apache.gravitino.Metalake.PROPERTY_IN_USE;
 import com.google.common.collect.Maps;
 import java.io.IOException;
 import java.time.Instant;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.gravitino.Entity.EntityType;
@@ -38,6 +39,7 @@ import 
org.apache.gravitino.exceptions.MetalakeNotInUseException;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NonEmptyEntityException;
+import org.apache.gravitino.exceptions.NonEmptyMetalakeException;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
@@ -120,9 +122,9 @@ public class MetalakeManager implements MetalakeDispatcher {
   @Override
   public BaseMetalake[] listMetalakes() {
     try {
-      return store
-          .list(Namespace.empty(), BaseMetalake.class, EntityType.METALAKE)
-          .toArray(new BaseMetalake[0]);
+      return store.list(Namespace.empty(), BaseMetalake.class, 
EntityType.METALAKE).stream()
+          .map(this::newMetalakeWithResolvedProperties)
+          .toArray(BaseMetalake[]::new);
     } catch (IOException ioe) {
       LOG.error("Listing Metalakes failed due to storage issues.", ioe);
       throw new RuntimeException(ioe);
@@ -140,7 +142,8 @@ public class MetalakeManager implements MetalakeDispatcher {
   @Override
   public BaseMetalake loadMetalake(NameIdentifier ident) throws 
NoSuchMetalakeException {
     try {
-      return store.get(ident, EntityType.METALAKE, BaseMetalake.class);
+      return newMetalakeWithResolvedProperties(
+          store.get(ident, EntityType.METALAKE, BaseMetalake.class));
     } catch (NoSuchEntityException e) {
       LOG.warn("Metalake {} does not exist", ident, e);
       throw new NoSuchMetalakeException(METALAKE_DOES_NOT_EXIST_MSG, ident);
@@ -150,6 +153,28 @@ public class MetalakeManager implements MetalakeDispatcher 
{
     }
   }
 
+  private BaseMetalake newMetalakeWithResolvedProperties(BaseMetalake 
metalakeEntity) {
+    Map<String, String> newProps =
+        metalakeEntity.properties() == null
+            ? new HashMap<>()
+            : new HashMap<>(metalakeEntity.properties());
+    newProps
+        .entrySet()
+        .removeIf(e -> 
metalakeEntity.propertiesMetadata().isHiddenProperty(e.getKey()));
+    newProps.putIfAbsent(
+        PROPERTY_IN_USE,
+        
metalakeEntity.propertiesMetadata().getDefaultValue(PROPERTY_IN_USE).toString());
+
+    return BaseMetalake.builder()
+        .withId(metalakeEntity.id())
+        .withName(metalakeEntity.name())
+        .withComment(metalakeEntity.comment())
+        .withProperties(newProps)
+        .withVersion(metalakeEntity.getVersion())
+        .withAuditInfo(metalakeEntity.auditInfo())
+        .build();
+  }
+
   /**
    * Creates a new Metalake.
    *
@@ -253,7 +278,7 @@ public class MetalakeManager implements MetalakeDispatcher {
       List<CatalogEntity> catalogEntities =
           store.list(Namespace.of(ident.name()), CatalogEntity.class, 
EntityType.CATALOG);
       if (!catalogEntities.isEmpty() && !force) {
-        throw new NonEmptyEntityException(
+        throw new NonEmptyMetalakeException(
             "Metalake %s has catalogs, please drop them first or use force 
option", ident);
       }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/metalake/MetalakeNormalizeDispatcher.java
 
b/core/src/main/java/org/apache/gravitino/metalake/MetalakeNormalizeDispatcher.java
index dbc9d6bdc..e32f6e946 100644
--- 
a/core/src/main/java/org/apache/gravitino/metalake/MetalakeNormalizeDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/metalake/MetalakeNormalizeDispatcher.java
@@ -19,7 +19,6 @@
 package org.apache.gravitino.metalake;
 
 import static org.apache.gravitino.Entity.SYSTEM_METALAKE_RESERVED_NAME;
-import static org.apache.gravitino.Metalake.PROPERTY_IN_USE;
 import static 
org.apache.gravitino.catalog.PropertiesMetadataHelpers.validatePropertyForAlter;
 import static 
org.apache.gravitino.catalog.PropertiesMetadataHelpers.validatePropertyForCreate;
 import static org.apache.gravitino.meta.BaseMetalake.PROPERTIES_METADATA;
@@ -37,7 +36,6 @@ import 
org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
 import org.apache.gravitino.exceptions.MetalakeInUseException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NonEmptyEntityException;
-import org.apache.gravitino.meta.BaseMetalake;
 
 public class MetalakeNormalizeDispatcher implements MetalakeDispatcher {
   private static final Set<String> RESERVED_WORDS = 
ImmutableSet.of(SYSTEM_METALAKE_RESERVED_NAME);
@@ -66,7 +64,7 @@ public class MetalakeNormalizeDispatcher implements 
MetalakeDispatcher {
 
   @Override
   public Metalake loadMetalake(NameIdentifier ident) throws 
NoSuchMetalakeException {
-    return newMetalakeWithResolvedProperties((BaseMetalake) 
dispatcher.loadMetalake(ident));
+    return dispatcher.loadMetalake(ident);
   }
 
   @Override
@@ -132,25 +130,6 @@ public class MetalakeNormalizeDispatcher implements 
MetalakeDispatcher {
     }
   }
 
-  private BaseMetalake newMetalakeWithResolvedProperties(BaseMetalake 
metalakeEntity) {
-    Map<String, String> newProps = 
Maps.newHashMap(metalakeEntity.properties());
-    newProps
-        .entrySet()
-        .removeIf(e -> 
metalakeEntity.propertiesMetadata().isHiddenProperty(e.getKey()));
-    newProps.putIfAbsent(
-        PROPERTY_IN_USE,
-        
metalakeEntity.propertiesMetadata().getDefaultValue(PROPERTY_IN_USE).toString());
-
-    return BaseMetalake.builder()
-        .withId(metalakeEntity.id())
-        .withName(metalakeEntity.name())
-        .withComment(metalakeEntity.comment())
-        .withProperties(newProps)
-        .withVersion(metalakeEntity.getVersion())
-        .withAuditInfo(metalakeEntity.auditInfo())
-        .build();
-  }
-
   private Pair<Map<String, String>, Map<String, String>> 
getMetalakeAlterProperty(
       MetalakeChange... metalakeChanges) {
     Map<String, String> upserts = Maps.newHashMap();
diff --git 
a/core/src/test/java/org/apache/gravitino/metalake/TestMetalakeManager.java 
b/core/src/test/java/org/apache/gravitino/metalake/TestMetalakeManager.java
index d21db2ce5..0d50c7fb7 100644
--- a/core/src/test/java/org/apache/gravitino/metalake/TestMetalakeManager.java
+++ b/core/src/test/java/org/apache/gravitino/metalake/TestMetalakeManager.java
@@ -90,8 +90,10 @@ public class TestMetalakeManager {
     NameIdentifier ident2 = NameIdentifier.of("test12");
     Map<String, String> props = ImmutableMap.of("key1", "value1");
 
-    BaseMetalake metalake1 = metalakeManager.createMetalake(ident1, "comment", 
props);
-    BaseMetalake metalake2 = metalakeManager.createMetalake(ident2, "comment", 
props);
+    metalakeManager.createMetalake(ident1, "comment", props);
+    BaseMetalake metalake1 = metalakeManager.loadMetalake(ident1);
+    metalakeManager.createMetalake(ident2, "comment", props);
+    BaseMetalake metalake2 = metalakeManager.loadMetalake(ident2);
 
     Set<BaseMetalake> metalakes = 
Sets.newHashSet(metalakeManager.listMetalakes());
     Assertions.assertTrue(metalakes.contains(metalake1));
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
index 284a07b84..8d1ba8565 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ExceptionHandlers.java
@@ -33,6 +33,8 @@ import 
org.apache.gravitino.exceptions.MetalakeAlreadyExistsException;
 import org.apache.gravitino.exceptions.MetalakeInUseException;
 import org.apache.gravitino.exceptions.MetalakeNotInUseException;
 import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.exceptions.NonEmptyCatalogException;
+import org.apache.gravitino.exceptions.NonEmptyMetalakeException;
 import org.apache.gravitino.exceptions.NonEmptySchemaException;
 import org.apache.gravitino.exceptions.NotFoundException;
 import org.apache.gravitino.exceptions.NotInUseException;
@@ -317,6 +319,9 @@ public class ExceptionHandlers {
       } else if (e instanceof InUseException) {
         return Utils.inUse(errorMsg, e);
 
+      } else if (e instanceof NonEmptyCatalogException) {
+        return Utils.nonEmpty(errorMsg, e);
+
       } else {
         return super.handle(op, catalog, metalake, e);
       }
@@ -354,6 +359,9 @@ public class ExceptionHandlers {
       } else if (e instanceof MetalakeInUseException) {
         return Utils.inUse(errorMsg, e);
 
+      } else if (e instanceof NonEmptyMetalakeException) {
+        return Utils.nonEmpty(errorMsg, e);
+
       } else {
         return super.handle(op, metalake, parent, e);
       }

Reply via email to