diff --git a/spring-data-graph-parent/pom.xml b/spring-data-graph-parent/pom.xml
index bfce9fcc2..5ae344b25 100644
--- a/spring-data-graph-parent/pom.xml
+++ b/spring-data-graph-parent/pom.xml
@@ -187,6 +187,12 @@
+
+ com.tinkerpop.blueprints
+ blueprints-core
+ ${blueprints.version}
+ optional
+
com.tinkerpop.blueprints
blueprints-neo4j-graph
diff --git a/spring-data-neo4j-rest/pom.xml b/spring-data-neo4j-rest/pom.xml
index 5f027d10f..a695d3384 100644
--- a/spring-data-neo4j-rest/pom.xml
+++ b/spring-data-neo4j-rest/pom.xml
@@ -58,6 +58,13 @@
org.neo4j.server.plugin
neo4j-cypher-plugin
${neo4j.version}
+ test
+
+
+ org.neo4j.server.plugin
+ neo4j-gremlin-plugin
+ ${neo4j.version}
+ test
org.neo4j.app
diff --git a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/JsonHelper.java b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/JsonHelper.java
index 4f8f0eca0..abe8834ea 100644
--- a/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/JsonHelper.java
+++ b/spring-data-neo4j-rest/src/main/java/org/springframework/data/neo4j/rest/JsonHelper.java
@@ -44,7 +44,7 @@ public class JsonHelper {
return (List
+
+ com.tinkerpop.blueprints
+ blueprints-core
+ optional
+
com.tinkerpop.blueprints
blueprints-neo4j-graph
optional
+
+ com.tinkerpop
+ gremlin
+ optional
+
+
commons-configuration
commons-configuration
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java
index 4a81fe2ac..3c820967b 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/conversion/QueryResultBuilder.java
@@ -21,6 +21,7 @@ import org.neo4j.helpers.collection.ClosableIterable;
import org.neo4j.helpers.collection.IteratorWrapper;
import java.util.Iterator;
+import java.util.Map;
/**
* @author mh
@@ -42,6 +43,14 @@ public class QueryResultBuilder implements QueryResult {
this.defaultConverter = defaultConverter;
}
+ public static String replaceParams(String statement, Map params) {
+ if (params==null || params.isEmpty()) return statement;
+ for (Map.Entry param : params.entrySet()) {
+ statement = statement.replaceAll(":"+param.getKey(),""+param.getValue());
+ }
+ return statement;
+ }
+
@Override
public ConvertedResult to(Class type) {
return this.to(type, defaultConverter);
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/GraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/GraphDatabase.java
index aeaa2c95e..9c70c8456 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/GraphDatabase.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/GraphDatabase.java
@@ -23,7 +23,6 @@ import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.springframework.core.convert.ConversionService;
-import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
@@ -95,7 +94,7 @@ public interface GraphDatabase {
*/
TraversalDescription createTraversalDescription();
- QueryEngine queryEngineFor(CypherQueryEngine.Type type);
+ QueryEngine queryEngineFor(QueryEngine.Type type);
void setConversionService(ConversionService conversionService);
}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java
index 3ef2d3fc4..f443c4a57 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/repository/GraphRepositoryFactory.java
@@ -27,7 +27,7 @@ import org.springframework.data.neo4j.core.NodeBacked;
import org.springframework.data.neo4j.core.RelationshipBacked;
import org.springframework.data.neo4j.support.GenericTypeExtractor;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
-import org.springframework.data.neo4j.support.query.QueryExecutor;
+import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -235,14 +235,14 @@ public class GraphRepositoryFactory extends RepositoryFactorySupport {
}
private static class GraphRepositoryQuery implements RepositoryQuery {
- private QueryExecutor queryExecutor;
+ private CypherQueryExecutor queryExecutor;
private final GraphQueryMethod queryMethod;
private final RepositoryMetadata metadata;
private boolean iterableResult;
private Class> compoundType;
public GraphRepositoryQuery(GraphQueryMethod queryMethod, RepositoryMetadata metadata, final GraphDatabaseContext graphDatabaseContext) {
- queryExecutor = new QueryExecutor(graphDatabaseContext);
+ queryExecutor = new CypherQueryExecutor(graphDatabaseContext);
this.queryMethod = queryMethod;
this.metadata = metadata;
this.iterableResult = Iterable.class.isAssignableFrom(queryMethod.getReturnType());
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java
index 292cea6e5..1f14efeae 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/DelegatingGraphDatabase.java
@@ -27,7 +27,9 @@ import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.Property;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
+import org.springframework.data.neo4j.support.query.GremlinQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
+
import java.util.Map;
/**
@@ -126,8 +128,12 @@ public class DelegatingGraphDatabase implements GraphDatabase {
}
@Override
- public QueryEngine queryEngineFor(CypherQueryEngine.Type type) {
- return new CypherQueryEngine(delegate, createResultConverter());
+ public QueryEngine queryEngineFor(QueryEngine.Type type) {
+ switch (type) {
+ case Cypher: return (QueryEngine)new CypherQueryEngine(delegate, createResultConverter());
+ case Gremlin: return (QueryEngine) new GremlinQueryEngine(delegate);
+ }
+ throw new IllegalArgumentException("Unknown Query Engine Type "+type);
}
private ConversionServiceQueryResultConverter createResultConverter() {
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java
index 5c4e4129b..93405f769 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java
@@ -240,8 +240,6 @@ public class GraphDatabaseContext {
return graphDatabaseService.getRelationshipById(id);
}
-
-
public GraphDatabaseService getGraphDatabaseService() {
return graphDatabaseService;
}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/Neo4jNodeBacking.aj b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/Neo4jNodeBacking.aj
index b126cbfad..2e9a3d358 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/Neo4jNodeBacking.aj
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/Neo4jNodeBacking.aj
@@ -42,7 +42,7 @@ import org.springframework.data.neo4j.core.EntityState;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.path.EntityPathPathIterableWrapper;
-import org.springframework.data.neo4j.support.query.QueryExecutor;
+import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
import javax.persistence.Transient;
import javax.persistence.Entity;
@@ -184,17 +184,17 @@ public aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMixinFields(traverser, targetType, Neo4jNodeBacking.aspectOf().graphDatabaseContext);
}
public Iterable NodeBacked.findAllByQuery(final String query, final Class targetType) {
- final QueryExecutor executor = new QueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
+ final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
return executor.query(query, targetType);
}
public Iterable> NodeBacked.findAllByQuery(final String query) {
- final QueryExecutor executor = new QueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
+ final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
return executor.queryForList(query);
}
public T NodeBacked.findByQuery(final String query, final Class targetType) {
- final QueryExecutor executor = new QueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
+ final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
return executor.queryForObject(query, targetType);
}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryEngine.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryEngine.java
index 95ccc4766..b62f88772 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryEngine.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryEngine.java
@@ -29,11 +29,10 @@ import org.springframework.data.neo4j.conversion.ResultConverter;
import java.util.Map;
-public class CypherQueryEngine implements QueryEngine, QueryOperations {
+public class CypherQueryEngine implements QueryEngine> {
final ExecutionEngine executionEngine;
private ResultConverter resultConverter;
- private final DefaultQueryOperations queryOperations;
public CypherQueryEngine(GraphDatabaseService graphDatabaseService) {
this(graphDatabaseService, new DefaultConverter());
@@ -43,34 +42,19 @@ public class CypherQueryEngine implements QueryEngine, QueryOperations {
public CypherQueryEngine(GraphDatabaseService graphDatabaseService, ResultConverter resultConverter) {
this.resultConverter = resultConverter != null ? resultConverter : new DefaultConverter();
this.executionEngine = new ExecutionEngine(graphDatabaseService);
- this.queryOperations = new DefaultQueryOperations(this);
}
@Override
- public QueryResult> query(String statement) {
+ public QueryResult> query(String statement, Map params) {
try {
- ExecutionResult result = parseAndExecuteQuery(statement);
+ String parametrizedQuery = QueryResultBuilder.replaceParams(statement,params);
+ ExecutionResult result = parseAndExecuteQuery(parametrizedQuery);
return new QueryResultBuilder>(result,resultConverter);
} catch (Exception e) {
throw new InvalidDataAccessResourceUsageException("Error executing statement " + statement, e);
}
}
- @Override
- public Iterable> queryForList(String statement) {
- return queryOperations.queryForList(statement);
- }
-
- @Override
- public Iterable query(String statement, Class type) {
- return queryOperations.query(statement, type);
- }
-
- @Override
- public T queryForObject(String statement, Class type) {
- return queryOperations.queryForObject(statement, type);
- }
-
private ExecutionResult parseAndExecuteQuery(String statement) {
try {
CypherParser parser = new CypherParser();
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/QueryExecutor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryExecutor.java
similarity index 55%
rename from spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/QueryExecutor.java
rename to spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryExecutor.java
index a5df1bafe..8262005ff 100644
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/QueryExecutor.java
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/CypherQueryExecutor.java
@@ -19,6 +19,8 @@ package org.springframework.data.neo4j.support.query;
import org.springframework.data.neo4j.support.GraphDatabaseContext;
import org.springframework.data.neo4j.support.conversion.EntityResultConverter;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -26,24 +28,31 @@ import java.util.Map;
* @since 10.06.11
* todo limits
*/
-public class QueryExecutor implements QueryOperations {
- private final QueryEngine queryEngine;
+public class CypherQueryExecutor implements QueryOperations> {
+ private final CypherQueryEngine queryEngine;
- public QueryExecutor(GraphDatabaseContext ctx) {
+ public CypherQueryExecutor(GraphDatabaseContext ctx) {
EntityResultConverter converter = new EntityResultConverter(ctx);
queryEngine = new CypherQueryEngine(ctx.getGraphDatabaseService(), converter);
}
- public Iterable> queryForList(String statement) {
- return queryEngine.query(statement);
+ public Iterable> queryForList(String statement, Map...params) {
+ return queryEngine.query(statement,mergeParams(params));
}
- public Iterable query(String statement, Class type) {
- return queryEngine.query(statement).to(type);
+ public Iterable query(String statement, Class type, Map...params) {
+ return queryEngine.query(statement,mergeParams(params)).to(type);
}
- public T queryForObject(String statement, Class type) {
- return queryEngine.query(statement).to(type).single();
+ public T queryForObject(String statement, Class type, Map...params) {
+ return (T) queryEngine.query(statement,mergeParams(params)).to(type).single();
+ }
+ private Map mergeParams(Map...params) {
+ if (params==null || params.length==0) return Collections.emptyMap();
+ Map result=new HashMap();
+ for (Map map : params) {
+ result.putAll(map);
+ }
+ return result;
}
-
}
\ No newline at end of file
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/DefaultQueryOperations.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/DefaultQueryOperations.java
deleted file mode 100644
index 43af09ac6..000000000
--- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/DefaultQueryOperations.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Copyright 2011 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.data.neo4j.support.query;
-
-import java.util.Map;
-
-/**
- * @author mh
- * @since 28.06.11
- */
-public class DefaultQueryOperations implements QueryOperations {
- private QueryEngine queryEngine;
-
- public DefaultQueryOperations(QueryEngine queryEngine) {
- this.queryEngine = queryEngine;
- }
-
- public Iterable> queryForList(String statement) {
- return queryEngine.query(statement);
- }
-
- public Iterable query(String statement, Class type) {
- return queryEngine.query(statement).to(type);
- }
-
- public T queryForObject(String statement, Class type) {
- return queryEngine.query(statement).to(type).single();
- }
-
-}
diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/GremlinExecutor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/GremlinExecutor.java
new file mode 100644
index 000000000..2b3a0718f
--- /dev/null
+++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/query/GremlinExecutor.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.data.neo4j.support.query;
+
+import com.tinkerpop.blueprints.pgm.Edge;
+import com.tinkerpop.blueprints.pgm.Vertex;
+import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jEdge;
+import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph;
+import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jVertex;
+import com.tinkerpop.gremlin.pipes.util.Table;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.helpers.collection.IterableWrapper;
+
+import javax.script.*;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@SuppressWarnings("ALL")
+public class GremlinExecutor {
+
+ public static final int REFRESH_ENGINE_COUNT = 10000;
+ private final String g = "g";
+ private volatile ScriptEngine engine;
+
+ private ScriptEngine createScriptEngine() {
+ return new ScriptEngineManager().getEngineByName("gremlin");
+ }
+
+ private static final AtomicInteger executionCount = new AtomicInteger();
+ private final GraphDatabaseService graphDatabaseService;
+
+ public GremlinExecutor(GraphDatabaseService graphDatabaseService) {
+ this.graphDatabaseService = graphDatabaseService;
+ }
+
+ public Iterable