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:
parent
7e04164b24
commit
137585b17f
|
@ -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>©rightYear;</year>
|
||||||
|
<holder>©rightHolder;</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>
|
||||||
|
|
|
@ -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><persistence-unit ...>
|
||||||
|
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||||
|
<class>...</class>
|
||||||
|
<properties>
|
||||||
|
<property name="hibernate.dialect" ... />
|
||||||
|
<!-- other hibernate properties -->
|
||||||
|
|
||||||
|
<property name="hibernate.ejb.event.post-insert"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-update"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-delete"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.pre-collection-update"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.pre-collection-remove"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-collection-recreate"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
|
||||||
|
<property name="org.hibernate.envers.versionsTableSuffix" value="_V" />
|
||||||
|
<property name="org.hibernate.envers.revisionFieldName" value="ver_rev" />
|
||||||
|
<!-- other envers properties -->
|
||||||
|
</properties>
|
||||||
|
</persistence-unit></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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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><persistence-unit ...>
|
||||||
|
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||||
|
<class>...</class>
|
||||||
|
<properties>
|
||||||
|
<property name="hibernate.dialect" ... />
|
||||||
|
<!-- other hibernate properties -->
|
||||||
|
|
||||||
|
<property name="hibernate.ejb.event.post-insert"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-update"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-delete"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.pre-collection-update"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.pre-collection-remove"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
<property name="hibernate.ejb.event.post-collection-recreate"
|
||||||
|
value="org.hibernate.envers.event.VersionsEventListener" />
|
||||||
|
</properties>
|
||||||
|
</persistence-unit></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<Person> 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<T> 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>
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue