HHH-3556: Envers documentation partially migrated

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15501 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Adam Warski 2008-11-04 17:44:43 +00:00
parent 7e04164b24
commit 137585b17f
7 changed files with 841 additions and 0 deletions

View File

@ -0,0 +1,57 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY versionNumber "3.3.0.GA">
<!ENTITY copyrightYear "2004">
<!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
]>
<book>
<bookinfo>
<title>Hibernate Envers - Easy Entity Auditing</title>
<subtitle>Hibernate Envers Reference Documentation</subtitle>
<releaseinfo>&versionNumber;</releaseinfo>
<productnumber>&versionNumber;</productnumber>
<issuenum>1</issuenum>
<copyright>
<year>&copyrightYear;</year>
<holder>&copyrightHolder;</holder>
</copyright>
<xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<!-- include translators... -->
</bookinfo>
<toc/>
<xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/quickstart.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/example.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/revisionlog.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/exceptions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</book>

View File

@ -0,0 +1,207 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="configuration">
<title>Configuration</title>
<para>
To start working with Envers, all configuration that you must do is add the event
listeners to persistence.xml, as described in the <xref linkend="quickstart"/>.
</para>
<para>
However, as Envers generates some tables, it is possible to set the prefix and suffix
that is added to the entity name to create a versions table for an entity, as well
as set the names of the fields that are generated.
</para>
<para>
In more detail, here are the properites that you can set:
</para>
<table frame="topbot">
<title>Envers Configuration Properties</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*"/>
<colspec colname="c2" colwidth="1*"/>
<colspec colname="c2" colwidth="1*"/>
<thead>
<row>
<entry>Property name</entry>
<entry>Default value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<property>org.hibernate.envers.auditTablePrefix</property>
</entry>
<entry>
</entry>
<entry>
String that will be prepended to the name of an audited entity to create
the name of the entity, that will hold audit information.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.auditTableSuffix</property>
</entry>
<entry>
_audit
</entry>
<entry>
String that will be appended to the name of an audited entity to create
the name of the entity, that will hold audit information. If you
audit an entity with a table name Person, in the default setting Envers
will generate a <literal>Person_audit</literal> table to store historical data.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.revisionFieldName</property>
</entry>
<entry>
REV
</entry>
<entry>
Name of a field in the audit entity that will hold the revision number.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.revisionTypeFieldName</property>
</entry>
<entry>
REVTYPE
</entry>
<entry>
Name of a field in the aduit entity that will hold the type of the
revision (currently, this can be: add, mod, del).
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.revisionOnCollectionChange</property>
</entry>
<entry>
true
</entry>
<entry>
Should a revision be generated when a not-owned relation field changes
(this can be either a collection in a one-to-many relation, or the field
using "mappedBy" attribute in a one-to-one relation).
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.warnOnUnsupportedTypes</property>
</entry>
<entry>
false
</entry>
<entry>
TODO: remove
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.doNotAuditOptimisticLockingField</property>
</entry>
<entry>
true
</entry>
<entry>
When true, properties to be used for optimistic locking, annotated with
<literal>@Version</literal>, will be automatically not audited
(their history won't be stored; it normally doesn't make sense to store it).
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
To change the name of the revision table and its fields (the table, in which the
numbers of revisions and their timestamps are stored), you can use the
<literal>@RevisionEntity</literal> annotation.
For more information, see <xref linkend="revisionlog"/>.
</para>
<para>
To set the value of any of the properties described above, simply add an entry to
your <literal>persistence.xml</literal>. For example:
</para>
<programlisting>&lt;persistence-unit ...&gt;
&lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
&lt;class&gt;...&lt;/class&gt;
&lt;properties&gt;
&lt;property name="hibernate.dialect" ... /&gt;
&lt;!-- other hibernate properties --&gt;
&lt;property name="hibernate.ejb.event.post-insert"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-update"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-delete"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="org.hibernate.envers.versionsTableSuffix" value="_V" /&gt;
&lt;property name="org.hibernate.envers.revisionFieldName" value="ver_rev" /&gt;
&lt;!-- other envers properties --&gt;
&lt;/properties&gt;
&lt;/persistence-unit&gt;</programlisting>
<para>
You can also set the name of the versions table on a per-entity basis, using the
<literal>@AuditTable</literal> annotation (see also in the javadoc). It may be tedious to add this
annotation to every audited entity, so if possible, it's better to use a prefix/suffix.
</para>
<para>
If you have a mapping with secondary tables, version tables for them will be generated in
the same way (by adding the prefix and suffix). If you wish to overwrite this behaviour,
you can use the <literal>@SecondaryAuditTable</literal> and
<literal>@SecondaryAuditTables</literal> annotations.
</para>
<para>
If you want to audit a relation mapped with <literal>@OneToMany+@JoinColumn</literal>,
please see <xref linkend="exceptions"/> for a description of the additional
<literal>@AuditJoinTable</literal> annotation that you'll probably want to use.
</para>
</chapter>

