handling of simple relationships, cleanup

This commit is contained in:
Michael Hunger
2010-08-06 03:54:53 +02:00
parent b1837a0d2e
commit b1063da00c
5 changed files with 117 additions and 60 deletions

View File

@@ -1,36 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="var" path="M2_REPO/javax/persistence/persistence-api/1.0.0/persistence-api-1.0.0.jar"/>
<classpathentry kind="var" path="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" sourcepath="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/data/data-commons/1.0.0.CI-SNAPSHOT/data-commons-1.0.0.CI-SNAPSHOT.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar" sourcepath="M2_REPO/org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.6.0/jcl-over-slf4j-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/jcl-over-slf4j/1.6.0/jcl-over-slf4j-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.8.1/junit-4.8.1.jar" sourcepath="M2_REPO/junit/junit/4.8.1/junit-4.8.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.15/log4j-1.2.15.jar" sourcepath="M2_REPO/log4j/log4j/1.2.15/log4j-1.2.15-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-core/2.9.1/lucene-core-2.9.1.jar" sourcepath="M2_REPO/org/apache/lucene/lucene-core/2.9.1/lucene-core-2.9.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-commons/1.0/neo4j-commons-1.0.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-index/1.0/neo4j-index-1.0.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-kernel/1.0/neo4j-kernel-1.0.jar" sourcepath="M2_REPO/org/neo4j/neo4j-kernel/1.0/neo4j-kernel-1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-utils/1.0/neo4j-utils-1.0.jar" sourcepath="M2_REPO/org/neo4j/neo4j-utils/1.0/neo4j-utils-1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.6.0/slf4j-api-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.6.0/slf4j-api-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.6.0/slf4j-log4j12-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.6.0/slf4j-log4j12-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aop/3.0.0.RELEASE/spring-aop-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-aop/3.0.0.RELEASE/spring-aop-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-asm/3.0.0.RELEASE/spring-asm-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-asm/3.0.0.RELEASE/spring-asm-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aspects/3.0.0.RELEASE/spring-aspects-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-aspects/3.0.0.RELEASE/spring-aspects-3.0.0.RELEASE-sources.jar">
<attributes>
<attribute name="org.eclipse.ajdt.aspectpath" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-beans/3.0.0.RELEASE/spring-beans-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-beans/3.0.0.RELEASE/spring-beans-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-context/3.0.0.RELEASE/spring-context-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-context/3.0.0.RELEASE/spring-context-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-core/3.0.0.RELEASE/spring-core-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-core/3.0.0.RELEASE/spring-core-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-expression/3.0.0.RELEASE/spring-expression-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-expression/3.0.0.RELEASE/spring-expression-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-test/3.0.0.RELEASE/spring-test-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-test/3.0.0.RELEASE/spring-test-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-tx/3.0.0.RELEASE/spring-tx-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-tx/3.0.0.RELEASE/spring-tx-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java|**/*.aj"/>
<classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/>
<classpathentry kind="src" path="src/main/java" including="**/*.java|**/*.aj"/>
<classpathentry kind="output" path="target/classes"/>
<classpathentry kind="var" path="M2_REPO/javax/persistence/persistence-api/1.0.0/persistence-api-1.0.0.jar"/>
<classpathentry kind="var" path="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" sourcepath="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/data/data-commons/1.0.0.CI-SNAPSHOT/data-commons-1.0.0.CI-SNAPSHOT.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1.jar" sourcepath="M2_REPO/org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1-sources.jar">
<attributes>
<attribute value="jar:file:/Users/mh14/.m2/repository/org/apache/geronimo/specs/geronimo-jta_1.1_spec/1.1.1/geronimo-jta_1.1_spec-1.1.1-javadoc.jar!/" name="javadoc_location"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/hsqldb/hsqldb/1.8.0.10/hsqldb-1.8.0.10.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.6.0/jcl-over-slf4j-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/jcl-over-slf4j/1.6.0/jcl-over-slf4j-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.8.1/junit-4.8.1.jar" sourcepath="M2_REPO/junit/junit/4.8.1/junit-4.8.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/log4j/log4j/1.2.15/log4j-1.2.15.jar" sourcepath="M2_REPO/log4j/log4j/1.2.15/log4j-1.2.15-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/lucene/lucene-core/2.9.2/lucene-core-2.9.2.jar" sourcepath="M2_REPO/org/apache/lucene/lucene-core/2.9.2/lucene-core-2.9.2-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-index/1.1/neo4j-index-1.1.jar" sourcepath="M2_REPO/org/neo4j/neo4j-index/1.1/neo4j-index-1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-kernel/1.1/neo4j-kernel-1.1.jar" sourcepath="M2_REPO/org/neo4j/neo4j-kernel/1.1/neo4j-kernel-1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/neo4j/neo4j-utils/1.1/neo4j-utils-1.1.jar" sourcepath="M2_REPO/org/neo4j/neo4j-utils/1.1/neo4j-utils-1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.6.0/slf4j-api-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.6.0/slf4j-api-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.6.0/slf4j-log4j12-1.6.0.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.6.0/slf4j-log4j12-1.6.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aop/3.0.0.RELEASE/spring-aop-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-aop/3.0.0.RELEASE/spring-aop-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-asm/3.0.0.RELEASE/spring-asm-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-asm/3.0.0.RELEASE/spring-asm-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-aspects/3.0.0.RELEASE/spring-aspects-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-aspects/3.0.0.RELEASE/spring-aspects-3.0.0.RELEASE-sources.jar">
<attributes>
<attribute name="org.eclipse.ajdt.aspectpath" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-beans/3.0.0.RELEASE/spring-beans-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-beans/3.0.0.RELEASE/spring-beans-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-context/3.0.0.RELEASE/spring-context-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-context/3.0.0.RELEASE/spring-context-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-core/3.0.0.RELEASE/spring-core-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-core/3.0.0.RELEASE/spring-core-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-expression/3.0.0.RELEASE/spring-expression-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-expression/3.0.0.RELEASE/spring-expression-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-jdbc/3.0.0.RELEASE/spring-jdbc-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-jdbc/3.0.0.RELEASE/spring-jdbc-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-test/3.0.0.RELEASE/spring-test-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-test/3.0.0.RELEASE/spring-test-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/springframework/spring-tx/3.0.0.RELEASE/spring-tx-3.0.0.RELEASE.jar" sourcepath="M2_REPO/org/springframework/spring-tx/3.0.0.RELEASE/spring-tx-3.0.0.RELEASE-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.ajdt.core.ASPECTJRT_CONTAINER"/>
</classpath>

View File

@@ -2,8 +2,5 @@
<project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="datastore-graph">
<wb-resource deploy-path="/" source-path="src/main/java"/>
<wb-resource deploy-path="/" source-path="/src/main/java"/>
<wb-resource deploy-path="/" source-path="/src/test/java"/>
<wb-resource deploy-path="/" source-path="/src/test/resources"/>
</wb-module>
</project-modules>

View File

@@ -4,14 +4,13 @@ import java.lang.reflect.Field;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.FieldSignature;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.util.GraphDatabaseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.persistence.graph.Direction;
import org.springframework.persistence.graph.GraphEntity;
import org.springframework.persistence.graph.Relationship;
import org.springframework.persistence.support.AbstractTypeAnnotatingMixinFields;
@@ -61,13 +60,17 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
entity.setUnderlyingNode(graphDatabaseService.createNode());
log.info("User-defined constructor called on class " + entity.getClass() + "; created Node [" + entity.getUnderlyingNode() +"]; " +
"Updating metamodel");
// TODO pull naming out into a strategy interface
// TODO pull naming out into a strategy interface, todo a separate one, or the Entity Instatiator
// graphEntityInstantiator.postEntityCreation(entity);
postEntityCreation(entity);
}
public void postEntityCreation(NodeBacked entity) {
Node subReference = Neo4jHelper.findSubreferenceNode(entity.getClass(), graphDatabaseService);
entity.getUnderlyingNode().createRelationshipTo(subReference, Neo4jHelper.INSTANCE_OF_RELATIONSHIP_TYPE);
graphDatabaseUtil.incrementAndGetCounter(subReference, Neo4jHelper.SUBREFERENCE_NODE_COUNTER_KEY);
}
// Introduced field
private Node NodeBacked.underlyingNode;
@@ -98,7 +101,8 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
Object around(NodeBacked entity) : entityFieldGet(entity) {
Field f = ((FieldSignature) thisJoinPoint.getSignature()).getField();
FieldSignature fieldSignature=(FieldSignature) thisJoinPoint.getSignature();
Field f = fieldSignature.getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
@@ -109,18 +113,15 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
Relationship r = f.getAnnotation(Relationship.class);
if (r == null) {
throw new IllegalStateException("Must have @Relationship on " + f);
}
// does it have to be there, isn't it enough to have a nodebacked as target?
Node me = entity.getUnderlyingNode();
if (me == null) {
throw new IllegalStateException("Entity must have a backing Node");
}
RelationshipType type = DynamicRelationshipType.withName(r.type());
org.neo4j.graphdb.Relationship singleRelationship = me.getSingleRelationship(type, r.direction().toNeo4jDir());
org.neo4j.graphdb.Relationship singleRelationship = getRelationship(me, fieldSignature);
// TODO is this correct
// [mh] i assume only for null
if (singleRelationship == null) {
log.info("GET " + f + ": " + f.getType().getName() + ": not set yet so returning field value");
return proceed(entity);
@@ -134,11 +135,23 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
log.info("Ignored GET " + f + ": " + f.getType().getName() + " not primitive or GraphEntity");
return proceed(entity);
}
private org.neo4j.graphdb.Relationship getRelationship(Node me, FieldSignature f) {
Relationship r = f.getField().getAnnotation(Relationship.class);
if (r == null) {
RelationshipType type=DynamicRelationshipType.withName(getNeo4jPropertyName((Signature)f));
return me.getSingleRelationship(type, Direction.OUTGOING);
}
RelationshipType type = DynamicRelationshipType.withName(r.type());
org.neo4j.graphdb.Relationship singleRelationship = me.getSingleRelationship(type, r.direction().toNeo4jDir());
return singleRelationship;
}
Object around(NodeBacked entity, Object newVal) : entityFieldSet(entity, newVal) {
Field f = ((FieldSignature) thisJoinPoint.getSignature()).getField();
FieldSignature fieldSignature=(FieldSignature) thisJoinPoint.getSignature();
Field f = fieldSignature.getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
String propName = getNeo4jPropertyName(thisJoinPoint.getSignature());
@@ -151,9 +164,10 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
if (isNeo4jRelationshipField(f)) {
Relationship r = f.getAnnotation(Relationship.class);
if (r == null) {
throw new IllegalStateException("Must have @Relationship on " + f);
graphEntityFieldSet(entity, (NodeBacked) newVal, getNeo4jPropertyName(thisJoinPoint.getSignature()),Direction.OUTGOING);
} else {
graphEntityFieldSet(entity, (NodeBacked) newVal, r.type(), r.direction().toNeo4jDir());
}
graphEntityFieldSet(entity, r, (NodeBacked) newVal);
log.info("SET " + f + " -> Neo4J relationship with value=[" + newVal + "]");
return null;
}
@@ -163,16 +177,19 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
}
}
private void graphEntityFieldSet(NodeBacked entity, Relationship r, NodeBacked newVal) {
// todo what happens to the previous value, remove relationships?
private void graphEntityFieldSet(NodeBacked entity, NodeBacked newVal, String relationshipName, Direction direction) {
RelationshipType type = DynamicRelationshipType.withName(relationshipName);
Node me = entity.getUnderlyingNode();
RelationshipType type = DynamicRelationshipType.withName(r.type());
Node targetNode = newVal.getUnderlyingNode();
if (r.direction() == Direction.OUTGOING) {
me.createRelationshipTo(targetNode, type);
}
else {
switch(direction) {
case OUTGOING : me.createRelationshipTo(targetNode, type); break;
case INCOMING : targetNode.createRelationshipTo(me, type); break;
case BOTH :
me.createRelationshipTo(targetNode, type);
targetNode.createRelationshipTo(me, type);
break;
}
}

View File

@@ -1,6 +1,8 @@
package org.springframework.persistence.test;
import org.springframework.persistence.graph.Direction;
import org.springframework.persistence.graph.GraphEntity;
import org.springframework.persistence.graph.Relationship;
@GraphEntity
public class Person {
@@ -10,7 +12,12 @@ public class Person {
private String name;
private int age;
Person spouse;
@Relationship(type="mother",direction=Direction.BOTH)
Person mother;
public Person(String name, int age) {
this.name = name;
this.age = age;
@@ -33,4 +40,22 @@ public class Person {
this.age = age;
}
public Person getSpouse() {
return spouse;
}
public void setSpouse(Person spouse) {
this.spouse = spouse;
}
public Person getMother() {
return mother;
}
public void setMother(Person mother) {
this.mother = mother;
}
}

View File

@@ -5,10 +5,12 @@ import junit.framework.Assert;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.persistence.graph.Direction;
import org.springframework.persistence.graph.neo4j.NodeBacked;
import org.springframework.persistence.support.EntityInstantiator;
import org.springframework.persistence.test.Person;
@@ -47,6 +49,18 @@ public class Neo4jGraphPersistenceTest {
insertedId = p.getId();
}
@Test
@Transactional
public void testCreateRelationshipOnSet() {
Person p = new Person("Michael", 35);
Person spouse=new Person("Tina",36);
p.setSpouse(spouse);
Assert.assertEquals("Tina", p.getSpouse().getUnderlyingNode().getProperty("Person.name"));
Node spouseNode=p.getUnderlyingNode().getSingleRelationship(DynamicRelationshipType.withName("Person.spouse"), org.neo4j.graphdb.Direction.OUTGOING).getEndNode();
Assert.assertEquals(spouse.getUnderlyingNode(), spouseNode);
}
@Test
@Transactional
public void testInstantiatedFinder() {