All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.metacat.common.QualifiedName Maven / Gradle / Ivy

/*
 * Copyright 2016 Netflix, Inc.
 *    Licensed 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 com.netflix.metacat.common;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.JsonNode;
import com.netflix.metacat.common.dto.PartitionDto;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * A fully qualified name that references a source of data.
 * @author amajumdar
 */
public final class QualifiedName implements Serializable {
    /**
     * Type of the connector resource.
     */
    public enum Type { CATALOG, DATABASE, TABLE, PARTITION, MVIEW }
    private final String catalogName;
    private final String databaseName;
    private final String partitionName;
    private final String tableName;
    private final String viewName;

    private String qualifiedName;
    private Map qualifiedNameMap;
    private Map parts;
    private Type type;

    private QualifiedName(@Nonnull final String catalogName,
        @Nullable final String databaseName,
        @Nullable final String tableName,
        @Nullable final String partitionName,
        @Nullable final String viewName
    ) {
        this.catalogName = standardizeRequired("catalogName", catalogName);
        this.databaseName = standardizeOptional(databaseName, true);
        this.tableName = standardizeOptional(tableName, true);
        this.partitionName = standardizeOptional(partitionName, false);
        this.viewName = standardizeOptional(viewName, true);

        if (this.databaseName.isEmpty() && (!this.tableName.isEmpty() || !this.partitionName.isEmpty())) {
            throw new IllegalStateException("databaseName is not present but tableName or partitionName are present");
        } else if (this.tableName.isEmpty() && !this.partitionName.isEmpty()) {
            throw new IllegalStateException("tableName is not present but partitionName is present");
        }

        if (!this.viewName.isEmpty()) {
            type = Type.MVIEW;
        } else if (!this.partitionName.isEmpty()) {
            type = Type.PARTITION;
        } else if (!this.tableName.isEmpty()) {
            type = Type.TABLE;
        } else if (!this.databaseName.isEmpty()) {
            type = Type.DATABASE;
        } else {
            type = Type.CATALOG;
        }
    }

    /**
     * Creates the name from the json.
     * @param node json node
     * @return qualified name
     */
    @JsonCreator
    public static QualifiedName fromJson(final JsonNode node) {
        final JsonNode catalogNameNode = node.path("catalogName");
        if (catalogNameNode.isMissingNode() || catalogNameNode.isNull() || !catalogNameNode.isTextual()) {
            // If catalogName is not present try to load from the qualifiedName node instead
            final JsonNode nameNode = node.path("qualifiedName");
            if (!nameNode.isNull() && nameNode.isTextual()) {
                return fromString(nameNode.asText(), false);
            } else {
                // if neither are available throw an exception
                throw new IllegalStateException("Node '" + node + "' is missing catalogName");
            }
        }
        final String catalogName = catalogNameNode.asText();
        final JsonNode databaseNameNode = node.path("databaseName");
        String databaseName = null;
        if (databaseNameNode != null) {
            databaseName = databaseNameNode.asText();
        }
        final JsonNode tableNameNode = node.path("tableName");
        String tableName = null;
        if (tableNameNode != null) {
            tableName = tableNameNode.asText();
        }
        final JsonNode partitionNameNode = node.path("partitionName");
        String partitionName = null;
        if (partitionNameNode != null) {
            partitionName = partitionNameNode.asText();
        }
        final JsonNode viewNameNode = node.path("viewName");
        String viewName = null;
        if (viewNameNode != null) {
            viewName = viewNameNode.asText();
        }
        return new QualifiedName(catalogName, databaseName, tableName, partitionName, viewName);
    }

    /**
     * Creates the qualified name from text.
     * @param s name
     * @return qualified name
     */
    public static QualifiedName fromString(@Nonnull final String s) {
        return fromString(s, false);
    }

