Added docs for typerepresentationstrategies. Added tests for noop strategies.

This commit is contained in:
David Montag
2011-03-30 22:51:09 -07:00
parent 632afae487
commit 098a61646e
12 changed files with 293 additions and 226 deletions

View File

@@ -0,0 +1,46 @@
package org.springframework.data.graph.neo4j.support;
import org.neo4j.graphdb.Node;
import org.springframework.data.graph.core.NodeBacked;
import org.springframework.data.graph.core.NodeTypeRepresentationStrategy;
public class NoopNodeTypeRepresentationStrategy implements NodeTypeRepresentationStrategy {
@Override
public void postEntityCreation(Node state, Class<? extends NodeBacked> type) {
}
@Override
public <U extends NodeBacked> Iterable<U> findAll(Class<U> clazz) {
throw new UnsupportedOperationException("findAll not supported.");
}
@Override
public long count(Class<? extends NodeBacked> entityClass) {
throw new UnsupportedOperationException("count not supported.");
}
@Override
public void preEntityRemoval(Node state) {
}
@Override
public Class<? extends NodeBacked> getJavaType(Node state) {
throw new UnsupportedOperationException("getJavaType not supported.");
}
@Override
public <U extends NodeBacked> U createEntity(Node state) {
throw new UnsupportedOperationException("Creation with stored type not supported.");
}
@Override
public <U extends NodeBacked> U createEntity(Node state, Class<U> type) {
return projectEntity(state, type);
}
@Override
public <U extends NodeBacked> U projectEntity(Node state, Class<U> type) {
return null;
}
}

View File

@@ -0,0 +1,46 @@
package org.springframework.data.graph.neo4j.support;
import org.neo4j.graphdb.Relationship;
import org.springframework.data.graph.core.RelationshipBacked;
import org.springframework.data.graph.core.RelationshipTypeRepresentationStrategy;
public class NoopRelationshipTypeRepresentationStrategy implements RelationshipTypeRepresentationStrategy {
@Override
public void postEntityCreation(Relationship state, Class<? extends RelationshipBacked> type) {
}
@Override
public <U extends RelationshipBacked> Iterable<U> findAll(Class<U> clazz) {
throw new UnsupportedOperationException("findAll not supported.");
}
@Override
public long count(Class<? extends RelationshipBacked> entityClass) {
throw new UnsupportedOperationException("count not supported.");
}
@Override
public void preEntityRemoval(Relationship state) {
}
@Override
public Class<? extends RelationshipBacked> getJavaType(Relationship state) {
throw new UnsupportedOperationException("getJavaType not supported.");
}
@Override
public <U extends RelationshipBacked> U createEntity(Relationship state) {
throw new UnsupportedOperationException("Creation with stored type not supported.");
}
@Override
public <U extends RelationshipBacked> U createEntity(Relationship state, Class<U> type) {
return projectEntity(state, type);
}
@Override
public <U extends RelationshipBacked> U projectEntity(Relationship state, Class<U> type) {
return null;
}
}

View File

@@ -1,92 +0,0 @@
package org.springframework.data.graph.neo4j.support;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.springframework.data.graph.core.NodeBacked;
import org.springframework.data.graph.core.NodeTypeRepresentationStrategy;
import org.springframework.data.graph.core.RelationshipBacked;
import org.springframework.data.graph.core.RelationshipTypeRepresentationStrategy;
public class NoopTypeRepresentationStrategy {
public static class NoopNodeStrategy implements NodeTypeRepresentationStrategy {
@Override
public void postEntityCreation(Node state, Class<? extends NodeBacked> type) {
}
@Override
public <U extends NodeBacked> Iterable<U> findAll(Class<U> clazz) {
throw new UnsupportedOperationException("findAll not supported.");
}
@Override
public long count(Class<? extends NodeBacked> entityClass) {
throw new UnsupportedOperationException("count not supported.");
}
@Override
public void preEntityRemoval(Node state) {
}
@Override
public Class<? extends NodeBacked> getJavaType(Node state) {
throw new UnsupportedOperationException("getJavaType not supported.");
}
@Override
public <U extends NodeBacked> U createEntity(Node state) {
throw new UnsupportedOperationException("Creation with stored type not supported.");
}
@Override
public <U extends NodeBacked> U createEntity(Node state, Class<U> type) {
return projectEntity(state, type);
}
@Override
public <U extends NodeBacked> U projectEntity(Node state, Class<U> type) {
return null;
}
}
public static class NoopRelationshipStrategy implements RelationshipTypeRepresentationStrategy {
@Override
public void postEntityCreation(Relationship state, Class<? extends RelationshipBacked> type) {
}
@Override
public <U extends RelationshipBacked> Iterable<U> findAll(Class<U> clazz) {
throw new UnsupportedOperationException("findAll not supported.");
}
@Override
public long count(Class<? extends RelationshipBacked> entityClass) {
throw new UnsupportedOperationException("count not supported.");
}
@Override
public void preEntityRemoval(Relationship state) {
}
@Override
public Class<? extends RelationshipBacked> getJavaType(Relationship state) {
throw new UnsupportedOperationException("getJavaType not supported.");
}
@Override
public <U extends RelationshipBacked> U createEntity(Relationship state) {
throw new UnsupportedOperationException("Creation with stored type not supported.");
}
@Override
public <U extends RelationshipBacked> U createEntity(Relationship state, Class<U> type) {
return projectEntity(state, type);
}
@Override
public <U extends RelationshipBacked> U projectEntity(Relationship state, Class<U> type) {
return null;
}
}
}

View File

