Joaquin Cardenas
Joaquin Cardenas

Reputation: 11

Spring Hibernate Envers: Capture entity being modified

Is it posible to capture the entity (Book) that is being modified inside a CustomEntityTrackingListener or a CustomRevisionListener ?

Im trying to get all the information that is being passed through the apis /saveBook or /update/{id}/{pages}, not just the revision information.

When auditing an Entity in envers, it creates automatically a _AUD table for each entity and a revision table to connect the entity and its _AUD table

Using a custom revision listener I can get only the info about the revision, but I would like to reach the entity itself is being modified and saved.

...
    @PostMapping("/saveBook")
    public Book saveBook(@RequestBody Book book) {
        return repository.save(book);
    }

    @PutMapping("/update/{id}/{pages}")
    public Book updateBook(@PathVariable int id, @PathVariable int pages) {
        Book book = repository.findById(id).get();
        book.setPages(pages);
        return repository.save(book);
    }
...
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Audited
public class Book {

    @Id
    @GeneratedValue
    private int id;

    private String name;

    private int pages;
}

@Entity
//@RevisionEntity(ExampleListener.class)
@RevisionEntity(CustomEntityTrackingRevisionListener.class)
public class ExampleRevEntity extends DefaultRevisionEntity {


    private String username;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @OneToMany(mappedBy="revision", cascade={CascadeType.PERSIST, CascadeType.REMOVE})
    private Set<ModifiedEntityTypeEntity> modifiedEntityTypes =
            new HashSet<ModifiedEntityTypeEntity>();

}



public class ExampleListener implements RevisionListener {

    @Override
    public void newRevision(Object revisionEntity) {
        ExampleRevEntity exampleRevEntity = (ExampleRevEntity) revisionEntity;
        //Identity identity = (Identity) Component.getInstance("org.jboss.seam.security.identity");

        exampleRevEntity.setUsername("Joaquin");
    }
}
public class CustomEntityTrackingRevisionListener implements EntityTrackingRevisionListener {
    @Override
    public void entityChanged(Class entityClass, String entityName,
                              Serializable entityId, RevisionType revisionType,
                              Object revisionEntity) {

        String type = entityClass.getName();
        //((CustomTrackingRevisionEntity)revisionEntity).addModifiedEntityType(type);
        ((ExampleRevEntity)revisionEntity).addModifiedEntityType(type);
    }

    @Override
    public void newRevision(Object revisionEntity) {

    }

}

Upvotes: 1

Views: 1531

Answers (2)

Arturo Franco Barrio
Arturo Franco Barrio

Reputation: 129

EntityTrackingRevisionListener.entityChanged() is executed after the object persistence, so you can get it from persistence context via find() method of your EntityManager using the identifier and entity class provided.

Upvotes: 1

Naros
Naros

Reputation: 21103

There are a couple ways you can accomplish this.

  • Introduce your own event listeners
  • Use a CDC (change data capture) technology like Debezium.

In the first approach, you would likely want to follow the suggestions in the Envers documentation about how you would do conditional auditing and introduce custom event listeners that extend the Envers listeners in order to deduce the changes and perform whatever tasks you need.

This can be a very daunting and tedious step because you have to understand both how Hibernate emits its data in the events, how to resolve differences, etc.

I believe the easier approach here would be to use a tool such as Debezium that enables you to setup a job that monitors a configured number of tables, in your use case the specific _AUD tables of interest. Every time Envers inserts into those tables, Debezium would react to the insert by generating an event that you can then react against asynchronously.

Debezium has several ways of being used including being embedded into an application which might be suitable for your use case or in a Kafka Connect instance that is separate from the application and provides redundancy and fault tolerance for event capture and dispatch.

Upvotes: 0

Related Questions