Skip to content

Commit

Permalink
EntityTrackingRevisionListener extension
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasz-antoniak committed Aug 25, 2012
1 parent 110c3a4 commit 19bde34
Show file tree
Hide file tree
Showing 22 changed files with 289 additions and 49 deletions.
Expand Up @@ -15,9 +15,10 @@ public interface EntityTrackingRevisionListener extends RevisionListener {
* @param entityName Name of the audited entity. May be useful when Java class is mapped multiple times,
* potentially to different tables.
* @param entityId Identifier of modified entity.
* @param entity The actual entity or persistent collection that has changed.
* @param revisionType Modification type (addition, update or removal).
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}.
*/
void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity);
void entityChanged(Class entityClass, String entityName, Serializable entityId, Object entity,

This comment has been minimized.

Copy link
@adamw

adamw Sep 3, 2012

Maybe wrap the parameters in an object so that more fields can be added there in a backward-compatible way in the future.

This comment has been minimized.

Copy link
@lukasz-antoniak

lukasz-antoniak Sep 9, 2012

Author Owner

I've been thinking about the same, done.

RevisionType revisionType, Object revisionEntity);
}
Expand Up @@ -100,7 +100,8 @@ protected final void onCollectionAction(
collectionEntry,
oldColl,
event.getAffectedOwnerIdOrNull(),
referencingPropertyName
referencingPropertyName,
event.getCollection()
);
auditProcess.addWorkUnit( workUnit );

Expand Down Expand Up @@ -196,7 +197,8 @@ private void generateFakeBidirecationalRelationWorkUnits(
rd,
revType,
changeData.getChangedElementIndex(),
nestedWorkUnit
nestedWorkUnit,
event.getCollection()
)
);
}
Expand Down
Expand Up @@ -56,7 +56,8 @@ public void onPostDelete(PostDeleteEvent event) {
getAuditConfiguration(),
event.getId(),
event.getPersister(),
event.getDeletedState()
event.getDeletedState(),
event.getEntity()
);
auditProcess.addWorkUnit( workUnit );

Expand Down
Expand Up @@ -55,7 +55,8 @@ public void onPostInsert(PostInsertEvent event) {
getAuditConfiguration(),
event.getId(),
event.getPersister(),
event.getState()
event.getState(),
event.getEntity()
);
auditProcess.addWorkUnit( workUnit );

Expand Down
Expand Up @@ -59,7 +59,8 @@ public void onPostUpdate(PostUpdateEvent event) {
event.getId(),
event.getPersister(),
newDbState,
event.getOldState()
event.getOldState(),
event.getEntity()
);
auditProcess.addWorkUnit( workUnit );

Expand Down
Expand Up @@ -98,11 +98,11 @@ public Object generate() {
return revisionInfo;
}

