package com.collabinate.server.engine; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Set; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Element; import com.tinkerpop.blueprints.Features; import com.tinkerpop.blueprints.Graph; import com.tinkerpop.blueprints.GraphQuery; import com.tinkerpop.blueprints.KeyIndexableGraph; import com.tinkerpop.blueprints.Parameter; import com.tinkerpop.blueprints.TransactionalGraph; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.blueprints.util.io.graphml.GraphMLReader; import com.tinkerpop.blueprints.util.io.graphml.GraphMLWriter; import com.tinkerpop.blueprints.util.wrappers.id.IdGraph; /** * Wrapper for the graph storage used by the engine classes. Ensures that the * graph is an ID graph and is key indexable. Also enables auto committing * transactions when calling commit. * * @author mafuba * */ public class CollabinateGraph implements KeyIndexableGraph { /** * The underlying graph implementation. */ private KeyIndexableGraph baseGraph; /** * The graph that allows IDs. */ private KeyIndexableGraph graph; /** * Whether the graph should commit transactions. */ private boolean allowCommits = true; /** * Whether the graph supports transactions. */ private boolean supportsTransactions = false; /** * Creates the internally used graph while maintaining a reference to the * base graph. * * @param baseGraph The base graph to maintain a reference to. */ public CollabinateGraph(KeyIndexableGraph baseGraph) { if (null == baseGraph) { throw new IllegalArgumentException("baseGraph must not be null"); } this.baseGraph = baseGraph; // ensure we can provide IDs to the graph KeyIndexableGraph idGraph; if (baseGraph.getFeatures().ignoresSuppliedIds) idGraph = new IdGraph<KeyIndexableGraph>(baseGraph, true, false); else idGraph = baseGraph; this.graph = idGraph; supportsTransactions = graph.getFeatures().supportsTransactions; } /** * Sets whether the graph should commit transactions. * * @param allowCommits The setting for whether the graph allows * transactions to be committed. True by default. */ public void setAllowCommits(boolean allowCommits) { this.allowCommits = allowCommits; } /** * Causes the graph database to commit the current transaction, if allow * commits is true. */ public void commit() { if (allowCommits && supportsTransactions) { ((TransactionalGraph)graph).commit(); } } /** * Outputs the graph to GraphML. * * @param graph The graph to export. * @return A String containing the GraphML for the database. */ public static String exportGraph(Graph graph) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { GraphMLWriter.outputGraph(graph, stream); return stream.toString(StandardCharsets.UTF_8.name()); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Outputs the graph to a GraphML file. * * @param fileName The file to which the data will be written. */ public void exportGraph(String fileName) { try { GraphMLWriter writer = new GraphMLWriter(baseGraph); writer.setNormalize(true); FileOutputStream file = new FileOutputStream(fileName); writer.outputGraph(file); file.flush(); file.close(); } catch (IOException e) { e.printStackTrace(); } } /** * Outputs the graph to a stream. * * @param stream The stream to which the data will be written. */ public void exportGraph(OutputStream stream) { try { GraphMLWriter.outputGraph(baseGraph, stream); } catch (IOException e) { e.printStackTrace(); } } /** * Inputs a graph from GraphML. * * @param data A String containing the GraphML for the database. */ public void importGraph(String data) { ByteArrayInputStream stream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); try { GraphMLReader.inputGraph(graph, stream); } catch (IOException e) { e.printStackTrace(); return; } } @Override public Features getFeatures() { return graph.getFeatures(); } @Override public Vertex addVertex(Object id) { return graph.addVertex(id); } @Override public Vertex getVertex(Object id) { return graph.getVertex(id); } @Override public void removeVertex(Vertex vertex) { graph.removeVertex(vertex); } @Override public Iterable<Vertex> getVertices() { return graph.getVertices(); } @Override public Iterable<Vertex> getVertices(String key, Object value) { return graph.getVertices(key, value); } @Override public Edge addEdge(Object id, Vertex outVertex, Vertex inVertex, String label) { return graph.addEdge(id, outVertex, inVertex, label); } @Override public Edge getEdge(Object id) { return graph.getEdge(id); } @Override public void removeEdge(Edge edge) { graph.removeEdge(edge); } @Override public Iterable<Edge> getEdges() { return graph.getEdges(); } @Override public Iterable<Edge> getEdges(String key, Object value) { return graph.getEdges(key, value); } @Override public GraphQuery query() { return graph.query(); } @Override public void shutdown() { graph.shutdown(); } @Override public <T extends Element> void dropKeyIndex(String key, Class<T> elementClass) { graph.dropKeyIndex(key, elementClass); } @Override public <T extends Element> void createKeyIndex(String key, Class<T> elementClass, @SuppressWarnings("rawtypes") Parameter... indexParameters) { graph.createKeyIndex(key, elementClass, indexParameters); } @Override public <T extends Element> Set<String> getIndexedKeys(Class<T> elementClass) { return graph.getIndexedKeys(elementClass); } }