DATAGRAPH-328 Upgrade SD-Commons to 1.5-SNAPSHOT, Added Auditing Support

This commit is contained in:
Michael Hunger
2013-01-29 15:38:57 +01:00
parent 0f0fa2ac5f
commit e08b7d12ee
24 changed files with 626 additions and 58 deletions

View File

@@ -33,9 +33,14 @@
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>

View File

@@ -32,9 +32,14 @@
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>

View File

@@ -124,7 +124,7 @@
<org.slf4j.version>1.6.1</org.slf4j.version>
<org.springframework.version.30>3.0.7.RELEASE</org.springframework.version.30>
<org.springframework.version>3.1.2.RELEASE</org.springframework.version>
<data.commons.version>1.4.0.RELEASE</data.commons.version>
<data.commons.version>1.5.0.BUILD-SNAPSHOT</data.commons.version>
<neo4j.version>1.8</neo4j.version>
<neo4j.spatial.version>0.9</neo4j.spatial.version>
<aspectj.version>1.6.12</aspectj.version>
@@ -281,9 +281,15 @@
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<artifactId>spring-data-commons</artifactId>
<version>${data.commons.version}</version>
</dependency>
<dependency>
@@ -752,6 +758,10 @@
<id>spring-libs-milestone</id>
<url>http://repo.springsource.org/libs-milestone</url>
</repository>
<repository>
<id>spring-libs-snapshot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
<repository>
<id>tinkerpop-repository</id>
<url>http://tinkerpop.com/maven2</url>

View File

@@ -36,9 +36,14 @@
</dependency>
<!-- Spring Data -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<!-- Logging -->

View File

@@ -16,6 +16,8 @@
package org.springframework.data.neo4j.annotation;
import org.springframework.data.annotation.Id;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -26,5 +28,6 @@ import java.lang.annotation.Target;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
@Id
public @interface GraphId {
}

View File

@@ -29,6 +29,8 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.annotation.RelationshipEntity;
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import org.springframework.util.ClassUtils;
import org.w3c.dom.Element;
@@ -43,6 +45,7 @@ public class DataGraphBeanDefinitionParser extends AbstractBeanDefinitionParser
public static final String ASPECTJ_CONFIG = "org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration";
public static final String CROSS_STORE_CONFIG = "org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext context) {
BeanDefinitionBuilder configBuilder = createConfigurationBeanDefinition(element);

View File

@@ -0,0 +1,101 @@
/**
* 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.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.springframework.data.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.neo4j.lifecycle.AuditingEventListener;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} to register a {@link AuditingEventListener} to transparently set auditing information on
* an entity.
*
* @author Oliver Gierke
*/
public class Neo4jAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return AuditingEventListener.class;
}
@Override
protected boolean shouldGenerateId() {
return true;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!registry.containsBeanDefinition(IS_NEW_STRATEGY_FACTORY)) {
String templateName = MAPPING_CONTEXT;
if (!registry.containsBeanDefinition(MAPPING_CONTEXT)) {
templateName = resolveMappingContextRef(element);
}
createIsNewStrategyFactoryBeanDefinition(templateName, parserContext, element);
}
BeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(IS_NEW_STRATEGY_FACTORY);
BeanDefinition handlerBeanDefinition = parser.parse(element, parserContext);
builder.addConstructorArgValue(handlerBeanDefinition);
}
static String resolveMappingContextRef(Element element) {
String ctxRef = element.getAttribute("mapping-context-ref");
if (StringUtils.hasText(ctxRef)) {
return ctxRef;
}
return "neo4jMappingContext";
}
private String createIsNewStrategyFactoryBeanDefinition(String mappingContextRef, ParserContext context,
Element element) {
BeanDefinitionBuilder mappingContextStrategyFactoryBuilder = BeanDefinitionBuilder
.rootBeanDefinition(MappingContextIsNewStrategyFactory.class);
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
context.registerBeanComponent(builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY));
return IS_NEW_STRATEGY_FACTORY;
}
static final String MAPPING_CONTEXT = "neo4jMappingContext";
static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory";
}

View File

