• Help |

View feed: Blog of Adam Warski

Envers in Anvers!

Posted on 2008-12-04 13:29:22.0 by Adam Warski [ View original post ]

December came, so it’s time for Devoxx! (formerly JavaPolis)

If you are planning to visit Antwerp this year, make sure to come and see the Envers presentation (first conference day, 3pm)! I will explain the basic concepts, how to use various parts of the library as well as show some use-cases. Also, if you have any questions or suggestions, it will be a great opportunity to meet :).

As you may already know, Envers is now a Hibernate core module. There is no official Hibernate release yet available with Envers included, but I’ve uploaded a preview jar, which will work fine with Hibernate 3.3.x. The migrated documentation is also avialable in html and pdf formats on the site. If you spot any errors, or find some information missing, please let me know! For Maven2 users, a snapshot of Hibernate-3.4.0 (which includes Envers) is deployed to the jboss snapshots repository (located here, instructions here).

Main changes in this preview release:

  • renaming of “versioning” to “auditing”, so now there is @Audited instead of @Versioned etc.
  • support for joined and table-per-class inheritance; this completes the JPA mappings supported
  • improved query API, extending the possibilities of specifying restrictions on revision properties
  • correct support for field and property access

As always, waiting for feedback on the forums!

Enjoy! :)
Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Typestate checker - introduction

Posted on 2008-11-17 13:17:29.0 by Adam Warski [ View original post ]

When dealing with mutable objects in Java, we quite often see that “states” of the class considered emerge. The (abstract) “state” depends of course on the content of the fields of the object. When methods are invoked, which mutate the fields, the state of the object may change. Also, it may be illegal to call some methods in one state, but legal in another.

So far, specifying the state space of an object, which methods can be called in which states, and how methods change the state, is done mainly in comments (javadocs). With the new possibilities brought by JSR 308 - type annotations, it’s now possible to do it in a much more structured way.

The basic idea is simple. Each state of our object is one annotation. We can define those annotations for example as inner classes. There are 2 immediate gains:

  • we enumerate all the states of our object, so the state space is well defined;
  • each state can be commented, so we have a very good place to describe when an object is in the given state and what does it mean.

As an example, let’s assume that we have a class for reading a remote resource, for example RemoteResourceReader. Objects of this class can be in one of the three states:

  • configuration - connection to the resource is being configured
  • open - connection to the resource is open, data can be read
  • closed - the connection is closed, data cannot be read

The inital state is configuration, in which we set the connection properties, like the URL, username, password, etc. Then, we can change the state to open, read some data, and close the connection, changing the state to closed. After that, we may re-open the connection to read more data, etc.

So how would the source of our class look like? First, we define the states:


public class RemoteResourceReader {
/** Connection to the resource is being configured */
public static @interface Configuration { }
/** Connection to the resource is open, data can be read */
public static @interface Open { }
/** Connection to the resource is closed, data cannot be read */
public static @interface Closed { }

(...)
}

Now, we have to specify what is the initial state and how methods change the state. Thanks to JSR 308, that is easy. Type annotations extend the number of places, where annotations are allowed; you may place them on any type. See its web page for more information.

One of the new places, where annotations are allowed, is the “method receiver”. This lets you specify meta-data (annotations) that apply to the object, on which the method is called. For example, we want to specify that the read method can be invoked on an object only when it is in the open state; similarly, the setURL method can be invoked only when the object is in the configuration state. Using JSR308, we can write it like this:


(...)
public String read() @Open { ... }
public void setURL(String newURL) @Configuration { ... }
(...)

However, to keep the code compatible with Java 5/6, we may place the annotations in comments. They will still be recognized by the JSR308 checker framework (why this is important - read on :) ).

Finally, what about state changes? Here, we also use the method receiver annotations. We may add an element to our state annotations, which will specify the state of the object after the method invocation. For example:


(...)
public void open() @Configuration(after=Open.class)
@Closed(after=Open.class) { ... }
public void close() @Open(after=Closed.class) { ... }
(...)

We have specified that:

  • we can invoke the open method, if the object was in the configuration or closed states. After invoking this method, the object will be in the open state
  • we can invoke the close method, only if the object was in the open state. After invoking this method, the object will be in the closed state

What are the benefits of using state annotations so far? Improved documentation: users immediately see in what states objects of the class can be, when it is legal to call a method and how the states change. However, there is more: you can check if your objects are in the correct state by using the typestate checker!

The typestate checker is built on top of the checkers framework, which out-of-the box provides other very useful checkers, for nullness and immutability. Be sure to try them out :).

