Top Banner
24

Devoxx 2012 hibernate envers

Jun 21, 2015

Download

Technology

Romain Linsolas

My presentation (Quickie) about Hibernate Envers, made at Devoxx 2012.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Devoxx 2012   hibernate envers
Page 2: Devoxx 2012   hibernate envers

Easy Entity AuditingWith Hibernate Envers

Romain LinsolasJava & Web Developer

Société Générale

@romaintaz

Page 3: Devoxx 2012   hibernate envers

3

Romain Linsolas

Who am I?■ Java & Web developer;■ Technical architect, Software Factory gardener;■ @ Société Générale (french bank)

http://linsolas.free.fr/wordpress

@romaintaz

https://github.com/linsolas

Page 4: Devoxx 2012   hibernate envers

(1) What is Hibernate Envers?

Page 5: Devoxx 2012   hibernate envers

Definition

Hibernate Envers

Hibernate module to enable easy auditing of persistent classes!

Audit = keep a revision of your entity after every "event" (insert, update, delete)

Available since 2009…

http://www.jboss.org/envers

http://docs.jboss.org/envers/docs/index.html

http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html/ch15.html

Page 6: Devoxx 2012   hibernate envers

(2) Activation

Page 7: Devoxx 2012   hibernate envers

7

Add the Envers library in classpath

<!-- Requires:

* Hibernate 3+

* Hibernate annotations -->

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-envers</artifactId>

<version>4.1.8.Final</version>

</dependency>

Page 8: Devoxx 2012   hibernate envers

(3) Start the audit

Page 9: Devoxx 2012   hibernate envers

9

Audit a simple entity class@Entity

@Audited

public class Person {

@Id @GeneratedValue

private int id;

private String name;

private String surname;

@ManyToOne

private Address address;

// getters, setters, constructors, equals and hashCode…

}

Page 10: Devoxx 2012   hibernate envers

10

Some useful Envers @nnotations@Audited

@AuditTable(“T_PERSON_AUDIT”)

public class Person {

@NotAudited

private String comments;

@AuditJoinTable(name=“T_PERSON_ADDRESS_AUDIT”,

inverseJoinColumns=@JoinColumn(name=“ADDRESS_ID”))

public List<Address> address;

}

Page 11: Devoxx 2012   hibernate envers

What about the database?

Table T_PERSON

Id Name Surname Comments

Table T_PERSON_AUD

Id REV Name Surname REVTYPE

Table REVINFO

REV REVTSTMP (additional info)

0 Add

1 Mod

2 Del

Page 12: Devoxx 2012   hibernate envers

12

Additional information in revisions@Entity

@RevisionEntity(UsernameRevisionListener.class)

public class MyEntityRevision extends DefaultRevisionEntity {

private String username; // + getter / setter

}

public class UsernameRevisionListener implements RevisionListener {

@Override

public void newRevision(Object revisionEntity) {

((MyEntityRevision) revisionEntity).setUsername(getCurrentUsername());

}

}

Page 13: Devoxx 2012   hibernate envers

Tracking modified fields<property name="org.hibernate.envers.global_with_modified_flag" value="true"/>

Or

@Audited(withModifiedFlag = true)

private String myField;

Table T_PERSON_AUD

Id REV Name Name_MOD Surname Surname_MOD REVTYPE

Still an experimental feature…

Page 14: Devoxx 2012   hibernate envers

(4) Query audit information

Page 15: Devoxx 2012   hibernate envers

15

AuditReader// Get all the revisions of my current object

int personId = somePerson.getId();

AuditReader auditReader = AuditReaderFactory.get(entityManager);

List<Number> allRevisions = auditReader.getRevisions(Person.class, personId);

for (Number n: allRevisions) {

Person p = auditReader.find(Person.class, personId, n);

System.out.printf("\t[Rev #%1$s] > %2$s\n", n, p);

}

[Rev #1] > Person { id=10, name='Romain', surname='', comments=''}

[Rev #3] > Person { id=10, name='Romain', surname='Linsolas', comments=''}

[Rev #4] > null

Page 16: Devoxx 2012   hibernate envers

16

AuditQuery - 1

AuditQuery query1 = auditReader.createQuery()

.forEntitiesAtRevision(Person.class, 42);

List<Person> persons = query1.getResultList();

Person { id=11, name='Chuck', surname='Norris', comments=''}

Person { id=10, name='Romain', surname='Linsolas', comments=''}

Page 17: Devoxx 2012   hibernate envers

17

AuditQuery - 2

AuditQuery query2 = auditReader.createQuery()

.forRevisionsOfEntity(Person.class, false, true);

List<Object[]> revisions = query2.getResultList();

Person EntityRevision REVTYPE{ id=10, name='Romain', surname='', comments='' }

{id=1, timestamp=1352936106653, username='Devoxx'} ADD

{ id=11, name='Chuck', surname='Norris', comments='' }

{id=2, timestamp=1352936106669, username='Devoxx'} ADD

{ id=10, name='Romain', surname='Linsolas', comments='' }

{id=3, timestamp=1352936106687, username='Devoxx'} MOD

{ id=10, name='null', surname='', comments='' }

{id=4, timestamp=1352936106734, username='Devoxx'} DEL

Page 18: Devoxx 2012   hibernate envers

18

AuditQuery - 3

List<Person> persons = auditReader.createQuery()

.forEntitiesAtRevision(Person.class, 42)

.addOrder(AuditEntity.property(“surname”).desc())

.add(AuditEntity.relatedId(“address”).eq(theAddressId))

.setFirstResult(4)

.setMaxResults(2)

.getResultList();

Page 19: Devoxx 2012   hibernate envers

AuditQuery - 4

AuditQuery query = auditReader().createQuery()

.forEntitiesAtRevision(Person.class, 42)

.add(AuditEntity.property("surname").hasChanged())

.add(AuditEntity.property("name").hasNotChanged());

Page 20: Devoxx 2012   hibernate envers

Demo

https://github.com/linsolas/devoxx-envers

Page 21: Devoxx 2012   hibernate envers

To summarize…

Pros

Really easy to use!

Configurable

Ready-to-use audit query tool

Fully integrated in Hibernate

No similar project (?)

Cons

Require Hibernate

Not compatible with Hibernate XML configuration (cf. HHH-3887)

Page 22: Devoxx 2012   hibernate envers

Q&A

Page 23: Devoxx 2012   hibernate envers

(5) Annexes

Page 24: Devoxx 2012   hibernate envers

24

Register Envers Listener<!-- Needed in persistence.xml or Hibernate configuration if you use older versions of Envers (3.x) -->

<property name="hibernate.ejb.event.post-insert"

value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />

<property name="hibernate.ejb.event.post-update"

value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />

<property name="hibernate.ejb.event.post-delete"

value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />

<property name="hibernate.ejb.event.pre-collection-update"

value="org.hibernate.envers.event.AuditEventListener" />

<property name="hibernate.ejb.event.pre-collection-remove"

value="org.hibernate.envers.event.AuditEventListener" />

<property name="hibernate.ejb.event.post-collection-recreate"

value="org.hibernate.envers.event.AuditEventListener" />