Skip to content

Commit

Permalink
[#3914] feat(server): Add REST server interface for Tag System (#3943)
Browse files Browse the repository at this point in the history
### What changes were proposed in this pull request?

This PR proposes to add REST server interface for Tag System

### Why are the changes needed?

This is a part of work for Tag system.

Fix: #3914 

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

Yes

### How was this patch tested?

UTs added.

---------

Co-authored-by: bknbkn <[email protected]>
Co-authored-by: Dev Parikh <[email protected]>
Co-authored-by: roryqi <[email protected]>
Co-authored-by: JinsYin <[email protected]>
Co-authored-by: rqyin <[email protected]>
  • Loading branch information
6 people authored Jul 22, 2024
1 parent 529429e commit 71e6651
Show file tree
Hide file tree
Showing 27 changed files with 3,093 additions and 9 deletions.
41 changes: 41 additions & 0 deletions api/src/main/java/org/apache/gravitino/MetadataObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import java.util.List;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;

/** The helper class for {@link MetadataObject}. */
Expand Down Expand Up @@ -94,6 +95,46 @@ public static MetadataObject of(List<String> names, MetadataObject.Type type) {
return new MetadataObjectImpl(getParentFullName(names), getLastName(names), type);
}

/**
* Get the parent metadata object of the given metadata object.
*
* @param object The metadata object
* @return The parent metadata object if it exists, otherwise null
*/
@Nullable
public static MetadataObject parent(MetadataObject object) {
if (object == null) {
return null;
}

// Return null if the object is the root object
if (object.type() == MetadataObject.Type.METALAKE
|| object.type() == MetadataObject.Type.CATALOG) {
return null;
}

MetadataObject.Type parentType;
switch (object.type()) {
case COLUMN:
parentType = MetadataObject.Type.TABLE;
break;
case TABLE:
case FILESET:
case TOPIC:
parentType = MetadataObject.Type.SCHEMA;
break;
case SCHEMA:
parentType = MetadataObject.Type.CATALOG;
break;

default:
throw new IllegalArgumentException(
"Unexpected to reach here for metadata object type: " + object.type());
}

return parse(object.parent(), parentType);
}

/**
* Parse the metadata object with the given full name and type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.EnumFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

/**
Expand All @@ -39,7 +40,8 @@ private static class ObjectMapperHolder {
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build()
.registerModule(new JavaTimeModule());
.registerModule(new JavaTimeModule())
.registerModule(new Jdk8Module());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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.gravitino.dto.requests;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.rest.RESTRequest;

/** Represents a request to create a tag. */
@Getter
@EqualsAndHashCode
@ToString
public class TagCreateRequest implements RESTRequest {

@JsonProperty("name")
private final String name;

@JsonProperty("comment")
@Nullable
private final String comment;

@JsonProperty("properties")
@Nullable
private Map<String, String> properties;

/**
* Creates a new TagCreateRequest.
*
* @param name The name of the tag.
* @param comment The comment of the tag.
* @param properties The properties of the tag.
*/
public TagCreateRequest(String name, String comment, Map<String, String> properties) {
this.name = name;
this.comment = comment;
this.properties = properties;
}

/** This is the constructor that is used by Jackson deserializer */
public TagCreateRequest() {
this(null, null, null);
}

/**
* Validates the request.
*
* @throws IllegalArgumentException If the request is invalid, this exception is thrown.
*/
@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(
StringUtils.isNotBlank(name), "\"name\" is required and cannot be empty");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* 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.gravitino.dto.requests;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.google.common.base.Preconditions;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.rest.RESTRequest;
import org.apache.gravitino.tag.TagChange;

/** Represents a request to update a tag. */
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = TagUpdateRequest.RenameTagRequest.class, name = "rename"),
@JsonSubTypes.Type(
value = TagUpdateRequest.UpdateTagCommentRequest.class,
name = "updateComment"),
@JsonSubTypes.Type(value = TagUpdateRequest.SetTagPropertyRequest.class, name = "setProperty"),
@JsonSubTypes.Type(
value = TagUpdateRequest.RemoveTagPropertyRequest.class,
name = "removeProperty")
})
public interface TagUpdateRequest extends RESTRequest {

/**
* Returns the tag change.
*
* @return the tag change.
*/
TagChange tagChange();

/** The tag update request for renaming a tag. */
@EqualsAndHashCode
@ToString
class RenameTagRequest implements TagUpdateRequest {

@Getter
@JsonProperty("newName")
private final String newName;

/**
* Creates a new RenameTagRequest.
*
* @param newName The new name of the tag.
*/
public RenameTagRequest(String newName) {
this.newName = newName;
}

/** This is the constructor that is used by Jackson deserializer */
public RenameTagRequest() {
this.newName = null;
}

@Override
public TagChange tagChange() {
return TagChange.rename(newName);
}

@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(StringUtils.isNotBlank(newName), "\"newName\" must not be blank");
}
}

/** The tag update request for updating a tag comment. */
@EqualsAndHashCode
@ToString
class UpdateTagCommentRequest implements TagUpdateRequest {

@Getter
@JsonProperty("newComment")
private final String newComment;

/**
* Creates a new UpdateTagCommentRequest.
*
* @param newComment The new comment of the tag.
*/
public UpdateTagCommentRequest(String newComment) {
this.newComment = newComment;
}

/** This is the constructor that is used by Jackson deserializer */
public UpdateTagCommentRequest() {
this.newComment = null;
}

@Override
public TagChange tagChange() {
return TagChange.updateComment(newComment);
}

@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(
StringUtils.isNotBlank(newComment), "\"newComment\" must not be blank");
}
}

/** The tag update request for setting a tag property. */
@EqualsAndHashCode
@ToString
class SetTagPropertyRequest implements TagUpdateRequest {

@Getter
@JsonProperty("property")
private final String property;

@Getter
@JsonProperty("value")
private final String value;

/**
* Creates a new SetTagPropertyRequest.
*
* @param property The property to set.
* @param value The value of the property.
*/
public SetTagPropertyRequest(String property, String value) {
this.property = property;
this.value = value;
}

/** This is the constructor that is used by Jackson deserializer */
public SetTagPropertyRequest() {
this.property = null;
this.value = null;
}

@Override
public TagChange tagChange() {
return TagChange.setProperty(property, value);
}

@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(
StringUtils.isNotBlank(property), "\"property\" must not be blank");
Preconditions.checkArgument(StringUtils.isNotBlank(value), "\"value\" must not be blank");
}
}

/** The tag update request for removing a tag property. */
@EqualsAndHashCode
@ToString
class RemoveTagPropertyRequest implements TagUpdateRequest {

@Getter
@JsonProperty("property")
private final String property;

/**
* Creates a new RemoveTagPropertyRequest.
*
* @param property The property to remove.
*/
public RemoveTagPropertyRequest(String property) {
this.property = property;
}

/** This is the constructor that is used by Jackson deserializer */
public RemoveTagPropertyRequest() {
this.property = null;
}

@Override
public TagChange tagChange() {
return TagChange.removeProperty(property);
}

@Override
public void validate() throws IllegalArgumentException {
Preconditions.checkArgument(
StringUtils.isNotBlank(property), "\"property\" must not be blank");
}
}
}
Loading

0 comments on commit 71e6651

Please sign in to comment.