Skip to content

Commit

Permalink
[apache#3460] feat(api): Add API design for Tag system (apache#3486)
Browse files Browse the repository at this point in the history
### What changes were proposed in this pull request?

This PR adds the API support for Tag system in Gravitino.

### Why are the changes needed?

This is the first step to add a tag system.

Fix: apache#3460 

### Does this PR introduce _any_ user-facing change?

Yes.

### How was this patch tested?

No. Test will be added later when implementing the logic.
  • Loading branch information
jerryshao authored May 23, 2024
1 parent ee6b9db commit 29a3d62
Show file tree
Hide file tree
Showing 10 changed files with 674 additions and 104 deletions.
79 changes: 79 additions & 0 deletions api/src/main/java/com/datastrato/gravitino/MetadataObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/

package com.datastrato.gravitino;

import com.datastrato.gravitino.annotation.Unstable;
import javax.annotation.Nullable;

/**
* The MetadataObject is the basic unit of the Gravitino system. It represents the metadata object
* in the Gravitino system. The object can be a metalake, catalog, schema, table, topic, etc.
*/
@Unstable
public interface MetadataObject {
/**
* The type of object in the Gravitino system. Every type will map one kind of the entity of the
* underlying system.
*/
enum Type {
/**
* A metalake is a concept of tenant. It means an organization. A metalake contains many data
* sources.
*/
METALAKE,
/**
* A catalog is a collection of metadata from a specific metadata source, like Apache Hive
* catalog, Apache Iceberg catalog, JDBC catalog, etc.
*/
CATALOG,
/**
* A schema is a sub collection of the catalog. The schema can contain filesets, tables, topics,
* etc.
*/
SCHEMA,
/** A fileset is mapped to a directory on a file system like HDFS, S3, ADLS, GCS, etc. */
FILESET,
/** A table is mapped the table of relational data sources like Apache Hive, MySQL, etc. */
TABLE,
/**
* A topic is mapped the topic of messaging data sources like Apache Kafka, Apache Pulsar, etc.
*/
TOPIC,
/** A column is a sub-collection of the table that represents a group of same type data. */
COLUMN
}

/**
* The parent full name of the object. If the object doesn't have parent, this method will return
* null.
*
* @return The parent full name of the object.
*/
@Nullable
String parent();

/**
* The name of th object.
*
* @return The name of the object.
*/
String name();

/**
* The full name of th object. Full name will be separated by "." to represent a string identifier
* of the object, like catalog, catalog.table, etc.
*
* @return The name of the object.
*/
String fullName();

/**
* The type of the object.
*
* @return The type of the object.
*/
Type type();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*/
package com.datastrato.gravitino.authorization;

import com.datastrato.gravitino.MetadataObject;
import com.datastrato.gravitino.annotation.Unstable;
import java.util.List;
import javax.annotation.Nullable;

/**
* The securable object is the entity which access can be granted. Unless allowed by a grant, access
Expand Down Expand Up @@ -41,38 +41,7 @@
* can use add `read table` privilege for `catalog1.schema1` directly
*/
@Unstable
public interface SecurableObject {

/**
* The parent full name of securable object. If the securable object doesn't have parent, this
* method will return null.
*
* @return The parent full name of securable object.
*/
@Nullable
String parent();

/**
* The name of th securable object.
*
* @return The name of the securable object.
*/
String name();

/**
* The full name of th securable object. If the parent isn't null, the full name will join the
* parent full name and the name with `.`, otherwise will return the name.
*
* @return The name of the securable object.
*/
String fullName();

/**
* The type of securable object
*
* @return The type of securable object.
*/
Type type();
public interface SecurableObject extends MetadataObject {

/**
* The privileges of the securable object. For example: If the securable object is a table, the
Expand All @@ -82,34 +51,4 @@ public interface SecurableObject {
* @return The privileges of the role.
*/
List<Privilege> privileges();

/**
* The type of securable object in the Gravitino system. Every type will map one kind of the
* entity of the underlying system.
*/
enum Type {
/**
* A catalog is a collection of metadata from a specific metadata source, like Apache Hive
* catalog, Apache Iceberg catalog, JDBC catalog, etc.
*/
CATALOG,
/**
* A schema is a sub collection of the catalog. The schema can contain filesets, tables, topics,
* etc.
*/
SCHEMA,
/** A fileset is mapped to a directory on a file system like HDFS, S3, ADLS, GCS, etc. */
FILESET,
/** A table is mapped the table of relational data sources like Apache Hive, MySQL, etc. */
TABLE,
/**
* A topic is mapped the topic of messaging data sources like Apache Kafka, Apache Pulsar, etc.
*/
TOPIC,
/**
* A metalake is a concept of tenant. It means an organization. A metalake contains many data
* sources.
*/
METALAKE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
*/
package com.datastrato.gravitino.authorization;

import com.datastrato.gravitino.MetadataObject;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;

/** The helper class for {@link SecurableObject}. */
Expand Down Expand Up @@ -139,7 +141,11 @@ public String name() {

@Override
public String fullName() {
return toString();
if (parent != null) {
return parent + "." + name;
} else {
return name;
}
}

@Override
Expand All @@ -159,11 +165,18 @@ public int hashCode() {

@Override
public String toString() {
if (parent != null) {
return parent + "." + name;
} else {
return name;
}
String privilegesStr =
privileges.stream()
.map(p -> "[" + p.simpleString() + "]")
.collect(Collectors.joining(","));

return "SecurableObject: [fullName="
+ fullName()
+ "], [type="
+ type
+ "], [privileges="
+ privilegesStr
+ "]";
}

@Override
Expand All @@ -189,9 +202,9 @@ public boolean equals(Object other) {
* @return The created {@link SecurableObject}
*/
public static SecurableObject parse(
String fullName, SecurableObject.Type type, List<Privilege> privileges) {
String fullName, MetadataObject.Type type, List<Privilege> privileges) {
if ("*".equals(fullName)) {
if (type != SecurableObject.Type.METALAKE) {
if (type != MetadataObject.Type.METALAKE) {
throw new IllegalArgumentException("If securable object isn't metalake, it can't be `*`");
}
return SecurableObjects.ofAllMetalakes(privileges);
Expand All @@ -215,7 +228,7 @@ public static SecurableObject parse(
* @return The created {@link SecurableObject}
*/
static SecurableObject of(
SecurableObject.Type type, List<String> names, List<Privilege> privileges) {
MetadataObject.Type type, List<String> names, List<Privilege> privileges) {
if (names == null) {
throw new IllegalArgumentException("Cannot create a securable object with null names");
}
Expand All @@ -234,8 +247,8 @@ static SecurableObject of(
}

if (names.size() == 1
&& type != SecurableObject.Type.CATALOG
&& type != SecurableObject.Type.METALAKE) {
&& type != MetadataObject.Type.CATALOG
&& type != MetadataObject.Type.METALAKE) {
throw new IllegalArgumentException(
"If the length of names is 1, it must be the CATALOG or METALAKE type");
}
Expand All @@ -245,9 +258,9 @@ static SecurableObject of(
}

if (names.size() == 3
&& type != SecurableObject.Type.FILESET
&& type != SecurableObject.Type.TABLE
&& type != SecurableObject.Type.TOPIC) {
&& type != MetadataObject.Type.FILESET
&& type != MetadataObject.Type.TABLE
&& type != MetadataObject.Type.TOPIC) {
throw new IllegalArgumentException(
"If the length of names is 3, it must be FILESET, TABLE or TOPIC");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/

package com.datastrato.gravitino.exceptions;

import com.google.errorprone.annotations.FormatMethod;

/** Exception thrown when a tag with specified name is not existed. */
public class NoSuchTagException extends NotFoundException {

/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message.
* @param args the arguments to the message.
*/
@FormatMethod
public NoSuchTagException(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 NoSuchTagException(Throwable cause, String message, Object... args) {
super(cause, message, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/

package com.datastrato.gravitino.exceptions;

import com.google.errorprone.annotations.FormatMethod;

/** Exception thrown when a tag with specified name already exists. */
public class TagAlreadyExistsException extends AlreadyExistsException {

/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message.
* @param args the arguments to the message.
*/
@FormatMethod
public TagAlreadyExistsException(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 TagAlreadyExistsException(Throwable cause, String message, Object... args) {
super(cause, message, args);
}
}
49 changes: 49 additions & 0 deletions api/src/main/java/com/datastrato/gravitino/tag/SupportsTags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 Datastrato Pvt Ltd.
* This software is licensed under the Apache License version 2.
*/

package com.datastrato.gravitino.tag;

import com.datastrato.gravitino.annotation.Evolving;
import com.datastrato.gravitino.exceptions.NoSuchTagException;

/**
* Interface for supporting getting or associate tags to objects. This interface will be mixed with
* metadata objects to provide tag operations.
*/
@Evolving
public interface SupportsTags {

/**
* List all the tag names for the specific object.
*
* @return The list of tag names.
*/
String[] listTags();

/**
* List all the tags with details for the specific object.
*
* @return The list of tags.
*/
Tag[] listTagsInfo();

/**
* Get a tag by its name for the specific object.
*
* @param name The name of the tag.
* @return The tag.
*/
Tag getTag(String name) throws NoSuchTagException;

/**
* Associate tags to the specific object. The tagsToAdd will be added to the object, and the
* tagsToRemove will be removed from the object.
*
* @param tagsToAdd The arrays of tag name to be added to the object.
* @param tagsToRemove The array of tag name to be removed from the object.
* @return The array of tag names that are associated with the object.
*/
String[] associateTags(String[] tagsToAdd, String[] tagsToRemove);
}
Loading

0 comments on commit 29a3d62

Please sign in to comment.