public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionInfo) {
public void entityChanged(Class entityClass, String entityName, Serializable entityId, Object entity,
RevisionType revisionType, Object revisionInfo) {
if (listener instanceof EntityTrackingRevisionListener) {
((EntityTrackingRevisionListener) listener).entityChanged(entityClass, entityName, entityId, revisionType,
revisionInfo);
((EntityTrackingRevisionListener) listener).entityChanged(entityClass, entityName, entityId, entity,
revisionType, revisionInfo);
}
}
}
Expand Up @@ -34,9 +34,9 @@ public DefaultTrackingModifiedEntitiesRevisionInfoGenerator(String revisionInfoE

@Override
@SuppressWarnings({"unchecked"})
public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
super.entityChanged(entityClass, entityName, entityId, revisionType, revisionEntity);
public void entityChanged(Class entityClass, String entityName, Serializable entityId, Object entity,
RevisionType revisionType, Object revisionEntity) {
super.entityChanged(entityClass, entityName, entityId, entity, revisionType, revisionEntity);
Set<String> modifiedEntityNames = (Set<String>) modifiedEntityNamesGetter.get(revisionEntity);
if (modifiedEntityNames == null) {
modifiedEntityNames = new HashSet<String>();
Expand Down
Expand Up @@ -37,8 +37,8 @@ public interface RevisionInfoGenerator {
Object generate();

/**
* @see EntityTrackingRevisionListener#entityChanged(Class, String, Serializable, RevisionType, Object)
* @see EntityTrackingRevisionListener#entityChanged(Class, String, Serializable, Object, RevisionType, Object)
*/
void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity);
void entityChanged(Class entityClass, String entityName, Serializable entityId, Object entity,
RevisionType revisionType, Object revisionEntity);
}
Expand Up @@ -37,7 +37,7 @@ public void entityChanged(Session session, Object currentRevisionData, AuditWork
entityId = ((PersistentCollectionChangeWorkUnit.PersistentCollectionChangeWorkUnitId) entityId).getOwnerId();
}
Class entityClass = Tools.getEntityClass(sessionImplementor, session, vwu.getEntityName());
revisionInfoGenerator.entityChanged(entityClass, vwu.getEntityName(), entityId, vwu.getRevisionType(),
currentRevisionData);
revisionInfoGenerator.entityChanged(entityClass, vwu.getEntityName(), entityId, vwu.getEntity(),
vwu.getRevisionType(), currentRevisionData);
}
}
Expand Up @@ -43,17 +43,19 @@ public abstract class AbstractAuditWorkUnit implements AuditWorkUnit {
protected final SessionImplementor sessionImplementor;
protected final AuditConfiguration verCfg;
protected final Serializable id;
protected final Object entity;
protected final String entityName;
protected final AuditStrategy auditStrategy;
protected final RevisionType revisionType;

private Object performedData;

protected AbstractAuditWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, RevisionType revisionType) {
Serializable id, RevisionType revisionType, Object entity) {
this.sessionImplementor = sessionImplementor;
this.verCfg = verCfg;
this.id = id;
this.entity = entity;
this.entityName = entityName;
this.revisionType = revisionType;
this.auditStrategy = verCfg.getAuditStrategy();
Expand Down Expand Up @@ -82,7 +84,11 @@ public Serializable getEntityId() {
return id;
}

public boolean isPerformed() {
public Object getEntity() {
return entity;
}

public boolean isPerformed() {
return performedData != null;
}

Expand Down
Expand Up @@ -41,8 +41,8 @@ public class AddWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
private final Map<String, Object> data;

public AddWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, EntityPersister entityPersister, Object[] state) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.ADD);
Serializable id, EntityPersister entityPersister, Object[] state, Object entity) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.ADD, entity);

this.data = new HashMap<String, Object>();
this.state = state;
Expand All @@ -51,8 +51,8 @@ public AddWorkUnit(SessionImplementor sessionImplementor, String entityName, Aud
}

public AddWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, Map<String, Object> data) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.ADD);
Serializable id, Map<String, Object> data, Object entity) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.ADD, entity);

this.data = data;
final String[] propertyNames = sessionImplementor.getFactory().getEntityPersister(getEntityName()).getPropertyNames();
Expand All @@ -77,7 +77,7 @@ public AuditWorkUnit merge(AddWorkUnit second) {
}

public AuditWorkUnit merge(ModWorkUnit second) {
return new AddWorkUnit(sessionImplementor, entityName, verCfg, id, second.getData());
return new AddWorkUnit(sessionImplementor, entityName, verCfg, id, second.getData(), second.getEntity());
}

public AuditWorkUnit merge(DelWorkUnit second) {
Expand Down
Expand Up @@ -35,6 +35,7 @@
public interface AuditWorkUnit extends WorkUnitMergeVisitor, WorkUnitMergeDispatcher {
Serializable getEntityId();
String getEntityName();
Object getEntity();

boolean containsWork();

Expand Down
Expand Up @@ -42,7 +42,7 @@ public class CollectionChangeWorkUnit extends AbstractAuditWorkUnit implements A

public CollectionChangeWorkUnit(SessionImplementor session, String entityName, String collectionPropertyName,
AuditConfiguration verCfg, Serializable id, Object entity) {
super(session, entityName, verCfg, id, RevisionType.MOD);
super(session, entityName, verCfg, id, RevisionType.MOD, entity);

this.entity = entity;
this.collectionPropertyName = collectionPropertyName;
Expand Down
Expand Up @@ -42,8 +42,8 @@ public class DelWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
private final String[] propertyNames;

public DelWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, EntityPersister entityPersister, Object[] state) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.DEL);
Serializable id, EntityPersister entityPersister, Object[] state, Object entity) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.DEL, entity);

this.state = state;
this.entityPersister = entityPersister;
Expand Down Expand Up @@ -73,7 +73,7 @@ public AuditWorkUnit merge(AddWorkUnit second) {
if (Tools.arraysEqual(second.getState(), state)) {
return null; // Return null if object's state has not changed.
}
return new ModWorkUnit(sessionImplementor, entityName, verCfg, id, entityPersister, second.getState(), state);
return new ModWorkUnit(sessionImplementor, entityName, verCfg, id, entityPersister, second.getState(), state, entity);
}

