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.query.CypherTransaction Maven / Gradle / Ivy
Go to download
pring Data Neo4j Wrapper for the Neo4j REST API, provides a Graph Database proxy for the remote invocation.
package org.neo4j.rest.graphdb.query;
import com.sun.jersey.api.client.ClientResponse;
import org.neo4j.helpers.collection.IterableWrapper;
import org.neo4j.helpers.collection.IteratorWrapper;
import org.neo4j.rest.graphdb.*;
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.helpers.collection.MapUtil.stringMap;
/**
* @author mh
* @since 24.09.14
*/
public class CypherTransaction {
@SuppressWarnings("unchecked")
public enum ResultType {
/** all nodes and rels collated in one bag **/
graph() {
@Override
public List get(Map data) {
Map graph = (Map) data.get(name());
List result = new ArrayList((List)graph.get("nodes"));
result.addAll((List) graph.get("relationships"));
return result;
}
public List getNodes(Map data) {
Map graph = (Map) data.get(name());
return (List)graph.get("nodes");
}
public List getRelationships(Map data) {
Map graph = (Map) data.get(name());
return (List)graph.get("relationships");
}
}, row, rest;
public List get(Map data) {
return (List) data.get(name());
}
}
public CypherTransaction(String baseUri, ResultType type) {
this.type = type;
this.request = new ExecutingRestRequest(baseUri);
}
public CypherTransaction(RestAPICypherImpl restAPI, ResultType type) {
this.type = type;
this.request = restAPI.getRestRequest();
}
public static class Result implements Iterable> {
private final List columns;
private final Iterable> rows;
private final Statement statement;
Result(List columns, Iterable> rows, Statement statement) {
this.columns = columns;
this.rows = rows;
this.statement = statement;
}
private static List toResults(List resultsData, List statements, ResultType type) {
List results=new ArrayList<>();
for (int i = 0; i < resultsData.size(); i++) {
results.add(toResult(resultsData.get(i), statements.get(i), type));
}
return results;
}
@SuppressWarnings("unchecked")
private static Result toResult(Map resultData, Statement statement, final ResultType type) {
List columns = (List) resultData.get("columns");
List rowsData = (List) resultData.get("data");
final boolean replace = statement.doReplace();
Iterable> rows = new IterableWrapper,Map>(rowsData) {
protected List underlyingObjectToObject(Map map) {
List row = type.get(map);
List graph = ResultType.graph.get(map);
if (replace) replaceGraphElements(row, (List) graph);
return row;
}
};
return new Result(columns, rows, statement);
}
// todo hack !!
private static void replaceGraphElements(List row, List graph) {
for (Map pc : graph) {
Object props = pc.get("properties");
int pos = -1;
for (int i = 0; i < row.size(); i++) {
Object o = row.get(i);
if (props.equals(o)) {
// row.set(i,pc);
if (pos == -1) pos = i; else pos = -2;
}
}
if (pos >= 0) row.set(pos,pc);
}
}
public List getColumns() {
return columns;
}
public Iterable> getRows() {
return rows;
}
public Statement getStatement() {
return statement;
}
@Override
public Iterator> iterator() {
return new IteratorWrapper,List>(rows.iterator()) {
protected Map underlyingObjectToObject(List objects) {
Map row = new LinkedHashMap<>(columns.size());
for (int i = 0; i < columns.size(); i++) {
row.put(columns.get(i), objects.get(i));
}
return row;
}
};
}
public boolean hasData() {
return rows.iterator().hasNext();
}
}
public static class Statement {
private final String statement;
private final ResultType type;
private final Map parameters;
private final boolean replace;
public Statement(String query, Map parameters, ResultType type, boolean replace) {
this.statement = query;
this.type = type;
this.replace = replace;
this.parameters = parameters == null ? Collections.emptyMap() : parameters;
}
public String getStatement() {
return statement;
}
public Map getParameters() {
return new LinkedHashMap<>(parameters);
}
public List getResultDataContents() {
return Arrays.asList(type.name(), ResultType.graph.name());
}
public ResultType getType() {
return type;
}
private boolean doReplace() { return replace; }
}
private final ResultType type;
private String transactionUrl = null;
private String commitUrl = null;
private final RestRequest request;
private final List statements = new ArrayList<>(10);
public void addAll(Statement...statements) {
this.statements.addAll(asList(statements));
}
public void addAll(Collection statements) {
this.statements.addAll(statements);
}
public void add(String statement, Map params) {
add(statement,params,false);
}
public void add(String statement, Map params, boolean replace) {
statements.add(new Statement(statement,params,type, replace));
}
public Result send(String statement, Map params) {
return send(statement,params,false);
}
public Result send(String statement, Map params, boolean replace) {
add(statement,params, replace);
List results = send(transactionUrl());
if (results.size() > 0) return results.get(results.size() - 1);
throw new CypherTransactionExecutionException("Error Sending",asList(new Statement(statement,params,type, replace)),errors("No.Results","No Results after single send"));
}
public Result commit(String statement, Map params) {
return commit(statement,params,false);
}
public Result commit(String statement, Map params, boolean replace) {
add(statement,params, replace);
List results = commit();
if (results.size() > 0) return results.get(results.size() - 1);
else throw new CypherTransactionExecutionException("Error Sending",asList(new Statement(statement,params,type, replace)),errors("No.Results","No Results after single commit"));
}
public List send() {
return send(transactionUrl());
}
public List commit() {
try {
if (statements.isEmpty()) add("return 1",null, false); // TODO hacking workaround b/c of periodic commit check in server accesses the first of an empty statement list with an NPE
return send(commitUrl());
} finally {
commitUrl = null;
}
}
private List send(String url) {
try {
RequestResult result = request.post(url, map("statements", statements));
if (result.statusIs(Response.Status.OK) || result.statusIs(Response.Status.CREATED)) {
ArrayList statementsCopy = new ArrayList<>(statements);
return Result.toResults(handleResult(result,statementsCopy), statementsCopy, type);
} else {
List> errors = errors("Http." + result.getStatus(), result.getText());
throw new CypherTransactionExecutionException("Error executing statements: " + result.getStatus() +
" " + result.getText(),statements, errors);
}
} finally {
statements.clear();
}
}
private List> errors(String code, String message) {
return asList(stringMap("code", code, "message", message));
}
public void rollback() {
if (transactionUrl != null) {
request.delete(transactionUrl);
}
transactionUrl = null;
commitUrl = null;
}
private String commitUrl() {
return (commitUrl == null) ? "transaction/commit" : commitUrl;
}
private String transactionUrl() {
return (transactionUrl==null) ? "transaction" : transactionUrl;
}
@SuppressWarnings("unchecked")
private List handleResult(RequestResult result, ArrayList statements) {
Map, ?> resultData = result.toMap();
List> errors = (List>) resultData.get("errors");
if (result.statusIs(ClientResponse.Status.CREATED)) transactionUrl = result.getLocation();
if (errors != null && !errors.isEmpty()) throw new CypherTransactionExecutionException("Error executing cypher statements ",statements, errors);
commitUrl = (String) resultData.get("commit");
return (List) resultData.get("results");
}
@Override
public String toString() {
return "Transaction: "+transactionUrl;
}
}