@@ -57,7 +57,7 @@ public class TypeRepresentationStrategyFactory {
@Override
public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator) {
return new NoopTypeRepresentationStrategy.NoopRelationshipStrategy();
return new NoopRelationshipTypeRepresentationStrategy();
}
},
Indexed {
@@ -74,12 +74,12 @@ public class TypeRepresentationStrategyFactory {
Noop {
@Override
public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<NodeBacked, Node> graphEntityInstantiator) {
return new NoopTypeRepresentationStrategy.NoopNodeStrategy();
return new NoopNodeTypeRepresentationStrategy();
}
@Override
public RelationshipTypeRepresentationStrategy getRelationshipTypeRepresentationStrategy(GraphDatabaseService graphDatabaseService, EntityInstantiator<RelationshipBacked, Relationship> relationshipEntityInstantiator) {
return new NoopTypeRepresentationStrategy.NoopRelationshipStrategy();
return new NoopRelationshipTypeRepresentationStrategy();
}
};

View File

@@ -1,7 +1,15 @@
package org.springframework.data.graph.neo4j.support;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.graph.annotation.NodeEntity;
import org.springframework.data.graph.annotation.RelationshipEntity;
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
@@ -11,77 +19,109 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/graph/neo4j/support/Neo4jGraphPersistenceTest-context.xml",
"classpath:org/springframework/data/graph/neo4j/support/NoopNodeTypeStrategyOverride-context.xml"})
"classpath:org/springframework/data/graph/neo4j/support/NoopTypeRepresentationStrategyOverride-context.xml"})
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
public class NoopTypeRepresentationStrategyTest {
//
// @Autowired
// private GraphDatabaseContext graphDatabaseContext;
// @Autowired
// private NoopTypeRepresentationStrategy nodeTypeStrategy;
//
// private Thing thing;
//
// @Before
// public void setUp() throws Exception {
// thing = createThing();
// }
@Autowired
private GraphDatabaseContext graphDatabaseContext;
@Autowired
private NoopNodeTypeRepresentationStrategy noopNodeStrategy;
@Autowired
private NoopRelationshipTypeRepresentationStrategy noopRelationshipStrategy;
private Thing thing;
private Link link;
@Before
public void setUp() throws Exception {
createThing();
}
@Test
public void testPostEntityCreation() throws Exception {
}
//
// @Test(expected = UnsupportedOperationException.class)
// public void testFindAll() throws Exception {
// nodeTypeStrategy.findAll(Thing.class);
// }
//
// @Test(expected = UnsupportedOperationException.class)
// public void testCount() throws Exception {
// nodeTypeStrategy.count(Thing.class);
// }
//
// @Test(expected = UnsupportedOperationException.class)
// public void testGetJavaType() throws Exception {
// nodeTypeStrategy.getJavaType(node(thing));
// }
//
// @Test
// public void testPreEntityRemoval() throws Exception {
// nodeTypeStrategy.preEntityRemoval(thing);
// }
//
// @Test
// public void testConfirmType() throws Exception {
// assertEquals(Thing.class, nodeTypeStrategy.confirmType(node(thing), Thing.class));
// }
//
// private static Node node(Thing thing) {
// return thing.getPersistentState();
// }
//
// private Thing createThing() {
// Transaction tx = graphDatabaseContext.beginTx();
// try {
// Node node = graphDatabaseContext.createNode();
// Thing thing = new Thing(node);
// nodeTypeStrategy.postEntityCreation(thing);
// tx.success();
// return thing;
// } finally {
// tx.finish();
// }
// }
//
// @NodeEntity
// public static class Thing {
// String name;
//
// public Thing() {
// }
//
// public Thing(Node n) {
// setPersistentState(n);
// }
// }
@Test(expected = UnsupportedOperationException.class)
public void testFindAllForNodeStrategy() throws Exception {
noopNodeStrategy.findAll(Thing.class);
}
@Test(expected = UnsupportedOperationException.class)
public void testFindAllForRelationshipStrategy() throws Exception {
noopRelationshipStrategy.findAll(Link.class);
}
@Test(expected = UnsupportedOperationException.class)
public void testCountForNodeStrategy() throws Exception {
noopNodeStrategy.count(Thing.class);
}
@Test(expected = UnsupportedOperationException.class)
public void testCountForRelationshipStrategy() throws Exception {
noopRelationshipStrategy.count(Link.class);
}
@Test(expected = UnsupportedOperationException.class)
public void testGetJavaTypeOnNodeStrategy() throws Exception {
noopNodeStrategy.getJavaType(null);
}
@Test(expected = UnsupportedOperationException.class)
public void testGetJavaTypeOnRelationshipStrategy() throws Exception {
noopRelationshipStrategy.getJavaType(null);
}
@Test
public void testPreEntityRemoval() throws Exception {
noopNodeStrategy.preEntityRemoval(node(thing));
noopRelationshipStrategy.preEntityRemoval(rel(link));
}
private static Node node(Thing thing) {
return thing.getPersistentState();
}
private static Relationship rel(Link link) {
return link.getPersistentState();
}
private Thing createThing() {
Transaction tx = graphDatabaseContext.beginTx();
try {
Node node = graphDatabaseContext.createNode();
thing = new Thing(node);
noopNodeStrategy.postEntityCreation(node, Thing.class);
Relationship rel = node.createRelationshipTo(graphDatabaseContext.createNode(), DynamicRelationshipType.withName("link"));
link = new Link(rel);
noopRelationshipStrategy.postEntityCreation(rel, Link.class);
tx.success();
return thing;
} finally {
tx.finish();
}
}
@NodeEntity
public static class Thing {
String name;
public Thing() {
}
public Thing(Node n) {
setPersistentState(n);
}
}
@RelationshipEntity
public static class Link {
public Link() {
}
public Link(Relationship rel) {
setPersistentState(rel);
}
}
}

View File

@@ -14,5 +14,6 @@
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--<bean id="typeRepresentationStrategy" class="org.springframework.data.graph.neo4j.support.NoopTypeRepresentationStrategy" />-->
<bean id="noopNodeStrategy" class="org.springframework.data.graph.neo4j.support.NoopNodeTypeRepresentationStrategy" />
<bean id="noopRelationshipStrategy" class="org.springframework.data.graph.neo4j.support.NoopRelationshipTypeRepresentationStrategy" />
</beans>

