Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.neo4j.rest.graphdb.RestAPICypherImpl Maven / Gradle / Ivy
Go to download
pring Data Neo4j Wrapper for the Neo4j REST API, provides a Graph Database proxy for the remote invocation.
/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j 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.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.rest.graphdb;
import org.apache.lucene.search.Query;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.index.impl.lucene.AbstractIndexHits;
import org.neo4j.rest.graphdb.converter.RestEntityExtractor;
import org.neo4j.rest.graphdb.converter.RestIndexHitsConverter;
import org.neo4j.rest.graphdb.entity.RestEntity;
import org.neo4j.rest.graphdb.entity.RestEntityCache;
import org.neo4j.rest.graphdb.entity.RestNode;
import org.neo4j.rest.graphdb.entity.RestRelationship;
import org.neo4j.rest.graphdb.index.IndexInfo;
import org.neo4j.rest.graphdb.index.RestIndex;
import org.neo4j.rest.graphdb.index.RestIndexManager;
import org.neo4j.rest.graphdb.index.SimpleIndexHits;
import org.neo4j.rest.graphdb.query.*;
import org.neo4j.rest.graphdb.transaction.TransactionFinishListener;
import org.neo4j.rest.graphdb.traversal.RestTraversalDescription;
import org.neo4j.rest.graphdb.traversal.RestTraverser;
import org.neo4j.rest.graphdb.util.QueryResult;
import org.neo4j.rest.graphdb.util.QueryResultBuilder;
import org.neo4j.rest.graphdb.util.ResultConverter;
import org.springframework.dao.DataIntegrityViolationException;
import javax.ws.rs.core.Response;
import java.util.*;
import static java.util.Arrays.asList;
import static org.neo4j.helpers.collection.MapUtil.map;
import static org.neo4j.rest.graphdb.RestAPIIndexImpl.queryPath;
import static org.neo4j.rest.graphdb.query.CypherTransaction.ResultType.row;
import static org.neo4j.rest.graphdb.query.CypherTransaction.Statement;
public class RestAPICypherImpl implements RestAPI {
public static final String _QUERY_RETURN_NODE = " RETURN id(n) as id, labels(n) as labels, n as properties";
public static final String _QUERY_RETURN_REL = " RETURN id(r) as id, type(r) as type, r as properties, id(startNode(r)) as start, id(endNode(r)) as end";
public static String MATCH_NODE_QUERY(String name) {
return " MATCH (" + name + ") WHERE id(" + name + ") = {id_" + name + "} ";
}
public static final String _MATCH_NODE_QUERY = " MATCH (n) WHERE id(n) = {id} ";
public static final String GET_NODE_QUERY = _MATCH_NODE_QUERY + _QUERY_RETURN_NODE;
public static final String _MATCH_REL_QUERY = " START r=rel({id}) ";
public static final String GET_REL_QUERY = _MATCH_REL_QUERY + _QUERY_RETURN_REL;
public static final String GET_REL_TYPES_QUERY = _MATCH_NODE_QUERY + " MATCH (n)-[r]-() RETURN distinct type(r) as relType";
private RestAPIIndex restAPIIndex;
private final RestEntityCache entityCache = new RestEntityCache(this);
private RestEntityExtractor restEntityExtractor = new RestEntityExtractor(this);
private String createNodeQuery(Collection labels) {
String labelString = toLabelString(labels);
return "CREATE (n" + labelString + " {props}) " + _QUERY_RETURN_NODE;
}
private String mergeQuery(String labelName, String key, Collection labels) {
StringBuilder setLabels = new StringBuilder();
if (labels != null) {
for (String label : labels) {
if (label.equals(labelName)) continue;
setLabels.append("SET n:").append(label).append(" ");
}
}
return "MERGE (n:`" + labelName + "` {`" + key + "`: {value}}) ON CREATE SET n={props} " + setLabels + _QUERY_RETURN_NODE;
}
private String toLabelString(Collection labels) {
if (labels == null || labels.size() == 0) return "";
StringBuilder sb = new StringBuilder();
for (String label : labels) {
sb.append(":").append(label);
}
return sb.toString();
}
private final RestAPI restAPI;
private final RestCypherTransactionManager txManager = new RestCypherTransactionManager(this);
protected RestAPICypherImpl(RestAPI restAPI) {
this.restAPI = restAPI;
restAPIIndex = new RestAPIIndexImpl(this);
}
@Override
public RestNode getNodeById(long id, Load force) {
if (force != Load.ForceFromServer) {
RestNode restNode = getNodeFromCache(id);
if (restNode != null) return restNode;
}
if (force == Load.FromCache) return new RestNode(RestNode.nodeUri(this, id), this);
Iterator> result = runQuery(GET_NODE_QUERY, map("id", id)).getRows().iterator();
if (!result.hasNext()) {
throw new NotFoundException("Node not found " + id);
}
List row = result.next();
return addToCache(toNode(row));
}
@Override
public RestNode addToCache(RestNode restNode) {
return entityCache.addToCache(restNode);
}
@Override
public RestRelationship addToCache(RestRelationship rel) {
return entityCache.addToCache(rel);
}
@Override
public RestNode getNodeFromCache(long id) {
return entityCache.getNode(id);
}
@Override
public RestRelationship getRelFromCache(long id) {
return entityCache.getRelationship(id);
}
@Override
public void removeNodeFromCache(long id) {
entityCache.removeNode(id);
}
@Override
public void removeRelFromCache(long id) {
entityCache.removeRelationship(id);
}
@Override
public RestNode getNodeById(long id) {
return getNodeById(id, Load.FromServer);
}
@Override
public RestRelationship getRelationshipById(long id) {
return getRelationshipById(id, Load.FromServer);
}
@Override
public RestRelationship getRelationshipById(long id, Load force) {
if (force != Load.ForceFromServer) {
RestRelationship restRel = getRelFromCache(id);
if (restRel != null) return restRel;
}
if (force == Load.FromCache) return new RestRelationship(RestRelationship.relUri(this, id), this);
try {
Iterator> result = runQuery(GET_REL_QUERY, map("id", id)).getRows().iterator();
if (!result.hasNext()) {
throw new NotFoundException("Relationship not found " + id);
}
List row = result.next();
return addToCache(toRel(row));
} catch (NotFoundException e) {
throw e;
} catch (CypherTransactionExecutionException ctee) {
if (ctee.contains("Neo.DatabaseError.Statement.ExecutionFailure","not found")) {
throw new NotFoundException("Relationship not found " + id);
}
throw ctee;
}
}
private RestNode toNode(List row) {
long id = ((Number) row.get(0)).longValue();
List labels = (List) row.get(1);
Map props = (Map) row.get(2);
return RestNode.fromCypher(id, labels, props, this);
}
private RestRelationship toRel(List row) {
long id = ((Number) row.get(0)).longValue();
String type = (String) row.get(1);
Map props = (Map) row.get(2);
long start = ((Number) row.get(3)).longValue();
long end = ((Number) row.get(4)).longValue();
return RestRelationship.fromCypher(id, type, props, start, end, this);
}
@Override
public RestNode createNode(Map props) {
return createNode(props, Collections.emptyList());
}
@Override
public RestNode createNode(Map props, Collection labels) {
Iterator> result = runQuery(createNodeQuery(labels), map("props", props(props))).getRows().iterator();
if (result.hasNext()) {
return addToCache(toNode(result.next()));
}
throw new RuntimeException("Error creating node with labels: " + labels + " and props: " + props + " no data returned");
}
@Override
public RestNode merge(String labelName, String key, Object value, Map nodeProperties, Collection labels) {
if (labelName == null || key == null || value == null)
throw new IllegalArgumentException("Label " + labelName + " key " + key + " and value must not be null");
nodeProperties = props(nodeProperties);
Map props = nodeProperties.containsKey(key) ? nodeProperties : MapUtil.copyAndPut(nodeProperties, key, value);
Map params = map("props", props, "value", value);
Iterator> result = runQuery(mergeQuery(labelName, key, labels), params).getRows().iterator();
if (!result.hasNext())
throw new RuntimeException("Error merging node with labels: " + labelName + " key " + key + " value " + value + " labels " + labels + " and props: " + props + " no data returned");
return addToCache(toNode(result.next()));
}
@Override
public RestRelationship createRelationship(Node startNode, Node endNode, RelationshipType type, Map props) {
String statement = MATCH_NODE_QUERY("n") + MATCH_NODE_QUERY("m") + " CREATE (n)-[r:`" + type.name() + "`]->(m) SET r={props} " + _QUERY_RETURN_REL;
Map params = map("id_n", startNode.getId(), "id_m", endNode.getId(), "props", props(props));
CypherTransaction.Result result = runQuery(statement, params);
if (!result.hasData())
throw new RuntimeException("Error creating relationship from " + startNode + " to " + endNode + " type " + type.name());
Iterator> it = result.getRows().iterator();
return toRel(it.next());
}
@Override
public void removeLabel(RestNode node, String label) {
CypherTransaction.Result result = runQuery(_MATCH_NODE_QUERY + (" REMOVE n:`" + label + "` ") + _QUERY_RETURN_NODE, map("id", node.getId()));
if (!result.hasData()) {
throw new RuntimeException("Error removing label " + label + " from node " + node);
}
}
@Override
public Iterable getNodesByLabel(String label) {
String statement = "MATCH (n:`" + label + "`) " + _QUERY_RETURN_NODE;
return queryForNodes(statement, null);
}
private Iterable queryForNodes(String statement, Map params) {
Iterable> result = runQuery(statement, params).getRows();
return new IterableWrapper>(result) {
protected RestNode underlyingObjectToObject(List row) {
return addToCache(toNode(row));
}
};
}
@Override
public Iterable getNodesByLabelAndProperty(String label, String property, Object value) {
String statement = "MATCH (n:`" + label + "`) WHERE n.`" + property + "` = {value} " + _QUERY_RETURN_NODE;
return queryForNodes(statement, map("value", value));
}
@Override
public Iterable getRelationshipTypes(RestNode node) {
Iterable> result = runQuery(GET_REL_TYPES_QUERY, map("id", node.getId())).getRows();
return new IterableWrapper>(result) {
protected RelationshipType underlyingObjectToObject(List row) {
return DynamicRelationshipType.withName(row.get(0).toString());
}
};
}
@Override
public int getDegree(RestNode restNode, RelationshipType type, Direction direction) {
String nodeDegreeQuery = "MATCH (n)" + relPattern(direction, type) + "() WHERE id(n) = {id} RETURN count(*) as degree";
Iterator> degree = runQuery(nodeDegreeQuery, map("id", restNode.getId())).getRows().iterator();
if (!degree.hasNext()) return 0;
return ((Number) degree.next().get(0)).intValue();
}
private String relPattern(Direction direction, RelationshipType... types) {
String typeString = toTypeString(types);
String relPattern = "-[r]-";
if (!typeString.isEmpty()) relPattern = "-[r " + typeString + "]-";
if (direction == Direction.OUTGOING) {
relPattern += ">";
} else if (direction == Direction.INCOMING) {
relPattern = "<" + relPattern;
}
return relPattern;
}
private String toTypeString(RelationshipType... types) {
if (types == null || types.length == 0) return "";
StringBuilder typeString = new StringBuilder();
for (RelationshipType type : types) {
if (type==null) continue;
if (typeString.length() > 0) typeString.append("|");
typeString.append(':').append('`').append(type.name()).append("`");
}
return typeString.toString();
}
@Override
public Iterable getRelationships(RestNode restNode, Direction direction, RelationshipType... types) {
String statement = _MATCH_NODE_QUERY + " MATCH (n)" + relPattern(direction, types) + "() " + _QUERY_RETURN_REL;
CypherTransaction.Result result = runQuery(statement, map("id", restNode.getId()));
return new IterableWrapper>(result.getRows()) {
protected Relationship underlyingObjectToObject(List row) {
return toRel(row);
}
};
}
@Override
public void addLabels(RestNode node, Collection labels) {
String statement = _MATCH_NODE_QUERY + " SET n" + toLabelString(labels) + _QUERY_RETURN_NODE;
CypherTransaction.Result result = runQuery(statement, map("id", node.getId()));
if (!result.hasData()) {
throw new RuntimeException("Error adding labels " + labels + " to node " + node);
}
}
public RestRequest getRestRequest() {
return restAPI.getRestRequest();
}
@Override
public Transaction beginTx() {
return txManager.beginTx();
}
public RestCypherTransactionManager getTxManager() {
return txManager;
}
@SuppressWarnings("unchecked")
public IndexHits getIndexQuery(Class entityType, String indexName, String key, Object value) {
String indexPath = RestAPIIndexImpl.indexPath(entityType, indexName, key, value);
RequestResult response = getRestRequest().get(indexPath);
if (response.statusIs(Response.Status.OK)) {
return new RestIndexHitsConverter(this, entityType).convertFromRepresentation(response);
} else {
return new SimpleIndexHits(Collections.emptyList(), 0, entityType, this);
}
}
@SuppressWarnings("unchecked")
public IndexHits queryIndexQuery(Class entityType, String indexName, String key, Object value) {
String indexPath = queryPath(entityType, indexName, key, value);
RequestResult response = getRestRequest().get(indexPath);
if (response.statusIs(Response.Status.OK)) {
return new RestIndexHitsConverter(this, entityType).convertFromRepresentation(response);
} else {
return new SimpleIndexHits(Collections.emptyList(), 0, entityType, this);
}
}
@Override
public IndexHits getIndex(Class entityType, String indexName, String key, Object value) {
if (value instanceof Query) return getIndexQuery(entityType, indexName, key, value);
String index = key == null ? ":`" + indexName + "`({query})" : ":`" + indexName + "`(`" + key + "`={query})";
if (Node.class.isAssignableFrom(entityType)) {
String statement = "start n=node" + index + _QUERY_RETURN_NODE;
CypherTransaction.Result result = runQuery(statement, map("query", value));
return toIndexHits(result, true);
}
if (Relationship.class.isAssignableFrom(entityType)) {
String statement = "start r=rel" + index + _QUERY_RETURN_REL;
CypherTransaction.Result result = runQuery(statement, map("query", value));
return toIndexHits(result, false);
}
throw new IllegalStateException("Unknown index entity type " + entityType);
}
@Override
public IndexHits queryIndex(Class entityType, String indexName, String key, Object value) {
if (value instanceof Query) return queryIndexQuery(entityType, indexName, key, value);
String index = ":`" + indexName + "`({query})";
if (key != null && !key.isEmpty() && !value.toString().contains(":")) value = key + ":"+value;
if (Node.class.isAssignableFrom(entityType)) {
String statement = "start n=node" + index + _QUERY_RETURN_NODE;
CypherTransaction.Result result = runQuery(statement, map("query", value));
return toIndexHits(result, true);
}
if (Relationship.class.isAssignableFrom(entityType)) {
String statement = "start r=rel" + index + _QUERY_RETURN_REL;
CypherTransaction.Result result = runQuery(statement, map("query", value));
return toIndexHits(result, false);
}
throw new IllegalStateException("Unknown index entity type " + entityType);
}
private IndexHits toIndexHits(CypherTransaction.Result result, final boolean isNode) {
final int size = IteratorUtil.count(result.getRows());
final Iterator> it = result.getRows().iterator();
return new AbstractIndexHits() {
@Override
public int size() {
return size;
}
@Override
public float currentScore() {
return 0;
}
@Override
protected S fetchNextOrNull() {
if (!it.hasNext()) return null;
return (S) (isNode ? addToCache(toNode(it.next())) : toRel(it.next()));
}
};
}
@Override
public RestIndexManager index() {
return restAPIIndex.index();
}
@Override
public void deleteEntity(RestEntity entity) {
if (entity instanceof Node) {
runQuery(_MATCH_NODE_QUERY + " DELETE n", map("id", entity.getId()));
removeNodeFromCache(entity.getId());
} else if (entity instanceof Relationship) {
runQuery(_MATCH_REL_QUERY + " DELETE r", map("id", entity.getId()));
removeRelFromCache(entity.getId());
}
}
@Override
public void setPropertyOnEntity(RestEntity entity, String key, Object value) {
if (entity instanceof Node) {
runQuery(_MATCH_NODE_QUERY + " SET n.`" + key + "` = {value} ", map("id", entity.getId(), "value", value));
} else if (entity instanceof Relationship) {
runQuery(_MATCH_REL_QUERY + " SET r.`" + key + "` = {value} ", map("id", entity.getId(), "value", value));
}
}
// TODO return entity ???
@Override
public void setPropertiesOnEntity(RestEntity entity, Map properties) {
if (entity instanceof Node) {
runQuery(_MATCH_NODE_QUERY + " SET n = {props} ", map("id", entity.getId(), "props", properties));
} else if (entity instanceof Relationship) {
runQuery(_MATCH_REL_QUERY + " SET r = {props} ", map("id", entity.getId(), "props", properties));
}
}
@Override
public void removeProperty(RestEntity entity, String key) {
if (entity instanceof Node) {
runQuery(_MATCH_NODE_QUERY + " REMOVE n.`" + key + "`", map("id", entity.getId()));
} else if (entity instanceof Relationship) {
runQuery(_MATCH_REL_QUERY + " REMOVE r.`" + key + "`", map("id", entity.getId()));
}
}
// todo handle within cypher tx
@Override
public RestNode getOrCreateNode(RestIndex index, String key, Object value, final Map properties, Collection labels) {
return restAPIIndex.getOrCreateNode(index, key, value, properties, labels);
}
// todo handle within cypher tx
@Override
public RestRelationship getOrCreateRelationship(RestIndex index, String key, Object value, final RestNode start, final RestNode end, final String type, final Map properties) {
return restAPIIndex.getOrCreateRelationship(index, key, value, start, end, type, properties);
}
public CypherResult query(String statement, Map params) {
return new CypherTxResult(runQuery(statement, params,true));
}
private List runQueries(Collection statements) {
if (!txManager.isActive()) {
CypherTransaction tx = newCypherTransaction();
tx.addAll(statements);
return tx.commit();
} else {
CypherTransaction tx = txManager.getCypherTransaction();
tx.addAll(statements);
return tx.send();
}
}
private CypherTransaction.Result runQuery(String statement, Map params, boolean replace) {
if (!txManager.isActive()) {
return newCypherTransaction().commit(statement, params, replace);
}
return txManager.getCypherTransaction().send(statement, params, replace);
}
private CypherTransaction.Result runQuery(String statement, Map params) {
return runQuery(statement,params,false);
}
public CypherTransaction newCypherTransaction() {
return new CypherTransaction(this, row);
}
public QueryResult> query(String statement, Map params, ResultConverter resultConverter) {
CypherTransaction.Result result = runQuery(statement, params,true);
Iterable it = new IterableWrapper,Map>(result) {
@Override
protected Map underlyingObjectToObject(Map value) {
return convertRestEntitiesInRow(value);
}
};
return new QueryResultBuilder<>(it, resultConverter); // new RestEntityConverter(resultConverter));
}
private Map convertRestEntitiesInRow(Map value) {
Map map= value;
for (Map.Entry entry : map.entrySet()) {
Object original = entry.getValue();
if (!(original instanceof Map)) continue;
Map mapValue = (Map) original;
if (mapValue.containsKey("id") && mapValue.containsKey("properties")) {
Object v = createRestEntity(mapValue);
if (v != null) entry.setValue(v);
}
}
return map;
}
class RestEntityConverter implements ResultConverter {
ResultConverter delegate;
public RestEntityConverter(ResultConverter delegate) {
this.delegate = delegate;
}
@Override
public Object convert(Object value, Class type) {
Map map= (Map) value;
for (Map.Entry entry : map.entrySet()) {
Object v = doConvert(entry.getValue(), type);
if (v != null) entry.setValue(v);
}
return map;
}
protected Object doConvert(Object value, Class type) {
if (PropertyContainer.class.isAssignableFrom(type) && value instanceof Map) {
return createRestEntity((Map)value);
}
return delegate.convert(value,type);
}
}
private static final String FULLPATH = "fullpath";
@Override
public RestTraverser traverse(RestNode restNode, Map description) {
final RequestResult result = getRestRequest().with(restNode.getUri()).post("traverse/" + FULLPATH, description);
if (result.statusOtherThan(Response.Status.OK)) throw new RuntimeException(String.format("Error executing traversal: %d %s",result.getStatus(), description));
final Object col = result.toEntity();
if (!(col instanceof Collection)) throw new RuntimeException(String.format("Unexpected traversal result, %s instead of collection", col != null ? col.getClass() : null));
return new RestTraverser((Collection) col,restNode.getRestApi());
}
public RequestResult batch(Collection> batchRequestData) {
return restAPI.batch(batchRequestData);
}
@Override
@SuppressWarnings("unchecked")
public RestIndex getIndex(String indexName) {
final RestIndexManager index = this.index();
if (index.existsForNodes(indexName)) return (RestIndex) index.forNodes(indexName);
if (index.existsForRelationships(indexName)) return (RestIndex) index.forRelationships(indexName);
throw new IllegalArgumentException("Index " + indexName + " does not yet exist");
}
@Override
@SuppressWarnings("unchecked")
public void createIndex(String type, String indexName, Map config) {
restAPIIndex.createIndex(type, indexName, config);
}
@Override
@SuppressWarnings("unchecked")
public RestIndex createIndex(Class type, String indexName, Map config) {
return restAPIIndex.createIndex(type,indexName,config);
}
@Override
public void close() {
restAPI.close();
}
@Override
public Relationship getOrCreateRelationship(Node start, Node end, RelationshipType type, Direction direction, Map props) {
/*
final Iterable existingRelationships = start.getRelationships(type, direction);
for (final Relationship existingRelationship : existingRelationships) {
if (existingRelationship != null && existingRelationship.getOtherNode(start).equals(end))
return existingRelationship;
}
if (direction == Direction.INCOMING) {
return end.createRelationshipTo(start, type);
} else {
return start.createRelationshipTo(end, type);
}
*/
String relPattern = relPattern(direction, type);
String statement = MATCH_NODE_QUERY("n") + MATCH_NODE_QUERY("m") + " MERGE (n)"+relPattern+"(m) ON CREATE SET r={props}" + _QUERY_RETURN_REL;
CypherTransaction.Result result = runQuery(statement, map("id_n", start.getId(), "id_m", end.getId(),"props", props(props)));
if (!result.hasData())
throw new RuntimeException("Error creating relationship from " + start + " to " + end + " type " + type.name() +" direction "+direction);
return toRel(result.getRows().iterator().next());
}
@Override
public Iterable updateRelationships(Node start, Collection endNodes, RelationshipType type, Direction direction, String targetLabel) {
String targetLabelPredicate = targetLabel == null ? "" : " AND (m:`"+targetLabel+"` OR m:`_"+targetLabel+"`)";
String relPattern = relPattern(direction, type);
String statement1 = "MATCH (n)"+relPattern+"(m) WHERE id(n) = {id_n} "+targetLabelPredicate+" AND NOT id(m) IN {ids_m} DELETE r RETURN id(r) as id_r";
String statement2 = MATCH_NODE_QUERY("n") + " MATCH (m) WHERE id(m) IN {ids_m} MERGE (n)"+relPattern+"(m)" + _QUERY_RETURN_REL;
Map params = map("id_n", start.getId(), "ids_m", nodeIds(endNodes));
List results = runQueries(asList(
new Statement(statement1, params, row,false),
new Statement(statement2, params, row,false)));
Iterable> mergeResults = results.get(1).getRows();
return new IterableWrapper>(mergeResults) {
@Override
protected Relationship underlyingObjectToObject(List row) {
return toRel(row);
}
};
}
private long[] nodeIds(Collection nodes) {
long[] ids = new long[nodes.size()];
int i=0;
for (Node node : nodes) {
ids[i++] = node.getId();
}
return ids;
}
public Map props(Map props) {
return props == null ? Collections.emptyMap() : props;
}
@Override
public boolean isAutoIndexingEnabled(Class extends PropertyContainer> clazz) {
return restAPIIndex.isAutoIndexingEnabled(clazz);
}
@Override
public void setAutoIndexingEnabled(Class extends PropertyContainer> clazz, boolean enabled) {
restAPIIndex.setAutoIndexingEnabled(clazz, enabled);
}
@Override
public Set getAutoIndexedProperties(Class forClass) {
return restAPIIndex.getAutoIndexedProperties(forClass);
}
@Override
public void startAutoIndexingProperty(Class forClass, String s) {
restAPIIndex.startAutoIndexingProperty(forClass, s);
}
@Override
public void stopAutoIndexingProperty(Class forClass, String s) {
restAPIIndex.stopAutoIndexingProperty(forClass, s);
}
@Override
public void delete(RestIndex index) {
restAPIIndex.delete(index);
}
@Override
public void removeFromIndex(RestIndex index, T entity, String key, Object value) {
restAPIIndex.removeFromIndex(index, entity, key, value);
}
@Override
public void removeFromIndex(RestIndex index, T entity, String key) {
restAPIIndex.removeFromIndex(index, entity, key);
}
@Override
public void removeFromIndex(RestIndex index, T entity) {
restAPIIndex.removeFromIndex(index, entity);
}
@Override
public void addToIndex(final T entity, final RestIndex index, final String key, final Object value) {
if (!getTxManager().isActive()) {
restAPIIndex.addToIndex(entity, index, key, value);
return;
}
getTxManager().getRemoteCypherTransaction().registerListener(new TransactionFinishListener() {
@Override
public void comitted() {
restAPIIndex.addToIndex(entity, index, key, value);
}
@Override
public void rolledBack() {
}
});
}
@Override
@SuppressWarnings("unchecked")
public T putIfAbsent(final T entity, final RestIndex index, final String key, final Object value) {
if (!getTxManager().isActive()) {
return restAPIIndex.putIfAbsent(entity, index, key, value);
}
getTxManager().getRemoteCypherTransaction().registerListener(new TransactionFinishListener() {
@Override
public void comitted() {
T result = restAPIIndex.putIfAbsent(entity, index, key, value);
if (result == null || result.equals(entity)) return;
throw new DataIntegrityViolationException("Unique property "+key+" was to be set to duplicate value "+value);
}
@Override
public void rolledBack() {
}
});
return entity;
}
@Override
public IndexInfo indexInfo(final String indexType) {
return restAPIIndex.indexInfo(indexType);
}
@Override
public boolean hasToUpdate(long lastUpdate) {
return restAPI.hasToUpdate(lastUpdate);
}
@Override
public Collection getAllLabelNames() {
return restAPI.getAllLabelNames();
}
@Override
public Iterable getRelationshipTypes() {
return restAPI.getRelationshipTypes();
}
@Override
public RestTraversalDescription createTraversalDescription() {
return restAPI.createTraversalDescription();
}
public String getBaseUri() {
return restAPI.getBaseUri();
}
@Override
public RestEntityExtractor getEntityExtractor() {
return restEntityExtractor;
}
@Override
public RestEntity createRestEntity(Map data) {
if (data.containsKey("id") && data.containsKey("properties")) {
long id = asLong(data, "id");
Map props = (Map) data.get("properties");
if (data.containsKey("type")) {
return RestRelationship.fromCypher(id,(String)data.get("type"),props,asLong(data, "startNode"),asLong(data, "endNode"),this);
}
if (data.containsKey("labels")) {
List labels = (List) data.get("labels");
return entityCache.addToCache(RestNode.fromCypher(id,labels,props, this));
}
}
final String uri = (String) data.get("self");
if (uri == null || uri.isEmpty()) return null;
if (uri.contains("/node/")) {
return entityCache.addToCache(new RestNode(data, this));
}
if (uri.contains("/relationship/")) {
return new RestRelationship(data, this);
}
return null;
}
protected long asLong(Map data, String idKey) {
Object idValue = data.get(idKey);
return idValue instanceof Number ? ((Number)idValue).longValue() : Long.parseLong(idValue.toString());
}
public Iterable getAllNodes() {
String statement = "MATCH (n) " + _QUERY_RETURN_NODE;
Iterable> result = runQuery(statement, null).getRows();
return new IterableWrapper>(result) {
@Override
protected Node underlyingObjectToObject(List row) {
return addToCache(toNode(row));
}
};
}
}