To use the typestate checker, go here for downloads and installation instructions. The only additional requirement is that you must annotate your state annotations with @State. The checker will verify, using flow analysis, if you invoke methods on objects in the correct state, pass parameters in the correct state etc. This version of the checker should be treated more like a proof-of-concept, than as a final version. It is in a very early development stage, so your comments and experiences are very welcome! :)

To complete the RemoteResourceReader example, here is a full version of the class, ready to be used with the typestate checker:


public class RemoteResourceReader {
/** Connection to the resource is being configured */
@State public static @interface Configuration {
Class<?> after default Object.class }
/** Connection to the resource is open, data can be read */
@State public static @interface Open {
Class<?> after default Object.class }
/** Connection to the resource is closed, data cannot be read */
@State public static @interface Closed {
Class<?> after default Object.class }

// Initial state of the object - specified in the
// constructor's receiver annotation
public RemoteResourceReader() /*@Configuration*/ { ... }

public void setURL(String newURL) /*@Configuration*/ { ... }

public void open() /*@Configuration(after=Open.class)*/
/*@Closed(after=Open.class)*/ { ... }

public String read() /*@Open*/ { ... }

public void close() /*@Open(after=Closed.class)*/ { ... }
}

Finally, here is some example code which demonstrates what errors are caught by the typestate checker:


void readMore(@Open RemoteResourceReader rrr) { ... }

void test() {
// initially in the 'configuration' state
RemoteResourceReader rrr = new RemoteResourceReader();

// ok: correct state
rrr.setUrl("http://something");

// error: not in the 'open' state
rrr.close();

// changing state from 'configuration' to 'open'
rrr.open();

// ok
String read = rrr.read();

// error: not in the 'configuration' state
rrr.setUrl("http://different");

// ok: parameter in the 'open' state
readMore(rrr);

// ok
rrr.close();

// error: parameter not in the correct state
readMore(rrr);
}

If you’d like to make experiments with the typestate checker on your own, go ahead and download it. The setup is really easy. And remember, that your feedback is very valuable and important!

I’d like to thank Michael Ernst and the rest of the JSR308 team for helping me with some questions that I had during development. The specification and framework is really good and worth taking a look at :)

Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers moves to Hibernate!

Posted on 2008-10-30 07:08:13.0 by Adam Warski [ View original post ]

I’m happy to announce that Envers is now a module of Hibernate! This means that:

  • the code is now in the hibernate-core repository (envers module). There will be no more commits to the old repository.
  • issue tracking moved to Hibernate’s JIRA. All open issues from the old JIRA have been moved there. When creating an Envers issue, please select the “envers” component.
  • envers is now built using maven2, which replaces the old ant build

The website, documentation and forum so far stay unchanged, but stay tuned for more updates :).

There will be some changes to Envers coming with this move. One of them is renaming of @Versioned to @Audited, to avoid confusion with the @Version annotation used in JPA for optimistic locking. The old @Versioned annotation will become deprecated, and after some time removed completely.

I would like to thank Steve Ebersole for doing the actual move and creating the maven build!

Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Adding structure to Seam events

Posted on 2008-10-23 09:19:07.0 by Adam Warski [ View original post ]

The idea described here is originally by Tomek Szymański. I just enhanced it a little.

Seam events are a very convenient tool to divide your business logic into smaller pieces, and add some new behaviour as necessary. However, they are very unstructured - an event name is just a String that you’ve got to remember. It’s hard to find out what events your application raises, what are the parameters and in what situations the events are actually raised - there’s no place (in code) to document it.

As a remedy, you can create a special package (let’s say events), where, for each event that your application raises, you create an interface corresponding to that event. So, if you raise an event org.myapp.events.MessageCreated, you create a MessageCreated interface in the org.myapp.events package. In the javadoc for this interface, you can describe when the event is raised and what are the parameters.

Furthermore, all components that contain methods, which observe the event, can implement the corresponding event interface (so it will be used as a marker interface). All modern IDEs let you find implementations of an interface, so finding out which methods are observing your event is trivial!

Taking it a step further, the marker interface may also contain a method declaration. An implementation of that method should observe the event. That way, you can make it even easier to provide information about the parameters of the event. For example:


package org.myapp.events;

public interface MessageCreated {
   void handleMessageCreated(Message message, User user);
}

package org.myapp.components;

@Name("sendEmails")
public class SendEmails implements MessageCreated {
   @Observer("org.myapp.events.MessageCreated")
   void handleMessageCreated(Message message, User user) {
      // Send an e-mail to the administrator that there is a new
      // message
   }
}

Finally, what about raising events? If you raise them programmatically, you may also use the interface, instead of the String form of the event name. For example:


public void sendMessage() {
   // ...
   Events.instance().raiseEvent(MessageCreated.class.getName(),
         message, user);
   // ...
}

