DATACOUCH-91 - Support auditing (via java config)

This commit adds support for auditing via the use of the four annotations (CreatedBy, LastModifiedBy, CreationDate, LastModificationDate), enabled via the EnableCouchbaseAuditing annotation.

As couchbase entities MUST have an id, the only case where the creation event can be detected is when the entity has a Version annotated field.
This commit is contained in:
Simon Baslé
2016-02-23 18:58:29 +01:00
parent dea461458b
commit 39fb52d2a6
10 changed files with 569 additions and 0 deletions

View File

@@ -24,6 +24,7 @@ import com.couchbase.client.java.env.CouchbaseEnvironment;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.convert.translation.TranslationService;
import org.springframework.data.support.IsNewStrategyFactory;
/**
* Contains default bean names for Couchbase beans.
@@ -108,4 +109,9 @@ public class BeanNames {
* The name for the bean that registers custom {@link Converter Converters} to encode/decode entity members.
*/
public static final String COUCHBASE_CUSTOM_CONVERSIONS = "couchbaseCustomConversions";
/**
* The name for the bean that will handle audit trail marking of entities.
*/
public static final String COUCHBASE_AUDITING_HANDLER = "couchbaseAuditingHandler";
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2012-2016 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.couchbase.core.mapping.event;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
/**
* Event listener to populate auditing related fields on an entity about to be saved.
*
* @author Oliver Gierke
* @author Simon Baslé
*/
public class AuditingEventListener implements ApplicationListener<BeforeConvertEvent<Object>> {
private final ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory;
/**
* Creates a new {@link AuditingEventListener} using the given {@link MappingContext} and {@link AuditingHandler}
* provided by the given {@link ObjectFactory}.
*
* @param auditingHandlerFactory must not be {@literal null}.
*/
public AuditingEventListener(ObjectFactory<IsNewAwareAuditingHandler> auditingHandlerFactory) {
Assert.notNull(auditingHandlerFactory, "IsNewAwareAuditingHandler must not be null!");
this.auditingHandlerFactory = auditingHandlerFactory;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(BeforeConvertEvent<Object> event) {
Object entity = event.getSource();
auditingHandlerFactory.getObject().markAudited(entity);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2012-2016 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.couchbase.repository.auditing;
import java.lang.annotation.Annotation;
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.support.RootBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
import org.springframework.data.auditing.config.AuditingConfiguration;
import org.springframework.data.config.ParsingUtils;
import org.springframework.data.couchbase.config.BeanNames;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.event.AuditingEventListener;
import org.springframework.data.support.IsNewStrategyFactory;
import org.springframework.util.Assert;
/**
* A support registrar that allows to set up auditing for Couchbase (including {@link AuditingHandler}
* and {@link IsNewStrategyFactory} set up). See {@link EnableCouchbaseAuditing} for the associated annotation.
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Simon Baslé
*/
public class CouchbaseAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableCouchbaseAuditing.class;
}
@Override
protected String getAuditingHandlerBeanName() {
return BeanNames.COUCHBASE_AUDITING_HANDLER;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
ensureMappingContext(registry, annotationMetadata);
super.registerBeanDefinitions(annotationMetadata, registry);
}
@Override
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
builder.addConstructorArgReference(BeanNames.COUCHBASE_MAPPING_CONTEXT);
return configureDefaultAuditHandlerAttributes(configuration, builder);
}
@Override
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
BeanDefinitionRegistry registry) {
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(AuditingEventListener.class);
listenerBeanDefinitionBuilder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(
getAuditingHandlerBeanName(), registry));
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
AuditingEventListener.class.getName(), registry);
}
private void ensureMappingContext(BeanDefinitionRegistry registry, Object source) {
if (!registry.containsBeanDefinition(BeanNames.COUCHBASE_MAPPING_CONTEXT)) {
RootBeanDefinition definition = new RootBeanDefinition(CouchbaseMappingContext.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
definition.setSource(source);
registry.registerBeanDefinition(BeanNames.COUCHBASE_MAPPING_CONTEXT, definition);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2012-2016 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.couchbase.repository.auditing;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.data.auditing.DateTimeProvider;
import org.springframework.data.domain.AuditorAware;
/**
* Annotation to enable auditing in Couchbase via annotation configuration.
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Simon Baslé
*/
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(CouchbaseAuditingRegistrar.class)
public @interface EnableCouchbaseAuditing {
/**
* Configures the {@link AuditorAware} bean to be used to lookup the current principal.
*/
String auditorAwareRef() default "";
/**
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
*/
boolean setDates() default true;
/**
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal true}.
*/
boolean modifyOnCreate() default true;
/**
* Configures a {@link DateTimeProvider} bean name that allows customizing the {@link org.joda.time.DateTime} to be
* used for setting creation and modification dates.
*/
String dateTimeProviderRef() default "";
}