@@ -28,6 +28,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.convert.DefaultTypeMapper;
import org.springframework.data.convert.TypeMapper;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.core.TypeRepresentationStrategy;
import org.springframework.data.neo4j.fieldaccess.FieldAccessorFactoryFactory;
@@ -55,6 +56,7 @@ import org.springframework.data.neo4j.support.relationship.RelationshipEntityIns
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
import org.springframework.data.neo4j.support.typerepresentation.ClassValueTypeInformationMapper;
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.transaction.PlatformTransactionManager;
import javax.validation.Validator;
@@ -114,6 +116,7 @@ public abstract class Neo4jConfiguration {
factoryBean.setTransactionManager(neo4jTransactionManager());
factoryBean.setGraphDatabase(graphDatabase());
factoryBean.setIsNewStrategyFactory(isNewStrategyFactory());
factoryBean.setIndexProvider(indexProvider());
@@ -122,6 +125,11 @@ public abstract class Neo4jConfiguration {
}
return factoryBean;
}
@Bean
public IsNewStrategyFactory isNewStrategyFactory() throws Exception {
return new MappingContextIsNewStrategyFactory(neo4jMappingContext());
}
@Bean
public Neo4jTemplate neo4jTemplate() throws Exception {

View File

@@ -0,0 +1,33 @@
/**
* 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.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
public class Neo4jNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
RepositoryConfigurationExtension extension = new Neo4jRepositoryConfigurationExtension();
RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension);
registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser);
registerBeanDefinitionParser("config", new DataGraphBeanDefinitionParser());
registerBeanDefinitionParser("auditing", new Neo4jAuditingBeanDefinitionParser());
}
}

View File

@@ -15,24 +15,8 @@
*/
package org.springframework.data.neo4j.lifecycle;
import org.springframework.context.ApplicationEvent;
public class AfterSaveEvent<T> extends ApplicationEvent {
private final T entity;
/**
* Create a new ApplicationEvent.
*
* @param source the component that published the event (never <code>null</code>)
* @param entity
*/
public class AfterSaveEvent<T> extends Neo4jLifecycleEvent<T> {
public AfterSaveEvent(Object source, T entity) {
super(source);
this.entity = entity;
}
public T getEntity() {
return entity;
super(source, entity);
}
}

View File

@@ -0,0 +1,53 @@
/**
* 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.lifecycle;
import org.springframework.context.ApplicationListener;
import org.springframework.util.Assert;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
/**
* Event listener to populate auditing related fields on an entity about to be saved.
*
* @author Oliver Gierke
*/
public class AuditingEventListener implements ApplicationListener<BeforeSaveEvent<Object>> {
private final IsNewAwareAuditingHandler<Object> auditingHandler;
/**
* Creates a new {@link AuditingEventListener} using the given {@link org.springframework.data.mapping.context.MappingContext} and {@link AuditingHandler}.
*
* @param auditingHandler must not be {@literal null}.
*/
public AuditingEventListener(IsNewAwareAuditingHandler<Object> auditingHandler) {
Assert.notNull(auditingHandler, "IsNewAwareAuditingHandler must not be null!");
this.auditingHandler = auditingHandler;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(BeforeSaveEvent<Object> event) {
Object entity = event.getEntity();
auditingHandler.markAudited(entity);
}
}

View File

@@ -15,22 +15,8 @@
*/
package org.springframework.data.neo4j.lifecycle;
import org.springframework.context.ApplicationEvent;
public class BeforeSaveEvent<T> extends ApplicationEvent {
private final T entity;
/**
* @param source the component that published the event (never <code>null</code>)
* @param entity the entity that is about to be saved
*/
public class BeforeSaveEvent<T> extends Neo4jLifecycleEvent<T> {
public BeforeSaveEvent(Object source, T entity) {
super(source);
this.entity = entity;
}
public T getEntity() {
return entity;
super(source, entity);
}
}

View File

@@ -15,18 +15,8 @@
*/
package org.springframework.data.neo4j.lifecycle;
import org.springframework.context.ApplicationEvent;
public class DeleteEvent<T> extends ApplicationEvent {
private final T entity;
public class DeleteEvent<T> extends Neo4jLifecycleEvent<T> {
public DeleteEvent(Object source, T entity) {
super(source);
this.entity = entity;
}
public T getEntity() {
return entity;
super(source, entity);
}
}

View File

@@ -0,0 +1,31 @@
/**
* 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.lifecycle;
import org.springframework.context.ApplicationEvent;
public class Neo4jLifecycleEvent<T> extends ApplicationEvent {
private final T entity;
public Neo4jLifecycleEvent(Object source,T entity) {
super(source);
this.entity = entity;
}
public T getEntity() {
return entity;
}
}

View File

@@ -66,7 +66,7 @@ public interface Neo4jPersistentProperty extends PersistentProperty<Neo4jPersist
Collection<? extends Annotation> getAnnotations();
<T extends Annotation> T getAnnotation(Class<T> annotationType);
<T extends Annotation> T getAnnotation(Class<? extends T> annotationType);
<T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType);

View File

@@ -21,6 +21,8 @@ import org.neo4j.graphdb.Relationship;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.conversion.ResultConverter;
import org.springframework.data.neo4j.core.GraphDatabase;
@@ -45,6 +47,7 @@ import org.springframework.data.neo4j.support.relationship.RelationshipEntityIns
import org.springframework.data.neo4j.support.relationship.RelationshipEntityStateFactory;
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategies;
import org.springframework.data.neo4j.support.typerepresentation.TypeRepresentationStrategyFactory;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
@@ -76,7 +79,7 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
private IndexProvider indexProvider;
private GraphDatabaseService graphDatabaseService;
private GraphDatabase graphDatabase;
private IsNewStrategyFactory isNewStrategyFactory;
private MappingInfrastructure mappingInfrastructure;
private TypeRepresentationStrategyFactory.Strategy typeRepresentationStrategy;
@@ -97,6 +100,9 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
public void afterPropertiesSet() {
try {
if (this.mappingContext == null) this.mappingContext = new Neo4jMappingContext();
if (this.isNewStrategyFactory == null) {
this.isNewStrategyFactory = new MappingContextIsNewStrategyFactory(mappingContext);
}
if (this.graphDatabaseService == null && graphDatabase instanceof DelegatingGraphDatabase) {
this.graphDatabaseService = ((DelegatingGraphDatabase) graphDatabase).getGraphDatabaseService();
}
@@ -280,6 +286,14 @@ public class MappingInfrastructureFactoryBean implements FactoryBean<Infrastruct
this.indexProvider = indexProvider;
}
public IsNewStrategyFactory getIsNewStrategyFactory() {
return isNewStrategyFactory;
}
public void setIsNewStrategyFactory(IsNewStrategyFactory newStrategyFactory) {
isNewStrategyFactory = newStrategyFactory;
}
@Override
public Infrastructure getObject() {
return mappingInfrastructure;

View File

@@ -20,6 +20,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.annotation.Transient;
import org.springframework.data.annotation.Version;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.AbstractPersistentProperty;
@@ -66,6 +67,7 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
private final Boolean isAssociation;
private final String neo4jPropertyName;
private final int hash;
private final boolean isVersionProperty;
public Neo4jPersistentPropertyImpl(Field field, PropertyDescriptor propertyDescriptor,
PersistentEntity<?, Neo4jPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder, Neo4jMappingContext ctx) {
@@ -83,6 +85,7 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
this.defaultValue = extractDefaultValue();
this.myAssociation = isAssociation() ? super.getAssociation() == null ? createAssociation() : super.getAssociation() : null;
this.query = extractQuery();
this.isVersionProperty = isAnnotationPresent(Version.class);
}
private String extractQuery() {
@@ -124,11 +127,16 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
return annotation!=null ? new IndexInfo(annotation,this) : null;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return (T) annotations.get(annotationType);
public <T extends Annotation> T getAnnotation(Class<? extends T> annotationType) {
return findAnnotation(annotationType);
}
@SuppressWarnings("unchecked")
public <A extends Annotation> A findAnnotation(Class<? extends A> annotationType) {
return (A) annotations.get(annotationType);
}
private RelationshipInfo extractRelationshipInfo(final Field field, Neo4jMappingContext ctx) {
if (isAnnotationPresent(RelatedTo.class)) {
return RelationshipInfo.fromField(field, getAnnotation(RelatedTo.class), getTypeInformation(), ctx);
@@ -166,6 +174,11 @@ class Neo4jPersistentPropertyImpl extends AbstractPersistentProperty<Neo4jPersis
return this.isIdProperty;
}
@Override
public boolean isVersionProperty() {
return isVersionProperty;
}
@Override
protected Association<Neo4jPersistentProperty> createAssociation() {
return new Association<Neo4jPersistentProperty>(this, null);

View File

@@ -1 +1 @@
http\://www.springframework.org/schema/data/neo4j=org.springframework.data.neo4j.config.DataGraphNamespaceHandler
http\://www.springframework.org/schema/data/neo4j=org.springframework.data.neo4j.config.Neo4jNamespaceHandler

View File

@@ -1,3 +1,4 @@
http\://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd=org/springframework/data/neo4j/config/spring-neo4j-2.0.xsd
http\://www.springframework.org/schema/data/neo4j/spring-neo4j-2.1.xsd=org/springframework/data/neo4j/config/spring-neo4j-2.1.xsd
http\://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd=org/springframework/data/neo4j/config/spring-neo4j-2.1.xsd
http\://www.springframework.org/schema/data/neo4j/spring-neo4j-2.2.xsd=org/springframework/data/neo4j/config/spring-neo4j-2.2.xsd
http\://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd=org/springframework/data/neo4j/config/spring-neo4j-2.2.xsd

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/data/neo4j"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://www.springframework.org/schema/data/neo4j"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd"/>
<xsd:element name="config">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="storeDirectory" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
default store-directory of the Neo4j database
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="graphDatabaseService" type="graphDatabaseServiceRef" />
<xsd:attribute name="base-package" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
base package for persistent entities.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="entityManagerFactory" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
entity manager factory bean reference for cross-store configuration
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="repositories">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="repository:repositories">
<xsd:attribute name="neo4j-template-ref" type="neo4jTemplateRef"/>
<xsd:attributeGroup ref="repository:repository-attributes"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="auditing">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.data.neo4j.lifecycle.AuditingEventListener" />
<tool:exports type="org.springframework.data.auditing.IsNewAwareAuditingHandler" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:attributeGroup ref="repository:auditing-attributes" />
<xsd:attribute name="neo4jTemplate" type="mappingContextRef" />
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="neo4jTemplateRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.neo4j.support.Neo4jTemplate"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="mappingContextRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.mapping.context.MappingContext"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="graphDatabaseServiceRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.neo4j.graphdb.GraphDatabaseService"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="entityManagerFactoryRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.orm.jpa.AbstractEntityManagerFactoryBean"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,78 @@
/**
* 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.config;
import org.joda.time.DateTime;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.lifecycle.BeforeSaveEvent;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
public class AuditingIntegrationTests {
@Test
public void enablesAuditingAndSetsPropertiesAccordingly() throws InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("auditing.xml", getClass());
runTest(context);
context.close();
}
@Test
public void enablesAuditingWithBeanConfigAndSetsPropertiesAccordingly() throws InterruptedException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("auditing-bean.xml", getClass());
runTest(context);
context.close();
}
private void runTest(ApplicationContext context) throws InterruptedException {
Entity entity = new Entity();
BeforeSaveEvent<Entity> event = new BeforeSaveEvent<Entity>(this,entity);
context.publishEvent(event);
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(entity.created));
Thread.sleep(10);
entity.id = 1L;
event = new BeforeSaveEvent<Entity>(this,entity);
context.publishEvent(event);
assertThat(entity.created, is(notNullValue()));
assertThat(entity.modified, is(not(entity.created)));
}
@NodeEntity
class Entity {
@CreatedDate
DateTime created;
@LastModifiedDate
DateTime modified;
@GraphId
Long id;
}
}

View File

@@ -0,0 +1,92 @@
/**
* 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.lifecycle;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
import org.springframework.data.neo4j.annotation.GraphId;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.data.neo4j.support.mapping.Neo4jMappingContext;
import org.springframework.data.support.IsNewStrategyFactory;
/**
* Unit tests for {@link AuditingEventListener}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class AuditingEventListenerUnitTests {
IsNewAwareAuditingHandler<Object> handler;
IsNewStrategyFactory factory;
AuditingEventListener listener;
@Before
public void setUp() {
Neo4jMappingContext mappingContext = new Neo4jMappingContext();
factory = new MappingContextIsNewStrategyFactory(mappingContext);
handler = spy(new IsNewAwareAuditingHandler<Object>(factory));
doNothing().when(handler).markCreated(Mockito.any(Object.class));
doNothing().when(handler).markModified(Mockito.any(Object.class));
listener = new AuditingEventListener(handler);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullAuditingHandler() {
new AuditingEventListener(null);
}
@Test
public void triggersCreationMarkForObjectWithEmptyId() {
Sample sample = new Sample();
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this,sample));
verify(handler, times(1)).markCreated(sample);
verify(handler, times(0)).markModified(any(Sample.class));
}
@Test
public void triggersModificationMarkForObjectWithSetId() {
Sample sample = new Sample();
sample.id = "id";
listener.onApplicationEvent(new BeforeSaveEvent<Object>(this,sample));
verify(handler, times(0)).markCreated(any(Sample.class));
verify(handler, times(1)).markModified(sample);
}
@NodeEntity
static class Sample {
@GraphId
String id;
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation="http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<neo4j:config graphDatabaseService="graphDatabaseService" />
<bean class="org.springframework.data.neo4j.lifecycle.AuditingEventListener">
<constructor-arg>
<bean class="org.springframework.data.auditing.IsNewAwareAuditingHandler">
<constructor-arg ref="isNewStrategyFactory"/>
</bean>
</constructor-arg>
</bean>
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"/>
</beans>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
xsi:schemaLocation="http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<neo4j:config graphDatabaseService="graphDatabaseService" />
<neo4j:auditing />
<bean id="graphDatabaseService" class="org.neo4j.test.ImpermanentGraphDatabase"/>
</beans>