Envers is back from vacations
By Adam Warski | September 3, 2008
Hello,
after a vacation break, Envers is back with a 1.1.0.beta1 release. You can find the release notes here.
There’s quite a lot of changes and improvements in this release. Firstly, Envers now only works with Hibernate 3.2.6 or Hibernate 3.3.0. That is because support (not yet complete) for persistent collections is added - and that requires collection event listeners, which were introduced in Hibernate 3.2.6.
However, thanks to the new listeners, you can now version many-to-many relations and unidirectional one-to-many relations (except for the mapping @OneToMany+@JoinColumn, which will be supported later).
Other improvements include:
- a configuration option (
org.jboss.envers.unversionedOptimisticLockingField) to automatically unversion fields in entities annotated with @Version, contributed by Nicolás Doroskevich - an
@Unversionedannotation, which lets you exclude some fields from versioning, while keeping the entity-wide @Versioned annotation, contributed by Sebastian Komander - a new implementation of the query system, which provides room for future improvements
- the revisions-of-entity query returns now by default a list of triples: the entity that was modified, revision entity containing all revision data and the revision type (see the beta javadoc for details); all this is read using only one database query; there are also slight API changes in version queries
- for Maven2 users, Envers is now deployed to JBoss’s repository, http://repository.jboss.org/maven2/org/jboss/envers/jboss-envers/.
I’d like to welcome and thank two new contributors: Nicolás and Sebastian. Don’t hesitate to follow their way :). As always, all forum users were very helpful in finding bugs and suggesting new ideas.
Finally, some updates on configuration. The Envers home page doesn’t yet reflect this (as it’s still a beta release). To use the new collection listeners, be sure that your persistence.xml includes the following:
<event type="post-insert"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event> <event type="post-update"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event> <event type="post-delete"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event> <event type="pre-collection-update"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event> <event type="pre-collection-remove"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event> <event type="post-collection-recreate"> <listener class="org.jboss.envers.event.VersionsEventListener"/> </event>
If you are using Envers with JBoss AS 4.2.x, you’ll have either to bundle the hibernate jars with your application, or upgrade hibernate in the lib directory of the AS, as the versioned used there is 3.2.4.SP1.
As always, waiting on the forums for your opinions and for bug reports in JIRA.
Adam
Topics: Envers, JBoss, Java | No Comments »
Envers 1.0.0.GA released!
By Adam Warski | July 16, 2008
Today the first general availability version of Envers has been released (downloads, release notes).
This is a stable version containig all the features found in the preview and beta versions. It doesn’t contain any major new additions, only some minor bug fixes and the possibility to generate revisions on collections change.
What does it mean? Imagine you have a Person and Address entities in a bidirectional many-to-one relation (each person has exactly one address and many people can live at the same address). Now you change an address of a person - hence, the content of the collection of persons for the new and old addresses change. In the preview and beta versions of Envers, no revision will be generated for the Addresses (only for Person), as data in the database tables is not modified (but data in the java beans is modified). Now, however, a revision will be created for all three entities.
You can switch to the old behaviour by setting the org.jboss.envers.revisionOnCollectionChange configuration option to false (see more on configuration).
There is also now a separate build for Hibernate 3.3.0.CR1.
If you’re an Ohloh user and like Envers, you can click on the “I use this” link on the project profile page.
Thanks to talios, aamonten, genman, liuxiaodu, andrewwheeler and other forum users for very valuable feedback, ideas, testing and bug reports.
Hope you enjoy this release,
Adam
Topics: Envers, JBoss, Java | 3 Comments »
Bi-temporal versioning with Envers
By Adam Warski | June 16, 2008
With the recent addition of queries to Envers, it is now possible to easily retrieve data in a bi-temporal way. If you are not familiar with bi-temporal versioning, a good introduction by Martin Fowler can be found here.
Suppose we want to store information about Persons and Addresses, at which these persons live. Moreover, we also want to store dates: when a Person registered the fact that he/she moved, and when did he/she actually move - these may be different, as a person may have first moved, and only registered the fact after a week. Storing the two dates: registered and actual, for some entity, is the basis of bi-temporal versioning.
We can store this information in a Registration entity, which is in a one-to-one relationship with Person, and one-to-many with Address. (Each Person can have at most one Registration, and therefore also Address; each Address can have many Registrations, and therefore many Persons living there.) The Registration entity can also store the registered and actual dates. Additionally, it can be versioned, so that all historical information is remembered.
Using queries, we can, for example, answer this question: “What did we know about the address of person X in the state of the database from date Y?”. To do this, we have to select a registration, which has the actual date as big (recent) as possible, but both the registration and actual dates must be before Y. Hence, the query can look like this:
versionsReader.createQuery()
.forRevisionsOfEntity(Registration.class, true)
.add(VersionsRestrictions.maximizeProperty("actualDate")
.add(VersionsRestrictions.relatedIdEq("person", personXId))
.add(VersionsRestrictions.le("registrationDate", dateY))
.add(VersionsRestrictions.le("actualDate", dateY)))
.getSingleResult();
You may experiment with bi-temporal versioning using the updated Envers+Seam demo. To run the demo, you’ll need JBoss AS 4.2. After downloading, unzip and deploy the -ds.xml and .ear files, start the server, and go to http://localhost:8080/envers_seam_demo. A screenshot from the demo:

Moreover, the second beta release of Envers is available. It contains minor feature additions (release notes).
Adam
Topics: Envers, JBoss, Java, Uncategorized | 2 Comments »
Envers beta - now with queries!
By Adam Warski | June 12, 2008
So far Envers made it easy to store historical data; now, with version 1.0.0.beta1 (download here), you can also query it, in two “dimensions”: for entities at a given revision and for revisions, at which an entity changed. The implementation mostly follows Hibernate Criteria, with some features removed, and some added.
For example the following query returns all persons with the name “John”, sorted by their surname, which lived at the address with the given id at revision 12:
List personsAtAddress =
getVersionsReader().createQuery()
.forEntitiesAtRevision(Person.class, 12)
.addOrder(Order.asc("surname"))
.add(VersionsRestrictions.relatedIdEq(
"address", addressId))
.add(VersionsRestrictions.eq("name", "John"))
.getResultList();
You can find more information about creating queries on this page.
Warning - the schema generated by this version of Envers is incompatible with the schema generated by the preview versions. If you have any data to migrate, please write on the forum. As this is the beta release, there will be no more schema changes until the 1.0 final release.
Thanks to the forum users: talios, aamonten, genman, liuxiaodu and others for bug reports, patches, testing and ideas!
Finally, the release notes for this release are located here.
As always, waiting for comments and bug reports :)
Adam
Topics: Envers, JBoss, Java | No Comments »
What data should be stored in versions tables? - a poll
By Adam Warski | June 4, 2008
Hello,
I’ve posted a poll on what data should be stored in versions tables in Envers, see here and cast your vote:
http://www.jboss.com/index.html?module=bb&op=viewtopic&t=136764
The results will determine the future implementation, so votes really count. And as always, comments & ideas are very welcome.
The two options, in short, are:
- Store only historical data in the versions table, making queries poorer and more difficult (you always have to combine data from two sources - the versions and “current” tables)
- Store all data in the versions table, making queries easier and more powerful. This however duplicates the “current” data.
Adam
Topics: Envers, JBoss, Java | No Comments »
Envers preview 3: logging data for revisions, Seam demo
By Adam Warski | May 6, 2008
With the preview 3 release of Envers, you can easily associate additional data with revisions. This could be, for example, the name of the user making the change. You simply need to annotate an entity with @RevisionEntity: an instance of this entity will be persisted with each new revision. To provide a way to fill the entity with custom data, you need to implement an interface, and pass it as a parameter to the annotation.
For example, to store the name of the currently logged in user in a JBoss Seam application, the implementation of the listener would look as follows:
public class ExampleListener
implements RevisionListener {
public void newRevision(Object revisionEntity) {
ExampleRevEntity exampleRevEntity =
(ExampleRevEntity) revisionEntity;
Identity identity =
(Identity) Component.getInstance(
"org.jboss.seam.security.identity");
exampleRevEntity.setUsername(
identity.getUsername());
}
}
For more details see here.
There is also a demo Envers+Seam application: a very simple wiki. It allows users to create and edit pages, view their history and see which users made the changes.
And, as always, waiting for your comments on the forums! Thanks to the current forum members for the bug reports and ideas!
Adam
Topics: Envers, JBoss, Java, Uncategorized | No Comments »
Value-to-variable binding “let” tag for JSF, Facelets and Seam
By Adam Warski | April 28, 2008
The “let” tag enables you to bind the value of any expression to a variable and later reuse it, without recalculating the value. The concept comes of course from functional programming. It is especially useful with Seam’s extended EL.
The usage is really simple:
<mamut:let var="result" value="#{anyElExpression}">
Now you can use #{result} as a normal variable.
</mamut>
I was looking at other tag libraries but couldn’t find anything similar. Or maybe there is?
The use case that motivated me to write this comes from the JBoss.ORG feeds application. There, in several places I have code similar to the following one:
<ui:repeat var="group" value="#{groupsService.all}">
<s:fragment rendered=
"#{groupsService.accFeeds(group).size() > 0}">
(some header)
<ui:repeat var="feed"
value="#{groupsService.accFeeds(group)}">
(...)
</ui:repeat>
</s:fragment>
<ui:repeat>
Of course calling groupsService.acceptedFeeds(group) twice is unnecessarily inefficient. I could move this call to a backing bean, but doing so would only cause me to write some really simple code many times. The version using the let tag calls the method only once:
<ui:repeat var="group" value="#{groupsService.all}">
<mamut:let var="acceptedFeeds"
value="#{groupsService.accFeeds(group)">
<s:fragment rendered="#{accFeeds.size() > 0}">
(some header)
<ui:repeat var="feed" value="#{accFeeds}">
(...)
</ui:repeat>
</s:fragment>
</mamut:let>
<ui:repeat>
If somebody finds this useful, I’ve put the jar here. To use it, just bundle the jar with your application. The namespace for the tag is the following:
xmlns:mamut="http://mamut.net.pl/jsf"
Adam
Topics: JBoss, Java | No Comments »
Envers preview 2: versioning relations
By Adam Warski | April 22, 2008
You can now download a second preview version of the Envers library!
As a quick reminder, the library enables you to easily version your JPA entities, by simply annotating their properties with @Versioned; it works as an extension to Hibernate and Hibernate Entity Manager.
In this release, in addition to versioning simple properties, like strings, numbers, dates, you can also version the most common type of relations, namely:
@OneToOne@OneToOne(mappedBy="...")@ManyToOne@OneToMany(mappedBy="...")
Envers has now a growing test suite, which already helped to eliminate some bugs. Moreover, here you will find a description on how to generate a database schema of your entities together with the versions tables.
If you’d like to share your opinion, you can now use the forum. Waiting for your posts there :).
Adam
Topics: Envers, JBoss, Java | No Comments »
Introducing Envers: Easy Entity Versioning
By Adam Warski | April 10, 2008
Hello,
Envers is a project which enables you to version your entities, simply by annotating them with @Versioned! It is still very young, and far from a mature project, but some basic functionalities already work.
The project’s web page can be found here: www.jboss.org/envers. There you can download a preview version, a short console demo as well as find a “quick start” guide.
I’d really like to know your opinion on this project, if you find it useful, what features would you expect and so on. So please comment! :)
Adam
Topics: Envers, JBoss, Java, Uncategorized | 2 Comments »
Clean URLs in Seam: URLRewriteFilter
By Adam Warski | March 31, 2008
Starting with Seam 2.0.1 (annoucement here, download here) you can fully use UrlRewriteFilter to make URLs in your Seam app nice and clean.
When using this filter, you need to define inbound-rules, which translate your pretty URLs into Seam views, for example: /myapp/view/rice –> /myapp/view.seam?name=rice.
Moreover, you can define outbound-rules, which do the translation the other way round: from Seam views into your pretty URLs. This way, you can separate the URL managing part and the Seam view files completely: if you decide to change the URLs, you just need to modify the UrlRewriteFilter configuration file, without the need to change any .xhtml files, where you can use the link-generating components (<s:link>, <s:button>) as always. (Before Seam 2.0.1, outbound rules didn’t work.)
There is one catch, however, when using the outbound-rules: you need to include the context name in them, as opposed to inboud-rules. For example, when your application is deployed in the context /myapp, to “hide” the home.seam page and make it being displayed when the user hits the root of your app (that is, /myapp or /myapp/), you’ll need the following rules:
<rule> <from>^/index.html$</from> <to>/home.seam</to> </rule>
<outbound-rule> <from>^/myapp/home.seam$</from> <to>/myapp/</to> </outbound-rule>
Very often, you’ll want to translate part of the URL path to a parameter, and also include the cid parameter without changes, if it is present. Hence, the translated parameter must once be preceded by a ?, and once by a &. Here’s how you would translate the view example from the beginning:
<rule> <from>^/view/(w+)$</from> <to>/view.seam?name=$1</to> </rule>
<rule> <from>^/view/(w+)?cid=(d+)$</from> <to>/view.seam?cid=$2&name=$1</to> </rule>
<outbound-rule> <from>^/myapp/view.seam?name=(w+)$</from> <to>/myapp/view/$1</to> </outbound-rule>
<outbound-rule> <from>^/myapp/view.seam?cid=(d+)&?name=(w+)$</from> <to>/myapp/view/$2?cid=$1</to> </outbound-rule>
Please refer to the UrlRewriteFilter manual for further configuration details.
Cheers,
Adam
Topics: JBoss, Java, Uncategorized | 2 Comments »