/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB Inc.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB 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 General Public License for more details.
*
* You should have received a copy of the GNU 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.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Set;
import edu.brown.catalog.CatalogUtil;
/**
* The base class for all objects in the Catalog. CatalogType instances all
* have a name and a path (from the root). They have fields and children.
* All fields are simple types. All children are CatalogType instances.
*
*/
public abstract class CatalogType implements Comparable<CatalogType> {
public static class UnresolvedInfo {
public String path;
}
LinkedHashMap<String, Object> m_fields = new LinkedHashMap<String, Object>();
LinkedHashMap<String, CatalogMap<? extends CatalogType>> m_childCollections = new LinkedHashMap<String, CatalogMap<? extends CatalogType>>();
String m_path;
String m_typename;
CatalogType m_parent;
CatalogMap<? extends CatalogType> m_parentMap;
Catalog m_catalog;
int m_relativeIndex;
int m_subTreeVersion;
int m_nodeVersion;
private transient String m_fullName = null;
private transient String m_toString = null;
private transient int m_num_fields = 0;
private transient Class<? extends CatalogType> m_class = null;
/**
* Add a field and update the count for the number of fields
* @param key
* @param val
*/
protected synchronized final void addField(String key, Object val) {
this.m_fields.put(key, val);
this.m_num_fields++;
}
/**
* Get the parent of this CatalogType instance
* @return The parent of this CatalogType instance
*/
public String getPath() {
return m_path;
}
/**
* Get the parent of this CatalogType instance
* @return The name of this CatalogType instance
*/
public String getTypeName() {
return m_typename;
}
public String getName() {
return this.getTypeName();
}
/**
* Get the parent of this CatalogType instance
* @return The parent of this CatalogType instance
*/
@SuppressWarnings("unchecked")
public <T extends CatalogType> T getParent() {
return (T)m_parent;
}
/**
* Get the root catalog object for this item
* @return The base Catalog object
*/
public Catalog getCatalog() {
return m_catalog;
}
/**
* Get the index of this catalog node relative to its
* siblings
* @return The index of this CatalogType instance
*/
public int getRelativeIndex() {
return m_relativeIndex;
}
public int getNodeVersion() {
return m_nodeVersion;
}
public int getSubTreeVersion() {
return m_subTreeVersion;
}
/**
* Get the set of field names of the fields of this CatalogType
* @return The set of field names
*/
public Set<String> getFields() {
return m_fields.keySet();
}
/**
* Get the value of a field knowing only the name of the field
* @param field The name of the field being requested
* @return The field requested or null
*/
public Object getField(String field) {
Object ret = null;
if (m_fields.containsKey(field)) {
ret = m_fields.get(field);
if (ret instanceof UnresolvedInfo) {
return resolve(field, ((UnresolvedInfo) ret).path);
}
}
return ret;
}
CatalogType resolve(String field, String path) {
CatalogType retval = m_catalog.getItemForRef(path);
m_fields.put(field, retval);
return retval;
}
/**
* This should only ever be called from CatalogMap.add(); it's my lazy hack
* to avoid using reflection to instantiate records.
*/
void setBaseValues(Catalog catalog, CatalogType parent, String path, String name) {
if ((name == null) || (catalog == null)) {
throw new CatalogException("Null value where it shouldn't be.");
}
m_catalog = catalog;
m_parent = parent;
m_path = path;
m_typename = name;
m_subTreeVersion = m_catalog.m_currentCatalogVersion;
m_nodeVersion = m_catalog.m_currentCatalogVersion;
catalog.registerGlobally(this);
}
public abstract void update();
public Set<String> getChildFields() {
return (m_childCollections.keySet());
}
CatalogType addChild(String collectionName, String childName) {
CatalogMap<? extends CatalogType> map = m_childCollections.get(collectionName);
if (map == null)
throw new CatalogException("No collection for name");
return map.add(childName);
}
public CatalogType getChild(String collectionName, String childName) {
CatalogMap<? extends CatalogType> map = m_childCollections.get(collectionName);
if (map == null)
return null;
return map.get(childName);
}
public CatalogMap<? extends CatalogType> getChildren(String collectionName) {
return (m_childCollections.get(collectionName));
}
public void set(String field, String value) {
if ((field == null) || (value == null)) {
throw new CatalogException("Null value where it shouldn't be.");
}
if (m_fields.containsKey(field) == false)
throw new CatalogException("Unexpected field name '" + field + "' for " + this);
Object current = m_fields.get(field);
value = value.trim();
// handle refs
if (value.startsWith("/")) {
UnresolvedInfo uinfo = new UnresolvedInfo();
uinfo.path = value;
m_fields.put(field, uinfo);
}
// null refs
else if (value.startsWith("null")) {
m_fields.put(field, null);
}
// handle booleans
else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
if (current.getClass() != Boolean.class)
throw new CatalogException("Unexpected type for field '" + field + "'.");
m_fields.put(field, Boolean.parseBoolean(value));
}
// handle strings
else if ((value.startsWith("\"") && value.endsWith("\"")) ||
(value.startsWith("'") && value.endsWith("'"))) {
if (current.getClass() != String.class)
throw new CatalogException("Unexpected type for field.");
value = value.substring(1, value.length() - 1);
m_fields.put(field, value);
}
// handle ints
else {
boolean isint = value.length() > 0;
for (int i = 0; i < value.length(); i++) {
if ((i == 0) && (value.length() > 1) && (value.charAt(i) == '-'))
continue;
if (!Character.isDigit(value.charAt(i)))
isint = false;
}
if (isint) {
if (current.getClass() != Integer.class)
throw new CatalogException("Unexpected type for field.");
int intValue = Integer.parseInt(value);
m_fields.put(field, intValue);
}
// error
else {
throw new CatalogException("Unexpected non-digit character in '" + value + "' for field '" + field + "'");
}
}
update();
updateVersioning();
}
void delete(String collectionName, String childName) {
if ((collectionName == null) || (childName == null)) {
throw new CatalogException("Null value where it shouldn't be.");
}
if (m_childCollections.containsKey(collectionName) == false)
throw new CatalogException("Unexpected collection name '" + collectionName + "' for " + this);
CatalogMap<? extends CatalogType> collection = m_childCollections.get(collectionName);
collection.delete(childName);
}
void updateVersioning() {
if (m_nodeVersion != m_catalog.m_currentCatalogVersion) {
m_nodeVersion = m_catalog.m_currentCatalogVersion;
updateSubTreeVersion();
}
}
void updateSubTreeVersion() {
if (m_subTreeVersion != m_catalog.m_currentCatalogVersion) {
m_subTreeVersion = m_catalog.m_currentCatalogVersion;
if (m_parentMap != null)
m_parentMap.updateVersioning();
}
}
void writeCreationCommand(StringBuilder sb) {
// skip root node command
if (m_path.equals("/"))
return;
int lastSlash = m_path.lastIndexOf("/");
String key = m_path.substring(lastSlash + 1);
String newPath = m_path.substring(0, lastSlash);
if (newPath.length() == 0)
newPath = "/";
String[] parts = key.split("\\[");
parts[1] = parts[1].substring(0, parts[1].length() - 1);
parts[1] = parts[1].trim();
sb.append("add ").append(newPath).append(" ");
sb.append(parts[0]).append(" ").append(parts[1]);
sb.append("\n");
}
void writeCommandForField(StringBuilder sb, String field) {
sb.append("set ").append(m_path).append(" ");
sb.append(field).append(" ");
Object value = m_fields.get(field);
if (value == null) {
if ((field.equals("partitioncolumn")) && (m_path.equals("/clusters[cluster]/databases[database]/procedures[delivery]")))
System.out.printf("null for field %s at path %s\n", field, getPath());
sb.append("null");
}
else if (value.getClass() == Integer.class)
sb.append(value);
else if (value.getClass() == Boolean.class)
sb.append(Boolean.toString((Boolean)value));
else if (value.getClass() == String.class)
sb.append("\"").append(value).append("\"");
else if (value instanceof CatalogType)
sb.append(((CatalogType)value).getPath());
else if (value instanceof UnresolvedInfo)
sb.append(((UnresolvedInfo)value).path);
else
throw new CatalogException("Unsupported field type '" + value + "'");
sb.append("\n");
}
void writeFieldCommands(StringBuilder sb) {
for (String field : m_fields.keySet()) {
writeCommandForField(sb, field);
}
}
void writeChildCommands(StringBuilder sb) {
for (String childCollection : m_childCollections.keySet()) {
CatalogMap<? extends CatalogType> map = m_childCollections.get(childCollection);
map.writeCommandsForMembers(sb);
}
}
public int compareTo(CatalogType o) {
if (this == o) {
return 0;
}
if (o != null) {
if (this.m_path == null || o.m_path == null) {
return (this.hashCode() - o.hashCode());
} else {
return this.m_path.compareTo(o.m_path);
}
}
return (1);
}
CatalogType deepCopy(Catalog catalog, CatalogType parent) {
CatalogType copy = null;
try {
copy = getClass().newInstance();
}
catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
copy.setBaseValues(catalog, parent, m_path, m_typename);
copy.m_relativeIndex = m_relativeIndex;
copy.m_nodeVersion = m_nodeVersion;
copy.m_subTreeVersion = m_subTreeVersion;
for (Entry<String, Object> e : m_fields.entrySet()) {
Object value = e.getValue();
if (value instanceof CatalogType) {
CatalogType type = (CatalogType) e.getValue();
UnresolvedInfo uinfo = new UnresolvedInfo();
uinfo.path = type.getPath();
value = uinfo;
}
copy.m_fields.put(e.getKey(), e.getValue());
}
for (Entry<String, CatalogMap<? extends CatalogType>> e : m_childCollections.entrySet()) {
CatalogMap<? extends CatalogType> mapCopy = copy.m_childCollections.get(e.getKey());
mapCopy.copyFrom(e.getValue());
}
copy.update();
catalog.registerGlobally(copy);
return copy;
}
/**
* Produce a more readable string representation that a simple
* hash code.
*/
@Override
public String toString() {
if (m_toString == null) {
m_toString = this.getClass().getSimpleName() + "{" + this.getTypeName() + "}";
}
return (m_toString);
}
/**
* Return the full name of this CatalogType
* @return
*/
public String fullName() {
if (m_fullName == null) {
m_fullName = CatalogUtil.getDisplayName(this, false);
}
return (m_fullName);
}
@Override
public boolean equals(Object obj) {
// It's null or not a CatalogType
if (obj == null || (obj instanceof CatalogType) == false) return (false);
if (this == obj) return (true);
CatalogType other = (CatalogType)obj;
// Are the fields the same value?
if (this.m_num_fields != other.m_num_fields) return (false);
// Quickly check whether they are at least the same class
if (this.m_class == null) this.m_class = this.getClass();
if (other.m_class == null) other.m_class = other.getClass();
if (this.m_class.equals(other.m_class) == false) return (false);
// SUPER HACK!!!
// The only thing that we care about matching up correctly by hash code will be database..
if (this instanceof Database) return (this.hashCode() == other.hashCode());
// Everything else can be about paths...
// All of this below is busted, so let's just compare paths if we can...
if (this.m_path == null) {
String name0 = this.getTypeName();
String name1 = other.getTypeName();
if (name0 != null) {
return (name0.equals(name1));
} else if (name1 != null) {
return (false);
}
return (other.m_path == null);
}
return (this.m_path.equals(other.m_path));
}
}