View File

@ -0,0 +1,86 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="example">
<title>Short example</title>
<para>
For example, using the entities defined above, the following code will generate
revision number 1, which will contain two new <literal>Person</literal> and
two new <literal>Address</literal> entities:
</para>
<programlisting>entityManager.getTransaction().begin();
Address address1 = new Address("Privet Drive", 4);
Person person1 = new Person("Harry", "Potter", address1);
Address address2 = new Address("Grimmauld Place", 12);
Person person2 = new Person("Hermione", "Granger", address2);
entityManager.persist(address1);
entityManager.persist(address2);
entityManager.persist(person1);
entityManager.persist(person2);
entityManager.getTransaction().commit();</programlisting>
<para>
Now we change some entities. This will generate revision number 2, which will contain
modifications of one person entity and two address entities (as the collection of
persons living at <literal>address2</literal> and <literal>address1</literal> changes):
</para>
<programlisting>entityManager.getTransaction().begin();
Address address1 = entityManager.find(Address.class, address1.getId());
Person person2 = entityManager.find(Person.class, person2.getId());
// Changing the address's house number
address1.setHouseNumber(5)
// And moving Hermione to Harry
person2.setAddress(address1);
entityManager.getTransaction().commit();</programlisting>
<para>
We can retrieve the old versions (the audit) easily:
</para>
<programlisting>AuditReader reader = AuditReaderFactory.get(entityManager);
Person person2_rev1 = reader.find(Person.class, person2.getId(), 1);
assert person2_rev1.getAddress().equals(new Address("Grimmauld Place", 12));
Address address1_rev1 = reader.find(Address.class, address1.getId(), 1);
assert address1_rev1.getPersons().getSize() == 1;
// and so on</programlisting>
</chapter>

View File

@ -0,0 +1,105 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="exceptions">
<title>Mapping exceptions</title>
<sect1 id="exceptions-wontbesupported">
<title>What isn't and will not be supported</title>
<para>
Bags (the corresponding Java type is List), as they can contain non-unique elements.
The reason is that persisting, for example a bag of String-s, violates a principle
of relational databases: that each table is a set of tuples. In case of bags,
however (which require a join table), if there is a duplicate element, the two
tuples corresponding to the elements will be the same. Hibernate allows this,
however Envers (or more precisely: the database connector) will throw an exception
when trying to persist two identical elements, because of a unique constraint violation.
</para>
<para>
There are at least two ways out if you need bag semantics:
</para>
<orderedlist>
<listitem>
<para>
use an indexed collection, with the <literal>@IndexColumn</literal> annotation, or
</para>
</listitem>
<listitem>
<para>
provide a unique id for your elements with the <literal>@CollectionId</literal> annotation.
</para>
</listitem>
</orderedlist>
</sect1>
<sect1 id="exceptions-willbesupported" revision="2">
<title>What isn't and <emphasis>will</emphasis> be supported</title>
<orderedlist>
<listitem>
<para>
collections of components
</para>
</listitem>
<listitem>
<para>
relations in components
</para>
</listitem>
<listitem>
<para>
joined and table-per-class inheritance
</para>
</listitem>
</orderedlist>
</sect1>
<sect1 id="exceptions-onetomanyjoincolumn" revision="3">
<title><literal>@OneToMany</literal>+<literal>@JoinColumn</literal></title>
<para>
When a collection is mapped using these two annotations, Hibernate doesn't
generate a join table. Envers, however, has to do this, so that when you read the
revisions in which the related entity has changed, you don't get false results.
</para>
<para>
To be able to name the additional join table, there is a special annotation:
<literal>@AuditJoinTable</literal>, which has similar semantics to JPA's
<literal>@JoinTable</literal>.
</para>
</sect1>
</chapter>