public AuditWorkUnit merge(ModWorkUnit second) {
Expand Down
Expand Up @@ -27,9 +27,8 @@ public FakeBidirectionalRelationWorkUnit(SessionImplementor sessionImplementor,
AuditConfiguration verCfg, Serializable id,
String referencingPropertyName, Object owningEntity,
RelationDescription rd, RevisionType revisionType,
Object index,
AuditWorkUnit nestedWorkUnit) {
super(sessionImplementor, entityName, verCfg, id, revisionType);
Object index, AuditWorkUnit nestedWorkUnit, Object entity) {
super(sessionImplementor, entityName, verCfg, id, revisionType, entity);
this.nestedWorkUnit = nestedWorkUnit;

// Adding the change for the relation.
Expand All @@ -40,14 +39,14 @@ public FakeBidirectionalRelationWorkUnit(SessionImplementor sessionImplementor,
public FakeBidirectionalRelationWorkUnit(FakeBidirectionalRelationWorkUnit original,
Map<String, FakeRelationChange> fakeRelationChanges,
AuditWorkUnit nestedWorkUnit) {
super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType);
super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType, nestedWorkUnit.getEntity());

this.fakeRelationChanges = fakeRelationChanges;
this.nestedWorkUnit = nestedWorkUnit;
}

public FakeBidirectionalRelationWorkUnit(FakeBidirectionalRelationWorkUnit original, AuditWorkUnit nestedWorkUnit) {
super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType);
super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType, nestedWorkUnit.getEntity());

this.nestedWorkUnit = nestedWorkUnit;

Expand Down
Expand Up @@ -39,8 +39,8 @@ public class ModWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit
private final boolean changes;

public ModWorkUnit(SessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg,
Serializable id, EntityPersister entityPersister, Object[] newState, Object[] oldState) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.MOD);
Serializable id, EntityPersister entityPersister, Object[] newState, Object[] oldState, Object entity) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.MOD, entity);

