Let’s say you are working on an application where users are constantly adding/changing new content. You will most likely have to keep a record what’s going on. For example you want to make a wiki-like software, it is crucial to keep a log who added/updated/deleted wiki entries.
If you need that functionality, and you are using Hibernate, then you are one happy coder! Enter ENVERS! As the good people at jboss site say: Easy Entity Auditing.
Here is what you need to do make your entities auditable:
- Download latest hibernate with envers bundled (I’m using 3.6.0.Final) and add it to your classpath
- Add envers event listeners to your session factory (I’m using spring in my project, so here is a part of my spring.xml):
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- Envers - Auditlogging --> <property name="eventListeners"> <map> <entry key="post-insert"><ref local="enversListener" /></entry> <entry key="post-update"><ref local="enversListener" /></entry> <entry key="post-delete"><ref local="enversListener" /></entry> <entry key="pre-collection-update"><ref local="enversListener" /></entry> <entry key="pre-collection-remove"><ref local="enversListener" /></entry> <entry key="post-collection-recreate"><ref local="enversListener" /></entry> </map> </property> </bean> <bean id="enversListener" class="org.hibernate.envers.event.AuditEventListener" />
- Annotate your class with @Audited. If you don’t want to keep track of all properties, just annotate the fields you need with the same @Audited.
And that is it :)
After completing all the three steps you will see new table called revinfo (that keeps all the revisions information, you can change it’s name, prefix/suffix, check out the docs) and <entity>_aud (log for the specified entity).
I had a problem that <entity>_aud didn’t have all the required fields, even with hibernate.hbm2ddl.auto set to update. Adam Warski (great guy that create Envers, thanks man!) gave somebody a great tip in jboss forum, that helped me. I’ve just added @Audited for my getters and everything worked smoothly.
One thing I needed more is to keep track WHO made the changes. Here is a nice tutorial how to do that. To keep it short:
- Extend DefaultRevisionEntity and annotate it with @RevisionEntity
@RevisionEntity(PectopahRevisionListener.class) public class PectopahRevisionEntity extends DefaultRevisionEntity { private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
- Create your own RevisionListener
public class PectopahRevisionListener implements RevisionListener { @Autowired private UserService userService; @Override public void newRevision(Object revisionEntity) { PectopahRevisionEntity pectopahRevisionEntity = (PectopahRevisionEntity) revisionEntity; User user = userDetails.getCurrentUser(); pectopahRevisionEntity.setUsername(user.getUsername()); } } }
- In case you are using hbm.xml files (like me), add the following:
<hibernate-mapping package="...your package..."> <class name="PectopahRevisionEntity" table="revinfo"> <id name="id" type="int"> <column name="rev" not-null="true"/> <generator class="native"/> </id> <property name="timestamp" type="long" column="timestamp" /> <property name="username" type="string" not-null="true"/> </class> </hibernate-mapping>
(here you could rename table’s name and/or fields).
Simple as that. There is also a simple mechanism how to retrieve info from audit log, but I’ll maybe cover that some other time, it’s almost 1am :)
It makes me really happy to find great tools like this one. Easy to setup, clean and simple API, and yeah it does the job!