////////////////////////////////////////////////////////////////////////////////////////// // // Implementation of a simple graph client for the ArangoDB. // // Copyright triAGENS GmbH Cologne. // ////////////////////////////////////////////////////////////////////////////////////////// package com.arangodb.blueprints.client; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.arangodb.ArangoDriver; import com.arangodb.ArangoException; import com.arangodb.CursorResult; import com.arangodb.ErrorNums; import com.arangodb.blueprints.client.ArangoDBBaseQuery.Direction; import com.arangodb.blueprints.client.ArangoDBBaseQuery.QueryType; import com.arangodb.entity.DeletedEntity; import com.arangodb.entity.EdgeDefinitionEntity; import com.arangodb.entity.EdgeEntity; import com.arangodb.entity.GraphEntity; import com.arangodb.entity.ImportResultEntity; import com.arangodb.entity.IndexEntity; import com.arangodb.entity.IndexType; import com.arangodb.entity.IndexesEntity; import com.arangodb.entity.marker.VertexEntity; import com.arangodb.util.AqlQueryOptions; import com.tinkerpop.blueprints.util.StringFactory; /** * The arangodb graph client class (handles the HTTP connection to arangodb) * * @author Achim Brandt (http://www.triagens.de) * @author Johannes Gocke (http://www.triagens.de) * @author Guido Schwab (http://www.triagens.de) * @author Jan Steemann (http://www.triagens.de) */ public class ArangoDBSimpleGraphClient { /** * the configuration (contains connection parameters etc.) */ private ArangoDBConfiguration configuration; /** * the ArangoDB driver (call shutdown!) */ private ArangoDriver driver; /** * Create a simple graph client * * @param configuration * the ArangoDB configuration */ public ArangoDBSimpleGraphClient(ArangoDBConfiguration configuration) { this.configuration = configuration; configuration.init(); driver = new ArangoDriver(configuration); } /** * Shutdown the client and free resources */ public void shutdown() { // TODO driver shutdown } /** * Request the version of ArangoDB * * @return the Version number * * @throws ArangoDBException * if an error occurs */ public String getVersion() throws ArangoDBException { try { return driver.getVersion().getVersion(); } catch (ArangoException e) { throw new ArangoDBException(e); } } /** * Create a new graph * * @param name * the name of the new graph * @param vertexCollectionName * the name of the vertex collection * @param edgeCollectionName * the name of the edge collection * * @return the graph * * @throws ArangoException * if the graph could not be created */ public ArangoDBSimpleGraph createGraph(String name, String vertexCollectionName, String edgeCollectionName) throws ArangoException { EdgeDefinitionEntity ed = new EdgeDefinitionEntity(); ed.setCollection(edgeCollectionName); ed.getFrom().add(vertexCollectionName); ed.getTo().add(vertexCollectionName); List<EdgeDefinitionEntity> edgeDefinitions = new ArrayList<EdgeDefinitionEntity>(); edgeDefinitions.add(ed); GraphEntity graphEntity = driver.createGraph(name, edgeDefinitions, null, true); return new ArangoDBSimpleGraph(graphEntity, vertexCollectionName, edgeCollectionName); } /** * Get a graph by name * * @param name * the name of the new graph * * @return the graph or null if the graph was not found * * @throws ArangoException * if the graph could not be created */ public GraphEntity getGraph(String name) throws ArangoException { try { return driver.getGraph(name); } catch (ArangoException e) { if (e.getErrorNumber() == ErrorNums.ERROR_GRAPH_NOT_FOUND) { return null; } throw e; } } /** * Delete a graph by name * * @param graph * the graph * * @return true if the graph was deleted * @throws ArangoException * if the graph could be deleted */ public boolean deleteGraph(GraphEntity graph) throws ArangoException { DeletedEntity deletedEntity = driver.deleteGraph(graph.getName()); return deletedEntity.getDeleted(); } /** * Creates a ArangoDBSimpleVertex object * * @param graph * the simple graph of the query * @param id * the id (key) of the vertex * @param properties * the vertex properties * @return ArangoDBSimpleVertex the created object * @throws ArangoDBException */ public ArangoDBSimpleVertex createVertex(ArangoDBSimpleGraph graph, String id, Map<String, Object> properties) throws ArangoDBException { Map<String, Object> tmpProperties = properties; if (tmpProperties == null) { tmpProperties = new HashMap<String, Object>(); } if (id != null) { tmpProperties.put(ArangoDBSimpleVertex._KEY, id); } else if (tmpProperties.containsKey(ArangoDBSimpleVertex._KEY)) { tmpProperties.remove(ArangoDBSimpleVertex._KEY); } try { VertexEntity<Map<String, Object>> vertexEntity = driver.graphCreateVertex(graph.getName(), graph.getVertexCollection(), tmpProperties, false); tmpProperties.put(ArangoDBSimpleVertex._KEY, vertexEntity.getDocumentKey()); tmpProperties.put(ArangoDBSimpleVertex._ID, vertexEntity.getDocumentHandle()); Long l = vertexEntity.getDocumentRevision(); tmpProperties.put(ArangoDBSimpleVertex._REV, l.toString()); } catch (ArangoException e) { throw new ArangoDBException(e); } return new ArangoDBSimpleVertex(tmpProperties); } /** * Get a vertex * * @param graph * the simple graph of the new vertex * @param id * the id (key) of the vertex * * @return the vertex * * @throws ArangoDBException * if creation failed */ public ArangoDBSimpleVertex getVertex(ArangoDBSimpleGraph graph, String id) throws ArangoDBException { @SuppressWarnings("rawtypes") VertexEntity<Map> vertexEntity; try { vertexEntity = driver.graphGetVertex(graph.getName(), graph.getVertexCollection(), id, Map.class); } catch (ArangoException e) { throw new ArangoDBException(e); } @SuppressWarnings("unchecked") Map<String, Object> entity = vertexEntity.getEntity(); return new ArangoDBSimpleVertex(entity); } /** * Save a vertex * * @param graph * the simple graph of the vertex * @param vertex * the vertex to save * * @return the vertex * * @throws ArangoDBException * if creation failed */ public ArangoDBSimpleVertex saveVertex(ArangoDBSimpleGraph graph, ArangoDBSimpleVertex vertex) throws ArangoDBException { VertexEntity<Map<String, Object>> vertexEntity; try { vertexEntity = driver.graphReplaceVertex(graph.getName(), graph.getVertexCollection(), vertex.getDocumentKey(), vertex.getProperties()); } catch (ArangoException e) { throw new ArangoDBException(e); } Long l = vertexEntity.getDocumentRevision(); vertex.getProperties().put(ArangoDBSimpleVertex._REV, l.toString()); return vertex; } /** * Delete a vertex by name * * @param graph * the simple graph of the vertex * @param vertex * the vertex to save * * @return true if the vertex was deleted * * @throws ArangoDBException * if deletion failed */ public boolean deleteVertex(ArangoDBSimpleGraph graph, ArangoDBSimpleVertex vertex) throws ArangoDBException { DeletedEntity graphDeleteVertex; try { graphDeleteVertex = driver.graphDeleteVertex(graph.getName(), graph.getVertexCollection(), vertex.getDocumentKey()); } catch (ArangoException e) { throw new ArangoDBException(e); } Boolean deleted = graphDeleteVertex.getDeleted(); if (deleted) { vertex.setDeleted(); } return deleted; } /** * Create a new edge * * @param graph * the simple graph * @param id * the id (key) of the new edge * @param label * the label of the new edge * @param from * the start vertex * @param to * the end vertex * @param properties * the predefined properties of the edge * * @return the edge * * @throws ArangoDBException * if creation failed */ public ArangoDBSimpleEdge createEdge( ArangoDBSimpleGraph graph, String id, String label, ArangoDBSimpleVertex from, ArangoDBSimpleVertex to, Map<String, Object> properties) throws ArangoDBException { Map<String, Object> tmpProperties = properties; if (tmpProperties == null) { tmpProperties = new HashMap<String, Object>(); } if (id != null) { tmpProperties.put(ArangoDBSimpleEdge._KEY, id); } else if (tmpProperties.containsKey(ArangoDBSimpleEdge._KEY)) { tmpProperties.remove(ArangoDBSimpleEdge._KEY); } if (label != null) { tmpProperties.put(StringFactory.LABEL, label); } else if (tmpProperties.containsKey(StringFactory.LABEL)) { tmpProperties.remove(StringFactory.LABEL); } tmpProperties.put(ArangoDBSimpleEdge._FROM, from.getDocumentId()); tmpProperties.put(ArangoDBSimpleEdge._TO, to.getDocumentId()); EdgeEntity<Map<String, Object>> edgeEntity; try { edgeEntity = driver.graphCreateEdge(graph.getName(), graph.getEdgeCollection(), id, from.getDocumentId(), to.getDocumentId(), tmpProperties, false); } catch (ArangoException e) { throw new ArangoDBException(e); } tmpProperties.put(ArangoDBSimpleEdge._ID, edgeEntity.getDocumentHandle()); tmpProperties.put(ArangoDBSimpleEdge._KEY, edgeEntity.getDocumentKey()); Long l = edgeEntity.getDocumentRevision(); tmpProperties.put(ArangoDBSimpleVertex._REV, l.toString()); return new ArangoDBSimpleEdge(tmpProperties); } /** * Get an edge * * @param graph * the simple graph * @param id * the id (key) of the edge * * @return the edge * * @throws ArangoDBException * if creation failed */ @SuppressWarnings({ "rawtypes", "unchecked" }) public ArangoDBSimpleEdge getEdge(ArangoDBSimpleGraph graph, String id) throws ArangoDBException { EdgeEntity<Map> edgeEntity; try { edgeEntity = driver.graphGetEdge(graph.getName(), graph.getEdgeCollection(), id, Map.class); } catch (ArangoException e) { throw new ArangoDBException(e); } Map<String, Object> properties = edgeEntity.getEntity(); return new ArangoDBSimpleEdge(properties); } /** * Save an edge * * @param graph * the simple graph * @param edge * the edge * * @return the edge * * @throws ArangoDBException * if saving failed */ public ArangoDBSimpleEdge saveEdge(ArangoDBSimpleGraph graph, ArangoDBSimpleEdge edge) throws ArangoDBException { EdgeEntity<Map<String, Object>> edgeEntity; try { edgeEntity = driver.graphReplaceEdge(graph.getName(), graph.getEdgeCollection(), edge.getDocumentKey(), edge.getProperties()); } catch (ArangoException e) { throw new ArangoDBException(e); } Long l = edgeEntity.getDocumentRevision(); edge.getProperties().put(ArangoDBSimpleVertex._REV, l.toString()); return edge; } /** * Delete an edge * * @param graph * the simple graph * @param edge * the edge * * @return true if the edge was deleted * * @throws ArangoDBException * if deletion failed */ public boolean deleteEdge(ArangoDBSimpleGraph graph, ArangoDBSimpleEdge edge) throws ArangoDBException { DeletedEntity deleteEntity; try { deleteEntity = driver.graphDeleteEdge(graph.getName(), graph.getEdgeCollection(), edge.getDocumentKey()); } catch (ArangoException e) { throw new ArangoDBException(e); } Boolean deleted = deleteEntity.getDeleted(); if (deleted) { edge.setDeleted(); } return deleted; } /** * Creates vertices (bulk import) * * @param graph * The graph * @param vertices * The list of new vertices * @param details * True, for details * * @return a ImportResultEntity object * * @throws ArangoDBException * if an error occurs */ public ImportResultEntity createVertices( ArangoDBSimpleGraph graph, List<ArangoDBSimpleVertex> vertices, boolean details) throws ArangoDBException { List<Map<String, Object>> values = new ArrayList<Map<String, Object>>(); for (ArangoDBSimpleVertex v : vertices) { values.add(v.getProperties()); } try { return driver.importDocuments(graph.getVertexCollection(), true, values); } catch (ArangoException e) { throw new ArangoDBException(e); } } /** * Creates edges (bulk import) * * @param graph * The graph * @param edges * The list of new edges * @param details * True, for details * * @return a ImportResultEntity object * * @throws ArangoDBException * if an error occurs */ public ImportResultEntity createEdges(ArangoDBSimpleGraph graph, List<ArangoDBSimpleEdge> edges, boolean details) throws ArangoDBException { List<Map<String, Object>> values = new ArrayList<Map<String, Object>>(); for (ArangoDBSimpleEdge e : edges) { values.add(e.getProperties()); } try { return driver.importDocuments(graph.getEdgeCollection(), true, values); } catch (ArangoException e) { throw new ArangoDBException(e); } } /** * Create a query to get all vertices of a graph * * @param graph * the simple graph * @param propertyFilter * a property filter * @param limit * limit the number of results * @param count * query total number of results * * @return ArangoDBBaseQuery the query object * * @throws ArangoDBException * if creation failed */ public ArangoDBBaseQuery getGraphVertices( ArangoDBSimpleGraph graph, ArangoDBPropertyFilter propertyFilter, Long limit, boolean count) throws ArangoDBException { return new ArangoDBBaseQuery(graph, this, QueryType.GRAPH_VERTICES).setCount(count).setLimit(limit) .setPropertyFilter(propertyFilter); } /** * Create a query to get all edges of a graph * * @param graph * the simple graph * @param propertyFilter * a property filter * @param labelsFilter * a labels filter * @param limit * maximum number of results * @param count * query total number of results * * @return ArangoDBBaseQuery the query object * * @throws ArangoDBException * if creation failed */ public ArangoDBBaseQuery getGraphEdges( ArangoDBSimpleGraph graph, ArangoDBPropertyFilter propertyFilter, List<String> labelsFilter, Long limit, boolean count) throws ArangoDBException { return new ArangoDBBaseQuery(graph, this, QueryType.GRAPH_EDGES).setCount(count).setLimit(limit) .setLabelsFilter(labelsFilter).setPropertyFilter(propertyFilter); } @SuppressWarnings("rawtypes") public CursorResult<Map> executeAqlQuery( String query, Map<String, Object> bindVars, AqlQueryOptions aqlQueryOptions) throws ArangoDBException { try { return driver.executeAqlQuery(query, bindVars, aqlQueryOptions, Map.class); } catch (ArangoException e) { throw new ArangoDBException(e); } } /** * Create a query to get all neighbors of a vertex * * @param graph * the simple graph * @param vertex * the vertex * @param propertyFilter * a property filter * @param labelsFilter * a list of labels * @param direction * a direction * @param limit * the maximum number of results * @param count * query total number of results * * @return ArangoDBBaseQuery the query object * * @throws ArangoDBException * if creation failed */ public ArangoDBBaseQuery getVertexNeighbors( ArangoDBSimpleGraph graph, ArangoDBSimpleVertex vertex, ArangoDBPropertyFilter propertyFilter, List<String> labelsFilter, Direction direction, Long limit, boolean count) throws ArangoDBException { return new ArangoDBBaseQuery(graph, this, QueryType.GRAPH_NEIGHBORS).setCount(count).setLimit(limit) .setDirection(direction).setStartVertex(vertex).setLabelsFilter(labelsFilter) .setPropertyFilter(propertyFilter); } /** * Create a query to get all edges of a vertex * * @param graph * the simple graph * @param vertex * the vertex * @param propertyFilter * a property filter * @param labelsFilter * a list of labels * @param direction * a direction * @param limit * the maximum number of results * @param count * query total number of results * * @return ArangoDBBaseQuery the query object * * @throws ArangoDBException * if creation failed */ public ArangoDBBaseQuery getVertexEdges( ArangoDBSimpleGraph graph, ArangoDBSimpleVertex vertex, ArangoDBPropertyFilter propertyFilter, List<String> labelsFilter, Direction direction, Long limit, boolean count) throws ArangoDBException { return new ArangoDBBaseQuery(graph, this, QueryType.GRAPH_EDGES).setCount(count).setLimit(limit) .setStartVertex(vertex).setLabelsFilter(labelsFilter).setPropertyFilter(propertyFilter) .setDirection(direction); } /** * Create an index on collection keys * * @param graph * the simple graph * @param type * the index type ("cap", "geo", "hash", "skiplist") * @param unique * true for a unique key * @param fields * a list of key fields * * @return ArangoDBIndex the index * * @throws ArangoDBException * if creation failed */ public ArangoDBIndex createVertexIndex( ArangoDBSimpleGraph graph, IndexType type, boolean unique, List<String> fields) throws ArangoDBException { return createIndex(graph.getVertexCollection(), type, unique, fields); } /** * Create an index on collection keys * * @param graph * the simple graph * @param type * the index type ("cap", "geo", "hash", "skiplist") * @param unique * true for a unique key * @param fields * a list of key fields * * @return ArangoDBIndex the index * * @throws ArangoDBException * if creation failed */ public ArangoDBIndex createEdgeIndex(ArangoDBSimpleGraph graph, IndexType type, boolean unique, List<String> fields) throws ArangoDBException { return createIndex(graph.getEdgeCollection(), type, unique, fields); } /** * Get an index * * @param id * id of the index * * @return ArangoDBIndex the index, or null if the index was not found * * @throws ArangoDBException * if creation failed */ public ArangoDBIndex getIndex(String id) throws ArangoDBException { IndexEntity index; try { index = driver.getIndex(id); } catch (ArangoException e) { if (e.getErrorNumber() == ErrorNums.ERROR_ARANGO_INDEX_NOT_FOUND) { return null; } throw new ArangoDBException(e); } return new ArangoDBIndex(index); } /** * Returns the indices of the vertex collection * * @param graph * The graph * * @return List of indices * * @throws ArangoDBException * if an error occurs */ public List<ArangoDBIndex> getVertexIndices(ArangoDBSimpleGraph graph) throws ArangoDBException { return getIndices(graph.getVertexCollection()); } /** * Returns the indices of the edge collection * * @param graph * The graph * * @return List of indices * * @throws ArangoDBException * if an error occurs */ public List<ArangoDBIndex> getEdgeIndices(ArangoDBSimpleGraph graph) throws ArangoDBException { return getIndices(graph.getEdgeCollection()); } /** * Deletes an index * * @param id * The identifier of the index * * @return true, if the index was deleted * * @throws ArangoDBException * if an error occurs */ public boolean deleteIndex(String id) throws ArangoDBException { try { driver.deleteIndex(id); } catch (ArangoException e) { throw new ArangoDBException(e); } return true; } /** * Create an index on collection keys * * @param collectionName * the collection name * @param type * the index type ("cap", "geo", "hash", "skiplist") * @param unique * true for a unique key * @param fields * a list of key fields * * @return ArangoDBIndex the index * * @throws ArangoDBException * if creation failed */ private ArangoDBIndex createIndex(String collectionName, IndexType type, boolean unique, List<String> fields) throws ArangoDBException { IndexEntity indexEntity; try { indexEntity = driver.createIndex(collectionName, type, unique, fields.toArray(new String[0])); } catch (ArangoException e) { throw new ArangoDBException(e); } return new ArangoDBIndex(indexEntity); } /** * Get the List of indices of a collection * * @param collectionName * the collection name * * @return Vector<ArangoDBIndex> List of indices * * @throws ArangoDBException * if creation failed */ private List<ArangoDBIndex> getIndices(String collectionName) throws ArangoDBException { List<ArangoDBIndex> indices = new ArrayList<ArangoDBIndex>(); IndexesEntity indexes; try { indexes = driver.getIndexes(collectionName); } catch (ArangoException e) { throw new ArangoDBException(e); } for (IndexEntity indexEntity : indexes.getIndexes()) { indices.add(new ArangoDBIndex(indexEntity)); } return indices; } /** * Returns the current connection configuration * * @return the configuration */ public ArangoDBConfiguration getConfiguration() { return configuration; } /** * Truncates a collection * * @param collectionName */ public void truncateCollection(String collectionName) throws ArangoDBException { try { driver.truncateCollection(collectionName); } catch (ArangoException e) { throw new ArangoDBException(e); } } public ArangoDriver getDriver() { return driver; } }