This isn't possible with the current implementation. But in fact in most such cases people are really looking for a workflow mechanism, not an auditing one. So I think it would be very hard to do in a generic way. The first obstacle is that the "future versions" normally need to carry some additional data attached.
I'm not really talking about a workflow solution, although it's sometimes an alternative or it can be added on top. Usually though, workflow solutions entail too much complexity for too little gain when there are only single transitions (pending to active data) and one datasource or connector. Unfortunately (for workflow engines), this is the most common use case.
Usually, when bi-temporal data is required, there's no additional data to be kept other than the fact that the given data hasn't yet been deemed current. But once you have a case for bi-temporal data, it's frequently also the case that this should allow also future-dated data, and not just present and past data. (Pending and future-dated data are two sides of the same coin). As an example, changing a customer's name or address might require a secondary approval in some organizations, such as banks. The only additional information required would be name of the user who entered the data first, something that could be kept in the global revision table. Another example might be a production plan at a factory, with references to the current plan as well as a new proposed plan, which has yet to be approved.
There are 4 problems that would need to be solved to allow this:
1. How to store pending versions in the schema
2. How to flag a version as pending when saving (so that envers knows to persist it as pending data and not a new current version)
3. How to retrieve pending versions
4. How to make a pending version the current one.
#1 From looking at the code it seems one possibility could be to track such changes by for example using a new audit strategy similar to ValidityAuditStrategy, and storing a negative end revision (e.g. -1 if only one pending version is allowed). This would then not interfere with any existing history.
#2 I suppose this could be handled through implementing a custom interface per entity, or a (boolean?) field with a new annotation flag, so that the audit strategy could discover these. (Btw, I must confess I liked the word Versioned better than Audited.....)
#3 I'm guessing this could be handled relatively straightforward using the criteria query api
#4 This should just be copying the changes over to the current version, and updating the end revision on both the current and pending versions. I suppose this might be the largest task.
Hmm, one significant difference I can see is that (if I understand correctly), you would need to keep some additional data per entity, not per revision. Such data is for example an "approved" boolean flag. In case of two-stage approvals it may need to be more. But maybe this should just be part of the entity, and subject to regular auditing (you would also like to know when somebody approved something).
The general scheme would be that the audit trail contains some data, but the "normal" tables don't contain the content of the latest revision, but the content of the database at revision X? I must say the concept is quite nice .
It's doable; e.g. you would have to persist data using an auditWriter, instead of an entityManager, so that Envers could only write to _AUD tables. Also, you would need a method to "rewind" the database to a given revision, that is apply all changes - that could be tricky also. And of course a place to store the revision number at which the database is currently.
As for @Versioned vs @Audited, the main reason to change was that there already is an @Version annotation and that would cause confusion.
I'd think any extra data would need to be part of the entity, as it is highly use-case dependent.
When you refer to the auditWriter, I take it I'd have to create this, as I don't see this in the source code? I guess I should probably use the AuditEventListener and ValidityAuditStrategy as a reference ?
Yes, extra data would have to be attached to the entity - but then it can just be some additional fields/relations on the entity, audited as all other fields.
As for the audit writer - also a yes, it's not there, as so far Envers supports only auditing in one direction.
I have this exact same requirement. I would love to help put together a solution or, alternatively, it would be great if you Adam could expand on your previous comment regarding approach, etc.
Many thanks in advance
We have the same requirement in our system as well. Has there been any more considerations on adding this functionality to the library ?
Nope, if you want future versions, you are probably looking for a BPM-like solution,not auditing
After looking at some BPM-solutions I find them a bit overkill for this seemingly simple problem. Instead I started looking at ways to use Envers as is with some few changes to allow for future versions. Suprisingly, it seems like this won't be that complicated.
The first step was to create a "pre-update" hibernate listener that simply vetoed all changes. This left the original entity unchanged when doing modifications. I used the default auditing strategy, which saved the modified data to the revision entity only. The only problem I found with this approach, was that the second level cache got the updated entity. When I refreshed the page to view the data I got the updated data. When I cleared the cache I got the unmodified data. I haven't looked into this yet, but I assume it's easy to stop saves to cache as well.
The next step is to save which revision is the active one. This should probably be saved to the main entity, and get a new entry in the revision table upon changing active revision number. This lets us track active version as well.
In order to find which revisions belongs to the past and which belongs to the future, we would need to compare revision numbers in the revision table against active revision from main table, possibly read this from the latest revision in the revision table.
The process of setting active version will probably need a change in the pre-update listener to allow changes to go though when setting active revision. This should really get the latest revision number afterwards, but as a revision number is generated before the end of a transactions, there is no way to know this at this point. One solution would be to make modified audit strategy that updates the main entity with an updated revision number as well.
As far as I can see, these modifications should enable saving of future revisions. This solution should be a lot easier than using a complex BPM-solution for this simple problem. These proposed additions come from the top of my head as I write, and it might be that there are some gaping holes that I can't think of right now.
Yep, sounds like this would work. Depends of course on the use-case if Envers fits or not. But I'm a bit afraid that in the near future you may need things like branching, merging etc.