    /**
     * Creates the qualified name from text.
     * @param s name
     * @param isView true if it represents a view
     * @return qualified name
     */
    public static QualifiedName fromString(@Nonnull final String s, final boolean isView) {
        //noinspection ConstantConditions
        final String name = s == null ? "" : s.trim();
        if (name.isEmpty()) {
            throw new IllegalArgumentException("passed in an empty definition name");
        }

        final String[] parts = name.split("/", 4);
        switch (parts.length) {
        case 1:
            return ofCatalog(parts[0]);
        case 2:
            return ofDatabase(parts[0], parts[1]);
        case 3:
            return ofTable(parts[0], parts[1], parts[2]);
        case 4:
            if (isView || !parts[3].contains("=")) {
                return ofView(parts[0], parts[1], parts[2], parts[3]);
            } else {
                return ofPartition(parts[0], parts[1], parts[2], parts[3]);
            }
        default:
            throw new IllegalArgumentException("Unable to convert '" + s + "' into a qualifiedDefinition");
        }
    }

    /**
     * Creates the qualified name representing a catalog.
     * @param catalogName catalog name
     * @return qualified name
     */
    public static QualifiedName ofCatalog(
        @Nonnull final String catalogName) {
        return new QualifiedName(catalogName, null, null, null, null);
    }

    /**
     * Creates the qualified name representing a database.
     * @param catalogName catalog name
     * @param databaseName database name
     * @return qualified name
     */
    public static QualifiedName ofDatabase(
        @Nonnull final String catalogName,
        @Nonnull final String databaseName) {
        return new QualifiedName(catalogName, databaseName, null, null, null);
    }

    /**
     * Creates the qualified name representing a view.
     * @param catalogName catalog name
     * @param databaseName database name
     * @param tableName table name
     * @param viewName view name
     * @return qualified name
     */
    public static QualifiedName ofView(
        @Nonnull final String catalogName,
        @Nonnull final String databaseName,
        @Nonnull final String tableName,
        @Nonnull final String viewName) {
        return new QualifiedName(catalogName, databaseName, tableName, null, viewName);
    }

    /**
     * Creates the qualified name representing a partition.
     * @param tableName table name
     * @param partitionDto partition
     * @return qualified name
     */
    public static QualifiedName ofPartition(
        @Nonnull final QualifiedName tableName,
        @Nonnull final PartitionDto partitionDto) {
        return ofPartition(
            tableName.catalogName,
            tableName.databaseName,
            tableName.tableName,
            partitionDto.getName().getPartitionName()
        );
    }

    /**
     * Creates the qualified name representing a partition.
     * @param catalogName catalog name
     * @param databaseName database name
     * @param tableName table name
     * @param partitionName partition name
     * @return qualified name
     */
    public static QualifiedName ofPartition(
        @Nonnull final String catalogName,
        @Nonnull final String databaseName,
        @Nonnull final String tableName,
        @Nonnull final String partitionName) {
        return new QualifiedName(catalogName, databaseName, tableName, partitionName, null);
    }