data = new HashMap<String, Object>();
changes = verCfg.getEntCfg().get(getEntityName()).getPropertyMapper().map(sessionImplementor, data,
Expand Down
Expand Up @@ -47,8 +47,8 @@ public class PersistentCollectionChangeWorkUnit extends AbstractAuditWorkUnit im
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
AuditConfiguration auditCfg, PersistentCollection collection,
CollectionEntry collectionEntry, Serializable snapshot, Serializable id,
String referencingPropertyName) {
super(sessionImplementor, entityName, auditCfg, new PersistentCollectionChangeWorkUnitId(id, collectionEntry.getRole()), RevisionType.MOD);
String referencingPropertyName, Object entity) {
super(sessionImplementor, entityName, auditCfg, new PersistentCollectionChangeWorkUnitId(id, collectionEntry.getRole()), RevisionType.MOD, entity);

this.referencingPropertyName = referencingPropertyName;

Expand All @@ -59,8 +59,8 @@ public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor,
public PersistentCollectionChangeWorkUnit(SessionImplementor sessionImplementor, String entityName,
AuditConfiguration verCfg, Serializable id,
List<PersistentCollectionChangeData> collectionChanges,
String referencingPropertyName) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.MOD);
String referencingPropertyName, Object entity) {
super(sessionImplementor, entityName, verCfg, id, RevisionType.MOD, entity);

this.collectionChanges = collectionChanges;
this.referencingPropertyName = referencingPropertyName;
Expand Down Expand Up @@ -156,7 +156,7 @@ public AuditWorkUnit dispatch(WorkUnitMergeVisitor first) {
mergedChanges.addAll(newChangesIdMap.values());

return new PersistentCollectionChangeWorkUnit(sessionImplementor, entityName, verCfg, id, mergedChanges,
referencingPropertyName);
referencingPropertyName, entity);
} else {
throw new RuntimeException("Trying to merge a " + first + " with a PersitentCollectionChangeWorkUnit. " +
"This is not really possible.");
Expand Down
Expand Up @@ -10,8 +10,8 @@
*/
public class CustomTrackingRevisionListener implements EntityTrackingRevisionListener {
@Override
public void entityChanged(Class entityClass, String entityName, Serializable entityId, RevisionType revisionType,
Object revisionEntity) {
public void entityChanged(Class entityClass, String entityName, Serializable entityId, Object entity,
RevisionType revisionType, Object revisionEntity) {
((CustomTrackingRevisionEntity)revisionEntity).addModifiedEntityType(entityClass.getName());
}

Expand Down
Expand Up @@ -26,16 +26,21 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;

import org.junit.Test;

import org.hibernate.envers.RevisionType;
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.manytomany.MapOwnedEntity;
import org.hibernate.envers.test.entities.manytomany.MapOwningEntity;
import org.hibernate.envers.test.tools.NotificationCheckRevisionListener;
import org.hibernate.envers.test.tools.TestTools;

import static org.hibernate.envers.test.tools.NotificationCheckRevisionListener.expectNotification;

/**
* @author Adam Warski (adam at warski dot org)
*/
Expand All @@ -51,7 +56,12 @@ protected Class<?>[] getAnnotatedClasses() {
return new Class[] { MapOwningEntity.class, MapOwnedEntity.class };
}

@Test
@Override
protected void addConfigOptions(Map options) {
options.put( "org.hibernate.envers.revision_listener", NotificationCheckRevisionListener.class.getName() );
}

@Test
@Priority(10)
public void initData() {
EntityManager em = getEntityManager();
Expand All @@ -72,7 +82,14 @@ public void initData() {
em.persist(ing1);
em.persist(ing2);

expectNotification( MapOwnedEntity.class, ed1.getId(), ed1, RevisionType.ADD );
expectNotification( MapOwnedEntity.class, ed2.getId(), ed2, RevisionType.ADD );
expectNotification( MapOwningEntity.class, ing1.getId(), ing1, RevisionType.ADD );
expectNotification( MapOwningEntity.class, ing2.getId(), ing2, RevisionType.ADD );
expectNotification( MapOwningEntity.class, ing2.getId(), TestTools.makeMap( "2", ed2 ), RevisionType.MOD );

em.getTransaction().commit();
NotificationCheckRevisionListener.checkAllExpectedNotificationsProcessed();

// Revision 2 (ing1: adding two mappings, ing2: replacing an existing mapping)

Expand All @@ -88,7 +105,15 @@ public void initData() {

ing2.getReferences().put("2", ed1);

expectNotification( MapOwningEntity.class, ing1.getId(), TestTools.makeMap( "1", ed1, "2", ed1 ), RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing1.getId(), ing1, RevisionType.MOD );
expectNotification( MapOwnedEntity.class, ed1.getId(), ed1, RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing2.getId(), TestTools.makeMap( "2", ed1 ), RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing2.getId(), ing2, RevisionType.MOD );
expectNotification( MapOwnedEntity.class, ed2.getId(), ed2, RevisionType.MOD );

em.getTransaction().commit();
NotificationCheckRevisionListener.checkAllExpectedNotificationsProcessed();

// No revision (ing1: adding an existing mapping, ing2: removing a non existing mapping)
em.getTransaction().begin();
Expand All @@ -101,6 +126,7 @@ public void initData() {
ing2.getReferences().remove("3");

em.getTransaction().commit();
NotificationCheckRevisionListener.checkAllExpectedNotificationsProcessed();

// Revision 3 (ing1: clearing, ing2: replacing with a new map)
em.getTransaction().begin();
Expand All @@ -112,7 +138,16 @@ public void initData() {
ing2.setReferences(new HashMap<String, MapOwnedEntity>());
ing2.getReferences().put("1", ed2);

expectNotification( MapOwningEntity.class, ing2.getId(), ing2, RevisionType.MOD );
expectNotification( MapOwnedEntity.class, ed1.getId(), ed1, RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing1.getId(), TestTools.makeMap(), RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing1.getId(), ing1, RevisionType.MOD );
expectNotification( MapOwningEntity.class, ing2.getId(), TestTools.makeMap( "1", ed2 ), RevisionType.MOD );
expectNotification( MapOwnedEntity.class, ed2.getId(),ed2, RevisionType.MOD );

This comment has been minimized.

Copy link
@lukasz-antoniak

lukasz-antoniak Aug 25, 2012

Author Owner

What do you think of above?

This comment has been minimized.

Copy link
@adamw

adamw Sep 3, 2012

Hmm maybe it would be better to add a "collection changed" callback to the listener?

This comment has been minimized.

Copy link
@lukasz-antoniak

lukasz-antoniak Sep 9, 2012

Author Owner

Done.


em.getTransaction().commit();
NotificationCheckRevisionListener.checkAllExpectedNotificationsProcessed();

//

ed1_id = ed1.getId();
Expand Down

0 comments on commit 19bde34

Please sign in to comment.