From bdf51f21dd948ca272b189488b84b735a224ca4b Mon Sep 17 00:00:00 2001 From: Michael Hunger Date: Sun, 2 Oct 2011 19:20:25 +0200 Subject: [PATCH] making all the tests green again merged pull requests from ractive fixed handling in ManagedSet fixed cypher query executer initialization extracted EntityStateHandler to resolve cyclic dependency introduced different modes for the initialization provided by the namespace fixed illegal method override for inherited persist --- .../config/DataGraphBeanDefinitionParser.java | 34 ++++++-- .../data/neo4j/config/Neo4jConfiguration.java | 23 +++-- .../GraphBackedEntityIterableWrapper.java | 45 ++++++++++ .../fieldaccess/ManagedFieldAccessorSet.java | 18 ++-- .../ManagedPrefixedDynamicProperties.java | 30 ++++--- .../NodeToNodesRelationshipFieldAccessor.java | 5 +- ...elationshipEntityFieldAccessorFactory.java | 30 +++---- ...neToNRelationshipFieldAccessorFactory.java | 7 +- .../neo4j/mapping/Neo4jPersistentEntity.java | 2 +- .../mapping/Neo4jPersistentEntityImpl.java | 14 +-- .../neo4j/support/EntityStateHandler.java | 85 +++++++++++++++++++ .../neo4j/support/GraphDatabaseContext.java | 52 +++++------- .../data/neo4j/support/ManagedEntity.java | 8 +- .../support/node/NodeEntityInstantiator.java | 11 ++- .../neo4j/support/node/NodeEntityState.java | 5 +- .../RelationshipEntityInstantiator.java | 11 ++- .../neo4j/mapping/Neo4jNodeConverterTest.java | 8 +- 17 files changed, 269 insertions(+), 119 deletions(-) create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java create mode 100644 spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java index 76be46e32..135d44090 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/DataGraphBeanDefinitionParser.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.annotation.ConfigurationClassPostProcessor; +import org.springframework.util.ClassUtils; import org.w3c.dom.Element; import static org.springframework.util.StringUtils.hasText; @@ -32,22 +33,40 @@ import static org.springframework.util.StringUtils.hasText; public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser { private static final String GRAPH_DATABASE_SERVICE = "graphDatabaseService"; + public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.config.Neo4jAspectConfiguration"; + public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.config.CrossStoreNeo4jConfiguration"; @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) { - BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(); + BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(element); setupGraphDatabase(element, context, configBuilder); setupEntityManagerFactory(element, configBuilder); setupConfigurationClassPostProcessor(context); return getSourcedBeanDefinition(configBuilder, element, context); } - private BeanDefinitionBuilder createConfigurationBeanDefinition() { - BeanDefinitionBuilder configBuilder = BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + + private BeanDefinitionBuilder createConfigurationBeanDefinition(Element element) { + BeanDefinitionBuilder configBuilder = createConfigBuilderByMode(element); configBuilder.setAutowireMode(Autowire.BY_TYPE.value()); return configBuilder; } + // todo cross-store + private BeanDefinitionBuilder createConfigBuilderByMode(Element element) { + if (isModeCrossStore(element)) return BeanDefinitionBuilder.rootBeanDefinition(CROSS_STORE_CONFIG); + if (isModeAspectJ()) return BeanDefinitionBuilder.rootBeanDefinition(ASPECTJ_CONFIG); + return BeanDefinitionBuilder.rootBeanDefinition(Neo4jConfiguration.class); + } + + private boolean isModeCrossStore(Element element) { + return isModeAspectJ() && isEntityManagerFactoryConfigured(element); + } + + private boolean isModeAspectJ() { + return ClassUtils.isPresent(ASPECTJ_CONFIG, getClass().getClassLoader()); + } + private void setupConfigurationClassPostProcessor(final ParserContext parserContext) { BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry(); @@ -72,12 +91,17 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser } private void setupEntityManagerFactory(Element element, BeanDefinitionBuilder configBuilder) { - String entityManagerFactory = element.getAttribute("entityManagerFactory"); - if (hasText(entityManagerFactory)) { + if (isEntityManagerFactoryConfigured(element)) { + String entityManagerFactory = element.getAttribute("entityManagerFactory"); configBuilder.addPropertyReference("entityManagerFactory", entityManagerFactory); } } + private boolean isEntityManagerFactoryConfigured(Element element) { + String entityManagerFactory = element.getAttribute("entityManagerFactory"); + return hasText(entityManagerFactory); + } + private String handleStoreDir(Element element, ParserContext context, BeanDefinitionBuilder configBuilder) { String storeDir = element.getAttribute("storeDirectory"); if (!hasText(storeDir)) return null; diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java index ca8340574..242765d19 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/config/Neo4jConfiguration.java @@ -16,9 +16,6 @@ package org.springframework.data.neo4j.config; -import javax.annotation.PostConstruct; -import javax.validation.Validator; - import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; @@ -30,8 +27,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.ConversionService; import org.springframework.dao.support.PersistenceExceptionTranslator; - - import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory; import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean; import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory; @@ -40,6 +35,7 @@ import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.mapping.Neo4jNodeConverterImpl; import org.springframework.data.neo4j.repository.DirectGraphRepositoryFactory; import org.springframework.data.neo4j.support.EntityInstantiator; +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; @@ -51,6 +47,9 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import org.springframework.transaction.jta.UserTransactionAdapter; +import javax.annotation.PostConstruct; +import javax.validation.Validator; + /** * Abstract base class for code based configuration of Spring managed Neo4j infrastructure. *

Subclasses are required to provide an implementation of graphDbService .... @@ -87,6 +86,7 @@ public abstract class Neo4jConfiguration { gdc.setConversionService(conversionService()); gdc.setMappingContext(mappingContext()); gdc.setConverter(neo4jConverter()); + gdc.setEntityStateHandler(entityStateHandler()); gdc.setNodeTypeRepresentationStrategy(typeRepresentationStrategyFactory.getNodeTypeRepresentationStrategy()); gdc.setRelationshipTypeRepresentationStrategy(typeRepresentationStrategyFactory.getRelationshipTypeRepresentationStrategy()); if (validator!=null) { @@ -95,6 +95,11 @@ public abstract class Neo4jConfiguration { return gdc; } + @Bean + public EntityStateHandler entityStateHandler() { + return new EntityStateHandler(mappingContext(),graphDatabaseService); + } + @Bean public Neo4jNodeConverterImpl neo4jConverter() throws Exception { return new Neo4jNodeConverterImpl(); @@ -106,13 +111,13 @@ public abstract class Neo4jConfiguration { } @Bean - protected RelationshipEntityInstantiator graphRelationshipInstantiator() { - return new RelationshipEntityInstantiator(mappingContext()); + protected RelationshipEntityInstantiator graphRelationshipInstantiator() throws Exception { + return new RelationshipEntityInstantiator(entityStateHandler()); } @Bean - protected EntityInstantiator graphEntityInstantiator() { - return new NodeEntityInstantiator(mappingContext()); + protected EntityInstantiator graphEntityInstantiator() throws Exception { + return new NodeEntityInstantiator(entityStateHandler()); } @Bean diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java new file mode 100644 index 000000000..cee856e77 --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/GraphBackedEntityIterableWrapper.java @@ -0,0 +1,45 @@ +/** + * 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.fieldaccess; + +import org.neo4j.graphdb.PropertyContainer; +import org.neo4j.helpers.collection.IterableWrapper; +import org.springframework.data.neo4j.support.GraphDatabaseContext; + +/** + * Simple wrapper to create an Iterable over @NodeEntities or @RelationshipEntities from an iterable over Nodes or Relationships. + * Creates NodeEntities on the fly while iterating the Iterator from original iterable. + */ +public class GraphBackedEntityIterableWrapper extends IterableWrapper { + private final Class targetType; + private final GraphDatabaseContext graphDatabaseContext; + + public GraphBackedEntityIterableWrapper(Iterable iterable, Class targetType, final GraphDatabaseContext graphDatabaseContext) { + super(iterable); + this.targetType = targetType; + this.graphDatabaseContext = graphDatabaseContext; + } + + @Override + protected ENTITY underlyingObjectToObject(STATE s) { + return graphDatabaseContext.createEntityFromState(s, targetType); + } + + public static GraphBackedEntityIterableWrapper create( + Iterable iterable, Class targetType, final GraphDatabaseContext graphDatabaseContext) { + return new GraphBackedEntityIterableWrapper(iterable, targetType, graphDatabaseContext); + } +} \ No newline at end of file diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java index 52ce0041f..8ccabc766 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedFieldAccessorSet.java @@ -16,10 +16,11 @@ package org.springframework.data.neo4j.fieldaccess; -import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity; +import org.springframework.data.neo4j.core.EntityState; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; import org.springframework.data.neo4j.support.GraphDatabaseContext; +import org.springframework.data.neo4j.support.ManagedEntity; import java.util.AbstractSet; import java.util.Collection; @@ -68,15 +69,20 @@ public class ManagedFieldAccessorSet extends AbstractSet { } private void update() { - final Neo4jPersistentEntity persistentEntity = property.getOwner(); - if (persistentEntity.isNodeEntity()) { - updateValue(); - } - if (persistentEntity.isRelationshipEntity()) { + if (ctx.isManaged(entity)) { + updateValueWithState(((ManagedEntity)entity).getEntityState()); + } else { updateValue(); } } + private Object updateValueWithState(EntityState entityState) { + final Object newValue = entityState.setValue(property, delegate); + if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); + property.setValue(entity, newValue); + return newValue; + } + private Object updateValue() { final Object newValue = fieldAccessor.setValue(entity,delegate); if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java index 7eae2fb26..eba9695a3 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/ManagedPrefixedDynamicProperties.java @@ -15,18 +15,13 @@ */ package org.springframework.data.neo4j.fieldaccess; -import java.lang.reflect.Field; -import java.util.Map; - -import org.neo4j.graphdb.Node; import org.springframework.data.neo4j.core.EntityState; - - - import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.DoReturn; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import scala.annotation.target.field; +import org.springframework.data.neo4j.support.ManagedEntity; + +import java.util.Map; /** * Updates the entity containing such a ManagedPrefixedDynamicProperties when some property is added, changed or @@ -82,10 +77,6 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties return d; } - private void update() { - updateValue(); - } - private Object updateValue() { final Object newValue = fieldAccessor.setValue(entity, this); if (newValue instanceof DoReturn) @@ -93,4 +84,19 @@ public class ManagedPrefixedDynamicProperties extends PrefixedDynamicProperties property.setValue(entity, newValue); return newValue; } + + private void update() { + if (graphDatabaseContext.isManaged(entity)) { + updateValueWithState(((ManagedEntity)entity).getEntityState()); + } else { + updateValue(); + } + } + + private Object updateValueWithState(EntityState entityState) { + final Object newValue = entityState.setValue(property, this); + if (newValue instanceof DoReturn) return DoReturn.unwrap(newValue); + property.setValue(entity, newValue); + return newValue; + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java index 82f9ab8b6..d1503e7bc 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/NodeToNodesRelationshipFieldAccessor.java @@ -20,11 +20,8 @@ import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; - - import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import org.springframework.util.Assert; import java.util.HashSet; import java.util.Set; @@ -59,7 +56,7 @@ public abstract class NodeToNodesRelationshipFieldAccessor extends AbstractNodeR @Override protected Node getState(final Object entity) { - return property.getOwner().getPersistentState(entity, graphDatabaseContext); + return graphDatabaseContext.getPersistentState(entity); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java index fe55d3613..c5b6b32b5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipEntityFieldAccessorFactory.java @@ -16,17 +16,15 @@ package org.springframework.data.neo4j.fieldaccess; -import org.neo4j.graphdb.*; +import org.neo4j.graphdb.Direction; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.RelationshipType; import org.springframework.dao.InvalidDataAccessApiUsageException; - - import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.GraphDatabaseContext; -import java.util.HashSet; -import java.util.Set; - import static org.springframework.data.neo4j.support.DoReturn.doReturn; public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccessorFactory { @@ -68,22 +66,16 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess @Override public Object getValue(final Object entity) { checkUnderlyingNode(entity); - final Set result = createEntitySetFromRelationships(entity); - return doReturn(new ManagedFieldAccessorSet(entity, result, property,graphDatabaseContext, this)); - } + return doReturn(iterableFrom(entity)); + } - private Set createEntitySetFromRelationships(final Object entity) { - final Set result = new HashSet(); - for (final Relationship rel : getStatesFromEntity(entity)) { - final Object relationshipEntity = graphDatabaseContext.createEntityFromState(rel, relatedType); - result.add(relationshipEntity); - } - return result; - } + private GraphBackedEntityIterableWrapper iterableFrom(final Object entity) { + return GraphBackedEntityIterableWrapper.create(getStatesFromEntity(entity), relatedType, graphDatabaseContext); + } @Override protected Iterable getStatesFromEntity(final Object entity) { - final Node persistentState = property.getOwner().getPersistentState(entity, graphDatabaseContext); + final Node persistentState = getState(entity); return persistentState.getRelationships(type, direction); } @@ -94,7 +86,7 @@ public class OneToNRelationshipEntityFieldAccessorFactory implements FieldAccess @Override protected Node getState(final Object entity) { - return property.getOwner().getPersistentState(entity, graphDatabaseContext); + return graphDatabaseContext.getPersistentState(entity); } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java index bc5f716da..adc5cee86 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/fieldaccess/OneToNRelationshipFieldAccessorFactory.java @@ -24,6 +24,7 @@ import org.springframework.data.neo4j.mapping.RelationshipInfo; import org.springframework.data.neo4j.support.GraphDatabaseContext; import java.util.Collections; +import java.util.HashSet; import java.util.Set; import static org.springframework.data.neo4j.support.DoReturn.doReturn; @@ -73,5 +74,9 @@ public class OneToNRelationshipFieldAccessorFactory extends NodeRelationshipFiel return doReturn(createManagedSet(entity, result)); } - } + @Override + public Object getDefaultImplementation() { + return new HashSet(); + } + } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntity.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntity.java index 3323861b9..3b9e2a21b 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntity.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntity.java @@ -35,5 +35,5 @@ public interface Neo4jPersistentEntity extends PersistentEntity T getPersistentState(Object entity, GraphDatabaseContext service); + Object getPersistentId(Object entity); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntityImpl.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntityImpl.java index 5510d0e10..eef283cb9 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntityImpl.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/mapping/Neo4jPersistentEntityImpl.java @@ -23,7 +23,6 @@ import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.mapping.model.MappingException; import org.springframework.data.neo4j.annotation.NodeEntity; import org.springframework.data.neo4j.annotation.RelationshipEntity; -import org.springframework.data.neo4j.support.GraphDatabaseContext; import org.springframework.data.util.TypeInformation; import java.lang.annotation.Annotation; @@ -97,19 +96,10 @@ public class Neo4jPersistentEntityImpl extends BasicPersistentEntity T getPersistentState(Object entity, GraphDatabaseContext service) { + public Object getPersistentId(Object entity) { final Neo4jPersistentProperty idProperty = getIdProperty(); if (idProperty==null) throw new MappingException("No field annotated with @GraphId found in "+ getEntityName()); - if (!Number.class.isAssignableFrom(idProperty.getType())) throw new IllegalArgumentException("The id of "+getEntityName()+" "+idProperty+" is not a number"); - final Number id = (Number) idProperty.getValue(entity); - if (id==null) return null; // todo create new node? - if (isNodeEntity()) { - return (T) service.getNodeById(id.longValue()); - } - if (isRelationshipEntity()) { - return (T) service.getRelationshipById(id.longValue()); - } - throw new IllegalArgumentException("The entity "+getEntityName()+" has to be either annotated with @NodeEntity or @RelationshipEntity"); + return idProperty.getValue(entity); } public String getEntityName() { diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java new file mode 100644 index 000000000..a8fb0cefe --- /dev/null +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/EntityStateHandler.java @@ -0,0 +1,85 @@ +/** + * 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.GraphDatabaseService; +import org.neo4j.graphdb.PropertyContainer; +import org.springframework.data.neo4j.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.mapping.Neo4jPersistentEntityImpl; + +/** + * @author mh + * @since 02.10.11 + */ +public class EntityStateHandler { + + private Neo4jMappingContext mappingContext; + private final GraphDatabaseService service; + + public EntityStateHandler(Neo4jMappingContext mappingContext, GraphDatabaseService service) { + this.mappingContext = mappingContext; + this.service = service; + } + + public void setPersistentState(Object entity, S state) { + if (entity instanceof PropertyContainer) { + return; + } + if (isManaged(entity)) { + ((ManagedEntity) entity).setPersistentState(state); + return; + } + final Class type = entity.getClass(); + final Neo4jPersistentEntityImpl persistentEntity = mappingContext.getPersistentEntity(type); + persistentEntity.setPersistentState(entity, state); + } + + public boolean isManaged(Object entity) { + return entity instanceof ManagedEntity; + } + + @SuppressWarnings("unchecked") + public S getPersistentState(Object entity) { + if (entity instanceof PropertyContainer) { + return (S) entity; + } + if (isManaged(entity)) { + return ((ManagedEntity) 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)) { + return (S) service.getNodeById(graphId); + } + if (isRelationshipEntity(type)) { + return (S) service.getRelationshipById(graphId); + } + throw new IllegalArgumentException("The entity " + persistentEntity.getEntityName() + " has to be either annotated with @NodeEntity or @RelationshipEntity"); + } + + public boolean isNodeEntity(Class targetType) { + return mappingContext.isNodeEntity(targetType); + } + + public boolean isRelationshipEntity(Class targetType) { + return mappingContext.isRelationshipEntity(targetType); + } +} diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java index 163f036cf..cc0cf6724 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/GraphDatabaseContext.java @@ -32,7 +32,6 @@ import org.springframework.data.neo4j.annotation.Indexed; import org.springframework.data.neo4j.core.*; import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.mapping.Neo4jNodeConverter; -import org.springframework.data.neo4j.mapping.Neo4jPersistentEntityImpl; import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty; import org.springframework.data.neo4j.support.query.CypherQueryExecutor; import org.springframework.data.util.TypeInformation; @@ -67,7 +66,8 @@ public class GraphDatabaseContext { private RelationshipTypeRepresentationStrategy relationshipTypeRepresentationStrategy; private Neo4jMappingContext mappingContext; - private final CypherQueryExecutor executor = new CypherQueryExecutor(this); + private CypherQueryExecutor cypherQueryExecutor; + private EntityStateHandler entityStateHandler; public Index getIndex(Class type) { @@ -128,33 +128,16 @@ public class GraphDatabaseContext { S state = getPersistentState(entity); return getTypeRepresentationStrategy(state, targetType).projectEntity(state, targetType); } - + @SuppressWarnings("unchecked") public S getPersistentState(Object entity) { - if (entity instanceof PropertyContainer) { - return (S) entity; - } - if (isManaged(entity)) { - return ((ManagedEntity)entity).getPersistentState(); - } - final Class type = entity.getClass(); - final Neo4jPersistentEntityImpl persistentEntity = mappingContext.getPersistentEntity(type); - return (S)persistentEntity.getPersistentState(entity,this); + return entityStateHandler.getPersistentState(entity); } // todo depending on type of mapping @SuppressWarnings("unchecked") public void setPersistentState(Object entity, S state) { - if (entity instanceof PropertyContainer) { - return; - } - if (isManaged(entity)) { - ((ManagedEntity)entity).setPersistentState(state); - return; - } - final Class type = entity.getClass(); - final Neo4jPersistentEntityImpl persistentEntity = mappingContext.getPersistentEntity(type); - persistentEntity.setPersistentState(entity,state); + entityStateHandler.setPersistentState(entity, state); } public void postEntityCreation(S node, Class entityClass) { @@ -163,8 +146,7 @@ public class GraphDatabaseContext { @SuppressWarnings("unchecked") public Iterable findAllByTraversal(Object entity, Class targetType, TraversalDescription traversalDescription) { - final Neo4jPersistentEntityImpl persistentEntity = mappingContext.getPersistentEntity(entity.getClass()); - final PropertyContainer state = persistentEntity.getPersistentState(entity, this); + final PropertyContainer state = entityStateHandler.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) traverser.nodes(); @@ -317,6 +299,7 @@ public class GraphDatabaseContext { public void setGraphDatabaseService(GraphDatabaseService graphDatabaseService) { this.graphDatabaseService = graphDatabaseService; + this.cypherQueryExecutor = new CypherQueryExecutor(this); } public NodeTypeRepresentationStrategy getNodeTypeRepresentationStrategy() { @@ -373,8 +356,8 @@ public class GraphDatabaseContext { } } - private boolean isManaged(Object entity) { - return entity instanceof ManagedEntity; + public boolean isManaged(Object entity) { + return entityStateHandler.isManaged(entity); } public void setConverter(Neo4jNodeConverter converter) { @@ -383,14 +366,19 @@ public class GraphDatabaseContext { public Object executeQuery(Object entity, String queryString, Map params, Neo4jPersistentProperty property) { final TypeInformation typeInformation = property.getTypeInformation(); - final Class targetType = typeInformation.getActualType().getType(); + final TypeInformation actualType = typeInformation.getActualType(); + final Class targetType = actualType.getType(); + if (actualType.isMap()) { + return cypherQueryExecutor.queryForList(queryString, params); + } if (typeInformation.isCollectionLike()) { - return executor.query(queryString, targetType, params); + return cypherQueryExecutor.query(queryString, targetType, params); } - if (typeInformation.isMap()) { - return executor.queryForList(queryString, params); - } - return executor.queryForObject(queryString, targetType, params); + return cypherQueryExecutor.queryForObject(queryString, targetType, params); + } + + public void setEntityStateHandler(EntityStateHandler entityStateHandler) { + this.entityStateHandler = entityStateHandler; } } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/ManagedEntity.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/ManagedEntity.java index 84d238695..73ba5512f 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/ManagedEntity.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/ManagedEntity.java @@ -15,16 +15,18 @@ */ package org.springframework.data.neo4j.support; -import org.neo4j.graphdb.PropertyContainer; +import org.springframework.data.neo4j.core.EntityState; /** * @author mh * @since 02.10.11 */ -public interface ManagedEntity { - T persist(); +public interface ManagedEntity { + U persist(); S getPersistentState(); + EntityState getEntityState(); + void setPersistentState(S state); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityInstantiator.java index 27be3cea1..0f2c155c5 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityInstantiator.java @@ -17,9 +17,8 @@ package org.springframework.data.neo4j.support.node; import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.Relationship; -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.support.AbstractConstructorEntityInstantiator; +import org.springframework.data.neo4j.support.EntityStateHandler; /** @@ -31,10 +30,10 @@ import org.springframework.data.neo4j.support.AbstractConstructorEntityInstantia */ public class NodeEntityInstantiator extends AbstractConstructorEntityInstantiator { - private final Neo4jMappingContext mappingContext; + private final EntityStateHandler entityStateHandler; - public NodeEntityInstantiator(Neo4jMappingContext mappingContext) { - this.mappingContext = mappingContext; + public NodeEntityInstantiator(EntityStateHandler entityStateHandler) { + this.entityStateHandler = entityStateHandler; } @@ -44,7 +43,7 @@ public class NodeEntityInstantiator extends AbstractConstructorEntityInstantiato } protected void setPersistentState(Object entity, Node node) { - this.mappingContext.setPersistentState(entity,node); + this.entityStateHandler.setPersistentState(entity,node); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java index bf286904d..4f45bb26c 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/node/NodeEntityState.java @@ -24,6 +24,7 @@ import org.springframework.data.neo4j.fieldaccess.DefaultEntityState; import org.springframework.data.neo4j.fieldaccess.DelegatingFieldAccessorFactory; import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity; import org.springframework.data.neo4j.support.GraphDatabaseContext; +import org.springframework.data.neo4j.support.ManagedEntity; /** * @author Michael Hunger @@ -65,7 +66,9 @@ public class NodeEntityState extends DefaultEntityState { @Override public void setPersistentState(Node node) { - graphDatabaseContext.setPersistentState(entity,node); + if (!(entity instanceof ManagedEntity)) { + graphDatabaseContext.setPersistentState(entity, node); + } super.setPersistentState(node); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityInstantiator.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityInstantiator.java index 1e2972a5e..a4b10cbdf 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityInstantiator.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/support/relationship/RelationshipEntityInstantiator.java @@ -17,9 +17,8 @@ package org.springframework.data.neo4j.support.relationship; import org.neo4j.graphdb.Relationship; - -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.support.AbstractConstructorEntityInstantiator; +import org.springframework.data.neo4j.support.EntityStateHandler; import sun.reflect.ReflectionFactory; /** @@ -30,15 +29,15 @@ import sun.reflect.ReflectionFactory; public class RelationshipEntityInstantiator extends AbstractConstructorEntityInstantiator { - private final Neo4jMappingContext mappingContext; + private final EntityStateHandler entityStateHandler; - public RelationshipEntityInstantiator(Neo4jMappingContext mappingContext) { - this.mappingContext = mappingContext; + public RelationshipEntityInstantiator(EntityStateHandler entityStateHandler) { + this.entityStateHandler = entityStateHandler; } @Override protected void setState(Object entity, Relationship relationship) { - this.mappingContext.setPersistentState(entity,relationship); + this.entityStateHandler.setPersistentState(entity,relationship); } @Override diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4jNodeConverterTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4jNodeConverterTest.java index a48a64e6d..d1c3e93de 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4jNodeConverterTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/mapping/Neo4jNodeConverterTest.java @@ -28,6 +28,7 @@ import org.springframework.data.neo4j.Person; import org.springframework.data.neo4j.Personality; import org.springframework.data.neo4j.fieldaccess.Neo4jConversionServiceFactoryBean; import org.springframework.data.neo4j.fieldaccess.NodeDelegatingFieldAccessorFactory; +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; @@ -63,10 +64,13 @@ public class Neo4jNodeConverterTest { private GraphDatabaseContext createContext(Neo4jMappingContext mappingContext) throws Exception { GraphDatabaseContext gdc = new GraphDatabaseContext(); - gdc.setGraphDatabaseService(new ImpermanentGraphDatabase()); + final ImpermanentGraphDatabase gdb = new ImpermanentGraphDatabase(); + gdc.setGraphDatabaseService(gdb); gdc.setMappingContext(mappingContext); - gdc.setNodeTypeRepresentationStrategy(new NoopNodeTypeRepresentationStrategy(new NodeEntityInstantiator(mappingContext))); + final EntityStateHandler entityStateHandler = new EntityStateHandler(mappingContext, gdb); + gdc.setNodeTypeRepresentationStrategy(new NoopNodeTypeRepresentationStrategy(new NodeEntityInstantiator(entityStateHandler))); gdc.setConversionService(new Neo4jConversionServiceFactoryBean().getObject()); + gdc.setEntityStateHandler(entityStateHandler); return gdc; }