    /**
     * Creates the qualified name representing a table.
     * @param catalogName catalog name
     * @param databaseName database name
     * @param tableName table name
     * @return qualified name
     */
    public static QualifiedName ofTable(
        @Nonnull final String catalogName,
        @Nonnull final String databaseName,
        @Nonnull final String tableName) {
        return new QualifiedName(catalogName, databaseName, tableName, null, null);
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof QualifiedName)) {
            return false;
        }
        final QualifiedName that = (QualifiedName) o;
        return Objects.equals(catalogName, that.catalogName)
            && Objects.equals(databaseName, that.databaseName)
            && Objects.equals(partitionName, that.partitionName)
            && Objects.equals(tableName, that.tableName)
            && Objects.equals(viewName, that.viewName);
    }

    public String getCatalogName() {
        return catalogName;
    }

    /**
     * Returns the database name.
     * @return database name
     */
    public String getDatabaseName() {
        if (databaseName.isEmpty()) {
            throw new IllegalStateException("This is not a database definition");
        }
        return databaseName;
    }

    /**
     * Returns the partition name.
     * @return partition name
     */
    public String getPartitionName() {
        if (partitionName.isEmpty()) {
            throw new IllegalStateException("This is not a partition definition");
        }
        return partitionName;
    }

    /**
     * Returns the table name.
     * @return table name
     */
    public String getTableName() {
        if (tableName.isEmpty()) {
            throw new IllegalStateException("This is not a table definition");
        }
        return tableName;
    }

    @Override
    public int hashCode() {
        return Objects.hash(catalogName, databaseName, partitionName, tableName, viewName);
    }

    public boolean isCatalogDefinition() {
        return !catalogName.isEmpty();
    }

    public boolean isDatabaseDefinition() {
        return !databaseName.isEmpty();
    }

    public boolean isPartitionDefinition() {
        return !partitionName.isEmpty();
    }

    public boolean isTableDefinition() {
        return !tableName.isEmpty();
    }

    private String standardizeOptional(final String value, final boolean forceLowerCase) {
        if (value == null) {
            return "";
        } else {
            String returnValue = value.trim();
            if (forceLowerCase) {
                returnValue = returnValue.toLowerCase();
            }
            return returnValue;
        }
    }

    private String standardizeRequired(final String name, final String value) {
        if (value == null) {
            throw new IllegalStateException(name + " cannot be null");
        }

        final String returnValue = value.trim();
        if (returnValue.isEmpty()) {
            throw new IllegalStateException(name + " cannot be an empty string");
        }

        return returnValue.toLowerCase();
    }

    /**
     * Returns the qualified name in the JSON format.
     * @return qualified name
     */
    @JsonValue
    public Map toJson() {
        if (qualifiedNameMap == null) {
            final Map map = new HashMap<>(5);
            map.put("qualifiedName", toString());
            map.put("catalogName", catalogName);

            if (!databaseName.isEmpty()) {
                map.put("databaseName", databaseName);
            }

            if (!tableName.isEmpty()) {
                map.put("tableName", tableName);
            }

            if (!partitionName.isEmpty()) {
                map.put("partitionName", partitionName);
            }

            if (!viewName.isEmpty()) {
                map.put("viewName", viewName);
            }

            qualifiedNameMap = map;
        }

        return qualifiedNameMap;
    }

    /**
     * Returns the qualified name in parts.
     * @return parts of the qualified name as a Map
     */
    public Map parts() {
        if (parts == null) {
            final Map map = new HashMap<>(4);
            map.put("catalogName", catalogName);

            if (!databaseName.isEmpty()) {
                map.put("databaseName", databaseName);
            }

            if (!tableName.isEmpty()) {
                map.put("tableName", tableName);
            }

            if (!partitionName.isEmpty()) {
                map.put("partitionName", partitionName);
            }

            if (!viewName.isEmpty()) {
                map.put("viewName", viewName);
            }

            parts = map;
        }

        return parts;
    }

    public boolean isViewDefinition() {
        return !viewName.isEmpty();
    }

    @Override
    public String toString() {
        if (qualifiedName == null) {
            final StringBuilder sb = new StringBuilder(catalogName);

            if (!databaseName.isEmpty()) {
                sb.append('/');
                sb.append(databaseName);
            }

            if (!tableName.isEmpty()) {
                sb.append('/');
                sb.append(tableName);
            }

            if (!partitionName.isEmpty()) {
                sb.append('/');
                sb.append(partitionName);
            }

            if (!viewName.isEmpty()) {
                sb.append('/');
                sb.append(viewName);
            }
            qualifiedName = sb.toString();
        }

        return qualifiedName;
    }

    /**
     * Creates a wild card string format of the qualified name.
     * @param sourceName catalog/source name
     * @param databaseName database name
     * @param tableName table name
     * @return wild card string format of the qualified name
     */
    public static String toWildCardString(final String sourceName, final String databaseName, final String tableName) {
        if (sourceName == null && databaseName == null && tableName == null) {
            return null;
        }
        final StringBuilder builder = new StringBuilder();
        if (sourceName != null) {
            builder.append(sourceName);
        } else {
            builder.append('%');
        }
        if (databaseName != null) {
            builder.append('/').append(databaseName);
        } else {
            builder.append("/%");
        }
        if (tableName != null) {
            builder.append('/').append(tableName);
        } else {
            builder.append("/%");
        }
        builder.append('%');
        return builder.toString();
    }

    public String getViewName() {
        return viewName;
    }

    public Type getType() {
        return type;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy