/* 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.lang.reflect.Field;
import java.util.Collection;
import java.util.Set;
/**
* 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> {
class CatalogReference<T extends CatalogType> {
T m_value = null;
String m_unresolvedPath = null;
public void setUnresolved(String path) {
// if null: value will be set to null
m_value = null;
m_unresolvedPath = path;
}
public void set(T value) {
m_value = value;
m_unresolvedPath = null;
}
@SuppressWarnings("unchecked")
synchronized T resolve() {
if (m_unresolvedPath != null) {
m_value = (T) getCatalog().getItemForPath(m_unresolvedPath);
m_unresolvedPath = null;
}
return m_value;
}
public T get() {
return m_unresolvedPath == null ? m_value : resolve();
}
public String getPath() {
if (m_unresolvedPath != null) return m_unresolvedPath;
else if (m_value != null) return m_value.getCatalogPath();
else return null;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof CatalogReference<?>) {
String myPath = getPath();
String otherPath = ((CatalogReference<?>) obj).getPath();
if (myPath == null) return otherPath == null;
return myPath.equals(otherPath);
}
return false;
}
}
String m_typename;
CatalogMap<? extends CatalogType> m_parentMap;
Integer m_relativeIndex = null;
// Annotation where additional non-runtime info can be squirreled away
// Used by the compiler report generator for now
Object m_annotation = null;
//Attachment to store expensive to materialize state
Object m_attachment = null;
/**
* Gets any annotation added to this instance.
* @return Annotation object or null.
*/
public Object getAnnotation() {
return m_annotation;
}
/**
* Sets the annotation object for this instance.
* @param annotation Annotation object or null.
*/
public void setAnnotation(Object annotation) {
m_annotation = annotation;
}
public Object getAttachment() {
return m_attachment;
}
public void setAttachment(Object attachment) {
m_attachment = attachment;
}
int getDepth() {
return m_parentMap.m_depth;
}
/**
* Get the full catalog path of this CatalogType instance
* @return The full catalog path of this CatalogType instance
*/
String getCatalogPath() {
StringBuilder sb = new StringBuilder();
getCatalogPath(sb);
return sb.toString();
}
void getCatalogPath(StringBuilder sb) {
m_parentMap.getPath(sb);
sb.append(Catalog.MAP_SEPARATOR);
sb.append(m_typename);
}
/**
* Get the name of this CatalogType instance
* @return The name of this CatalogType instance
*/
public String getTypeName() {
return m_typename;
}
/**
* Get the parent of this CatalogType instance
* @return The parent of this CatalogType instance
*/
public CatalogType getParent() {
// parent map only null for class Catalog which overrides this
assert(m_parentMap != null);
return m_parentMap.m_parent;
}
/**
* Get the root catalog object for this item
* @return The base Catalog object
*/
public Catalog getCatalog() {
return m_parentMap.m_catalog;
}
/**
* Get the index of this catalog node relative to its
* siblings
* @return The index of this CatalogType instance
*/
public int getRelativeIndex() {
if (m_relativeIndex == null) {
m_parentMap.recomputeRelativeIndexes();
}
return m_relativeIndex;
}
/**
* Get the set of field names of the fields of this CatalogType
* @return The set of field names
*/
public abstract String[] getFields();
abstract String[] getChildCollections();
/**
* 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 abstract Object getField(String field);
/**
* This is my lazy hack to avoid using reflection to instantiate records.
*/
void setBaseValues(CatalogMap<? extends CatalogType> parentMap, String name) {
if (name == null) {
throw new CatalogException("Null value where it shouldn't be.");
}
m_parentMap = parentMap;
m_typename = name;
}
abstract void initChildMaps();
@SuppressWarnings("unchecked")
CatalogMap<? extends CatalogType> getCollection(String collectionName) {
try {
return (CatalogMap<? extends CatalogType>) getField(collectionName);
}
catch (ClassCastException | NullPointerException e) {
throw new CatalogException("Collection name given isn't a collection.");
}
}
abstract void set(String field, String value);
void writeCreationCommand(StringBuilder sb) {
sb.append("add ");
m_parentMap.m_parent.getCatalogPath(sb);
sb.append(' ');
sb.append(m_parentMap.m_name);
sb.append(' ');
sb.append(m_typename);
sb.append("\n");
}
void writeCommandForField(StringBuilder sb, String field, boolean printFullPath) {
sb.append("set ");
if (printFullPath) {
getCatalogPath(sb);
sb.append(' ');
}
else {
sb.append("$PREV "); // use caching to shrink output + speed parsing
}
sb.append(field).append(' ');
Object value = getField(field);
if (value == null) {
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)
((CatalogType)value).getCatalogPath(sb);
else
throw new CatalogException("Unsupported field type '" + value + "'");
sb.append("\n");
}
void writeFieldCommands(StringBuilder sb, Set<String> whiteListFields) {
int i = 0;
for (String field : getFields()) {
if (whiteListFields == null || whiteListFields.contains(field)) {
writeCommandForField(sb, field, i == 0);
++i;
}
}
}
void writeChildCommands(StringBuilder sb) {
writeChildCommands(sb, null, null);
}
/**
* Write catalog commands of the children in the white list.
* @param whiteList A white list of CatalogType classes
*/
void writeChildCommands(StringBuilder sb, Collection<Class<? extends CatalogType> > whiteList, Set<String> whiteListFields) {
for (String childCollection : getChildCollections()) {
CatalogMap<? extends CatalogType> map = getCollection(childCollection);
if (whiteList == null || whiteList.contains(map.m_cls)) {
map.writeCommandsForMembers(sb, whiteListFields);
}
}
}
@Override
public int compareTo(CatalogType o) {
if (this == o) {
return 0;
}
// null comparands will throw an exception here:
return getCatalogPath().compareTo(o.getCatalogPath());
}
abstract void copyFields(CatalogType obj);
CatalogType deepCopy(Catalog catalog, CatalogMap<? extends CatalogType> parentMap) {
CatalogType copy = null;
try {
copy = getClass().newInstance();
}
catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
assert(parentMap.m_parent.getCatalog() == catalog);
copy.setBaseValues(parentMap, m_typename);
copy.initChildMaps();
copy.m_relativeIndex = m_relativeIndex;
copyFields(copy);
return copy;
}
/**
* Produce a more readable string representation that a simple
* hash code.
*/
@Override
public String toString() {
return (this.getClass().getSimpleName() + "{" + m_typename + "}");
}
@Override
public int hashCode()
{
int result = 1;
// Generate something reasonably unique but consistent for this element
result = 37 * result + getCatalogPath().hashCode();
result = 31 * result + m_typename.hashCode();
return result;
}
/**
* Fails an assertion if any child of this object doesn't think
* it's part of the same catalog.
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public void validate() throws IllegalArgumentException, IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
if (CatalogType.class.isAssignableFrom(field.getType())) {
CatalogType ct = (CatalogType) field.get(this);
assert(ct.getCatalog() == getCatalog()) : ct.getCatalogPath() + " has wrong catalog";
}
if (CatalogReference.class.isAssignableFrom(field.getType())) {
@SuppressWarnings("unchecked")
CatalogReference<? extends CatalogType> cr = (CatalogReference<? extends CatalogType>) field.get(this);
if (cr.m_value != null) {
assert(cr.m_value.getCatalog() == getCatalog()) : cr.m_value.getCatalogPath() + " has wrong catalog";
}
}
if (CatalogMap.class.isAssignableFrom(field.getClass())) {
@SuppressWarnings("unchecked")
CatalogMap<? extends CatalogType> cm = (CatalogMap<? extends CatalogType>) field.get(this);
for (CatalogType ct : cm) {
assert(ct.getCatalog() == getCatalog()) : ct.getCatalogPath() + " has wrong catalog";
ct.validate();
}
}
}
}
}