This has two benefits. Firstly, by finding the usages of the MessageCreated interface, you know where the event is raised. Secondly, it’s refactor-safe: when you decide to rename the event, you just rename or move the interface. Your IDE does the rest for you (unless your IDE is vim ;) ).

Of course, you’ll still need to use the String form of the event’s name in the @Raise annotation and when raising events in pages.xml.

To sum up: creating marker interfaces for events gives you a place to document them, and can provide partial safe refactoring of event names. What are your practicies when using Seam events?

Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers 1.1.0.GA released

Posted on 2008-10-21 14:29:18.0 by Adam Warski [ View original post ]

Today Envers 1.1.0.GA has been released. For the impatient: go straight to the downloads! :) This release contains only minor modifications from the last beta version. You can see the release notes for this version here, and combined release notes for all 1.1.0 versions here.

The main emphasis of this release is support for persistent collections. You can now version any relation, collections of “simple” types, maps, etc. All collection mappings defined by JPA are now supported, and most of what Hibernate additionally allows also. One exception is that collections of components won’t yet work, and the second exception is described here.

There are also improvements to the revision-of-entity query. You can now easily retrieve the history of an entity along with the revision metadata (like the date when a revision was commited) using a single query. See here for details.

Both demos have been updated to use the newest version of Envers. The wiki part of the Seam demo is additionally enhanced by adding a set of links (String-s) to each wiki page (of course this set of links is also versioned).

All comments, negative or positive, are as always very welcome on the forum. Thanks to all contributors and forum users, who have been very helpful in finding bugs and designing new features! :)

Enjoy!
Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers on JDD 08

Posted on 2008-10-14 03:51:39.0 by Adam Warski [ View original post ]

If you’ll be visting Java Developers’ Day 2008 in Cracow, Poland on Thursday, be sure to stop by and see my presentation of Envers. It will be an introductory talk, in Polish; I’ll post the slides on the website after it.

See you there!
Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers 1.1.0.beta2 released with collections support

Posted on 2008-09-27 04:44:29.0 by Adam Warski [ View original post ]

Today Envers 1.1.0.beta2 has been released. This release focuses on supporting persistent collections. In earlier versions, it was only possible to version collections belonging to one-to-many bidirectional relations. Right now Envers supports (almost: see here which and why) all persistent collections supported by Hibernate:

  • one-to-many uni- and bi-directional
  • many-to-many uni- and bi-directional
  • sets and indexed lists of “simple” types, like strings, numbers, etc.
  • various maps (mapped with @MapKey, @MapKeyManyToMany, …)

Moreover, there is preliminary support for custom user types. Please test! :) Detailed release notes can be found here.

You can head straight to the downloads, and then, if you have any problems or questions, to the forums.

I’ve also pushed 1.1.0.beta2 to JBoss’s Maven2 repository, and 1.0.0.GA made it to the central maven repository.

Enjoy!
Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers on Herbstcampus 2008

Posted on 2008-09-19 12:04:02.0 by Adam Warski [ View original post ]

Yesterday I came back from Herbstcampus 2008 in Nürnberg. I gave there a talk on Envers. Thanks to all who attended! I’d also like to thank the organisers, everything went smoothly and I felt really welcome there :).

You can find the slides here. They lack of course the added value of “live comments”, but if you’ve got any questions, please write on the forum.

Adam


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers is back from vacations

Posted on 2008-09-03 05:58:52.0 by Adam Warski [ View original post ]

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 @Unversioned annotation, 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:


&#60;property name=&#34;hibernate.ejb.event.post-insert&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;
&#60;property name=&#34;hibernate.ejb.event.post-update&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;
&#60;property name=&#34;hibernate.ejb.event.post-delete&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;
&#60;property name=&#34;hibernate.ejb.event.pre-collection-update&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;
&#60;property name=&#34;hibernate.ejb.event.pre-collection-remove&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;
&#60;property name=&#34;hibernate.ejb.event.post-collection-recreate&#34;
  value=&#34;org.jboss.envers.event.VersionsEventListener&#34; /&#62;

Or if you are using Envers directly with Hibernate:


&#60;event type=&#34;post-insert&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;
&#60;event type=&#34;post-update&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;
&#60;event type=&#34;post-delete&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;
&#60;event type=&#34;pre-collection-update&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;
&#60;event type=&#34;pre-collection-remove&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;
&#60;event type=&#34;post-collection-recreate&#34;&#62;
&#60;listener class=&#34;org.jboss.envers.event.VersionsEventListener&#34;/&#62;
&#60;/event&#62;

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


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!

Envers 1.0.0.GA released!

Posted on 2008-07-16 06:51:30.0 by Adam Warski [ View original post ]

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


Post to DZone   Post to del.icio.us   Digg this!   Stumble It!