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!
How can you retrieve the user name form the revision number?
Hi,
here is my part of the code that retrieves data from audit reader (I’ve removed some unrelated fragments)
Just to make it clear rejoiceDao.getSession() returns hibernate session. And in the post you have a definition of PectopahRevisionEntity. Poi is the classes that was annotated as @Audit. I think that should do the trick :)
Keep on working, great job!
I am not certain where you are getting your info, but good topic.
I needs to spend a while learning much more or working
out more. Thank you for wonderful information I was in
search of this information for my mission.