From 94823500624432de101e464f6adf72d98b37a347 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 21 Nov 2012 20:31:18 +0100 Subject: [PATCH] DATAMONGO-577 - Added support for auditing. Introduced AuditingEventListener to invoke auditing subsystem available through Spring Data Commons. Added namespace element to transparently activate it. --- .../config/AbstractMongoConfiguration.java | 14 + .../data/mongodb/config/BeanNames.java | 2 + .../config/MappingMongoConverterParser.java | 21 +- .../MongoAuditingBeanDefinitionParser.java | 79 +++ .../mongodb/config/MongoNamespaceHandler.java | 12 +- .../mapping/BasicMongoPersistentEntity.java | 40 -- .../mapping/BasicMongoPersistentProperty.java | 8 - .../core/mapping/MongoPersistentEntity.java | 16 - .../core/mapping/MongoPersistentProperty.java | 7 - .../data/mongodb/core/mapping/Version.java | 3 + .../mapping/event/AuditingEventListener.java | 53 ++ .../mapping/event/BeforeConvertEvent.java | 12 +- .../MappingMongoEntityInformation.java | 8 +- .../main/resources/META-INF/spring.schemas | 5 +- .../data/mongodb/config/spring-mongo-1.2.xsd | 483 ++++++++++++++++++ .../config/AuditingIntegrationTests.java | 68 +++ .../event/AuditingEventListenerUnitTests.java | 89 ++++ .../data/mongodb/config/auditing.xml | 12 + .../MongoMonitorIntegrationTests-context.xml | 5 +- ...MongoNamespaceIntegrationTests-context.xml | 6 +- 20 files changed, 849 insertions(+), 94 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingBeanDefinitionParser.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/AuditingEventListener.java create mode 100644 spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.2.xsd create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingIntegrationTests.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/AuditingEventListenerUnitTests.java create mode 100644 spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/auditing.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java index 6333d0ef6..25a90215f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java @@ -27,12 +27,15 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.data.annotation.Persistent; import org.springframework.data.authentication.UserCredentials; +import org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.core.convert.CustomConversions; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.support.CachingIsNewStrategyFactory; +import org.springframework.data.support.IsNewStrategyFactory; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -136,6 +139,17 @@ public abstract class AbstractMongoConfiguration { return mappingContext; } + /** + * Returns a {@link MappingContextIsNewStrategyFactory} wrapped into a {@link CachingIsNewStrategyFactory}. + * + * @return + * @throws ClassNotFoundException + */ + @Bean + public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException { + return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(mongoMappingContext())); + } + /** * Register custom {@link Converter}s in a {@link CustomConversions} object if required. These * {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java index 2c4ef69d5..f7d3f8243 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/BeanNames.java @@ -26,4 +26,6 @@ public abstract class BeanNames { static final String MONGO = "mongo"; static final String DB_FACTORY = "mongoDbFactory"; static final String VALIDATING_EVENT_LISTENER = "validatingMongoEventListener"; + static final String IS_NEW_STRATEGY_FACTORY = "isNewStrategyFactory"; + } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java index 8bfd4aaa6..f3cc3597c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java @@ -49,6 +49,8 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.annotation.Persistent; import org.springframework.data.config.BeanComponentDefinitionBuilder; +import org.springframework.data.config.ParsingUtils; +import org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory; import org.springframework.data.mongodb.core.convert.CustomConversions; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator; @@ -88,6 +90,8 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext); String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition); + createIsNewStrategyFactoryBeanDefinition(ctxRef, parserContext, element); + // Need a reference to a Mongo instance String dbFactoryRef = element.getAttribute("db-factory-ref"); if (!StringUtils.hasText(dbFactoryRef)) { @@ -163,7 +167,7 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { return new RuntimeBeanReference(validatorName); } - private String potentiallyCreateMappingContext(Element element, ParserContext parserContext, + static String potentiallyCreateMappingContext(Element element, ParserContext parserContext, BeanDefinition conversionsDefinition) { String ctxRef = element.getAttribute("mapping-context-ref"); @@ -241,7 +245,7 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { return null; } - public Set getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) { + private static Set getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) { String basePackage = element.getAttribute(BASE_PACKAGE); @@ -280,6 +284,19 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { return null; } + public static String createIsNewStrategyFactoryBeanDefinition(String mappingContextRef, ParserContext context, + Element element) { + + BeanDefinitionBuilder mappingContextStrategyFactoryBuilder = BeanDefinitionBuilder + .rootBeanDefinition(MappingContextIsNewStrategyFactory.class); + mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef); + + context.getRegistry().registerBeanDefinition(IS_NEW_STRATEGY_FACTORY, + ParsingUtils.getSourceBeanDefinition(mappingContextStrategyFactoryBuilder, context, element)); + + return IS_NEW_STRATEGY_FACTORY; + } + /** * {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingBeanDefinitionParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingBeanDefinitionParser.java new file mode 100644 index 000000000..a2fe8db76 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoAuditingBeanDefinitionParser.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012 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.mongodb.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.IsNewAwareAuditingHandlerBeanDefinitionParser; +import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener; +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 MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element) + */ + @Override + protected Class getBeanClass(Element element) { + return AuditingEventListener.class; + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#shouldGenerateId() + */ + @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(BeanNames.IS_NEW_STRATEGY_FACTORY)) { + + String mappingContextName = BeanNames.MAPPING_CONTEXT; + + if (!registry.containsBeanDefinition(BeanNames.MAPPING_CONTEXT)) { + mappingContextName = MappingMongoConverterParser.potentiallyCreateMappingContext(element, parserContext, null); + } + + MappingMongoConverterParser.createIsNewStrategyFactoryBeanDefinition(mappingContextName, parserContext, element); + } + + BeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(BeanNames.IS_NEW_STRATEGY_FACTORY); + BeanDefinition handlerBeanDefinition = parser.parse(element, parserContext); + + builder.addConstructorArgValue(handlerBeanDefinition); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java index a01de7878..048536b58 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoNamespaceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-2012 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. @@ -21,17 +21,16 @@ import org.springframework.data.repository.config.RepositoryBeanDefinitionParser import org.springframework.data.repository.config.RepositoryConfigurationExtension; /** - * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB based repositories. + * {@link org.springframework.beans.factory.xml.NamespaceHandler} for Mongo DB configuration. * * @author Oliver Gierke */ public class MongoNamespaceHandler extends NamespaceHandlerSupport { /* - * (non-Javadoc) - * - * @see org.springframework.beans.factory.xml.NamespaceHandler#init() - */ + * (non-Javadoc) + * @see org.springframework.beans.factory.xml.NamespaceHandler#init() + */ public void init() { RepositoryConfigurationExtension extension = new MongoRepositoryConfigurationExtension(); @@ -42,5 +41,6 @@ public class MongoNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("mongo", new MongoParser()); registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser()); registerBeanDefinitionParser("jmx", new MongoJmxParser()); + registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser()); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java index dd7c3740e..32c65fcf8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/BasicMongoPersistentEntity.java @@ -23,7 +23,6 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.mapping.model.BasicPersistentEntity; -import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mongodb.MongoCollectionUtils; import org.springframework.data.util.TypeInformation; import org.springframework.expression.Expression; @@ -38,7 +37,6 @@ import org.springframework.util.StringUtils; * * @author Jon Brisbin * @author Oliver Gierke - * @author Patryk Wasik */ public class BasicMongoPersistentEntity extends BasicPersistentEntity implements MongoPersistentEntity, ApplicationContextAware { @@ -73,27 +71,6 @@ public class BasicMongoPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity extends PersistentEntity { @@ -31,19 +30,4 @@ public interface MongoPersistentEntity extends PersistentEntity> { + + private final IsNewAwareAuditingHandler auditingHandler; + + /** + * Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}. + * + * @param auditingHandler must not be {@literal null}. + */ + public AuditingEventListener(IsNewAwareAuditingHandler 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(BeforeConvertEvent event) { + + Object entity = event.getSource(); + auditingHandler.markAudited(entity); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeConvertEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeConvertEvent.java index 231ce37c3..cbd12aace 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeConvertEvent.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/event/BeforeConvertEvent.java @@ -1,11 +1,11 @@ /* - * Copyright (c) 2011 by the original author(s). + * Copyright 2011-2012 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 + * 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, @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.mongodb.core.mapping.event; /** - * @author Jon Brisbin + * Event being thrown before a domain object is converted to be persisted. + * + * @author Jon Brisbin + * @author Oliver Gierke */ public class BeforeConvertEvent extends MongoMappingEvent { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 252614269008845243L; public BeforeConvertEvent(T source) { super(source, null); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java index 879579464..d28d0abfa 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MappingMongoEntityInformation.java @@ -16,6 +16,7 @@ package org.springframework.data.mongodb.repository.support; import java.io.Serializable; + import org.springframework.data.mapping.model.BeanWrapper; import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; @@ -57,7 +58,8 @@ public class MappingMongoEntityInformation extends A this.customCollectionName = customCollectionName; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.repository.support.EntityInformation#getId(java.lang.Object) */ @SuppressWarnings("unchecked") @@ -65,6 +67,10 @@ public class MappingMongoEntityInformation extends A MongoPersistentProperty idProperty = entityMetadata.getIdProperty(); + if (idProperty == null) { + return null; + } + try { return (ID) BeanWrapper.create(entity, null).getProperty(idProperty); } catch (Exception e) { diff --git a/spring-data-mongodb/src/main/resources/META-INF/spring.schemas b/spring-data-mongodb/src/main/resources/META-INF/spring.schemas index c516faaa8..0e2202232 100644 --- a/spring-data-mongodb/src/main/resources/META-INF/spring.schemas +++ b/spring-data-mongodb/src/main/resources/META-INF/spring.schemas @@ -1,3 +1,4 @@ -http\://www.springframework.org/schema/data/mongo/spring-mongo-1.1.xsd=org/springframework/data/mongodb/config/spring-mongo-1.1.xsd http\://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd=org/springframework/data/mongodb/config/spring-mongo-1.0.xsd -http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.1.xsd +http\://www.springframework.org/schema/data/mongo/spring-mongo-1.1.xsd=org/springframework/data/mongodb/config/spring-mongo-1.1.xsd +http\://www.springframework.org/schema/data/mongo/spring-mongo-1.2.xsd=org/springframework/data/mongodb/config/spring-mongo-1.2.xsd +http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.2.xsd diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.2.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.2.xsd new file mode 100644 index 000000000..de08d5808 --- /dev/null +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.2.xsd @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The WriteConcern that will be the default value used when asking the MongoDbFactory for a DB object + + + + + + + + + + + + + + The reference to a MongoTemplate. Will default to 'mongoTemplate'. + + + + + + + Enables creation of indexes for queries that get derived from the method name + and thus reference domain class properties. Defaults to false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The reference to a DbFactory. + + + + + + + + + + + + The reference to a Mongo. Will default to 'mongo'. + + + + + + + The reference to a MappingContext. Will default to 'mappingContext'. + + + + + + + The reference to a MongoTemplate. Will default to 'mongoTemplate'. + + + + + + + Disables JSR-303 validation on MongoDB documents before they are saved. By default it is set to false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The WriteConcern that will be the default value used when asking the MongoDbFactory for a DB object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A reference to a custom converter. + + + + + + + + + \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingIntegrationTests.java new file mode 100644 index 000000000..108c73b53 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/AuditingIntegrationTests.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012 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.mongodb.config; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +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.mongodb.core.mapping.event.BeforeConvertEvent; + +/** + * Integration test for the auditing support. + * + * @author Oliver Gierke + */ +public class AuditingIntegrationTests { + + @Test + public void enablesAuditingAndSetsPropertiesAccordingly() { + + ApplicationContext context = new ClassPathXmlApplicationContext("auditing.xml", getClass()); + + Entity entity = new Entity(); + BeforeConvertEvent event = new BeforeConvertEvent(entity); + context.publishEvent(event); + + assertThat(entity.created, is(notNullValue())); + assertThat(entity.modified, is(entity.created)); + + entity.id = 1L; + event = new BeforeConvertEvent(entity); + context.publishEvent(event); + + assertThat(entity.created, is(notNullValue())); + assertThat(entity.modified, is(not(entity.created))); + } + + class Entity { + + @CreatedDate + DateTime created; + + @LastModifiedDate + DateTime modified; + + @Id + Long id; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/AuditingEventListenerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/AuditingEventListenerUnitTests.java new file mode 100644 index 000000000..fffa01ed4 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/event/AuditingEventListenerUnitTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012 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.mongodb.core.mapping.event; + +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.annotation.Id; +import org.springframework.data.auditing.IsNewAwareAuditingHandler; +import org.springframework.data.mapping.model.MappingContextIsNewStrategyFactory; +import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.support.IsNewStrategyFactory; + +/** + * Unit tests for {@link AuditingEventListener}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class AuditingEventListenerUnitTests { + + IsNewAwareAuditingHandler handler; + + IsNewStrategyFactory factory; + AuditingEventListener listener; + + @Before + public void setUp() { + + MongoMappingContext mappingContext = new MongoMappingContext(); + factory = new MappingContextIsNewStrategyFactory(mappingContext); + + handler = spy(new IsNewAwareAuditingHandler(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 BeforeConvertEvent(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 BeforeConvertEvent(sample)); + + verify(handler, times(0)).markCreated(any(Sample.class)); + verify(handler, times(1)).markModified(sample); + } + + static class Sample { + + @Id + String id; + } +} diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/auditing.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/auditing.xml new file mode 100644 index 000000000..b91883d3c --- /dev/null +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/config/auditing.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/monitor/MongoMonitorIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/monitor/MongoMonitorIntegrationTests-context.xml index 7adcf8fc3..d967bf814 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/monitor/MongoMonitorIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/monitor/MongoMonitorIntegrationTests-context.xml @@ -1,14 +1,11 @@ - + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml index b80e84c56..dfc2715f8 100644 --- a/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/mongodb/repository/config/MongoNamespaceIntegrationTests-context.xml @@ -5,9 +5,9 @@ xmlns:repository="http://www.springframework.org/schema/data/repository" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd - http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.0.xsd - http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd - http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> + http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">