Lessons from JBoss Envers

My good pal Daniel Mirilli just sent me a link to the JBoss Envers project. The idea behind it is that you can automatically track version changes of persistent fields using a new annotation called “@Versioned”. This makes something that is otherwise pretty complex – saving a whole history of changes for an object – as simple as declaring that you need it.

This is a great example of what makes for elegant design: you abstract a concrete business need into a reusable concept, then turn it into an “aspect” to get it out of the immediate code. You can now “take it for granted”. Before I got to know AOP I wrote a framework that did all this the hard way: I had parent classes for “entities”, inherited attributes like “ID” and template methods for things like type-specific attibutes: PKs, unique keys (more than one allowed), “natural” ordering, and so on. Three years ago, I would have done this differently: annotations, or AspectJ aspects, or something along those lines. Then, more recently, EJB 3.0 provided this out of the box with their @Entity annotations and so on.

The beauty behind AOP, no matter what the technology, is that it allows you to design elegantly through abstractions – and yet make them concrete.

Anyway, back to JBoss Envers. I haven’t looked at the details, but it seems like an elegant solution to a problem that I’ve seen more than once: “entities” that need to be “versioned”. That is, you want an audit trail for everything you do to them. And you can never delete them (logical delete, maybe). The product I currently work on has some pretty intense versioning requirements, which is why Mirilli sent me the link to this project (thanks, buddy!). But I know enough about the specific requirements of my product to suspect that Envers wouldn’t be able to do it for us.

In fact, my product’s business rules are convoluted enough that I actually spent about a week doing what the creators of Envers did: trying to wrap my head around it all by turning it into generalized abstractions. In the process, I actually created my own UML 2.0 extension language in order to diagram these versions and explain it all to myself. It’s one thing to keep an audit trail, but what if you can look up previous versions? And what if those previous versions relate to other versioned entities? I realized that in such cases there can be more than one type of “relate”: specific version relationships (Foo version 12 refers to Bar version 5), general version relationships (all versions of Foo refer to the latest version of Bar), and even rules-based general version relationships (all versions of Foo refer to the active or editable version of Bar, which may not be the latest)! Also, note I said “refer” here, implying a uni-directional reference. The relationship can be bi-directional, but what if the back reference follows different rules from the forward reference?

Sorry to muck around in the details like that. It’s not your problem (I hope). What I wanted to highlight here is that this process of abstraction and creating a new “language” around some tricky business rules can actually become something practical when whittled with the tools of an AOP framework, annotations, or what have you. And Envers, whether it works or not, has reminded me of that: when Foo refers to Bar, why not do something like this:

public class Foo {

@Versioned(type=VersionReferenceType.GENERAL, rule=VersionReferenceRule.LATEST)

private Bar bar;

}

Instead, I’m currently relying on inheritance from base classes and custom code in various places in the persistence and domain layers that are only loosely tied to the object references. But now Envers has gotten me thinking again…

Advertisements

3 Responses to Lessons from JBoss Envers

  1. adamw1pl says:

    Hello!
    Great to see interest in Envers 🙂

    As you already probably know, the way that Envers currently works, is that if you have a (versioned) relation, version X of entity Foo will relate to version X of entity Bar. Implementing the “VersionReferenceRule.LATEST” would be quite easy (just a different proxy on the reference); (and you can always implement this logic in a facade to the entity 🙂 ).

    What would be the other values of the VersionReferenceType and VersionReferenceRule? The “rules” approach is an interesting idea … I guess you won’t always be able to capture the rules in a static way, some run-time checks would be required, so in the general case you would need to provide a method which, given an object, the reference type and a revision number, would decide which version of the reference would be read.

    Maybe if you’d like to discuss this on a broader scale, feel free to write on the forum: http://www.jboss.com/index.html?module=bb&op=viewforum&f=283

    Adam

  2. Timothy High says:

    Thanks for the input!

    The “specific version reference” that I mentioned is a bit more generalized than yours: version X of Foo can refer to version Y of Bar – the idea is that each entity is versioned separately.

    As for the rules-based approach, although I was using a constant/enumeration to declare the rule, I don’t actually think it would work that way in the general case (say, for Envers). We use rules like “latest”, “active”, “writable”. For the case of Envers, I would envision it more like a configurable set of rules that could be converted into a WHERE clause based on declared fields and values.

    Example: RULE = “Latest”
    @Versioned(type=VersionReferenceType.RULE, rule=”MAX(Bar.version)”)
    private Bar bar;

    Example: RULE = “Latest Writable”
    @Versioned(type=VersionReferenceType.RULE, rule=”MAX(Bar.version) && Bar.status=’WRITABLE'”)
    private Bar bar;

    That last example is more complicated than that in SQL, and wouldn’t actually work the way I wrote it. But Envers could take advantage of special known concepts like the version number and the concept “LATEST” to simplify the rule definition without resorting to inner selects or other SQL quirks.

    I’ll move this discussion over to the forum as you suggested.

  3. […] is the sort of thing that smells like an aspect to me. I want to add the “auditing” aspect to my already-existing code without having […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: