Skip to content

Commit

Permalink
DATAMONGO-577 - Added support for auditing.
Browse files Browse the repository at this point in the history
Introduced AuditingEventListener to invoke auditing subsystem available through Spring Data Commons. Added <mongo:auditing /> namespace element to transparently activate it.
  • Loading branch information
odrotbohm committed Nov 27, 2012
1 parent 772a140 commit 9482350
Show file tree
Hide file tree
Showing 20 changed files with 849 additions and 94 deletions.
Expand Up @@ -27,12 +27,15 @@
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;

Expand Down Expand Up @@ -136,6 +139,17 @@ public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
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
Expand Down
Expand Up @@ -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";

}
Expand Up @@ -49,6 +49,8 @@
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;
Expand Down Expand Up @@ -88,6 +90,8 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
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)) {
Expand Down Expand Up @@ -163,7 +167,7 @@ private RuntimeBeanReference getValidator(Object source, ParserContext parserCon
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");
Expand Down Expand Up @@ -241,7 +245,7 @@ private BeanDefinition getCustomConversions(Element element, ParserContext parse
return null;
}

public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {
private static Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {

String basePackage = element.getAttribute(BASE_PACKAGE);

Expand Down Expand Up @@ -280,6 +284,19 @@ public BeanMetadataElement parseConverter(Element element, ParserContext parserC
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.
*
Expand Down
@@ -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);
}
}
@@ -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.
Expand All @@ -21,17 +21,16 @@
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();
Expand All @@ -42,5 +41,6 @@ public void init() {
registerBeanDefinitionParser("mongo", new MongoParser());
registerBeanDefinitionParser("db-factory", new MongoDbFactoryParser());
registerBeanDefinitionParser("jmx", new MongoJmxParser());
registerBeanDefinitionParser("auditing", new MongoAuditingBeanDefinitionParser());
}
}
Expand Up @@ -23,7 +23,6 @@
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;
Expand All @@ -38,7 +37,6 @@
*
* @author Jon Brisbin
* @author Oliver Gierke
* @author Patryk Wasik
*/
public class BasicMongoPersistentEntity<T> extends BasicPersistentEntity<T, MongoPersistentProperty> implements
MongoPersistentEntity<T>, ApplicationContextAware {
Expand Down Expand Up @@ -73,27 +71,6 @@ public BasicMongoPersistentEntity(TypeInformation<T> typeInformation) {
}
}

/*
* (non-Javadoc)
* @see org.springframework.data.mapping.MutablePersistentEntity#addPersistentProperty(P)
*/
@Override
public void addPersistentProperty(MongoPersistentProperty property) {

if (property.isVersionProperty()) {

if (this.versionProperty != null) {
throw new MappingException(String.format(
"Attempt to add version property %s but already have property %s registered "
+ "as version. Check your mapping configuration!", property.getField(), versionProperty.getField()));
}

this.versionProperty = property;
}

super.addPersistentProperty(property);
}

/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
Expand All @@ -110,27 +87,10 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getCollection()
*/
public String getCollection() {

Expression expression = parser.parseExpression(collection, ParserContext.TEMPLATE_EXPRESSION);
return expression.getValue(context, String.class);
}

/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#getVersionProperty()
*/
public MongoPersistentProperty getVersionProperty() {
return versionProperty;
}

/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentEntity#hasVersionProperty()
*/
public boolean hasVersionProperty() {
return getVersionProperty() != null;
}

/**
* {@link Comparator} implementation inspecting the {@link MongoPersistentProperty}'s order.
*
Expand Down
Expand Up @@ -153,14 +153,6 @@ public DBRef getDBRef() {
return getField().getAnnotation(DBRef.class);
}

/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#isVersionProperty()
*/
public boolean isVersionProperty() {
return getField().isAnnotationPresent(Version.class);
}

/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.mapping.MongoPersistentProperty#usePropertyAccess()
Expand Down
Expand Up @@ -21,7 +21,6 @@
* MongoDB specific {@link PersistentEntity} abstraction.
*
* @author Oliver Gierke
* @author Patryk Wasik
*/
public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersistentProperty> {

Expand All @@ -31,19 +30,4 @@ public interface MongoPersistentEntity<T> extends PersistentEntity<T, MongoPersi
* @return
*/
String getCollection();

/**
* Returns the {@link MongoPersistentProperty} that represents the version attribute of an entity. Will not be
* {@literal null} if {@link #hasVersionProperty()}.
*
* @return
*/
MongoPersistentProperty getVersionProperty();

/**
* Returns whether the entity has a property representing the version of the entity.
*
* @return
*/
boolean hasVersionProperty();
}
Expand Up @@ -56,13 +56,6 @@ public interface MongoPersistentProperty extends PersistentProperty<MongoPersist
*/
DBRef getDBRef();

/**
* Returns whether the property is representing the version attribute of an entity.
*
* @return
*/
boolean isVersionProperty();

/**
* Simple {@link Converter} implementation to transform a {@link MongoPersistentProperty} into its field name.
*
Expand Down
Expand Up @@ -27,10 +27,13 @@
*
* @since 1.4
* @author Patryk Wasik
* @deprecated use {@link org.springframework.data.annotation.Version} instead.
*/
@Deprecated
@Documented
@Target({ FIELD })
@Retention(RUNTIME)
@org.springframework.data.annotation.Version
public @interface Version {

}

0 comments on commit 9482350

Please sign in to comment.