Today I come with a Java tip.
If you are like me and you first want to check out the code, then go to https://github.com/mgonto/jpa-passive-logging-example/blob/master/app/models/observer Or you can first read the explanation and then go to the code as you like.
I was asked to do a JPA model logging framework. The idea was to Log every change that happens to some specified models. However, I didn’t want to add information about this logging to the current models. This would make the code uglier and much harder to read. I wanted to be able to passively log the changes without making any change to the model besides some Inheritance or something like that.
That’s when I remembered that JPA has a lot of Listeners. So, I would use @PostDelete and @PostPersist to log creation and deletion of entities. That was easy enough. Now, the problem was how to log modifications on the model.
There’s a @PostLoad hook on JPA that is called inmediately after some entity is loaded into the EntityManager. And there’s also a @PreUpdate hook that is called just before making an update to the database.
So what did I do? In the @PostLoad I save all of the Object properties into a Map<PropertyName, PropertyValue>. I save that in a transient field in the object for future reference. Then, in the @PreUpdate, I convert the current object to a map of the same type and I check for the differences. For every difference that is there, I create a logging event for modification. And that’s basically the magic :).
You can see the whole example at https://github.com/mgonto/jpa-passive-logging-example
The example was made using Play! Framework 1.2 with JPA, but you can actually make this work with any JPA app. You can use Spring MVC, Struts, etc.
You’ll also see that I’ve added several tests so that you can see how this works :).
All of the listener’s “magic” is in https://github.com/mgonto/jpa-passive-logging-example/blob/master/app/models/observer/AuditableModelListener.java
The most important code is in https://github.com/mgonto/jpa-passive-logging-example/blob/master/app/models/observer
Enjoy logging guys