/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/
/* WARNING: THIS FILE IS AUTO-GENERATED
DO NOT MODIFY THIS SOURCE
ALL CHANGES MUST BE MADE IN THE CATALOG GENERATOR */
package org.voltdb.catalog;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
/**
* A safe interface to a generic map of CatalogType instances. It is safe
* because it is mostly read-only. All operations that modify the map are
* either non-public, or they are convenience methods which generate
* catalog commands and execute them on the root Catalog instance. By
* generating commands, transactional safety is easier to assure.
*
* @param <T> The subclass of CatalogType that this map will contain.
*/
public final class CatalogMap<T extends CatalogType> implements Iterable<T> {
TreeMap<String, T> m_items = null;
Class<T> m_cls;
Catalog m_catalog;
CatalogType m_parent;
String m_name;
String m_cachedPath = null;
boolean m_hasComputedOrder = false;
int m_depth;
CatalogMap(Catalog catalog, CatalogType parent, String name, Class<T> cls, int depth) {
m_catalog = catalog;
m_parent = parent;
m_name = name;
m_cls = cls;
m_depth = depth;
if (depth <= 3) {
m_cachedPath = getPath();
}
}
public String getPath() {
if (m_cachedPath != null) {
return m_cachedPath;
}
// if parent is the catalog root, don't add an extra slash to the existing one
return m_parent == m_catalog ? ("/" + m_name) : (m_parent.getCatalogPath() + "/" + m_name);
}
public void getPath(StringBuilder sb) {
if (m_cachedPath != null) {
sb.append(m_cachedPath);
return;
}
// if parent is the catalog root, don't add an extra slash to the existing one
if (m_parent != m_catalog) {
sb.append(m_parent.getCatalogPath()).append('/');
}
sb.append(m_name);
}
/**
* Get an item from the map by name
* @param name The name of the requested CatalogType instance in the map
* @return The item found in the map, or null if not found
*/
public T get(String name) {
if (m_items == null) return null;
return m_items.get(name.toUpperCase());
}
public T getExact(String name) {
if (m_items == null) return null;
return m_items.get(name);
}
/**
* Get an item from the map by name, ignoring case
* @param name The name of the requested CatalogType instance in the map
* @return The item found in the map, or null if not found
*/
public T getIgnoreCase(String name) {
if (m_items == null) return null;
return m_items.get(name.toUpperCase());
}
/**
* How many items are in the map?
* @return The number of items in the map
*/
public int size() {
if (m_items == null) return 0;
return m_items.size();
}
/**
* Is the map empty?
* @return A boolean indicating whether the map is empty
*/
public boolean isEmpty() {
if (m_items == null) return true;
return (m_items.size() == 0);
}
/**
* Get an iterator for the items in the map
* @return The iterator for the items in the map
*/
@Override
public Iterator<T> iterator() {
if (m_items == null) {
m_items = new TreeMap<String, T>();
}
return m_items.values().iterator();
}
/**
* Create a new instance of a CatalogType as a child of this map with a
* given name. Note: this just makes a catalog command and calls
* catalog.execute(..).
* @param name The name of the new instance to create, the thing to add
* @return The newly created CatalogType instance
*/
public T add(String name) {
try {
if (m_items == null) {
m_items = new TreeMap<String, T>();
}
String mapKey = name.toUpperCase();
if (m_items.containsKey(mapKey)) {
throw new CatalogException("Catalog item '" + mapKey + "' already exists for " + m_parent);
}
T x = m_cls.newInstance();
x.setBaseValues(this, name);
x.initChildMaps();
m_items.put(mapKey, x);
if (m_hasComputedOrder) {
recomputeRelativeIndexes();
}
return x;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* Remove a {@link CatalogType} object from this collection.
* @param name The name of the object to remove.
*/
public void delete(String name) {
try {
String mapKey = name.toUpperCase();
if ((m_items == null) || (m_items.containsKey(mapKey) == false)) {
throw new CatalogException("Catalog item '" + mapKey + "' doesn't exists in " + m_parent);
}
m_items.remove(mapKey);
// assign a relative index to every child item
int index = 1;
for (Entry<String, T> e : m_items.entrySet()) {
e.getValue().m_relativeIndex = index++;
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
void writeCommandsForMembers(StringBuilder sb, Set<String> whiteListFields) {
for (T type : this) {
type.writeCreationCommand(sb);
type.writeFieldCommands(sb, whiteListFields);
type.writeChildCommands(sb);
}
}
@SuppressWarnings("unchecked")
void copyFrom(CatalogMap<? extends CatalogType> catalogMap) {
CatalogMap<T> castedMap = (CatalogMap<T>) catalogMap;
m_hasComputedOrder = castedMap.m_hasComputedOrder;
if (castedMap.m_items == null) {
return;
}
if (m_items == null) {
m_items = new TreeMap<String, T>();
}
for (Entry<String, T> e : castedMap.m_items.entrySet()) {
m_items.put(e.getKey(), (T) e.getValue().deepCopy(m_catalog, this));
}
}
@Override
public boolean equals(Object obj) {
// returning false if null isn't the convention, oh well
if (obj == null)
return false;
if (obj.getClass() != getClass())
return false;
// Do the identity check
if (obj == this)
return true;
@SuppressWarnings("unchecked")
CatalogMap<T> other = (CatalogMap<T>) obj;
if (other.size() != size())
return false;
if (m_items == null) {
return (other.m_items == null) || (other.m_items.size() == 0);
}
for (Entry<String, T> e : m_items.entrySet()) {
assert(e.getValue() != null);
T type = other.get(e.getKey());
if (type == null)
return false;
if (type.equals(e.getValue()) == false)
return false;
}
return true;
}
@Override
public int hashCode() {
if (m_items == null) return 0;
// based on implementation of equals
int result = size();
for (Entry<String, T> e : m_items.entrySet()) {
String key = e.getKey();
if (key != null) {
result += key.hashCode();
}
T value = e.getValue();
if (value != null) {
result += value.hashCode();
}
}
return result;
}
void recomputeRelativeIndexes() {
if (m_items == null) return;
// assign a relative index to every child item
int index = 1;
for (Entry<String, T> e : m_items.entrySet()) {
e.getValue().m_relativeIndex = index++;
}
m_hasComputedOrder = true;
}
}