Added Entity Persistence, Fetching, Lazy Loading
* fixed documenting test * destructured GraphDatabaseService * fixed tests
This commit is contained in:
@@ -39,7 +39,8 @@ import org.springframework.data.neo4j.annotation.GraphTraversal;
|
||||
|
||||
import org.springframework.data.neo4j.aspects.core.NodeBacked;
|
||||
import org.springframework.data.neo4j.aspects.core.RelationshipBacked;
|
||||
import org.springframework.data.neo4j.fieldaccess.GraphBackedEntityIterableWrapper;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.RelationshipResult;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.DoReturn;
|
||||
import org.springframework.data.neo4j.core.EntityPath;
|
||||
@@ -158,32 +159,19 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
|
||||
}
|
||||
|
||||
public <T extends NodeBacked> T NodeBacked.projectTo(Class<T> targetType) {
|
||||
return (T)Neo4jNodeBacking.aspectOf().graphDatabaseContext.projectTo( this, targetType);
|
||||
return (T)graphDatabaseContext().projectTo( this, targetType);
|
||||
}
|
||||
|
||||
public Relationship NodeBacked.relateTo(NodeBacked target, String type) {
|
||||
return this.relateTo(target,type,false);
|
||||
return this.relateTo(target, type, false);
|
||||
}
|
||||
public Relationship NodeBacked.relateTo(NodeBacked target, String type, boolean allowDuplicates) {
|
||||
if (target==null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (type==null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
|
||||
if (!allowDuplicates) {
|
||||
Relationship relationship=getRelationshipTo(target,type);
|
||||
if (relationship!=null) return relationship;
|
||||
}
|
||||
return this.getPersistentState().createRelationshipTo(target.getPersistentState(), DynamicRelationshipType.withName(type));
|
||||
final RelationshipResult result = entityStateHandler().relateTo(this, target, type, allowDuplicates);
|
||||
return result.relationship;
|
||||
}
|
||||
|
||||
public Relationship NodeBacked.getRelationshipTo(NodeBacked target, String type) {
|
||||
Node node = this.getPersistentState();
|
||||
Node targetNode = target.getPersistentState();
|
||||
if (node==null || targetNode==null) return null;
|
||||
Iterable<Relationship> relationships = node.getRelationships(DynamicRelationshipType.withName(type), org.neo4j.graphdb.Direction.OUTGOING);
|
||||
for (Relationship relationship : relationships) {
|
||||
if (relationship.getOtherNode(node).equals(targetNode)) return relationship;
|
||||
}
|
||||
return null;
|
||||
return graphDatabaseContext().getRelationshipTo(this,target,null,type);
|
||||
}
|
||||
|
||||
public Long NodeBacked.getNodeId() {
|
||||
@@ -194,113 +182,70 @@ public privileged aspect Neo4jNodeBacking { // extends AbstractTypeAnnotatingMix
|
||||
public <T> Iterable<T> NodeBacked.findAllByTraversal(final Class<T> targetType, TraversalDescription traversalDescription) {
|
||||
if (!hasPersistentState()) throw new IllegalStateException("No node attached to " + this);
|
||||
final Traverser traverser = traversalDescription.traverse(this.getPersistentState());
|
||||
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
|
||||
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
|
||||
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
|
||||
return (Iterable<T>)Neo4jNodeBacking.aspectOf().convertToGraphEntity(traverser,targetType);
|
||||
}
|
||||
|
||||
private Iterable<?> convertToGraphEntity(Traverser traverser, final Class<?> targetType) {
|
||||
final GraphDatabaseContext ctx = Neo4jNodeBacking.aspectOf().graphDatabaseContext;
|
||||
if (NodeBacked.class.isAssignableFrom(targetType)) {
|
||||
return GraphBackedEntityIterableWrapper.create(traverser.nodes(), (Class<? extends NodeBacked>) targetType, ctx);
|
||||
}
|
||||
if (RelationshipBacked.class.isAssignableFrom(targetType)) {
|
||||
return GraphBackedEntityIterableWrapper.create(traverser.relationships(), (Class<? extends RelationshipBacked>) targetType, ctx);
|
||||
}
|
||||
throw new IllegalStateException("Can't determine valid type for traversal target "+targetType);
|
||||
|
||||
return graphDatabaseContext().convertResultsTo(traverser, targetType);
|
||||
}
|
||||
|
||||
public <T> Iterable<T> NodeBacked.findAllByQuery(final String query, final Class<T> targetType, Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(graphDatabaseContext());
|
||||
return executor.query(query, targetType,params);
|
||||
}
|
||||
|
||||
public Iterable<Map<String,Object>> NodeBacked.findAllByQuery(final String query,Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(graphDatabaseContext());
|
||||
return executor.queryForList(query,params);
|
||||
}
|
||||
|
||||
public <T> T NodeBacked.findByQuery(final String query, final Class<T> targetType,Map<String,Object> params) {
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
final CypherQueryExecutor executor = new CypherQueryExecutor(graphDatabaseContext());
|
||||
return executor.queryForObject(query, targetType,params);
|
||||
}
|
||||
|
||||
public <S extends NodeBacked, E extends NodeBacked> Iterable<EntityPath<S,E>> NodeBacked.findAllPathsByTraversal(TraversalDescription traversalDescription) {
|
||||
if (!hasPersistentState()) throw new IllegalStateException("No node attached to " + this);
|
||||
final Traverser traverser = traversalDescription.traverse(this.getPersistentState());
|
||||
return new EntityPathPathIterableWrapper<S, E>(traverser, Neo4jNodeBacking.aspectOf().graphDatabaseContext);
|
||||
return new EntityPathPathIterableWrapper<S, E>(traverser, graphDatabaseContext());
|
||||
}
|
||||
|
||||
public <R extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N target, Class<R> relationshipClass, String relationshipType) {
|
||||
return this.relateTo(target,relationshipClass,relationshipType,false);
|
||||
return graphDatabaseContext().relateTo(this, target, relationshipClass, relationshipType, false);
|
||||
}
|
||||
public <R extends RelationshipBacked, N extends NodeBacked> R NodeBacked.relateTo(N target, Class<R> relationshipClass, String relationshipType, boolean allowDuplicates) {
|
||||
if (target==null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null");
|
||||
if (relationshipType==null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
|
||||
Relationship rel = this.relateTo(target,relationshipType,allowDuplicates);
|
||||
|
||||
GraphDatabaseContext gdc = Neo4jNodeBacking.aspectOf().graphDatabaseContext;
|
||||
gdc.postEntityCreation(rel, relationshipClass);
|
||||
return (R) gdc.createEntityFromState(rel, relationshipClass);
|
||||
return graphDatabaseContext().relateTo(this,target,relationshipClass, relationshipType,allowDuplicates);
|
||||
}
|
||||
|
||||
public void NodeBacked.remove() {
|
||||
Neo4jNodeBacking.aspectOf().graphDatabaseContext.removeNodeEntity(this);
|
||||
graphDatabaseContext().removeNodeEntity(this);
|
||||
}
|
||||
|
||||
public void NodeBacked.removeRelationshipTo(NodeBacked target, String relationshipType) {
|
||||
if (target==null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (relationshipType==null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
|
||||
Node node=this.getPersistentState();
|
||||
Node targetNode=target.getPersistentState();
|
||||
if (node==null || targetNode==null) return;
|
||||
for (Relationship rel : this.getPersistentState().getRelationships(DynamicRelationshipType.withName(relationshipType))) {
|
||||
if (rel.getOtherNode(node).equals(targetNode)) {
|
||||
rel.delete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
graphDatabaseContext().removeRelationshipTo(this,target,relationshipType);
|
||||
}
|
||||
|
||||
public <R extends RelationshipBacked> R NodeBacked.getRelationshipTo( NodeBacked target, Class<R> relationshipClass, String type) {
|
||||
if (target ==null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (relationshipClass==null) throw new IllegalArgumentException("Relationship class is null");
|
||||
if (type==null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
Node node=this.getPersistentState();
|
||||
Node targetNode= target.getPersistentState();
|
||||
if (node==null || targetNode==null) return null;
|
||||
for (Relationship rel : node.getRelationships(DynamicRelationshipType.withName(type))) {
|
||||
if (rel.getOtherNode(node).equals(targetNode)) {
|
||||
return (R)Neo4jNodeBacking.aspectOf().graphDatabaseContext.createEntityFromState(rel, relationshipClass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return (R)graphDatabaseContext().getRelationshipTo(this,target,relationshipClass,type);
|
||||
}
|
||||
|
||||
public static GraphDatabaseContext graphDatabaseContext() {
|
||||
return Neo4jNodeBacking.aspectOf().graphDatabaseContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @return result of equals operation fo the underlying node, false if there is none
|
||||
*/
|
||||
public final boolean NodeBacked.equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (!hasPersistentState()) return false;
|
||||
if (obj instanceof NodeBacked) {
|
||||
return this.getPersistentState().equals(((NodeBacked) obj).getPersistentState());
|
||||
}
|
||||
return false;
|
||||
public boolean NodeBacked.equals(Object obj) {
|
||||
return entityStateHandler().equals(this, obj);
|
||||
}
|
||||
|
||||
public static EntityStateHandler entityStateHandler() {
|
||||
return graphDatabaseContext().getEntityStateHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return result of the hashCode of the underlying node (if any, otherwise identityHashCode)
|
||||
*/
|
||||
public final int NodeBacked.hashCode() {
|
||||
if (!hasPersistentState()) return System.identityHashCode(this);
|
||||
return getPersistentState().hashCode();
|
||||
public int NodeBacked.hashCode() {
|
||||
return entityStateHandler().hashCode(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,7 @@ public class IndexingRelationshipTypeRepresentationStrategyTest {
|
||||
@Test
|
||||
@Transactional
|
||||
public void testPostEntityCreationOfRelationshipBacked() throws Exception {
|
||||
Index<Relationship> typesIndex = graphDatabaseService.index().forRelationships(IndexingNodeTypeRepresentationStrategy.INDEX_NAME);
|
||||
Index<Relationship> typesIndex = graphDatabaseService.index().forRelationships(IndexingRelationshipTypeRepresentationStrategy.INDEX_NAME);
|
||||
IndexHits<Relationship> linkHits = typesIndex.get(IndexingNodeTypeRepresentationStrategy.INDEX_KEY, link.getClass().getName());
|
||||
Relationship rel = linkHits.getSingle();
|
||||
assertEquals(rel(link), rel);
|
||||
|
||||
@@ -93,7 +93,8 @@
|
||||
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
|
||||
</property>
|
||||
<property name="mappingContext" ref="mappingContext"/>
|
||||
<property name="nodeEntityConverter" ref="nodeEntityConverter"/>
|
||||
<property name="relationshipEntityStateFactory" ref="relationshipEntityStateFactory"/>
|
||||
<property name="nodeEntityStateFactory" ref="nodeEntityStateFactory"/>
|
||||
</bean>
|
||||
|
||||
|
||||
|
||||
@@ -1,325 +1,325 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>movies</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Movies</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>3.0.6.RELEASE</spring.version>
|
||||
<slf4j.version>1.6.1</slf4j.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<neo4j.version>1.5-SNAPSHOT</neo4j.version>
|
||||
<spring-data-graph.version>2.0.0.BUILD-SNAPSHOT</spring-data-graph.version>
|
||||
<aspectj.version>1.6.12.M1</aspectj.version>
|
||||
<org.slf4j-version>1.6.1</org.slf4j-version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-maven-release</id>
|
||||
<name>Spring Maven Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-maven-snapshot</id>
|
||||
<name>Spring Maven Snapshot Repository</name>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<url>http://maven.springframework.org/snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-maven-milestone</id>
|
||||
<name>Spring Maven Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>neo4j-public-repository</id>
|
||||
<url>http://m2.neo4j.org/</url>
|
||||
<name>Publicly available Maven 2 repository for Neo4j</name>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jboss-public-repo</id>
|
||||
<url>http://repository.jboss.org/maven2/</url>
|
||||
<name>JBoss public available repo</name>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-maven-release</id>
|
||||
<name>Spring Maven Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-maven-milestone</id>
|
||||
<name>Spring Maven Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.16</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j-aspects</artifactId>
|
||||
<version>${spring-data-graph.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>opensymphony</groupId>
|
||||
<artifactId>sitemesh</artifactId>
|
||||
<version>2.4.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>4.0.2.GA</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<version>1.7.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>1.0.0.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Neo4j Libraries -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>neo4j-kernel</artifactId>
|
||||
<version>${neo4j.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>7.1.2.v20100523</version>
|
||||
<configuration>
|
||||
<webAppConfig>
|
||||
<contextPath>/</contextPath>
|
||||
</webAppConfig>
|
||||
<!--scanIntervalSeconds>1</scanIntervalSeconds -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<!-- Must use java 1.5 or higher for annotations -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<useFile>true</useFile>
|
||||
<includes>
|
||||
<include>**/*Tests.java</include>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/Abstract*.java</exclude>
|
||||
</excludes>
|
||||
<junitArtifactName>junit:junit</junitArtifactName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.2</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<outxml>true</outxml>
|
||||
<aspectLibraries>
|
||||
<aspectLibrary>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
</aspectLibrary>
|
||||
<aspectLibrary>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j-aspects</artifactId>
|
||||
</aspectLibrary>
|
||||
</aspectLibraries>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>movies</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Movies</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>3.0.6.RELEASE</spring.version>
|
||||
<slf4j.version>1.6.1</slf4j.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<neo4j.version>1.5-SNAPSHOT</neo4j.version>
|
||||
<spring-data-graph.version>2.0.0.BUILD-SNAPSHOT</spring-data-graph.version>
|
||||
<aspectj.version>1.6.12.M1</aspectj.version>
|
||||
<org.slf4j-version>1.6.1</org.slf4j-version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-maven-release</id>
|
||||
<name>Spring Maven Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-maven-snapshot</id>
|
||||
<name>Spring Maven Snapshot Repository</name>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<url>http://maven.springframework.org/snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-maven-milestone</id>
|
||||
<name>Spring Maven Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>neo4j-public-repository</id>
|
||||
<url>http://m2.neo4j.org/</url>
|
||||
<name>Publicly available Maven 2 repository for Neo4j</name>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jboss-public-repo</id>
|
||||
<url>http://repository.jboss.org/maven2/</url>
|
||||
<name>JBoss public available repo</name>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-maven-release</id>
|
||||
<name>Spring Maven Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-maven-milestone</id>
|
||||
<name>Spring Maven Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.16</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j-rest</artifactId>
|
||||
<version>${spring-data-graph.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>opensymphony</groupId>
|
||||
<artifactId>sitemesh</artifactId>
|
||||
<version>2.4.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>4.0.2.GA</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<version>1.7.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>1.0.0.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Neo4j Libraries -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>neo4j-kernel</artifactId>
|
||||
<version>${neo4j.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>7.1.2.v20100523</version>
|
||||
<configuration>
|
||||
<webAppConfig>
|
||||
<contextPath>/</contextPath>
|
||||
</webAppConfig>
|
||||
<!--scanIntervalSeconds>1</scanIntervalSeconds -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<!-- Must use java 1.5 or higher for annotations -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<useFile>true</useFile>
|
||||
<includes>
|
||||
<include>**/*Tests.java</include>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/Abstract*.java</exclude>
|
||||
</excludes>
|
||||
<junitArtifactName>junit:junit</junitArtifactName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>aspectj-maven-plugin</artifactId>
|
||||
<version>1.2</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<outxml>true</outxml>
|
||||
<aspectLibraries>
|
||||
<aspectLibrary>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aspects</artifactId>
|
||||
</aspectLibrary>
|
||||
<aspectLibrary>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-neo4j-aspects</artifactId>
|
||||
</aspectLibrary>
|
||||
</aspectLibraries>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
<neo4j:config storeDirectory="data/graph.db"/>
|
||||
<neo4j:repositories base-package="org.neo4j.cineasts.repository"/>
|
||||
|
||||
<!--neo4j:config graphDatabaseService="graphDatabaseService"/>
|
||||
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
|
||||
<constructor-arg value="http://localhost:7474"/>
|
||||
</bean-->
|
||||
|
||||
<bean class="org.neo4j.cineasts.movieimport.MovieDbApiClient">
|
||||
<constructor-arg value="926d2a79e82920b62f03b1cb57e532e6"/>
|
||||
</bean>
|
||||
|
||||
@@ -68,6 +68,7 @@ public class UserAccountRelationshipsTest extends AbstractTestWithUserAccount {
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
@Ignore
|
||||
public void testAddRecommendation() {
|
||||
UserAccount user = userAccountRepo.findUserAccount(userId);
|
||||
Restaurant rest = restaurantRepository.findRestaurant(22L);
|
||||
|
||||
@@ -123,6 +123,11 @@
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>neo4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>neo4j-cypher</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.neo4j</groupId>
|
||||
@@ -145,6 +150,12 @@
|
||||
<dependency>
|
||||
<groupId>com.tinkerpop.blueprints</groupId>
|
||||
<artifactId>blueprints-neo4j-graph</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.neo4j</groupId>
|
||||
<artifactId>neo4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ public abstract class Neo4jConfiguration {
|
||||
gdc.setGraphDatabaseService(getGraphDatabaseService());
|
||||
gdc.setConversionService(conversionService());
|
||||
gdc.setMappingContext(mappingContext());
|
||||
gdc.setNodeEntityConverter(nodeEntityConverter());
|
||||
gdc.setNodeEntityStateFactory(nodeEntityStateFactory());
|
||||
gdc.setRelationshipEntityStateFactory(relationshipEntityStateFactory());
|
||||
gdc.setEntityStateHandler(entityStateHandler());
|
||||
gdc.setNodeTypeRepresentationStrategy(nodeTypeRepresentationStrategy());
|
||||
gdc.setRelationshipTypeRepresentationStrategy(relationshipTypeRepresentationStrategy());
|
||||
|
||||
@@ -93,7 +93,7 @@ public class QueryFieldAccessorFactory implements FieldAccessorFactory {
|
||||
}
|
||||
|
||||
private Object executeQuery(Object entity, String queryString, Map<String, Object> params) {
|
||||
return graphDatabaseContext.executeQuery(entity,queryString,params,property);
|
||||
return graphDatabaseContext.executeQuery(queryString,params,property);
|
||||
}
|
||||
|
||||
private Map<String, Object> createPlaceholderParams(Object entity) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public class Neo4jEntityConverterImpl<T,S extends PropertyContainer> implements
|
||||
// 1) source -> type alias
|
||||
// 2) type alias -> type
|
||||
// 3) check for subtype matching / enforcement
|
||||
final TypeInformation<R> requestedTypeInformation = ClassTypeInformation.from(requestedType);
|
||||
final TypeInformation<R> requestedTypeInformation = requestedType == null ? null : ClassTypeInformation.from(requestedType);
|
||||
final TypeInformation<? extends R> targetType = typeMapper.readType(source, requestedTypeInformation);
|
||||
|
||||
// retrieve meta-information about the type
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.neo4j.graphdb.GraphDatabaseService;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.EntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.ManagedEntity;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 11.10.11
|
||||
*/
|
||||
public class Neo4jEntityPersister implements Neo4jEntityConverter<Object,Node> {
|
||||
Neo4jEntityConverter<Object,Node> nodeConverter;
|
||||
Neo4jEntityConverter<Object,Relationship> relationshipConverter;
|
||||
private EntityStateHandler entityStateHandler;
|
||||
private final Neo4jMappingContext mappingContext;
|
||||
|
||||
|
||||
public Neo4jEntityPersister(GraphDatabaseService graphDatabaseService, Neo4jMappingContext mappingContext, ConversionService conversionService,
|
||||
EntityStateFactory<Node> nodeEntityStateFactory, EntityStateFactory<Relationship> relationshipEntityStateFactory,
|
||||
TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy, TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy) {
|
||||
this.mappingContext = mappingContext;
|
||||
|
||||
this.entityStateHandler = new EntityStateHandler(mappingContext, graphDatabaseService);
|
||||
|
||||
final EntityInstantiator<Node> nodeEntityInstantiator = new CachedInstantiator<Node>(new NodeEntityInstantiator(entityStateHandler));
|
||||
TypeMapper<Node> nodeTypeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(nodeTypeRepresentationStrategy), asList(new ClassValueTypeInformationMapper()));
|
||||
SourceStateTransmitter<Node> nodeStateTransmitter = new SourceStateTransmitter<Node>(nodeEntityStateFactory);
|
||||
|
||||
final EntityInstantiator<Relationship> relationshipEntityInstantiator = new CachedInstantiator<Relationship>(new RelationshipEntityInstantiator(entityStateHandler));
|
||||
TypeMapper<Relationship> relationShipTypeMapper = new DefaultTypeMapper<Relationship>(new TRSTypeAliasAccessor<Relationship>(relationshipTypeRepresentationStrategy), asList(new ClassValueTypeInformationMapper()));
|
||||
SourceStateTransmitter<Relationship> relationshipStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory);
|
||||
|
||||
Neo4jEntityFetchHandler fetchHandler=new Neo4jEntityFetchHandler(entityStateHandler, conversionService, relationshipStateTransmitter , nodeStateTransmitter);
|
||||
|
||||
this.nodeConverter = new CachedConverter<Node>(
|
||||
new Neo4jEntityConverterImpl<Object,Node>(mappingContext, conversionService, nodeEntityInstantiator,
|
||||
entityStateHandler, nodeTypeMapper, nodeStateTransmitter, fetchHandler));
|
||||
|
||||
this.relationshipConverter = new CachedConverter<Relationship>(
|
||||
new Neo4jEntityConverterImpl<Object,Relationship>(mappingContext, conversionService,
|
||||
relationshipEntityInstantiator, entityStateHandler, relationShipTypeMapper,
|
||||
relationshipStateTransmitter, fetchHandler));
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
|
||||
return createEntityFromState(state,null);
|
||||
}
|
||||
|
||||
static class StackedEntityCache {
|
||||
private long depth;
|
||||
private final Map<PropertyContainer,Object> objects =new HashMap<PropertyContainer, Object>();
|
||||
private static ThreadLocal<StackedEntityCache> stackedEntityCache = new ThreadLocal<StackedEntityCache>() {
|
||||
@Override
|
||||
protected StackedEntityCache initialValue() {
|
||||
return new StackedEntityCache();
|
||||
}
|
||||
};
|
||||
|
||||
public static void push() {
|
||||
cache().depth++;
|
||||
}
|
||||
public static void pop() {
|
||||
if (--cache().depth==0) {
|
||||
stackedEntityCache.remove();
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T get(PropertyContainer state) {
|
||||
return (T) cache().objects.get(state);
|
||||
}
|
||||
public static <T> T add(PropertyContainer state, T value) {
|
||||
cache().objects.put(state, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private static StackedEntityCache cache() {
|
||||
return stackedEntityCache.get();
|
||||
}
|
||||
|
||||
public static boolean contains(PropertyContainer state) {
|
||||
return cache().objects.containsKey(state);
|
||||
}
|
||||
}
|
||||
static class CachedInstantiator<S extends PropertyContainer> implements EntityInstantiator<S> {
|
||||
private final EntityInstantiator<S> delegate;
|
||||
|
||||
CachedInstantiator(EntityInstantiator<S> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T createEntityFromState(S state, Class<T> type) {
|
||||
try {
|
||||
if (state==null) throw new IllegalArgumentException("State must not be null");
|
||||
StackedEntityCache.push();
|
||||
if (StackedEntityCache.contains(state)) return StackedEntityCache.get(state);
|
||||
return StackedEntityCache.add(state, delegate.createEntityFromState(state, type));
|
||||
} finally {
|
||||
StackedEntityCache.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
static class CachedConverter<S extends PropertyContainer> implements Neo4jEntityConverter<Object,S> {
|
||||
private final Neo4jEntityConverter<Object,S> delegate;
|
||||
|
||||
CachedConverter(Neo4jEntityConverter<Object, S> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> getMappingContext() {
|
||||
return delegate.getMappingContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionService getConversionService() {
|
||||
return delegate.getConversionService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R read(Class<R> type, S state) {
|
||||
try {
|
||||
if (state==null) throw new IllegalArgumentException("State must not be null");
|
||||
StackedEntityCache.push();
|
||||
if (StackedEntityCache.contains(state)) return StackedEntityCache.get(state);
|
||||
return StackedEntityCache.add(state, delegate.read(type, state));
|
||||
} finally {
|
||||
StackedEntityCache.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object source, S sink) {
|
||||
delegate.write(source,sink);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
|
||||
if (state == null) throw new IllegalArgumentException("state has to be either a Node or Relationship");
|
||||
if (isNode(state)) {
|
||||
return nodeConverter.read(type, (Node) state);
|
||||
}
|
||||
if (isRelationship(state)) {
|
||||
return relationshipConverter.read(type, (Relationship) state);
|
||||
}
|
||||
throw new IllegalArgumentException("state has to be either a Node or Relationship");
|
||||
}
|
||||
|
||||
private boolean isRelationship(PropertyContainer state) {
|
||||
return state instanceof Relationship;
|
||||
}
|
||||
|
||||
private boolean isNode(PropertyContainer state) {
|
||||
return state instanceof Node;
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T projectTo(Object entity, Class<T> targetType) {
|
||||
S state = getPersistentState(entity);
|
||||
return createEntityFromState(state, targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> S getPersistentState(Object entity) {
|
||||
return entityStateHandler.getPersistentState(entity);
|
||||
}
|
||||
|
||||
|
||||
public Object persist(Object entity) {
|
||||
final Class<?> type = entity.getClass();
|
||||
if (isManaged(entity)) {
|
||||
return ((ManagedEntity)entity).persist();
|
||||
} else {
|
||||
return persist(entity, type);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isManaged(Object entity) {
|
||||
return entityStateHandler.isManaged(entity);
|
||||
}
|
||||
|
||||
private Object persist(Object entity, Class<?> type) {
|
||||
if (isNodeEntity(type)) {
|
||||
final Node node = this.<Node>getPersistentState(entity);
|
||||
this.nodeConverter.write(entity, node);
|
||||
return entity; // TODO ?
|
||||
}
|
||||
if (isRelationshipEntity(type)) {
|
||||
final Relationship relationship = this.<Relationship>getPersistentState(entity);
|
||||
this.relationshipConverter.write(entity, relationship);
|
||||
return entity; // TODO ?
|
||||
}
|
||||
throw new IllegalArgumentException("@NodeEntity or @RelationshipEntity annotation required on domain class"+type);
|
||||
}
|
||||
|
||||
public boolean isNodeEntity(Class<?> targetType) {
|
||||
return mappingContext.isNodeEntity(targetType);
|
||||
}
|
||||
|
||||
public boolean isRelationshipEntity(Class targetType) {
|
||||
return mappingContext.isRelationshipEntity(targetType);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer> void setPersistentState(Object entity, S state) {
|
||||
entityStateHandler.setPersistentState(entity,state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingContext<? extends Neo4jPersistentEntity<?>, Neo4jPersistentProperty> getMappingContext() {
|
||||
return mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConversionService getConversionService() {
|
||||
return this.nodeConverter.getConversionService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R read(Class<R> type, Node source) {
|
||||
return createEntityFromState(source, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object source, Node sink) {
|
||||
nodeConverter.write(source,sink);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import scala.annotation.target.field;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.neo4j.graphdb.index.IndexManager;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.10.11
|
||||
*/
|
||||
public class EntityRemover {
|
||||
|
||||
private EntityStateHandler entityStateHandler;
|
||||
private TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy;
|
||||
private TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy;
|
||||
private IndexManager indexManager;
|
||||
|
||||
public EntityRemover(EntityStateHandler entityStateHandler, TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy, TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy, IndexManager indexManager) {
|
||||
this.entityStateHandler = entityStateHandler;
|
||||
this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy;
|
||||
this.relationshipTypeRepresentationStrategy = relationshipTypeRepresentationStrategy;
|
||||
this.indexManager = indexManager;
|
||||
}
|
||||
|
||||
public void removeNodeEntity(Object entity) {
|
||||
Node node = entityStateHandler.getPersistentState(entity, Node.class);
|
||||
if (node == null) return;
|
||||
nodeTypeRepresentationStrategy.preEntityRemoval(node);
|
||||
for (Relationship relationship : node.getRelationships()) {
|
||||
removeRelationship(relationship);
|
||||
}
|
||||
removeFromIndexes(node);
|
||||
node.delete();
|
||||
}
|
||||
|
||||
public void removeRelationshipEntity(Object entity) {
|
||||
Relationship relationship = entityStateHandler.getPersistentState(entity, Relationship.class);
|
||||
if (relationship == null) return;
|
||||
removeRelationship(relationship);
|
||||
}
|
||||
|
||||
private void removeRelationship(Relationship relationship) {
|
||||
relationshipTypeRepresentationStrategy.preEntityRemoval(relationship);
|
||||
removeFromIndexes(relationship);
|
||||
relationship.delete();
|
||||
}
|
||||
|
||||
private void removeFromIndexes(Node node) {
|
||||
for (String indexName : indexManager.nodeIndexNames()) {
|
||||
indexManager.forNodes(indexName).remove(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeFromIndexes(Relationship relationship) {
|
||||
for (String indexName : indexManager.relationshipIndexNames()) {
|
||||
indexManager.forRelationships(indexName).remove(relationship);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRelationshipTo(Object start, Object target, String type) {
|
||||
final RelationshipResult result = entityStateHandler.removeRelationshipTo(start, target, type);
|
||||
if (result!=null && result.type == RelationshipResult.Type.DELETED) {
|
||||
relationshipTypeRepresentationStrategy.preEntityRemoval(result.relationship);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,23 @@ public class EntityStateHandler {
|
||||
return ManagedEntity.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
public boolean hasPersistentState(Object entity) {
|
||||
if (entity instanceof PropertyContainer) return true;
|
||||
if (isManaged(entity)) return ((ManagedEntity) entity).getPersistentState() != null;
|
||||
return getId(entity) != null;
|
||||
}
|
||||
|
||||
private Number getId(Object entity) {
|
||||
final Class<?> type = entity.getClass();
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
final Object id = persistentEntity.getPersistentId(entity);
|
||||
if (id == null) return null; // todo create new node?
|
||||
if (id instanceof Number) {
|
||||
return ((Number) id);
|
||||
}
|
||||
throw new IllegalArgumentException("The id of " + persistentEntity.getEntityName() + " " + persistentEntity.getIdProperty() + " is not a number");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> S getPersistentState(Object entity) {
|
||||
if (entity instanceof PropertyContainer) {
|
||||
@@ -64,17 +81,14 @@ public class EntityStateHandler {
|
||||
if (isManaged(entity)) {
|
||||
return ((ManagedEntity<S, Object>) entity).getPersistentState();
|
||||
}
|
||||
final Class<?> type = entity.getClass();
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(type);
|
||||
final Object id = persistentEntity.getPersistentId(entity);
|
||||
if (id == null) return null; // todo create new node?
|
||||
if (!(id instanceof Number))
|
||||
throw new IllegalArgumentException("The id of " + persistentEntity.getEntityName() + " " + persistentEntity.getIdProperty() + " is not a number");
|
||||
long graphId = ((Number) id).longValue();
|
||||
if (isNodeEntity(type)) {
|
||||
final Number id = getId(entity);
|
||||
if (id == null) return null;
|
||||
long graphId = id.longValue();
|
||||
final Neo4jPersistentEntityImpl<?> persistentEntity = mappingContext.getPersistentEntity(entity.getClass());
|
||||
if (persistentEntity.isNodeEntity()) {
|
||||
return (S) service.getNodeById(graphId);
|
||||
}
|
||||
if (isRelationshipEntity(type)) {
|
||||
if (persistentEntity.isRelationshipEntity()) {
|
||||
return (S) service.getRelationshipById(graphId);
|
||||
}
|
||||
throw new IllegalArgumentException("The entity " + persistentEntity.getEntityName() + " has to be either annotated with @NodeEntity or @RelationshipEntity");
|
||||
@@ -115,4 +129,81 @@ public class EntityStateHandler {
|
||||
}
|
||||
return (S) startNode.createRelationshipTo(endNode, DynamicRelationshipType.withName(relType.toString()));
|
||||
}
|
||||
|
||||
public RelationshipResult relateTo(Object source, Object target, String type) {
|
||||
return this.relateTo(source, target, type, false);
|
||||
}
|
||||
|
||||
// todo gdc.postEntityCreation(rel), return createEntityFromState(rel)
|
||||
public RelationshipResult relateTo(Object source, Object target, String type, boolean allowDuplicates) {
|
||||
if (source == null) throw new IllegalArgumentException("Source entity is null");
|
||||
if (target == null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (type == null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
|
||||
if (!allowDuplicates) {
|
||||
Relationship relationship = getRelationshipTo(source, target, type);
|
||||
if (relationship != null) return new RelationshipResult(relationship, RelationshipResult.Type.EXISTING);
|
||||
}
|
||||
|
||||
final Node sourceNode = getPersistentState(source, Node.class);
|
||||
final Node targetNode = getPersistentState(target, Node.class);
|
||||
|
||||
if (sourceNode == null) throw new IllegalArgumentException("Source Node is null");
|
||||
if (targetNode == null) throw new IllegalArgumentException("Target Node is null");
|
||||
|
||||
final Relationship relationship = sourceNode.createRelationshipTo(targetNode, DynamicRelationshipType.withName(type));
|
||||
return new RelationshipResult(relationship, RelationshipResult.Type.NEW);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends PropertyContainer> R getPersistentState(Object entity, Class<R> type) {
|
||||
final PropertyContainer state = getPersistentState(entity);
|
||||
if (type==null || type.isInstance(state)) return (R)state;
|
||||
throw new IllegalArgumentException("Target state is not the requested "+type+" but "+state);
|
||||
}
|
||||
|
||||
public RelationshipResult removeRelationshipTo(Object source, Object target, String relationshipType) {
|
||||
final Relationship relationship = getRelationshipTo(source, target, relationshipType);
|
||||
if (relationship!=null) {
|
||||
relationship.delete();
|
||||
return new RelationshipResult(relationship, RelationshipResult.Type.DELETED);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Relationship getRelationshipTo(Object source, Object target, String type) {
|
||||
if (source == null) throw new IllegalArgumentException("Source entity is null");
|
||||
if (target == null) throw new IllegalArgumentException("Target entity is null");
|
||||
if (type == null) throw new IllegalArgumentException("Relationshiptype is null");
|
||||
Node node = getPersistentState(source);
|
||||
Node targetNode = getPersistentState(target);
|
||||
if (node == null || targetNode == null) return null;
|
||||
Iterable<Relationship> relationships = node.getRelationships(DynamicRelationshipType.withName(type),Direction.OUTGOING);
|
||||
for (Relationship relationship : relationships) {
|
||||
if (relationship.getOtherNode(node).equals(targetNode)) return relationship;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final boolean equals(Object first, Object second) {
|
||||
if (second == first) return true;
|
||||
if (second == null) return false;
|
||||
final PropertyContainer firstState = getPersistentState(first);
|
||||
if (firstState == null) return false;
|
||||
final PropertyContainer secondState = getPersistentState(second);
|
||||
if (secondState == null) return false;
|
||||
return firstState.equals(secondState);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return result of the hashCode of the underlying node (if any, otherwise identityHashCode)
|
||||
*/
|
||||
public final int hashCode(Object entity) {
|
||||
if (entity == null) throw new IllegalArgumentException("Entity is null");
|
||||
final PropertyContainer state = getPersistentState(entity);
|
||||
if (state == null) return System.identityHashCode(entity);
|
||||
return state.hashCode();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,22 +21,22 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.graphdb.index.IndexManager;
|
||||
import org.neo4j.graphdb.traversal.*;
|
||||
import org.neo4j.graphdb.traversal.TraversalDescription;
|
||||
import org.neo4j.graphdb.traversal.Traverser;
|
||||
import org.neo4j.helpers.collection.ClosableIterable;
|
||||
import org.neo4j.helpers.collection.IterableWrapper;
|
||||
import org.neo4j.index.impl.lucene.LuceneIndexImplementation;
|
||||
import org.neo4j.kernel.AbstractGraphDatabase;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.EntityConverter;
|
||||
import org.springframework.data.neo4j.annotation.Indexed;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.annotation.RelationshipEntity;
|
||||
import org.springframework.data.neo4j.core.*;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jEntityConverter;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.fieldaccess.GraphBackedEntityIterableWrapper;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jEntityPersister;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jNodeConverter;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
|
||||
import org.springframework.data.neo4j.support.node.EntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.query.CypherQueryExecutor;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
@@ -50,7 +50,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Mediator class for the graph related services like the {@link GraphDatabaseService}, the used
|
||||
* {@link org.springframework.data.neo4j.core.TypeRepresentationStrategy}, entity instantiators for nodes and relationships as well as a spring conversion service.
|
||||
*
|
||||
* <p/>
|
||||
* It delegates the appropriate methods to those services. The services are not intended to be accessible from outside.
|
||||
*
|
||||
* @author Michael Hunger
|
||||
@@ -64,7 +64,6 @@ public class GraphDatabaseContext {
|
||||
|
||||
private GraphDatabaseService graphDatabaseService;
|
||||
private ConversionService conversionService;
|
||||
private Neo4jEntityConverter<Object,Node> converter;
|
||||
private Validator validator;
|
||||
private TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy;
|
||||
|
||||
@@ -73,31 +72,63 @@ public class GraphDatabaseContext {
|
||||
private Neo4jMappingContext mappingContext;
|
||||
private CypherQueryExecutor cypherQueryExecutor;
|
||||
private EntityStateHandler entityStateHandler;
|
||||
private Neo4jEntityPersister entityPersister;
|
||||
private EntityStateFactory<Node> nodeEntityStateFactory;
|
||||
private EntityStateFactory<Relationship> relationshipEntityStateFactory;
|
||||
private EntityRemover entityRemover;
|
||||
private TypeRepresentationStrategies typeRepresentationStrategies;
|
||||
|
||||
static class IndexProvider {
|
||||
private IndexManager indexManager;
|
||||
private Neo4jMappingContext mappingContext;
|
||||
|
||||
IndexProvider(IndexManager indexManager, Neo4jMappingContext mappingContext) {
|
||||
this.indexManager = indexManager;
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type) {
|
||||
return getIndex(type, null);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName) {
|
||||
return getIndex(type, indexName, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName, Boolean fullText) {
|
||||
if (indexName == null) indexName = Indexed.Name.get(type);
|
||||
if (fullText == null) {
|
||||
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName);
|
||||
if (mappingContext.isRelationshipEntity(type))
|
||||
return (Index<S>) getIndexManager().forRelationships(indexName);
|
||||
throw new IllegalArgumentException("Wrong index type supplied: " + type + " expected Node- or Relationship-Entity");
|
||||
|
||||
}
|
||||
Map<String, String> config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG;
|
||||
|
||||
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName, config);
|
||||
if (mappingContext.isRelationshipEntity(type))
|
||||
return (Index<S>) getIndexManager().forRelationships(indexName, config);
|
||||
throw new IllegalArgumentException("Wrong index type supplied: " + type + " expected Node- or Relationship-Entity");
|
||||
}
|
||||
|
||||
public IndexManager getIndexManager() {
|
||||
return indexManager;
|
||||
}
|
||||
}
|
||||
IndexProvider indexProvider;
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type) {
|
||||
return getIndex(type, null);
|
||||
return indexProvider.getIndex(type, null);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName) {
|
||||
return getIndex(type, indexName, null);
|
||||
return indexProvider.getIndex(type, indexName, null);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer, T> Index<S> getIndex(Class<T> type, String indexName, Boolean fullText) {
|
||||
if (indexName==null) indexName = Indexed.Name.get(type);
|
||||
if (fullText == null){
|
||||
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName);
|
||||
if (mappingContext.isRelationshipEntity(type)) return (Index<S>) getIndexManager().forRelationships(indexName);
|
||||
throw new IllegalArgumentException("Wrong index type supplied: " + type+" expected Node- or Relationship-Entity");
|
||||
|
||||
}
|
||||
Map<String, String> config = fullText ? LuceneIndexImplementation.FULLTEXT_CONFIG : LuceneIndexImplementation.EXACT_CONFIG;
|
||||
|
||||
if (mappingContext.isNodeEntity(type)) return (Index<S>) getIndexManager().forNodes(indexName, config);
|
||||
if (mappingContext.isRelationshipEntity(type)) return (Index<S>) getIndexManager().forRelationships(indexName, config);
|
||||
throw new IllegalArgumentException("Wrong index type supplied: " + type+" expected Node- or Relationship-Entity");
|
||||
return indexProvider.getIndex(type,indexName,fullText);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +136,7 @@ public class GraphDatabaseContext {
|
||||
*/
|
||||
public boolean transactionIsRunning() {
|
||||
if (!(graphDatabaseService instanceof AbstractGraphDatabase)) {
|
||||
return true; // assume always running tx (e.g. for REST or other remotes)
|
||||
return true; // assume always running tx (e.g. for REST or other remotes)
|
||||
}
|
||||
try {
|
||||
final TransactionManager txManager = ((AbstractGraphDatabase) graphDatabaseService).getConfig().getTxModule().getTxManager();
|
||||
@@ -116,152 +147,83 @@ public class GraphDatabaseContext {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> ClosableIterable<T> findAll(final Class<T> entityClass) {
|
||||
return getTypeRepresentationStrategy(entityClass).findAll(entityClass);
|
||||
}
|
||||
|
||||
public <T> long count(final Class<T> entityClass) {
|
||||
return getTypeRepresentationStrategy(entityClass).count(entityClass);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
|
||||
return getTypeRepresentationStrategy(state).createEntity(state);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
|
||||
if (state==null) throw new IllegalArgumentException("state has to be either a Node or Relationship, not null");
|
||||
return getTypeRepresentationStrategy(state, type).createEntity(state, type);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T projectTo(Object entity, Class<T> targetType) {
|
||||
S state = getPersistentState(entity);
|
||||
return getTypeRepresentationStrategy(state, targetType).projectEntity(state, targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> S getPersistentState(Object entity) {
|
||||
return entityStateHandler.getPersistentState(entity);
|
||||
}
|
||||
|
||||
// todo depending on type of mapping
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> void setPersistentState(Object entity, S state) {
|
||||
entityStateHandler.setPersistentState(entity, state);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> void postEntityCreation(S node, Class<T> entityClass) {
|
||||
getTypeRepresentationStrategy(node, entityClass).postEntityCreation(node, entityClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Iterable<T> findAllByTraversal(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
|
||||
final PropertyContainer state = entityStateHandler.getPersistentState(entity);
|
||||
public <T> Iterable<T> findAllByTraversal(Object entity, Class<?> targetType, TraversalDescription traversalDescription) {
|
||||
final PropertyContainer state = entityPersister.getPersistentState(entity);
|
||||
if (state == null) throw new IllegalStateException("No node attached to " + this);
|
||||
final Traverser traverser = traversalDescription.traverse((Node) state);
|
||||
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
|
||||
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
|
||||
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
|
||||
return (Iterable<T>)convertToGraphEntity(traverser, targetType);
|
||||
return (Iterable<T>) convertToGraphEntity(traverser, targetType);
|
||||
}
|
||||
|
||||
private Iterable<?> convertToGraphEntity(Traverser traverser, final Class<?> targetType) {
|
||||
if (isNodeEntity(targetType)) {
|
||||
return new IterableWrapper<Object,Node>(traverser.nodes()) {
|
||||
return new IterableWrapper<Object, Node>(traverser.nodes()) {
|
||||
@Override
|
||||
protected Object underlyingObjectToObject(Node node) {
|
||||
return createEntityFromState(node,targetType);
|
||||
return createEntityFromState(node, targetType);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (isRelationshipEntity(targetType)) {
|
||||
return new IterableWrapper<Object,Relationship>(traverser.relationships()) {
|
||||
return new IterableWrapper<Object, Relationship>(traverser.relationships()) {
|
||||
@Override
|
||||
protected Object underlyingObjectToObject(Relationship relationship) {
|
||||
return createEntityFromState(relationship, targetType);
|
||||
}
|
||||
};
|
||||
}
|
||||
throw new IllegalStateException("Can't determine valid type for traversal target "+targetType);
|
||||
throw new IllegalStateException("Can't determine valid type for traversal target " + targetType);
|
||||
|
||||
}
|
||||
|
||||
public <T> ClosableIterable<T> findAll(final Class<T> entityClass) {
|
||||
return typeRepresentationStrategies.findAll(entityClass);
|
||||
}
|
||||
|
||||
public <T> long count(final Class<T> entityClass) {
|
||||
return typeRepresentationStrategies.count(entityClass);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromStoredType(S state) {
|
||||
return entityPersister.createEntityFromStoredType(state);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T createEntityFromState(S state, Class<T> type) {
|
||||
return entityPersister.createEntityFromState(state, type);
|
||||
}
|
||||
|
||||
public <S extends PropertyContainer, T> T projectTo(Object entity, Class<T> targetType) {
|
||||
return entityPersister.projectTo(entity, targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> S getPersistentState(Object entity) {
|
||||
return entityPersister.getPersistentState(entity);
|
||||
}
|
||||
|
||||
// todo depending on type of mapping
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends PropertyContainer> void setPersistentState(Object entity, S state) {
|
||||
entityPersister.setPersistentState(entity, state);
|
||||
}
|
||||
|
||||
@Deprecated() // TODO remove
|
||||
public <S extends PropertyContainer, T> void postEntityCreation(S node, Class<T> entityClass) {
|
||||
typeRepresentationStrategies.postEntityCreation(node, entityClass);
|
||||
}
|
||||
|
||||
public void removeNodeEntity(Object entity) {
|
||||
Node node = getPersistentState(entity);
|
||||
if (node == null) return;
|
||||
nodeTypeRepresentationStrategy.preEntityRemoval(node);
|
||||
for (Relationship relationship : node.getRelationships()) {
|
||||
removeRelationship(relationship);
|
||||
}
|
||||
removeFromIndexes(node);
|
||||
node.delete();
|
||||
entityRemover.removeNodeEntity(entity);
|
||||
}
|
||||
|
||||
public void removeRelationshipEntity(Object entity) {
|
||||
Relationship relationship = getPersistentState(entity);
|
||||
if (relationship == null) return;
|
||||
removeRelationship(relationship);
|
||||
entityRemover.removeRelationshipEntity(entity);
|
||||
}
|
||||
|
||||
private void removeRelationship(Relationship relationship) {
|
||||
relationshipTypeRepresentationStrategy.preEntityRemoval(relationship);
|
||||
removeFromIndexes(relationship);
|
||||
relationship.delete();
|
||||
}
|
||||
|
||||
private void removeFromIndexes(Node node) {
|
||||
IndexManager indexManager = getIndexManager();
|
||||
for (String indexName : indexManager.nodeIndexNames()) {
|
||||
indexManager.forNodes(indexName).remove(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeFromIndexes(Relationship relationship) {
|
||||
IndexManager indexManager = getIndexManager();
|
||||
for (String indexName : indexManager.relationshipIndexNames()) {
|
||||
indexManager.forRelationships(indexName).remove(relationship);
|
||||
}
|
||||
}
|
||||
|
||||
private IndexManager getIndexManager() {
|
||||
return graphDatabaseService.index();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> TypeRepresentationStrategy<?> getTypeRepresentationStrategy(Class<T> type) {
|
||||
if (mappingContext.isNodeEntity(type)) {
|
||||
return (TypeRepresentationStrategy<?>)nodeTypeRepresentationStrategy;
|
||||
} else if (mappingContext.isRelationshipEntity(type)) {
|
||||
return (TypeRepresentationStrategy<?>)relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer, T> TypeRepresentationStrategy<S> getTypeRepresentationStrategy(S state, Class<T> type) {
|
||||
if (state instanceof Node && mappingContext.isNodeEntity(type)) {
|
||||
return (TypeRepresentationStrategy<S>) nodeTypeRepresentationStrategy;
|
||||
} else if (state instanceof Relationship && mappingContext.isRelationshipEntity(type)) {
|
||||
return (TypeRepresentationStrategy<S>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type "+type+" is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer, T> TypeRepresentationStrategy<S> getTypeRepresentationStrategy(S state) {
|
||||
if (state instanceof Node) {
|
||||
return (TypeRepresentationStrategy<S>) nodeTypeRepresentationStrategy;
|
||||
} else if (state instanceof Relationship) {
|
||||
return (TypeRepresentationStrategy<S>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegates to {@link GraphDatabaseService}
|
||||
*/
|
||||
@@ -279,7 +241,7 @@ public class GraphDatabaseContext {
|
||||
/**
|
||||
* Delegates to {@link GraphDatabaseService}
|
||||
*/
|
||||
public Node getReferenceNode() {
|
||||
public Node getReferenceNode() {
|
||||
return graphDatabaseService.getReferenceNode();
|
||||
}
|
||||
|
||||
@@ -304,17 +266,97 @@ public class GraphDatabaseContext {
|
||||
return graphDatabaseService.getRelationshipById(id);
|
||||
}
|
||||
|
||||
public GraphDatabaseService getGraphDatabaseService() {
|
||||
return graphDatabaseService;
|
||||
}
|
||||
|
||||
public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void createCypherExecutor() {
|
||||
public void postConstruct() {
|
||||
this.typeRepresentationStrategies = new TypeRepresentationStrategies(mappingContext, nodeTypeRepresentationStrategy, relationshipTypeRepresentationStrategy);
|
||||
this.cypherQueryExecutor = new CypherQueryExecutor(this);
|
||||
this.entityPersister = new Neo4jEntityPersister(graphDatabaseService, mappingContext, conversionService,
|
||||
nodeEntityStateFactory, relationshipEntityStateFactory, nodeTypeRepresentationStrategy, relationshipTypeRepresentationStrategy);
|
||||
this.entityRemover = new EntityRemover(entityStateHandler, nodeTypeRepresentationStrategy, relationshipTypeRepresentationStrategy, graphDatabaseService.index());
|
||||
this.indexProvider = new IndexProvider(graphDatabaseService.index(), mappingContext);
|
||||
}
|
||||
|
||||
|
||||
public boolean isNodeEntity(Class<?> targetType) {
|
||||
return targetType.isAnnotationPresent(NodeEntity.class);
|
||||
//return mappingContext.isNodeEntity(targetType);
|
||||
}
|
||||
|
||||
public boolean isRelationshipEntity(Class targetType) {
|
||||
return targetType.isAnnotationPresent(RelationshipEntity.class);
|
||||
// return mappingContext.isRelationshipEntity(targetType);
|
||||
}
|
||||
|
||||
public Object save(Object entity) {
|
||||
return entityPersister.persist(entity);
|
||||
}
|
||||
|
||||
public boolean isManaged(Object entity) {
|
||||
return entityStateHandler.isManaged(entity);
|
||||
}
|
||||
|
||||
public Object executeQuery(String queryString, Map<String, Object> params, Neo4jPersistentProperty property) {
|
||||
final TypeInformation<?> typeInformation = property.getTypeInformation();
|
||||
final TypeInformation<?> actualType = typeInformation.getActualType();
|
||||
final Class<?> targetType = actualType.getType();
|
||||
if (actualType.isMap()) {
|
||||
return cypherQueryExecutor.queryForList(queryString, params);
|
||||
}
|
||||
if (typeInformation.isCollectionLike()) {
|
||||
return cypherQueryExecutor.query(queryString, targetType, params);
|
||||
}
|
||||
return cypherQueryExecutor.queryForObject(queryString, targetType, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Iterable<T> convertResultsTo(Traverser traverser, Class<T> targetType) {
|
||||
if (Node.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.nodes();
|
||||
if (Relationship.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser.relationships();
|
||||
if (Path.class.isAssignableFrom(targetType)) return (Iterable<T>) traverser;
|
||||
if (isNodeEntity(targetType)) {
|
||||
return GraphBackedEntityIterableWrapper.create(traverser.nodes(), targetType, this);
|
||||
}
|
||||
if (isRelationshipEntity(targetType)) {
|
||||
return GraphBackedEntityIterableWrapper.create(traverser.relationships(), targetType, this);
|
||||
}
|
||||
throw new IllegalStateException("Can't determine valid type for traversal target " + targetType);
|
||||
}
|
||||
|
||||
|
||||
public <R> R getRelationshipTo(Object source, Object target, Class<R> relationshipClass, String type) {
|
||||
final Relationship relationship = entityStateHandler.getRelationshipTo(source, target, type);
|
||||
if (relationship == null) return null;
|
||||
return entityPersister.createEntityFromState(relationship, relationshipClass);
|
||||
}
|
||||
|
||||
public void removeRelationshipTo(Object start, Object target, String type) {
|
||||
entityRemover.removeRelationshipTo(start, target, type);
|
||||
}
|
||||
|
||||
public <R> R relateTo(Object source, Object target, Class<R> relationshipClass, String relationshipType, boolean allowDuplicates) {
|
||||
final RelationshipResult result = entityStateHandler.relateTo(source, target, relationshipType, allowDuplicates);
|
||||
if (result.type == RelationshipResult.Type.NEW) {
|
||||
// TODO
|
||||
postEntityCreation(result.relationship, relationshipClass);
|
||||
}
|
||||
return createEntityFromState(result.relationship, relationshipClass);
|
||||
}
|
||||
|
||||
|
||||
public void setEntityStateHandler(EntityStateHandler entityStateHandler) {
|
||||
this.entityStateHandler = entityStateHandler;
|
||||
}
|
||||
|
||||
public void setNodeEntityStateFactory(EntityStateFactory<Node> nodeEntityStateFactory) {
|
||||
this.nodeEntityStateFactory = nodeEntityStateFactory;
|
||||
}
|
||||
|
||||
public void setRelationshipEntityStateFactory(EntityStateFactory<Relationship> relationshipEntityStateFactory) {
|
||||
this.relationshipEntityStateFactory = relationshipEntityStateFactory;
|
||||
}
|
||||
|
||||
public EntityStateHandler getEntityStateHandler() {
|
||||
return entityStateHandler;
|
||||
}
|
||||
|
||||
public TypeRepresentationStrategy<Node> getNodeTypeRepresentationStrategy() {
|
||||
@@ -334,12 +376,12 @@ public class GraphDatabaseContext {
|
||||
}
|
||||
|
||||
public ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public Validator getValidator() {
|
||||
return validator;
|
||||
@@ -353,49 +395,13 @@ public class GraphDatabaseContext {
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
public boolean isNodeEntity(Class<?> targetType) {
|
||||
return targetType.isAnnotationPresent(NodeEntity.class);
|
||||
//return mappingContext.isNodeEntity(targetType);
|
||||
|
||||
public GraphDatabaseService getGraphDatabaseService() {
|
||||
return graphDatabaseService;
|
||||
}
|
||||
|
||||
public boolean isRelationshipEntity(Class targetType) {
|
||||
return targetType.isAnnotationPresent(RelationshipEntity.class);
|
||||
// return mappingContext.isRelationshipEntity(targetType);
|
||||
}
|
||||
|
||||
public Object save(Object entity) {
|
||||
if (isManaged(entity)) {
|
||||
return ((ManagedEntity)entity).persist();
|
||||
} else {
|
||||
final Node node = this.<Node>getPersistentState(entity);
|
||||
this.converter.write(entity, node);
|
||||
return entity; // TODO ?
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isManaged(Object entity) {
|
||||
return entityStateHandler.isManaged(entity);
|
||||
}
|
||||
|
||||
public void setNodeEntityConverter(Neo4jEntityConverter<Object, Node> converter) {
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public Object executeQuery(Object entity, String queryString, Map<String, Object> params, Neo4jPersistentProperty property) {
|
||||
final TypeInformation<?> typeInformation = property.getTypeInformation();
|
||||
final TypeInformation<?> actualType = typeInformation.getActualType();
|
||||
final Class<?> targetType = actualType.getType();
|
||||
if (actualType.isMap()) {
|
||||
return cypherQueryExecutor.queryForList(queryString, params);
|
||||
}
|
||||
if (typeInformation.isCollectionLike()) {
|
||||
return cypherQueryExecutor.query(queryString, targetType, params);
|
||||
}
|
||||
return cypherQueryExecutor.queryForObject(queryString, targetType, params);
|
||||
}
|
||||
|
||||
public void setEntityStateHandler(EntityStateHandler entityStateHandler) {
|
||||
this.entityStateHandler = entityStateHandler;
|
||||
public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) {
|
||||
this.graphDatabaseService = graphDatabaseService;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.10.11
|
||||
*/
|
||||
public class RelationshipResult {
|
||||
public final Relationship relationship;
|
||||
public final Type type;
|
||||
|
||||
RelationshipResult(Relationship relationship, Type type) {
|
||||
this.relationship = relationship;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public enum Type { NEW, EXISTING, DELETED }
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.neo4j.graphdb.PropertyContainer;
|
||||
import org.neo4j.graphdb.Relationship;
|
||||
import org.neo4j.helpers.collection.ClosableIterable;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.10.11
|
||||
*/
|
||||
public class TypeRepresentationStrategies implements TypeRepresentationStrategy<PropertyContainer> {
|
||||
private final Neo4jMappingContext mappingContext;
|
||||
private final TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy;
|
||||
private final TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy;
|
||||
|
||||
TypeRepresentationStrategies(Neo4jMappingContext mappingContext,
|
||||
TypeRepresentationStrategy<Node> nodeTypeRepresentationStrategy,
|
||||
TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy) {
|
||||
this.mappingContext = mappingContext;
|
||||
this.nodeTypeRepresentationStrategy = nodeTypeRepresentationStrategy;
|
||||
this.relationshipTypeRepresentationStrategy = relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> TypeRepresentationStrategy<?> getTypeRepresentationStrategy(Class<T> type) {
|
||||
if (mappingContext.isNodeEntity(type)) {
|
||||
return (TypeRepresentationStrategy<?>) nodeTypeRepresentationStrategy;
|
||||
} else if (mappingContext.isRelationshipEntity(type)) {
|
||||
return (TypeRepresentationStrategy<?>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer, T> TypeRepresentationStrategy<S> getTypeRepresentationStrategy(S state, Class<T> type) {
|
||||
if (state instanceof Node && mappingContext.isNodeEntity(type)) {
|
||||
return (TypeRepresentationStrategy<S>) nodeTypeRepresentationStrategy;
|
||||
} else if (state instanceof Relationship && mappingContext.isRelationshipEntity(type)) {
|
||||
return (TypeRepresentationStrategy<S>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type " + type + " is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <S extends PropertyContainer, T> TypeRepresentationStrategy<S> getTypeRepresentationStrategy(S state) {
|
||||
if (state instanceof Node) {
|
||||
return (TypeRepresentationStrategy<S>) nodeTypeRepresentationStrategy;
|
||||
} else if (state instanceof Relationship) {
|
||||
return (TypeRepresentationStrategy<S>) relationshipTypeRepresentationStrategy;
|
||||
}
|
||||
throw new IllegalArgumentException("Type is not NodeBacked nor RelationshipBacked.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postEntityCreation(PropertyContainer state, Class<?> type) {
|
||||
getTypeRepresentationStrategy(state, type).postEntityCreation(state, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> ClosableIterable<U> findAll(Class<U> type) {
|
||||
return getTypeRepresentationStrategy(type).findAll(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count(Class<?> type) {
|
||||
return getTypeRepresentationStrategy(type).count(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> Class<U> getJavaType(PropertyContainer state) {
|
||||
return getTypeRepresentationStrategy(state).getJavaType(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preEntityRemoval(PropertyContainer state) {
|
||||
getTypeRepresentationStrategy(state).preEntityRemoval(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> U createEntity(PropertyContainer state) throws IllegalStateException {
|
||||
return getTypeRepresentationStrategy(state).createEntity(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> U createEntity(PropertyContainer state, Class<U> type) throws IllegalStateException, IllegalArgumentException {
|
||||
return getTypeRepresentationStrategy(state, type).createEntity(state, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> U projectEntity(PropertyContainer state, Class<U> type) {
|
||||
return getTypeRepresentationStrategy(state).projectEntity(state, type);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.conversion.EntityResultConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -47,18 +46,14 @@ public class CypherQueryExecutor implements QueryOperations<Map<String,Object>>
|
||||
}
|
||||
|
||||
public Iterable<Map<String, Object>> queryForList(String statement, Map<String,Object> params) {
|
||||
return queryEngine.query(statement,mergeParams(params));
|
||||
return queryEngine.query(statement, params);
|
||||
}
|
||||
|
||||
public <T> Iterable<T> query(String statement, Class<T> type, Map<String,Object> params) {
|
||||
return queryEngine.query(statement,mergeParams(params)).to(type);
|
||||
return queryEngine.query(statement, params).to(type);
|
||||
}
|
||||
|
||||
public <T> T queryForObject(String statement, Class<T> type, Map<String,Object> params) {
|
||||
return (T) queryEngine.query(statement,mergeParams(params)).to(type).single();
|
||||
}
|
||||
private Map<String,Object> mergeParams(Map<String,Object> params) {
|
||||
if (params==null) return Collections.emptyMap();
|
||||
return params;
|
||||
return (T) queryEngine.query(statement, params).to(type).single();
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ import org.springframework.data.neo4j.support.EntityInstantiator;
|
||||
|
||||
public class IndexingRelationshipTypeRepresentationStrategy implements RelationshipTypeRepresentationStrategy {
|
||||
|
||||
public static final String INDEX_NAME = "__types__";
|
||||
public static final String INDEX_NAME = "__rel_types__";
|
||||
public static final String TYPE_PROPERTY_NAME = "__type__";
|
||||
public static final String INDEX_KEY = "className";
|
||||
private EntityInstantiator<Relationship> relationshipEntityInstantiator;
|
||||
|
||||
@@ -15,32 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.neo4j.mapping;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.graphdb.index.Index;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean;
|
||||
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
|
||||
import org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory;
|
||||
import org.springframework.data.neo4j.model.Friendship;
|
||||
import org.springframework.data.neo4j.model.Group;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.model.Personality;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopNodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopRelationshipTypeRepresentationStrategy;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -52,17 +34,7 @@ import static org.junit.Assert.assertEquals;
|
||||
* @author mh
|
||||
* @since 19.09.11
|
||||
*/
|
||||
public class Neo4jEntityConverterTest {
|
||||
|
||||
public static final DynamicRelationshipType PERSONS = DynamicRelationshipType.withName("persons");
|
||||
private static final RelationshipType KNOWS = DynamicRelationshipType.withName("knows");
|
||||
private Neo4jEntityConverterImpl<Object,Node> converter;
|
||||
private Transaction tx;
|
||||
private GraphDatabaseContext gdc;
|
||||
private Group group;
|
||||
private Person michael;
|
||||
private Person emil;
|
||||
private Person andres;
|
||||
public class Neo4jEntityConverterTest extends Neo4jPersistentTestBase {
|
||||
|
||||
/* OUCH
|
||||
|
||||
@@ -92,76 +64,6 @@ public class Neo4jEntityConverterTest {
|
||||
|
||||
*/
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Neo4jMappingContext mappingContext = new Neo4jMappingContext();
|
||||
gdc = createContext(mappingContext);
|
||||
tx = gdc.beginTx();
|
||||
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = createNodeEntityStateFactory(mappingContext);
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = createRelationshipEntityStateFactory(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdc.getGraphDatabaseService());
|
||||
final NodeEntityInstantiator entityInstantiator = new NodeEntityInstantiator(entityStateHandler);
|
||||
final TypeRepresentationStrategy<Node> typeRepresentationStrategy = gdc.getNodeTypeRepresentationStrategy();
|
||||
TypeMapper<Node> typeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(typeRepresentationStrategy),asList(new ClassValueTypeInformationMapper()));
|
||||
SourceStateTransmitter<Node> nodeStateTransmitter = new SourceStateTransmitter<Node>(nodeEntityStateFactory);
|
||||
SourceStateTransmitter<Relationship> relationshipStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory);
|
||||
final ConversionService conversionService = gdc.getConversionService();
|
||||
|
||||
Neo4jEntityFetchHandler fetchHandler=new Neo4jEntityFetchHandler(entityStateHandler, conversionService, relationshipStateTransmitter , nodeStateTransmitter);
|
||||
|
||||
converter = new Neo4jEntityConverterImpl<Object,Node>(mappingContext, conversionService, entityInstantiator, entityStateHandler, typeMapper, nodeStateTransmitter, fetchHandler);
|
||||
gdc.setNodeEntityConverter(converter);
|
||||
group = new Group();
|
||||
michael = new Person("Michael", 37);
|
||||
emil = new Person("Emil", 30);
|
||||
andres = new Person("Andrés", 36);
|
||||
}
|
||||
|
||||
private NodeEntityStateFactory createNodeEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = new NodeEntityStateFactory();
|
||||
nodeEntityStateFactory.setMappingContext(mappingContext);
|
||||
nodeEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
nodeEntityStateFactory.setNodeDelegatingFieldAccessorFactory(new NodeDelegatingFieldAccessorFactory(gdc));
|
||||
return nodeEntityStateFactory;
|
||||
}
|
||||
private RelationshipEntityStateFactory createRelationshipEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = new RelationshipEntityStateFactory();
|
||||
relationshipEntityStateFactory.setMappingContext(mappingContext);
|
||||
relationshipEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
relationshipEntityStateFactory.setRelationshipDelegatingFieldAccessorFactory(new RelationshipDelegatingFieldAccessorFactory(gdc));
|
||||
return relationshipEntityStateFactory;
|
||||
}
|
||||
|
||||
private GraphDatabaseContext createContext(Neo4jMappingContext mappingContext) throws Exception {
|
||||
GraphDatabaseContext gdc = new GraphDatabaseContext();
|
||||
final ImpermanentGraphDatabase gdb = new ImpermanentGraphDatabase();
|
||||
gdc.setGraphDatabaseService(gdb);
|
||||
gdc.setMappingContext(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdb);
|
||||
gdc.setNodeTypeRepresentationStrategy(new NoopNodeTypeRepresentationStrategy(new NodeEntityInstantiator(entityStateHandler)));
|
||||
gdc.setRelationshipTypeRepresentationStrategy(new NoopRelationshipTypeRepresentationStrategy(new RelationshipEntityInstantiator(entityStateHandler)));
|
||||
gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject());
|
||||
gdc.setEntityStateHandler(entityStateHandler);
|
||||
gdc.createCypherExecutor();
|
||||
return gdc;
|
||||
}
|
||||
|
||||
|
||||
private List<Node> groupMemberNodes() {
|
||||
return groupMemberNodes(groupNode());
|
||||
}
|
||||
|
||||
private List<Node> groupMemberNodes(Node node) {
|
||||
return getRelatedNodes(node, "persons", Direction.OUTGOING);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
tx.failure();
|
||||
tx.finish();
|
||||
gdc.getGraphDatabaseService().shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteEntityToNewNode() {
|
||||
@@ -178,31 +80,23 @@ public class Neo4jEntityConverterTest {
|
||||
assertEquals("node found in index", createdNode, found);
|
||||
}
|
||||
|
||||
private Node michaelNode() {
|
||||
return gdc.getNodeById(michael.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteEntityToExistingNode() {
|
||||
final Node existingNode = createNewNode();
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
assertEquals("Entity uses provided node", (Long) existingNode.getId(), michael.getId());
|
||||
assertEquals("Michael", existingNode.getProperty("name"));
|
||||
}
|
||||
|
||||
private Node createNewNode() {
|
||||
return gdc.createNode();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateExistingNode() {
|
||||
final Node existingNode = createNewNode();
|
||||
existingNode.setProperty("name", "Test");
|
||||
assertEquals("Test", existingNode.getProperty("name"));
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
assertEquals("Michael", existingNode.getProperty("name"));
|
||||
michael.setName("Emil");
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
assertEquals("Emil", existingNode.getProperty("name"));
|
||||
}
|
||||
|
||||
@@ -211,7 +105,7 @@ public class Neo4jEntityConverterTest {
|
||||
final Node existingNode = createNewNode();
|
||||
michael.setBirthdate(new Date(100));
|
||||
michael.setPersonality(Personality.EXTROVERT);
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
assertEquals("100", existingNode.getProperty("birthdate"));
|
||||
assertEquals("EXTROVERT", existingNode.getProperty("personality"));
|
||||
}
|
||||
@@ -223,7 +117,7 @@ public class Neo4jEntityConverterTest {
|
||||
existingNode.setProperty("age", 36);
|
||||
existingNode.setProperty("personality", "EXTROVERT");
|
||||
existingNode.setProperty("birthdate", "100");
|
||||
final Person p = converter.read(Person.class, existingNode);
|
||||
final Person p = readPerson(existingNode);
|
||||
assertEquals("Michael", p.getName());
|
||||
assertEquals(36, p.getAge());
|
||||
assertEquals(new Date(100), p.getBirthdate());
|
||||
@@ -233,9 +127,9 @@ public class Neo4jEntityConverterTest {
|
||||
@Test
|
||||
public void testDeleteProperty() {
|
||||
final Node existingNode = createNewNode();
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
michael.setName(null);
|
||||
converter.write(michael, existingNode);
|
||||
write(michael, existingNode);
|
||||
assertEquals(false, existingNode.hasProperty("name"));
|
||||
}
|
||||
|
||||
@@ -243,7 +137,7 @@ public class Neo4jEntityConverterTest {
|
||||
public void testReadEntityFromExistingNode() {
|
||||
final Node node = createNewNode();
|
||||
node.setProperty("name", "Emil");
|
||||
final Person p = converter.read(Person.class, node);
|
||||
final Person p = readPerson(node);
|
||||
assertEquals("Emil", p.getName());
|
||||
}
|
||||
|
||||
@@ -257,31 +151,6 @@ public class Neo4jEntityConverterTest {
|
||||
assertEquals("added additional relationship end node", emil.getId(), (Long) boss.getId());
|
||||
}
|
||||
|
||||
private Group storeInGraph(Group g) {
|
||||
final Long id = g.getId();
|
||||
if (id != null) {
|
||||
converter.write(g, gdc.getNodeById(id));
|
||||
} else {
|
||||
converter.write(g, null);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
private Person storeInGraph(Person p) {
|
||||
final Long id = p.getId();
|
||||
if (id != null) {
|
||||
converter.write(p, gdc.getNodeById(id));
|
||||
} else {
|
||||
converter.write(p, null);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private <T> T storeInGraph(T obj) {
|
||||
converter.write(obj, null);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRelationshipWithPreExistingNode() {
|
||||
storeInGraph(michael);
|
||||
@@ -292,10 +161,6 @@ public class Neo4jEntityConverterTest {
|
||||
assertEquals("added michaelNode to group", michael.getId(), (Long) michaelNode.getId());
|
||||
}
|
||||
|
||||
private Node groupNode() {
|
||||
return gdc.getNodeById(group.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRelationshipWithTwoExistingNodes() {
|
||||
storeInGraph(michael);
|
||||
@@ -318,14 +183,6 @@ public class Neo4jEntityConverterTest {
|
||||
}
|
||||
|
||||
|
||||
private <T> Set<T> set(T... objs) {
|
||||
return new HashSet<T>(asList(objs));
|
||||
}
|
||||
|
||||
private <T> Set<T> set(Iterable<T> objs) {
|
||||
return IteratorUtil.addToCollection(objs, new HashSet<T>());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRelationshipCascadeOverTwoSteps() {
|
||||
andres.setBoss(emil);
|
||||
@@ -337,14 +194,6 @@ public class Neo4jEntityConverterTest {
|
||||
assertEquals(emil.getId(), (Long) getRelatedNodes(andresNode(), "boss", Direction.INCOMING).get(0).getId());
|
||||
}
|
||||
|
||||
private Node andresNode() {
|
||||
return gdc.getNodeById(andres.getId());
|
||||
}
|
||||
|
||||
private Node emilNode() {
|
||||
return gdc.getNodeById(emil.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteSingleRelationship() {
|
||||
emil.setBoss(andres);
|
||||
@@ -375,7 +224,7 @@ public class Neo4jEntityConverterTest {
|
||||
groupNode.createRelationshipTo(p1, PERSONS);
|
||||
groupNode.createRelationshipTo(p2, PERSONS);
|
||||
|
||||
Group g = converter.read(Group.class, groupNode);
|
||||
Group g = readGroup(groupNode);
|
||||
assertEquals(set(readPerson(p1), readPerson(p2)), set(g.getPersons()));
|
||||
}
|
||||
|
||||
@@ -387,7 +236,7 @@ public class Neo4jEntityConverterTest {
|
||||
groupNode.createRelationshipTo(p1, PERSONS);
|
||||
groupNode.createRelationshipTo(p2, PERSONS);
|
||||
|
||||
Group g = converter.read(Group.class, groupNode);
|
||||
Group g = readGroup(groupNode);
|
||||
assertEquals(set(readPerson(p1), readPerson(p2)), set(g.getReadOnlyPersons()));
|
||||
}
|
||||
|
||||
@@ -413,18 +262,6 @@ public class Neo4jEntityConverterTest {
|
||||
assertEquals(set(emilNode()), set(groupMemberNodes()));
|
||||
}
|
||||
|
||||
public Person readPerson(Node node) {
|
||||
return converter.read(Person.class, node);
|
||||
}
|
||||
|
||||
private List<Node> getRelatedNodes(Node startNode, String type, Direction direction) {
|
||||
List<Node> result = new ArrayList<Node>();
|
||||
for (Relationship relationship : startNode.getRelationships(DynamicRelationshipType.withName(type), direction)) {
|
||||
result.add(relationship.getOtherNode(startNode));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRelationshipWithNonExistingNode() {
|
||||
michael.setBoss(emil);
|
||||
@@ -451,7 +288,7 @@ public class Neo4jEntityConverterTest {
|
||||
julianNode.setProperty("name", "Julian");
|
||||
groupNode.createRelationshipTo(julianNode, PERSONS);
|
||||
|
||||
Group g = converter.read(Group.class, groupNode);
|
||||
Group g = readGroup(groupNode);
|
||||
Person julian = IteratorUtil.first(g.getPersons());
|
||||
assertEquals("Julian", julian.getName());
|
||||
}
|
||||
@@ -464,7 +301,7 @@ public class Neo4jEntityConverterTest {
|
||||
Relationship friendshipRelationship = michaelNode().createRelationshipTo(andresNode(), KNOWS);
|
||||
friendshipRelationship.setProperty("Friendship.years", 19);
|
||||
|
||||
Person m = converter.read(Person.class, michaelNode());
|
||||
Person m = readPerson(michaelNode());
|
||||
Friendship friendship = IteratorUtil.first(m.getFriendships());
|
||||
|
||||
assertEquals((Long) friendshipRelationship.getId(), friendship.getId());
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.neo4j.graphdb.Node;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.model.Friendship;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.support.ManagedEntity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.10.11
|
||||
*/
|
||||
public class Neo4jEntityPersisterTest extends Neo4jPersistentTestBase {
|
||||
|
||||
@Test
|
||||
public void testCreateEntityFromStoredType() throws Exception {
|
||||
final Node personNode = gdc.createNode();
|
||||
personNode.setProperty("name","Michael");
|
||||
final Person person = entityPersister.createEntityFromState(personNode, Person.class);
|
||||
assertEquals("Michael",person.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEntityFromState() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProjectTo() throws Exception {
|
||||
storeInGraph(michael);
|
||||
final Developer developer = entityPersister.projectTo(michael, Developer.class);
|
||||
assertEquals(michael.getId(), developer.id);
|
||||
assertEquals(michael.getName(), developer.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPersistentState() throws Exception {
|
||||
storeInGraph(michael);
|
||||
assertEquals(michaelNode(), entityPersister.getPersistentState(michael));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersist() throws Exception {
|
||||
entityPersister.persist(michael);
|
||||
assertEquals((Long) michaelNode().getId(), michael.getId());
|
||||
assertEquals(michaelNode(), entityPersister.getPersistentState(michael));
|
||||
assertEquals(michaelNode().getProperty("name"), michael.getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsManaged() throws Exception {
|
||||
assertEquals(false,entityPersister.isManaged(michael));
|
||||
assertEquals(true,entityPersister.isManaged(Mockito.mock(ManagedEntity.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNodeEntity() throws Exception {
|
||||
assertEquals(true,entityPersister.isNodeEntity(Person.class));
|
||||
assertEquals(false, entityPersister.isNodeEntity(Friendship.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRelationshipEntity() throws Exception {
|
||||
assertEquals(false,entityPersister.isRelationshipEntity(Person.class));
|
||||
assertEquals(true, entityPersister.isRelationshipEntity(Friendship.class));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* 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.mapping;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.neo4j.graphdb.*;
|
||||
import org.neo4j.helpers.collection.IteratorUtil;
|
||||
import org.neo4j.test.ImpermanentGraphDatabase;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.convert.DefaultTypeMapper;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
import org.springframework.data.neo4j.annotation.GraphId;
|
||||
import org.springframework.data.neo4j.annotation.NodeEntity;
|
||||
import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean;
|
||||
import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory;
|
||||
import org.springframework.data.neo4j.fieldaccess.RelationshipDelegatingFieldAccessorFactory;
|
||||
import org.springframework.data.neo4j.model.Group;
|
||||
import org.springframework.data.neo4j.model.Person;
|
||||
import org.springframework.data.neo4j.support.EntityStateHandler;
|
||||
import org.springframework.data.neo4j.support.GraphDatabaseContext;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.node.NodeEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityInstantiator;
|
||||
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopNodeTypeRepresentationStrategy;
|
||||
import org.springframework.data.neo4j.support.typerepresentation.NoopRelationshipTypeRepresentationStrategy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author mh
|
||||
* @since 12.10.11
|
||||
*/
|
||||
public class Neo4jPersistentTestBase {
|
||||
private Transaction tx;
|
||||
private Neo4jEntityConverterImpl<Object,Node> nodeConverter;
|
||||
protected GraphDatabaseContext gdc;
|
||||
protected NodeEntityStateFactory nodeEntityStateFactory;
|
||||
protected RelationshipEntityStateFactory relationshipEntityStateFactory;
|
||||
protected EntityStateHandler entityStateHandler;
|
||||
protected NodeEntityInstantiator nodeEntityInstantiator;
|
||||
protected TypeMapper<Node> nodeTypeMapper;
|
||||
protected SourceStateTransmitter<Node> nodeStateTransmitter;
|
||||
protected SourceStateTransmitter<Relationship> relationshipStateTransmitter;
|
||||
protected ConversionService conversionService;
|
||||
protected Neo4jEntityFetchHandler fetchHandler;
|
||||
protected Neo4jMappingContext mappingContext;
|
||||
protected Neo4jEntityPersister entityPersister;
|
||||
|
||||
|
||||
protected Group group;
|
||||
protected Person michael;
|
||||
protected Person emil;
|
||||
protected Person andres;
|
||||
public static final RelationshipType PERSONS = DynamicRelationshipType.withName("persons");
|
||||
protected static final RelationshipType KNOWS = DynamicRelationshipType.withName("knows");
|
||||
|
||||
@NodeEntity
|
||||
public static class Developer {
|
||||
@GraphId
|
||||
Long id;
|
||||
String name;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mappingContext = new Neo4jMappingContext();
|
||||
gdc = createContext(mappingContext);
|
||||
tx = gdc.beginTx();
|
||||
|
||||
nodeEntityStateFactory = createNodeEntityStateFactory(mappingContext);
|
||||
relationshipEntityStateFactory = createRelationshipEntityStateFactory(mappingContext);
|
||||
gdc.setNodeEntityStateFactory(nodeEntityStateFactory);
|
||||
gdc.setRelationshipEntityStateFactory(relationshipEntityStateFactory);
|
||||
|
||||
gdc.postConstruct();
|
||||
|
||||
entityStateHandler = gdc.getEntityStateHandler();
|
||||
|
||||
nodeEntityInstantiator = new NodeEntityInstantiator(entityStateHandler);
|
||||
nodeTypeMapper = new DefaultTypeMapper<Node>(new TRSTypeAliasAccessor<Node>(gdc.getNodeTypeRepresentationStrategy()),asList(new ClassValueTypeInformationMapper()));
|
||||
nodeStateTransmitter = new SourceStateTransmitter<Node>(nodeEntityStateFactory);
|
||||
relationshipStateTransmitter = new SourceStateTransmitter<Relationship>(relationshipEntityStateFactory);
|
||||
conversionService = gdc.getConversionService();
|
||||
fetchHandler = new Neo4jEntityFetchHandler(entityStateHandler, conversionService, relationshipStateTransmitter, nodeStateTransmitter);
|
||||
|
||||
nodeConverter = new Neo4jEntityConverterImpl<Object,Node>(mappingContext, conversionService, nodeEntityInstantiator, entityStateHandler, nodeTypeMapper, nodeStateTransmitter, fetchHandler);
|
||||
|
||||
entityPersister = new Neo4jEntityPersister(gdc.getGraphDatabaseService(), mappingContext, conversionService,
|
||||
nodeEntityStateFactory, relationshipEntityStateFactory,
|
||||
gdc.getNodeTypeRepresentationStrategy(), gdc.getRelationshipTypeRepresentationStrategy());
|
||||
|
||||
group = new Group();
|
||||
michael = new Person("Michael", 37);
|
||||
emil = new Person("Emil", 30);
|
||||
andres = new Person("Andrés", 36);
|
||||
}
|
||||
|
||||
private NodeEntityStateFactory createNodeEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final NodeEntityStateFactory nodeEntityStateFactory = new NodeEntityStateFactory();
|
||||
nodeEntityStateFactory.setMappingContext(mappingContext);
|
||||
nodeEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
nodeEntityStateFactory.setNodeDelegatingFieldAccessorFactory(new NodeDelegatingFieldAccessorFactory(gdc));
|
||||
return nodeEntityStateFactory;
|
||||
}
|
||||
|
||||
private RelationshipEntityStateFactory createRelationshipEntityStateFactory(Neo4jMappingContext mappingContext) {
|
||||
final RelationshipEntityStateFactory relationshipEntityStateFactory = new RelationshipEntityStateFactory();
|
||||
relationshipEntityStateFactory.setMappingContext(mappingContext);
|
||||
relationshipEntityStateFactory.setGraphDatabaseContext(gdc);
|
||||
relationshipEntityStateFactory.setRelationshipDelegatingFieldAccessorFactory(new RelationshipDelegatingFieldAccessorFactory(gdc));
|
||||
return relationshipEntityStateFactory;
|
||||
}
|
||||
|
||||
private GraphDatabaseContext createContext(Neo4jMappingContext mappingContext) throws Exception {
|
||||
GraphDatabaseContext gdc = new GraphDatabaseContext();
|
||||
final ImpermanentGraphDatabase gdb = new ImpermanentGraphDatabase();
|
||||
gdc.setGraphDatabaseService(gdb);
|
||||
gdc.setMappingContext(mappingContext);
|
||||
final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdb);
|
||||
gdc.setNodeTypeRepresentationStrategy(new NoopNodeTypeRepresentationStrategy(new NodeEntityInstantiator(entityStateHandler)));
|
||||
gdc.setRelationshipTypeRepresentationStrategy(new NoopRelationshipTypeRepresentationStrategy(new RelationshipEntityInstantiator(entityStateHandler)));
|
||||
gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject());
|
||||
gdc.setEntityStateHandler(entityStateHandler);
|
||||
return gdc;
|
||||
}
|
||||
|
||||
protected List<Node> groupMemberNodes() {
|
||||
return groupMemberNodes(groupNode());
|
||||
}
|
||||
|
||||
private List<Node> groupMemberNodes(Node node) {
|
||||
return getRelatedNodes(node, "persons", Direction.OUTGOING);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
tx.failure();
|
||||
tx.finish();
|
||||
gdc.getGraphDatabaseService().shutdown();
|
||||
}
|
||||
|
||||
protected Node michaelNode() {
|
||||
return gdc.getNodeById(michael.getId());
|
||||
}
|
||||
|
||||
protected Node createNewNode() {
|
||||
return gdc.createNode();
|
||||
}
|
||||
|
||||
protected Group storeInGraph(Group g) {
|
||||
final Long id = g.getId();
|
||||
if (id != null) {
|
||||
write(g, gdc.getNodeById(id));
|
||||
} else {
|
||||
write(g, null);
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
protected Person storeInGraph(Person p) {
|
||||
final Long id = p.getId();
|
||||
if (id != null) {
|
||||
write(p, gdc.getNodeById(id));
|
||||
} else {
|
||||
write(p,null);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
protected Object write(Object entity, Node node) {
|
||||
entityPersister.write(entity, node);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T storeInGraph(T obj) {
|
||||
return (T) write(obj,null);
|
||||
}
|
||||
|
||||
protected Node groupNode() {
|
||||
return gdc.getNodeById(group.getId());
|
||||
}
|
||||
|
||||
protected <T> Set<T> set(T... objs) {
|
||||
return new HashSet<T>(asList(objs));
|
||||
}
|
||||
|
||||
protected <T> Set<T> set(Iterable<T> objs) {
|
||||
return IteratorUtil.addToCollection(objs, new HashSet<T>());
|
||||
}
|
||||
|
||||
protected Node andresNode() {
|
||||
return gdc.getNodeById(andres.getId());
|
||||
}
|
||||
|
||||
protected Node emilNode() {
|
||||
return gdc.getNodeById(emil.getId());
|
||||
}
|
||||
|
||||
public Person readPerson(Node node) {
|
||||
return entityPersister.read(Person.class, node);
|
||||
}
|
||||
public Group readGroup(Node node) {
|
||||
return entityPersister.read(Group.class, node);
|
||||
}
|
||||
|
||||
protected List<Node> getRelatedNodes(Node startNode, String type, Direction direction) {
|
||||
List<Node> result = new ArrayList<Node>();
|
||||
for (Relationship relationship : startNode.getRelationships(DynamicRelationshipType.withName(type), direction)) {
|
||||
result.add(relationship.getOtherNode(startNode));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class Person {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
return "["+graphId+"] " + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test;
|
||||
package org.springframework.data.test;
|
||||
|
||||
|
||||
import org.junit.After;
|
||||
@@ -35,7 +35,7 @@ public abstract class DocumentingTestBase {
|
||||
public void outputDocs() throws IOException {
|
||||
final File directory = new File(docbookDirectory(),"snippets");
|
||||
if (directory.isFile() || !directory.exists() && !directory.mkdirs()) throw new RuntimeException("Could not create directory "+directory);
|
||||
final String name = getClass().getSimpleName();
|
||||
final String name = getSnippetName();
|
||||
final PrintWriter writer = new PrintWriter(new FileWriter(getSnippetFileName(directory,name)));
|
||||
writer.write(createHeader());
|
||||
writer.write(createTitle());
|
||||
@@ -45,6 +45,11 @@ public abstract class DocumentingTestBase {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private String getSnippetName() {
|
||||
final String className = getClass().getSimpleName();
|
||||
return className.replace("Tests?$","");
|
||||
}
|
||||
|
||||
private File docbookDirectory() {
|
||||
return new File(determineRoot(),DOCBOOK_DIR);
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test;
|
||||
package org.springframework.data.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.snippets;
|
||||
package org.springframework.data.test.snippets;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -26,21 +26,20 @@ import org.springframework.data.neo4j.conversion.ResultConverter;
|
||||
import org.springframework.data.neo4j.core.GraphDatabase;
|
||||
import org.springframework.data.neo4j.template.Neo4jOperations;
|
||||
import org.springframework.data.neo4j.template.Neo4jTemplate;
|
||||
import org.springframework.test.DocumentingTestBase;
|
||||
import org.springframework.data.test.DocumentingTestBase;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.neo4j.helpers.collection.MapUtil.map;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = {"classpath*:DocumentingTest-context.xml"})
|
||||
public class SnippetNeo4jTemplateMethods extends DocumentingTestBase {
|
||||
public class SnippetNeo4jTemplateMethodsTest extends DocumentingTestBase {
|
||||
@Autowired
|
||||
private GraphDatabase graphDatabase;
|
||||
private static final RelationshipType WORKS_WITH = DynamicRelationshipType.withName("WORKS_WITH");
|
||||
@@ -66,10 +65,9 @@ public class SnippetNeo4jTemplateMethods extends DocumentingTestBase {
|
||||
neo.createRelationship(mark, thomas, WORKS_WITH, map("project", "spring-data"));
|
||||
|
||||
neo.index("devs", thomas, "name", "Thomas");
|
||||
|
||||
// Cypher
|
||||
assert "Mark".equals(neo.query("start p=({p_person}) match p<-[:WORKS_WITH]-other return other.name",
|
||||
map("person", thomas)).to(String.class).single());
|
||||
// Cypher TODO
|
||||
assertEquals( "Mark", neo.query("start p=node({person}) match p<-[:WORKS_WITH]-other return other.name",
|
||||
map("person", asList(thomas.getId()))).to(String.class).single());
|
||||
|
||||
|
||||
// SNIPPET template
|
||||
@@ -79,18 +77,18 @@ public class SnippetNeo4jTemplateMethods extends DocumentingTestBase {
|
||||
// SNIPPET template
|
||||
|
||||
// Gremlin
|
||||
assert thomas.equals(neo.execute("g.v(person).out('WORKS_WITH')",
|
||||
map("person", mark)).to(Node.class).single());
|
||||
assertEquals(thomas, neo.execute("g.v(person).out('WORKS_WITH')",
|
||||
map("person", mark.getId())).to(Node.class).single());
|
||||
|
||||
// Index lookup
|
||||
assert mark.equals(neo.lookup("devs", "name", "Mark").to(Node.class).single());
|
||||
assertEquals(thomas, neo.lookup("devs", "name", "Thomas").to(Node.class).single());
|
||||
|
||||
// Index lookup with Result Converter
|
||||
assert "Mark".equals(neo.lookup("devs", "name", "Mark").to(String.class, new ResultConverter<PropertyContainer, String>() {
|
||||
assertEquals("Thomas", neo.lookup("devs", "name", "Thomas").to(String.class, new ResultConverter<PropertyContainer, String>() {
|
||||
public String convert(PropertyContainer element, Class<String> type) {
|
||||
return (String) element.getProperty("name");
|
||||
}
|
||||
}));
|
||||
}).single());
|
||||
// SNIPPET template
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user