package edu.brown.graphs; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONStringer; import org.voltdb.catalog.Database; import org.voltdb.utils.NotImplementedException; import edu.brown.utils.JSONSerializable; import edu.brown.utils.JSONUtil; import edu.brown.utils.StringUtil; public abstract class AbstractGraphElement implements JSONSerializable, Comparable<AbstractGraphElement> { // private static final Logger LOG = Logger.getLogger(AbstractGraphElement.class.getName()); private Map<IGraph<?, ?>, Map<String, Object>> attributes; private Long element_id; private transient boolean enable_verbose = false; private static final AtomicLong NEXT_ELEMENT_ID = new AtomicLong(1000); public AbstractGraphElement() { // Nothing... } /** * Copies the attributes from all the graphs from another vertex into * the attribute set for this vertex * @param graph * @param copy */ public AbstractGraphElement(IGraph<?, ?> graph, AbstractGraphElement copy) { this(); if (copy != null) { for (IGraph<?, ?> copy_graph : copy.attributes.keySet()) { for (String key : copy.getAttributes(copy_graph)) { Object value = copy.getAttribute(copy_graph, key); this.setAttribute(graph, key, value); } // FOR } // FOR } } private Map<IGraph<?, ?>, Map<String, Object>> lazyAttributeAllocation() { if (this.attributes == null) { synchronized (this) { if (this.attributes == null) { this.attributes = new HashMap<IGraph<?, ?>, Map<String,Object>>(); } } // SYNCH } return (this.attributes); } @Override public int compareTo(AbstractGraphElement o) { if (o != null) { Long id0 = this.getElementId(); Long id1 = o.getElementId(); return (id0.compareTo(id1)); } return -1; } private long computeElementId() { return (NEXT_ELEMENT_ID.getAndIncrement()); } public Long getElementId() { if (this.element_id == null) { synchronized (this) { if (this.element_id == null) this.element_id = computeElementId(); } // SYNCH } return this.element_id; } public Set<String> getAttributes(IGraph<?, ?> graph) { this.lazyAttributeAllocation(); Set<String> ret = null; if (this.attributes.containsKey(graph)) { ret = this.attributes.get(graph).keySet(); } return (ret); } public Map<IGraph<?, ?>, Map<String, Object>> getAllAttributeValues() { this.lazyAttributeAllocation(); return (this.attributes); } public Map<String, Object> getAttributeValues(IGraph<?, ?> graph) { this.lazyAttributeAllocation(); return (this.attributes.get(graph)); } public boolean hasAttribute(IGraph<?, ?> graph, String key) { this.lazyAttributeAllocation(); return (this.attributes.containsKey(graph) && this.attributes.get(graph).containsKey(key)); } @SuppressWarnings("unchecked") public <T> T getAttribute(IGraph<?, ?> graph, String key) { this.lazyAttributeAllocation(); return (this.attributes.containsKey(graph) ? (T)this.attributes.get(graph).get(key) : null); } @SuppressWarnings("unchecked") public <T, E extends Enum<?>> T getAttribute(IGraph<?, ?> graph, E e) { return ((T)this.getAttribute(graph, e.name())); } public <T> void setAttribute(IGraph<?, ?> graph, String key, T value) { this.lazyAttributeAllocation(); if (!this.attributes.containsKey(graph)) { this.attributes.put(graph, new HashMap<String, Object>()); } this.attributes.get(graph).put(key, value); } public <T, E extends Enum<?>> void setAttribute(IGraph<?, ?> graph, E key, T value) { this.setAttribute(graph, key.name(), value); } public void copyAttributes(IGraph<?, ?> graph0, IGraph<?, ?> graph1) { this.lazyAttributeAllocation(); for (String key : this.getAttributes(graph0)) { this.setAttribute(graph1, key, this.getAttribute(graph0, key)); } // FOR } /** * Enable verbose output when toString() is called * @param enableVerbose */ public void setVerbose(boolean enableVerbose) { this.enable_verbose = enableVerbose; } public boolean getVerbose() { return (this.enable_verbose); } public String debug() { this.lazyAttributeAllocation(); String ret = this.getClass().getSimpleName() + "{" + this.toString() + "}\n"; for (IGraph<?, ?> graph : this.attributes.keySet()) { ret += this.debug(graph); } // FOR return (ret); } public String debug(IGraph<?, ?> graph) { this.lazyAttributeAllocation(); String ret = StringUtil.SPACER + graph + "\n"; for (String key : this.attributes.get(graph).keySet()) { ret += StringUtil.SPACER + StringUtil.SPACER + key + ": " + this.attributes.get(graph).get(key) + "\n"; } // FOR return (ret); } // ---------------------------------------------------------------------------- // SERIALIZATION METHODS // ---------------------------------------------------------------------------- protected abstract void toJSONStringImpl(JSONStringer stringer) throws JSONException; protected abstract void fromJSONObjectImpl(JSONObject object, Database catalog_db) throws JSONException; @Override public String toJSONString() { return (JSONUtil.toJSONString(this)); } @Override public void toJSON(JSONStringer stringer) throws JSONException { this.toJSONStringImpl(stringer); stringer.key("ELEMENT_ID").value(this.getElementId()); } @Override public void load(File input_path, Database catalog_db) throws IOException { throw new NotImplementedException("Cannot load a " + this.getClass().getSimpleName() + " from a file"); } @Override public void save(File output_path) throws IOException { throw new NotImplementedException("Cannot save a " + this.getClass().getSimpleName() + " to a file"); } /** * For a given Enum, write out the contents of the corresponding field to the JSONObject * We assume that the given object has matching fields that correspond to the Enum members, except * that their names are lower case. * @param <E> * @param stringer * @param members * @throws JSONException */ protected <E extends Enum<?>> void fieldsToJSONString(JSONStringer stringer, Class<? extends AbstractGraphElement> base_class, E members[]) throws JSONException { JSONUtil.fieldsToJSON(stringer, this, base_class, members); } @Override public void fromJSON(JSONObject object, Database catalog_db) throws JSONException { this.element_id = object.getLong("ELEMENT_ID"); NEXT_ELEMENT_ID.set(this.element_id); this.fromJSONObjectImpl(object, catalog_db); } /** * For the given enum, load in the values from the JSON object into the current object * @param <E> * @param object * @param catalog_db * @param members * @throws JSONException */ protected <E extends Enum<?>> void fieldsFromJSONObject(JSONObject object, Database catalog_db, Class<? extends AbstractGraphElement> base_class, E members[]) throws JSONException { JSONUtil.fieldsFromJSON(object, catalog_db, this, base_class, members); } }