/* * 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.cassandra.schema; import java.util.HashSet; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.Iterables; import org.apache.cassandra.exceptions.ConfigurationException; import static java.lang.String.format; /** * An immutable representation of keyspace metadata (name, params, tables, types, and functions). */ public final class KeyspaceMetadata { public final String name; public final KeyspaceParams params; public final Tables tables; public final Views views; public final Types types; public final Functions functions; private KeyspaceMetadata(String name, KeyspaceParams params, Tables tables, Views views, Types types, Functions functions) { this.name = name; this.params = params; this.tables = tables; this.views = views; this.types = types; this.functions = functions; } public static KeyspaceMetadata create(String name, KeyspaceParams params) { return new KeyspaceMetadata(name, params, Tables.none(), Views.none(), Types.none(), Functions.none()); } public static KeyspaceMetadata create(String name, KeyspaceParams params, Tables tables) { return new KeyspaceMetadata(name, params, tables, Views.none(), Types.none(), Functions.none()); } public static KeyspaceMetadata create(String name, KeyspaceParams params, Tables tables, Views views, Types types, Functions functions) { return new KeyspaceMetadata(name, params, tables, views, types, functions); } public KeyspaceMetadata withSwapped(KeyspaceParams params) { return new KeyspaceMetadata(name, params, tables, views, types, functions); } public KeyspaceMetadata withSwapped(Tables regular) { return new KeyspaceMetadata(name, params, regular, views, types, functions); } public KeyspaceMetadata withSwapped(Views views) { return new KeyspaceMetadata(name, params, tables, views, types, functions); } public KeyspaceMetadata withSwapped(Types types) { return new KeyspaceMetadata(name, params, tables, views, types, functions); } public KeyspaceMetadata withSwapped(Functions functions) { return new KeyspaceMetadata(name, params, tables, views, types, functions); } public Iterable<TableMetadata> tablesAndViews() { return Iterables.concat(tables, views.metadatas()); } @Nullable public TableMetadata getTableOrViewNullable(String tableOrViewName) { ViewMetadata view = views.getNullable(tableOrViewName); return view == null ? tables.getNullable(tableOrViewName) : view.metadata; } public Set<String> existingIndexNames(String cfToExclude) { Set<String> indexNames = new HashSet<>(); for (TableMetadata table : tables) if (cfToExclude == null || !table.name.equals(cfToExclude)) for (IndexMetadata index : table.indexes) indexNames.add(index.name); return indexNames; } public Optional<TableMetadata> findIndexedTable(String indexName) { for (TableMetadata table : tablesAndViews()) if (table.indexes.has(indexName)) return Optional.of(table); return Optional.empty(); } @Override public int hashCode() { return Objects.hashCode(name, params, tables, views, functions, types); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof KeyspaceMetadata)) return false; KeyspaceMetadata other = (KeyspaceMetadata) o; return name.equals(other.name) && params.equals(other.params) && tables.equals(other.tables) && views.equals(other.views) && functions.equals(other.functions) && types.equals(other.types); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("name", name) .add("params", params) .add("tables", tables) .add("views", views) .add("functions", functions) .add("types", types) .toString(); } public void validate() { if (!SchemaConstants.isValidName(name)) { throw new ConfigurationException(format("Keyspace name must not be empty, more than %s characters long, " + "or contain non-alphanumeric-underscore characters (got \"%s\")", SchemaConstants.NAME_LENGTH, name)); } params.validate(name); tablesAndViews().forEach(TableMetadata::validate); Set<String> indexNames = new HashSet<>(); for (TableMetadata table : tables) { for (IndexMetadata index : table.indexes) { if (indexNames.contains(index.name)) throw new ConfigurationException(format("Duplicate index name %s in keyspace %s", index.name, name)); indexNames.add(index.name); } } } }