View File

@@ -23,10 +23,11 @@
backing graph store afterwards.
</para>
<para>
The connection between the two entities is kept via a FOREIGN_ID field in the node that contains the JPA id (currently only single
value ids are supported). The entity class can be resolved via the NodeTypeStrategy that preserves the Java type hierarchy within the graph.
With the id and class, you can then retrieve the appropriate JPA entity for a given node.
</para>
The connection between the two entities is kept via a FOREIGN_ID field in the node that contains the JPA id
(currently only single value ids are supported). The entity class can be resolved via the
TypeRepresentationStrategy that manages the Java type hierarchy within the graph. With the id and class,
you can then retrieve the appropriate JPA entity for a given node.
</para>
<para>
The other direction is handled by indexing the Node with the FOREIGN_ID index which contains a concatenation of the fully qualified class
name of the JPA entity and the id. So it is possible on instantiation of a JPA id via the entity manager (or some other means like creating

View File

@@ -2,6 +2,7 @@
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section>
<title>Finding nodes with finders</title>
<note>TODO: rewrite to repositories</note>
<para>Spring Data Graph also comes with a typed, repository-like Finder implementation that provides methods for
locating nodes and relationships. Those methods return instances of the node and relationship entities,
not the graph primitives from Neo4j. Finders delegate to the configured <code>NodeTypeStrategy</code> for type
@@ -68,15 +69,8 @@ Iterable<Person> davesFriends = graphRepository.findAllByTraversal(dave,
Internally the mapping from java types to the graph is handled by a <code>NodeTypeStrategy</code> instance
that is configured with the <code>GraphDatabaseContext</code>. The strategy is called on entity creation and
removal and provides methods for retrieving entities based on type. It also comes with methods confirming or
retrieving java types from the actual graph node. (see also <xref linkend="nodetypestrategy"/>)
</para>
<para>
The default strategy (<code>IndexingNodeTypeStrategy</code>)
uses indexing (index "__types__") and node properties ("__type__") to store the type information in the graph.
The second strategy uses an in graph structure to represent the inheritance hierarchy links the actual node
entity nodes to their concrete class nodes. Instance counts are updated on each of the class nodes in the hierarchy.
The last provided strategy is a No-Op strategy that doesn't care about type information.
retrieving java types from the actual graph node. (see also
<xref linkend="reference:programming-model:typerepresentationstrategy"/>)
</para>
</section>
</section>

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section id="nodetypestrategy">
<title>Storing Type Information in the Graph</title>
<para>
There are several ways to represent the Java type hierarchy of the data model in the graph. In general for all
node and relationship entities type information is needed to perform certain repository operations. Some of
this type information is saved in the graph database.
</para>
<para>
Implementations of <code>NodeTypeStrategy</code> take care of persisting this information on entity instance
creation. They also provide the repository methods that use this type information to perform their operations
like findAll, count, etc.
</para>
<para>
There are three available implementations to choose from.
<itemizedlist>
<listitem>
<para><code>IndexingNodeTypeStrategy</code></para>
<para>
Stores entity types in the integrated index. Each entity node gets indexed with its type and
any supertypes that are also <code>@NodeEntity</code>-annotated. The special index used for this
is called <code>__types__</code>. Additionally, in order to get the type of an entity node, each
node has a property <code>__type__</code> with the type of that entity.
</para>
</listitem>
<listitem>
<para><code>SubReferenceNodeTypeStrategy</code></para>
<para>
Stores entity types in a tree in the graph representing the type hierarchy. Each entity
has a INSTANCE_OF relationship to a type node representing that entity's type. The type may or
may not have a SUBCLASS_OF relationship to another type node.
</para>
</listitem>
<listitem>
<para><code>NoopNodeTypeStrategy</code></para>
<para>
Does not store any type information, and does hence not support finding by type, counting by type,
or retrieving the type of any entity.
</para>
</listitem>
</itemizedlist>
</para>
<para>
The default implementation is <code>IndexingNodeTypeStrategy</code> for new graphs. If using an existing
graph, Spring Data Graph will default to the strategy first used when the graph was created.
</para>
</section>

View File

@@ -14,7 +14,7 @@
<xi:include href="finders.xml"/>
<xi:include href="transactions.xml"/>
<xi:include href="attachdetach.xml"/>
<xi:include href="nodetypestrategy.xml"/>
<xi:include href="typerepresentationstrategy.xml"/>
<xi:include href="introducedmethods.xml"/>
<xi:include href="projection.xml"/>
<xi:include href="beanvalidation.xml"/>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<section id="reference:programming-model:typerepresentationstrategy">
<title>Storing type information in the graph</title>
<para>
There are several ways to represent the Java type hierarchy of the data model in the graph. In general, for all
node and relationship entities, type information is needed to perform certain repository operations. Some of
this type information is saved in the graph database.
</para>
<para>
Implementations of
<code>TypeRepresentationStrategy</code>
take care of persisting this information on entity instance
creation. They also provide the repository methods that use this type information to perform their operations,
like findAll and count.
</para>
<para>
There are three available implementations for node entities to choose from.
<itemizedlist>
<listitem>
<para>
<code>IndexingNodeTypeRepresentationStrategy</code>
</para>
<para>
Stores entity types in the integrated index. Each entity node gets indexed with its type and
any supertypes that are also<code>@NodeEntity</code>-annotated. The special index used for this
is called<code>__types__</code>. Additionally, in order to get the type of an entity node, each
node has a property
<code>__type__</code>
with the type of that entity.
</para>
</listitem>
<listitem>
<para>
<code>SubReferenceNodeTypeRepresentationStrategy</code>
</para>
<para>
Stores entity types in a tree in the graph representing the type hierarchy. Each entity
has a INSTANCE_OF relationship to a type node representing that entity's type. The type may or
may not have a SUBCLASS_OF relationship to another type node.
</para>
</listitem>
<listitem>
<para>
<code>NoopNodeTypeRepresentationStrategy</code>
</para>
<para>
Does not store any type information, and does hence not support finding by type, counting by type,
or retrieving the type of any entity.
</para>
</listitem>
</itemizedlist>
</para>
<para>
There are two implementations for relationship entities available, same behavior as the corresponding ones
above:
<itemizedlist>
<listitem>
<para>
<code>IndexingRelationshipTypeRepresentationStrategy</code>
</para>
</listitem>
<listitem>
<para>
<code>NoopRelationshipTypeRepresentationStrategy</code>
</para>
</listitem>
</itemizedlist>
</para>
<para>
Spring Data Graph will by default autodetect which are the most suitable strategies for node and relationship
entities. For new data stores, it will always opt for the indexing strategies. If a data store was created
with the older<code>SubReferenceNodeTypeRepresentationStrategy</code>, then it will continue to use that
strategy for node entities. It will however in that case use the no-op strategy for relationship entities,
which means that the old data stores have no support for searching for relationship entities. The indexing
strategies are recommended for all new users.
</para>
</section>

View File

@@ -98,6 +98,7 @@
</section>
<section>
<title>Setting Up Spring Data Graph - Spring Configuration</title>
<note>Out of date - should we even have this section?</note>
<para>The concrete configuration for Spring Data Graph is quite verbose as there is no autowiring involved. It sets up the following parts.
<itemizedlist>
<listitem>
@@ -120,7 +121,7 @@
<para>Finder factory</para>
</listitem>
<listitem>
<para>an appropriate NodeTypeStrategy</para>
<para>TypeRepresentationStrategies</para>
</listitem>
</itemizedlist>