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

@@ -0,0 +1,17 @@
package org.springframework.data.couchbase.repository.auditing;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
@Configuration
@EnableCouchbaseRepositories
@EnableCouchbaseAuditing(modifyOnCreate = false)
public class AuditedApplicationConfig extends IntegrationTestApplicationConfig {
@Bean
public AuditedAuditorAware couchbaseAuditorAware() {
return new AuditedAuditorAware();
}
}

View File

@@ -0,0 +1,18 @@
package org.springframework.data.couchbase.repository.auditing;
import org.springframework.data.domain.AuditorAware;
import org.springframework.stereotype.Component;
public class AuditedAuditorAware implements AuditorAware<String> {
private String auditor = "auditor";
@Override
public String getCurrentAuditor() {
return auditor;
}
public void setAuditor(String auditor) {
this.auditor = auditor;
}
}

View File

@@ -0,0 +1,129 @@
package org.springframework.data.couchbase.repository.auditing;
import java.util.Date;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.core.mapping.Document;
@Document
public class AuditedItem {
@Id
private final String id;
private String value;
@CreatedBy
private String creator;
@LastModifiedBy
private String lastModifiedBy;
@LastModifiedDate
private Date lastModification;
@CreatedDate
private Date creationDate;
@Version
private long version;
public AuditedItem(String id, String value) {
this.id = id;
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public Date getLastModification() {
return lastModification;
}
public void setLastModification(Date lastModification) {
this.lastModification = lastModification;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
@Override
public String toString() {
return "AuditedItem{" +
"id='" + id + '\'' +
", value='" + value + '\'' +
", creator='" + creator + '\'' +
", lastModifiedBy='" + lastModifiedBy + '\'' +
", lastModification=" + lastModification +
", creationDate=" + creationDate +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AuditedItem that = (AuditedItem) o;
if (!id.equals(that.id)) return false;
if (!value.equals(that.value)) return false;
if (creator != null ? !creator.equals(that.creator) : that.creator != null) return false;
if (lastModifiedBy != null ? !lastModifiedBy.equals(that.lastModifiedBy) : that.lastModifiedBy != null)
return false;
if (lastModification != null ? !lastModification.equals(that.lastModification) : that.lastModification != null)
return false;
return creationDate != null ? creationDate.equals(that.creationDate) : that.creationDate == null;
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + value.hashCode();
result = 31 * result + (creator != null ? creator.hashCode() : 0);
result = 31 * result + (lastModifiedBy != null ? lastModifiedBy.hashCode() : 0);
result = 31 * result + (lastModification != null ? lastModification.hashCode() : 0);
result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
return result;
}
}

View File

@@ -0,0 +1,7 @@
package org.springframework.data.couchbase.repository.auditing;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
public interface AuditedRepository extends CouchbaseRepository<AuditedItem, String> {
}

View File

@@ -0,0 +1,89 @@
package org.springframework.data.couchbase.repository.auditing;
import static org.junit.Assert.*;
import java.util.Date;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AuditedApplicationConfig.class)
public class AuditingTests {
@Autowired
private AuditedRepository repository;
@Autowired
private AuditedAuditorAware auditorAware;
private static final String KEY = "auditedTest";
@After
public void cleanupAuditedEntity() {
repository.getCouchbaseOperations().getCouchbaseBucket().remove(KEY);
}
@Test
public void testCreationEventIsRegistered() {
assertFalse(repository.exists(KEY));
Date start = new Date();
AuditedItem item = new AuditedItem(KEY, "creation");
auditorAware.setAuditor("auditor");
repository.save(item);
AuditedItem persisted = repository.findOne(KEY);
assertNotNull("expected entity to be persisted", persisted);
assertNotNull("expected creation date audit trail", persisted.getCreationDate());
assertEquals("expected creation user audit trail", "auditor", persisted.getCreator());
assertTrue("creation date is too early", persisted.getCreationDate().after(start));
assertTrue("creation date is too late", persisted.getCreationDate().before(new Date()));
assertNull("expected modification date to be empty", persisted.getLastModification());
assertNull("expected modification user to be empty", persisted.getLastModifiedBy());
assertNotNull("expected version to be non null", persisted.getVersion());
assertTrue("expected version to be greater than 0", persisted.getVersion() > 0L);
}
@Test
public void testUpdateEventIsRegistered() {
assertFalse(repository.exists(KEY));
String expectedCreator = "user1";
String expectedUpdater = "user2";
AuditedItem item = new AuditedItem(KEY, "creation");
auditorAware.setAuditor(expectedCreator);
repository.save(item);
AuditedItem created = repository.findOne(KEY);
auditorAware.setAuditor(expectedUpdater);
repository.save(item);
AuditedItem updated = repository.findOne(KEY);
assertNotNull("expected entity to be persisted", updated);
assertNotNull("expected creation date audit trail", updated.getCreationDate());
assertEquals("expected creation user audit trail", expectedCreator, updated.getCreator());
assertNotNull("expected modification date audit trail", updated.getLastModification());
assertTrue("expected modification date to be after creation date", updated.getCreationDate().before(updated.getLastModification()));
assertEquals("expected modification user to be the modifier", expectedUpdater, updated.getLastModifiedBy());
assertNotNull("expected version to be non null", updated.getVersion());
assertTrue("expected version to be greater than 0", updated.getVersion() > 0L);
assertTrue("expected updated version to be different from the one at creation", created.getVersion() != updated.getVersion());
}
}