View File

@ -0,0 +1,84 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<preface id="preface">
<title>Preface</title>
<para>
The Envers project aims to enable easy auditing of persistent classes. All that you
have to do is annotate your persistent class or some of its properties, that you
want to audit, with <literal>@Audited</literal>. For each audited entity, a table
will be created, which will hold the history of changes made to the entity. You
can then retrieve and query historical data without much effort.
</para>
<para>
Similarly to Subversion, the library has a concept of revisions. Basically, one
transaction is one revision (unless the transaction didn't modify any audited entities).
As the revisions are global, having a revision number, you can query for various
entities at that revision, retrieving a (partial) view of the database at that
revision. You can find a revision number having a date, and the other way round,
you can get the date at which a revision was commited.
</para>
<para>
The library works with Hibernate and Hibernate Annotations or Entity Manager.
For the auditing to work properly, the entities must have immutable unique
identifiers (primary keys). You can use Envers wherever Hibernate works:
standalone, inside JBoss AS, with JBoss Seam or Spring.
</para>
<para>
Some of the features:
</para>
<orderedlist>
<listitem>
<para>
versioning of all mappings defined by the JPA specification, except joined and
table-per-class inheritance
</para>
</listitem>
<listitem>
<para>
versioning of some Hibernate mappings, which extend JPA, like custom types and
collections/maps of "simple" types (Strings, Integers, etc.)
(see <xref linkend="exceptions"/> for one exception)
</para>
</listitem>
<listitem>
<para>
logging data for each revision using a "revision entity"
</para>
</listitem>
<listitem>
<para>
querying historical data
</para>
</listitem>
</orderedlist>
</preface>

View File

@ -0,0 +1,148 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="quickstart">
<title>Quickstart</title>
<para>
When configuring your persistence unit (the persistence.xml file), add the following event
listeners: (this will allow Envers to check if any audited entities were modified)
</para>
<programlisting>&lt;persistence-unit ...&gt;
&lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;/provider&gt;
&lt;class&gt;...&lt;/class&gt;
&lt;properties&gt;
&lt;property name="hibernate.dialect" ... /&gt;
&lt;!-- other hibernate properties --&gt;
&lt;property name="hibernate.ejb.event.post-insert"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-update"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-delete"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.VersionsEventListener" /&gt;
&lt;/properties&gt;
&lt;/persistence-unit&gt;</programlisting>
<para>
Then, annotate your persistent class with <literal>@Audited</literal> - this will make all
properties versioned. For example:
</para>
<programlisting>import org.hibernate.envers.Audited;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
@Entity
@Audited // that's the important part :)
public class Person {
@Id
@GeneratedValue
private int id;
private String name;
private String surname;
@ManyToOne
private Address address;
// add getters, setters, constructors, equals and hashCode here
}</programlisting>
<para>
And the referenced entity:
</para>
<programlisting>@Entity
@Audited
public class Address {
@Id
@GeneratedValue
private int id;
private String streetName;
private Integer houseNumber;
private Integer flatNumber;
@OneToMany(mappedBy = "address")
private Set&lt;Person&gt; persons;
// add getters, setters, constructors, equals and hashCode here
}
</programlisting>
<para>
And that's it! You create, modify and delete the entites as always. If you look
at the generated schema, you will notice that it is unchanged by adding auditing
for the Address and Person entities. Also, the data they hold is the same. There are,
however, two new tables - <literal>Address_audit</literal> and <literal>Person_audit</literal>,
which store the historical data, whenever you commit a transaction.
</para>
<para>
Instead of annotating the whole class and auditing all properties, you can annotate
only some persistent properties with <literal>@Audited</literal>. This will cause only
these properties to be audited.
</para>
<para>
You can access the audit of an entity using the <literal>AuditReader</literal> interface, which you
can obtain when having an open EntityManager. See also the javadocs.
</para>
<programlisting>AuditReader reader = AuditReaderFactory.get(entityManager);
Person oldPerson = reader.find(Person.class, personId, revision)
</programlisting>
<para>
The <literal>T find(Class&lt;T&gt; cls, Object primaryKey, Number revision)</literal>
method returns an entity with the given primary key, with the data it contained at
the given revision. If the entity didn't exist at this revision, <literal>null</literal>
is returned. Only the audited properties will be set on the returned entity.
The rest will be <literal>null</literal>.
</para>
<para>
You can also get a list of revisions at which an entity was modified using the
<literal>getRevisions</literal> method, as well as retrieve the date,
at which a revision was created using the <literal>getRevisionDate</literal> method.
</para>
</chapter>

View File

@ -0,0 +1,154 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="revisionlog">
<title>Logging data for revisions</title>
<para>
Envers provides an easy way to log additional data for each revision. You simply need
to annotate one entity with <literal>@RevisionEntity</literal>, and a new instance of
this entity will be persisted when a new revision is created (that is, whenever an
audited entity is modified). As revisions are global, you can have at most one revisions entity.
</para>
<para>
This entity must have at least two properties:
</para>
<orderedlist>
<listitem>
<para>
an integer- or long-valued property, annotated with <literal>@RevisionNumber</literal>. Most
often, this will be an auto-generated primary key.
</para>
</listitem>
<listitem>
<para>
a long-valued property, annotated with <literal>@RevisionTimestamp</literal>. Value of
this property will be automatically set by Envers.
</para>
</listitem>
</orderedlist>
<para>
You can either add these properties to your entity, or extend
<literal>org.hibernate.envers.DefaultRevisionEntity</literal>, which already has those two properties.
</para>
<para>
To fill the entity with additional data, you'll need to implement the
<literal>org.jboss.envers.RevisionListener</literal> interface. Its newRevision method will
be called when a new revision is created, before persisting the revision entity.
The implementation should be stateless and thread-safe. The listener then has to be
attached to the revisions entity by specifying it as a parameter to the
<literal>@RevisionEntity</literal> annotation.
</para>
<para>
A simplest example of a revisions entity, which with each revision associates the
username of the user making the change is:
</para>
<programlisting>package org.jboss.envers.example;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.DefaultRevisionEntity;
import javax.persistence.Entity;
@Entity
@RevisionEntity(ExampleListener.class)
public class ExampleRevEntity extends DefaultRevisionEntity {
private String username;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
}</programlisting>
<para>
Or, if you don't want to extend any class:
</para>
<programlisting>package org.hibernate.envers.example;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
import org.hibernate.envers.RevisionEntity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Entity;
@Entity
@RevisionEntity(ExampleListener.class)
public class ExampleRevEntity {
@Id
@GeneratedValue
@RevisionNumber
private int id;
@RevisionTimestamp
private long timestamp;
private String username;
// Getters, setters, equals, hashCode ...
}</programlisting>
<para>
An example listener, which, if used in a JBoss Seam application, stores the
currently logged in user username:
</para>
<programlisting>package org.hibernate.envers.example;
import org.hibernate.envers.RevisionListener;
import org.jboss.seam.security.Identity;
import org.jboss.seam.Component;
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());
}
}</programlisting>
<para>
Having an "empty" revision entity - that is, with no additional properties except the
two mandatory ones - is also an easy way to change the names of the table and of the
properties in the revisions table automatically generated by Envers.
</para>
<para>
In case there is no entity annotated with <literal>@RevisionEntity</literal>, a default
table will be generated, with the name <literal>REVINFO</literal>.
</para>
</chapter>