HHH-6036: Removing old Envers docs

This commit is contained in:
adamw 2011-03-31 15:59:36 +02:00
parent e71762a313
commit 33cc3f3f62
20 changed files with 0 additions and 2555 deletions

View File

@ -1,176 +0,0 @@
THE HIBERNATE DOCUMENTATION
christian@hibernate.org
COPYRIGHT NOTICE: This documentation system and all its source files are
licensed under the GNU Lesser Public License (LGPL). Authors and translators
retain the copyright of their work. All font and other build files (the DocBook
system) are property of their respective copyright holders. Some of the files
(especially font files) might require a license from the respective vendor; you
are responsible to check and obtain these licenses as necessary before you use
and/or distribute these files.
Preface
The Hibernate documentation is a modular documentation, it uses
various XML files (written with the DocBook DTD) and a Java-based
build process to generate HTML and PDF output. Use a simple text
editor with XML support, such as JEdit, to edit the source files. You
will need Java and Ant installed for the output generation. The toolset
is Java only and should work on any operating system.
Note: Always use 4 spaces to indent, no tabstops (code examples will
be broken otherwise).
1. How to get it
Check out a copy of Hibernate from the repository. A regular
Hibernate download will not contain the build process for the
documentation, only the PDF/HTML output, use the repository!
See http://www.hibernate.org/Download/DownloadOverview
2. Working on the original language
The original and master language is English, hence the "en" subdirectory
in /doc/reference/ is authorative. We use "id" and "revision" attributes on
XML elements to track changes. Here are the rules, they are mandatory:
2a. Changing existing content involves an update of the "revision" of the XML
element you are working on (e.g. a <sect1>, <sect2> or even a <para>).
If a <sect1> has a revision="1", you update it to "2" after updating the
content in that section.
You can also add a revision attribute to an element if there is none,
start with revision="1". You should not add a revision attribute to each
paragraph, try to only add/use revision attributes to sections. You can'
t add a revision attribute to elements without an "id" attribute!
2b. Adding new content involves adding new elements (even new files), such
as <sect1>, <para> and so on. Any new element (or its new parent element)
needs an "id" attribute if the new content is to be included in the change
tracking. If you add a section, give it a unique short text
identifer, look at the parent element's identifier for the common prefix.
2c. Deleting content involves removing old elements. Just remove them and
make sure that the parent elements revision is updated, if the removed
element did not itself have an identifer and a revision. If you remove an
element with its own identifier, everything is fine and no other changes are
necessary.
3. Starting a new language
If you start a translation for a new language, you have to copy
the default language (English) and start an initial translation.
3a. First, duplicate the default language "en" by duplicating the directory
/doc/reference/en. For example, a new German translation
will be a copy of that directory in /doc/reference/de. We use the ISO
codes to name the language subdirectories.
3b. You also have to add your new language to the language build file,
/doc/reference/build.xml. Look for the lines that have a "TRANSLATOR"
comment and duplicate them. Change the default "en" to your language
code, every language listed here will be included in both the PDF/HTML
generation and the revision diff change tracking reports (discussed later).
4. The initial translation
If you just copied the default language, start translating the DocBook
XML modules and illustrations in the new language subdirectory. For
example, all modules for German would be in /doc/reference/de/modules
and all illustrations in /doc/reference/de/images, note that you also have
to translate the master.xml in your language subdirectory.
The initial translation is straightforward: Translate all modules and
all illustrations, but don't add any files, don't add any new XML elements
(like a section or a chapter, not even a paragraph). Simply translate
sentence by sentence. This is very important.
Note that every DocBook XML file needs an encoding, specific to a
language. Add a line like this at the top of every file, if it doesn't exist:
<?xml version='1.0' encoding="iso-8859-1"?>
You can use UTF-8 or any other character set, please experiment with
the builds to see what works for you.
If you need a new section or paragraph, because your translation requires
more explanation, you can add it if you also add an "id" and a "revision"
to that new section or paragraph.
For example, if you add a new <para> element to the existing document,
give it an identifier, a short unique string that extends the identifier
string of the parent element: <para id="queryhql-projection-specialnote">
would be a special paragraph in the <sect1 id="queryhql-projection">
section in the chapter <chapter id="queryhql">.
Never add a new element in a translated version without also adding a new
unique identifier value! Also, you have to mark this new element as "only
relevant in the translated version". Simply set the "revision" attribute of
your new element to "-1". For example, set the previously created
paragraph to "only relevant in the translation" by declaring
<para id="queryhql-projection-specialnote" revision="-1">.
Changes to that paragraph will not be tracked, it is your responsibility to
watch out for neccessary updates. Any element with revision="-1" will not be
tracked.
5. Updating translated documentation
Translators get updates by updating their working directory from the
repository. As a translator you will get an e-mail from us when translation
is required, you can then update your copy. Or, subscribe to the commit
mailing list to get all updates automatically.
The documentation tools can generate a report after you updated
from the repository and show you what needs to be translated and/or removed
in your local translation copy. To generate that report, run "ant all.revdiff"
in the doc/reference/ subdirectory. Click on the generated HTML report
file for your language and you will see what has to be updated and/or
removed.
If the report indicates that content in the original has been removed,
simply remove the identified XML element from your language modules.
If the report detects a new revision, open the file that has been updated
in your translation, find the identified XML element and update/translate
its contents. Important: Make sure you also update the "revision"
attribute of that XML element by setting it to the same version as in
the original file, hence both the original XML file and your translated
file should have the same revision number for all elements. If an
XML element in your translation doesn't have a revision, but the original
file has, add a new "revision" attribute to your XML element.
The HTML report shows the identifiers and revisions for both the original
and the translated files, use it to compare.
Rerun the "ant all.revdiff" report generation as often as you like until
no more differences are detected. You should always try to get your
copy clean, with all updated revisions and all identified elements
synchronzied.
6. Committing a translation
All translators will be asked to submit their translated versions from
time to time. This will be a manual process, you will get an e-mail from
the Hibernate team and simply send your language subdirectory as
a ZIP file to us. It will then be integrated in the main Hibernate
distribution and on the website. Or, you can contact us for commit access
to the repository, where you can maintain a translation directly.
7. Generating PDF and HTML output
The documentation is generated with the target 'ant all.doc'.
To build the reference docs for a particular language only, use
"ant -Dlang=en", for example, and call either lang.all, lang.docpdf,
lang.dochtml, or lang.dochtmlsingle for the target of your choice.
You can also call lang.section-check to track down missing identifiers in
a particular language, or you can call lang.revdiff to get a difference
report for a particular language, compared with the English reference.

View File

@ -1,23 +0,0 @@
<!DOCTYPE bookinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<bookinfo id="Hibernate_Envers_-_Easy_Entity_Auditing.xml">
<title>Hibernate Envers - Easy Entity Auditing</title>
<subtitle>Hibernate Envers Reference Documentation</subtitle>
<releaseinfo>&version;</releaseinfo>
<pubdate>&today;</pubdate>
<edition>1.0</edition>
<pubsnumber>1</pubsnumber>
<productname>JBoss Hibernate Envers</productname>
<productnumber>&version;</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>

View File

@ -1,64 +0,0 @@
<?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/queries.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/schema.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/tables.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/partitioning.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/source.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/exceptions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/migration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/links.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</book>

View File

@ -1,5 +0,0 @@
<!ENTITY version "WORKING">
<!ENTITY today "TODAY">
<!ENTITY copyrightYear "2004">
<!ENTITY copyrightHolder "Red Hat Inc.">
<!ENTITY semi ";">

View File

@ -1,64 +0,0 @@
<?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 % BOOK_ENTITIES SYSTEM "Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<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="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<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/queries.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/schema.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/tables.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/partitioning.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/source.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/exceptions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/migration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="content/links.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</book>

View File

@ -1,359 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="configuration">
<title>Configuration</title>
<section id="config-basics">
<title>Basic 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 entities, and maps them to tables, it is possible to set the prefix and suffix
that is added to the entity name to create an audit table for an entity, as well
as set the names of the fields that are generated.
</para>
</section>
<section id="config-audit-strategy">
<title>Choosing an audit strategy</title>
<para>
After the basic configuration it is important to choose the audit strategy that will be used to persist and
retrieve audit information. There is a trade-off is between the performance of persisting and the performance
of querying the audit information. Currently there two audit strategies:
<orderedlist>
<listitem>
<para>
The default audit strategy persists the audit data together with a start revision. For each row
inserted, updated or deleted in an audited table, one or more rows are inserted in the audit tables,
together with the start revision of its validity. Rows in the audit tables are never updated after insertion.
Queries of audit information use subqueries to select the applicable rows in the audit tables.
These subqueries are notoriously slow and difficult to index.
</para>
</listitem>
<listitem>
<para>
The alternative is a validity audit strategy. This strategy stores the start-revision and the end-revision
of audit information. For each row inserted, updated or deleted in an audited table, one or more rows
are inserted in the audit tables, together with the start revision of its validity. But at the same time
the end-revision field of the previous audit rows (if available) are set to this revision.
Queries on the audit information can then use 'between start and end revision' instead of subqueries
as used by the default audit strategy.
The consequence of this strategy is that persisting audit information will be a bit slower, because of the
extra updates involved, but retrieving audit information will be a lot faster. This can be improved by
adding extra indexes.
</para>
</listitem>
</orderedlist>
</para>
</section>
<section id="config-reference">
<title>Reference</title>
<para>
In more detail, here are the properties that you can set:
</para>
<table frame="topbot">
<title>Envers Configuration Properties</title>
<tgroup cols="3">
<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.audit_table_prefix</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.audit_table_suffix</property>
</entry>
<entry>
_AUD
</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_AUD</literal> table to store historical data.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.revision_field_name</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.revision_type_field_name</property>
</entry>
<entry>
REVTYPE
</entry>
<entry>
Name of a field in the audit entity that will hold the type of the
revision (currently, this can be: add, mod, del).
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.revision_on_collection_change</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.do_not_audit_optimistic_locking_field</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>
<row>
<entry>
<property>org.hibernate.envers.store_data_at_delete</property>
</entry>
<entry>
false
</entry>
<entry>
Should the entity data be stored in the revision when the entity is deleted (instead of only
storing the id and all other properties as null). This is not normally needed, as the data is
present in the last-but-one revision. Sometimes, however, it is easier and more efficient to
access it in the last revision (then the data that the entity contained before deletion is
stored twice).
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.default_schema</property>
</entry>
<entry>
null (same as normal tables)
</entry>
<entry>
The default schema name that should be used for audit tables. Can be overriden using the
<literal>@AuditTable(schema="...")</literal> annotation. If not present, the schema will
be the same as the schema of the normal tables.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.default_catalog</property>
</entry>
<entry>
null (same as normal tables)
</entry>
<entry>
The default catalog name that should be used for audit tables. Can be overriden using the
<literal>@AuditTable(catalog="...")</literal> annotation. If not present, the catalog will
be the same as the catalog of the normal tables.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.audit_strategy</property>
</entry>
<entry>
org.hibernate.envers.strategy.DefaultAuditStrategy
</entry>
<entry>
The audit strategy that should be used when persisting audit data. The default stores only the
revision, at which an entity was modified. An alternative, the
<literal>org.hibernate.envers.strategy.ValidityAuditStrategy</literal> stores both the
start revision and the end revision. Together these define when an audit row was valid, hence
the name ValidityAuditStrategy.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.audit_strategy_validity_end_rev_field_name</property>
</entry>
<entry>
REVEND
</entry>
<entry>
The column name that will hold the end revision number in audit entities. This property is only
valid if the validity audit strategy is used.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.audit_strategy_validity_store_revend_timestamp</property>
</entry>
<entry>
false
</entry>
<entry>
Should the timestamp of the end revision be stored, until which the data was valid, in addition to the end revision itself.
This is useful to be able to purge old Audit records out of a relational database by using table partitioning.
Partitioning requires a column that exists within the table.
This property is only evaluated if the ValidityAuditStrategy is used.
</entry>
</row>
<row>
<entry>
<property>org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name</property>
</entry>
<entry>
REVEND_TSTMP
</entry>
<entry>
Column name of the timestamp of the end revision until which the data was valid.
Only used if the ValidityAuditStrategy is used, and
org.hibernate.envers.audit_strategy_validity_store_revend_timestamp evaluates to true
</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.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-update"
value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-delete"
value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.AuditEventListener" /&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>
The <literal>EJB3Post...EvenListener</literal>s are needed, so that ejb3 entity lifecycle callback
methods work (<literal>@PostPersist, @PostUpdate, @PostRemove</literal>.
</para>
<para>
You can also set the name of the audit table on a per-entity basis, using the
<literal>@AuditTable</literal> annotation. 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, audit 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'd like to override auditing behaviour of some fields/properties in an embedded component, you can use
the <literal>@AuditOverride(s)</literal> annotation on the place where you use the component.
</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>
<para>
If you want to audit a relation, where the target entity is not audited (that is the case for example with
dictionary-like entities, which don't change and don't have to be audited), just annotate it with
<literal>@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)</literal>. Then, when reading historic
versions of your entity, the relation will always point to the "current" related entity.
</para>
</section>
</chapter>

View File

@ -1,89 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<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

@ -1,114 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="exceptions">
<title>Mapping exceptions</title>
<section 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>
</section>
<section id="exceptions-willbesupported" revision="2">
<title>What isn't and <emphasis>will</emphasis> be supported</title>
<orderedlist>
<listitem>
<para>
collections of components
</para>
</listitem>
</orderedlist>
</section>
<section 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>
<para>
One special case are relations mapped with <literal>@OneToMany</literal>+<literal>@JoinColumn</literal> on
the one side, and <literal>@ManyToOne</literal>+<literal>@JoinColumn(insertable=false, updatable=false</literal>)
on the many side.
Such relations are in fact bidirectional, but the owning side is the collection (see alse
<ulink url="http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-collection-extratype">here</ulink>).
</para>
<para>
To properly audit such relations with Envers, you can use the <literal>@AuditMappedBy</literal> annotation.
It enables you to specify the reverse property (using the <literal>mappedBy</literal> element). In case
of indexed collections, the index column must also be mapped in the referenced entity (using
<literal>@Column(insertable=false, updatable=false)</literal>, and specified using
<literal>positionMappedBy</literal>. This annotation will affect only the way
Envers works. Please note that the annotation is experimental and may change in the future.
</para>
</section>
</chapter>

View File

@ -1,77 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="links">
<title>Links</title>
<para>
Some useful links:
</para>
<orderedlist>
<listitem>
<para>
<ulink url="http://hibernate.org">Hibernate</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://community.jboss.org/en/envers?view=discussions">Forum</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://anonsvn.jboss.org/repos/hibernate/core/trunk/envers/">Anonymous SVN</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://opensource.atlassian.com/projects/hibernate/browse/HHH">JIRA issue tracker</ulink>
(when adding issues concerning Envers, be sure to select the "envers" component!)
</para>
</listitem>
<listitem>
<para>
<ulink url="irc://irc.freenode.net:6667/envers">IRC channel</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://www.jboss.org/feeds/view/envers">Blog</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="https://community.jboss.org/wiki/EnversFAQ">FAQ</ulink>
</para>
</listitem>
</orderedlist>
</chapter>

View File

@ -1,160 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="migration">
<title>Migration from Envers standalone</title>
<para>
With the inclusion of Envers as a Hibernate module, some of the public API and configuration defaults
changed. In general, "versioning" is renamed to "auditing" (to avoid confusion with the annotation used
for indicating an optimistic locking field - <literal>@Version</literal>).
</para>
<para>
Because of changing some configuration defaults, there should be no more problems using Envers out-of-the-box
with Oracle and other databases, which don't allow tables and field names to start with "_".
</para>
<section id="migrations-code">
<title>Changes to code</title>
<para>
Public API changes involve changing "versioning" to "auditing". So, <literal>@Versioned</literal>
became <literal>@Audited</literal>; <literal>@VersionsTable</literal> became <literal>@AuditTable</literal>
and so on.
</para>
<para>
Also, the query interface has changed slightly, mainly in the part for specifying restrictions,
projections and order. Please refer to the Javadoc for further details.
</para>
</section>
<section id="migrations-configuration">
<title>Changes to configuration</title>
<para>
First of all, the name of the event listener changed. It is now named
<literal>org.hibernate.envers.event.AuditEventListener</literal>, instead of
<literal>org.jboss.envers.event.VersionsEventListener</literal>. So to make Envers
work, you will have to change these settings in your <literal>persistence.xml</literal>
or Hibernate configuration.
</para>
<para>
Secondly, the names of the audit (versions) tables and additional auditing (versioning) fields
changed. The default suffix added to the table name is now <literal>_AUD</literal>, instead of
<literal>_versions</literal>. The name of the field that holds the revision number, and which
is added to each audit (versions) table, is now <literal>REV</literal>, instead of
<literal>_revision</literal>. Finally, the name of the field that holds the type of the revision,
is now <literal>REVTYPE</literal>, instead of <literal>_rev_type</literal>.
</para>
<para>
If you have a schema generated with the old version of Envers, you will
have to set those properties, to use the new version of Envers without problems:
</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;!-- Envers listeners --&gt;
&lt;property name="org.hibernate.envers.auditTableSuffix" value="_versions" /&gt;
&lt;property name="org.hibernate.envers.revisionFieldName" value="_revision" /&gt;
&lt;property name="org.hibernate.envers.revisionTypeFieldName" value="_rev_type" /&gt;
&lt;!-- other envers properties --&gt;
&lt;/properties&gt;
&lt;/persistence-unit&gt;</programlisting>
<para>
The <literal>org.hibernate.envers.doNotAuditOptimisticLockingField</literal> property is
now by default <literal>true</literal>, instead of <literal>false</literal>. You probably
never would want to audit the optimistic locking field.
Also, the <literal>org.hibernate.envers.warnOnUnsupportedTypes</literal> configuraiton
option was removed. In case you are using some unsupported types, use the <literal>@NotAudited</literal>
annotation.
</para>
<para>
See <xref linkend="configuration"/> for details on the configuration and a description of the
configuration options.
</para>
</section>
<section id="migrations-revisionlog">
<title>Changes to the revision entity</title>
<para>
This section applies only if you don't have a custom revision entity.
The name of the revision entity generated by default changed, so if you used the default one, you'll
have to add a custom revision entity, and map it to the old table. Here's the class
that you have to create:
</para>
<programlisting><![CDATA[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;
import javax.persistence.Column;
import javax.persistence.Table;
@Entity
@RevisionEntity
@Table(name="_revisions_info")
public class ExampleRevEntity {
@Id
@GeneratedValue
@RevisionNumber
@Column(name="revision_id")
private int id;
@RevisionTimestamp
@Column(name="revision_timestamp")
private long timestamp;
// Getters, setters, equals, hashCode ...
}]]></programlisting>
</section>
</chapter>

View File

@ -1,358 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="partitioning">
<title>Audit table partitioning</title>
<section id="partitioning-benefits">
<title>Benefits of audit table partitioning</title>
<para>
Because audit tables tend to grow indefinitely they can quickly become really large. When the audit tables have grown
to a certain limit (varying per RDBMS and/or operating system) it makes sense to start using table partitioning.
SQL table partitioning offers a lot of advantages including, but certainly not limited to:
<orderedlist>
<listitem>
<para>
Improved query performance by selectively moving rows to various partitions (or even purging old rows)
</para>
</listitem>
<listitem>
<para>
Faster data loads, index creation, etc.
</para>
</listitem>
</orderedlist>
</para>
</section>
<section id="partitioning-columns">
<title>Suitable columns for audit table partitioning</title>
<para>
Generally SQL tables must be partitioned on a column that exists within the table. As a rule it makes sense to use
either the <emphasis>end revision</emphasis> or the <emphasis>end revision timestamp</emphasis> column for
partioning of audit tables.
<note>
<para>
End revision information is not available for the default AuditStrategy.
</para>
<para>
Therefore the following Envers configuration options are required:
</para>
<para>
<literal>org.hibernate.envers.audit_strategy</literal> =
<literal>org.hibernate.envers.strategy.ValidityAuditStrategy</literal>
</para>
<para>
<literal>org.hibernate.envers.audit_strategy_validity_store_revend_timestamp</literal> =
<literal>true</literal>
</para>
<para>
Optionally, you can also override the default values following properties:
</para>
<para>
<literal>org.hibernate.envers.audit_strategy_validity_end_rev_field_name</literal>
</para>
<para>
<literal>org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name</literal>
</para>
<para>
For more information, see <xref linkend="configuration"/>.
</para>
</note>
</para>
<para>
The reason why the end revision information should be used for audit table partioning is based on the assumption that
audit tables should be partionioned on an &apos;increasing level of interestingness&apos;, like so:
</para>
<para>
<orderedlist>
<listitem>
<para>
A couple of partitions with audit data that is not very (or no longer) interesting.
This can be stored on slow media, and perhaps even be purged eventually.
</para>
</listitem>
<listitem>
<para>
Some partitions for audit data that is potentially interesting.
</para>
</listitem>
<listitem>
<para>
One partition for audit data that is most likely to be interesting.
This should be stored on the fastest media, both for reading and writing.
</para>
</listitem>
</orderedlist>
</para>
</section>
<section id="partitioning-example">
<title>Audit table partitioning example</title>
<para>
In order to determine a suitable column for the &apos;increasing level of interestingness&apos;,
consider a simplified example of a salary registration for an unnamed agency.
</para>
<para>
Currently, the salary table contains the following rows for a certain person X:
<table frame="topbot">
<title>Salaries table</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*"/>
<colspec colname="c2" colwidth="1*"/>
<thead>
<row>
<entry>Year</entry>
<entry>Salary (USD)</entry>
</row>
</thead>
<tbody>
<row>
<entry>2006</entry>
<entry>3300</entry>
</row>
<row>
<entry>2007</entry>
<entry>3500</entry>
</row>
<row>
<entry>2008</entry>
<entry>4000</entry>
</row>
<row>
<entry>2009</entry>
<entry>4500</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
The salary for the current fiscal year (2010) is unknown. The agency requires that all changes in registered
salaries for a fiscal year are recorded (i.e. an audit trail). The rationale behind this is that decisions
made at a certain date are based on the registered salary at that time. And at any time it must be possible
reproduce the reason why a certain decision was made at a certain date.
</para>
<para>
The following audit information is available, sorted on in order of occurrence:
<table frame="topbot">
<title>Salaries - audit table</title>
<tgroup cols="5">
<colspec colname="c1" colwidth="1*"/>
<colspec colname="c2" colwidth="1*"/>
<colspec colname="c3" colwidth="1*"/>
<colspec colname="c4" colwidth="1*"/>
<colspec colname="c5" colwidth="1*"/>
<thead>
<row>
<entry>Year</entry>
<entry>Revision type</entry>
<entry>Revision timestamp</entry>
<entry>Salary (USD)</entry>
<entry>End revision timestamp</entry>
</row>
</thead>
<tbody>
<row>
<entry>2006</entry>
<entry>ADD</entry>
<entry>2007-04-01</entry>
<entry>3300</entry>
<entry>null</entry>
</row>
<row>
<entry>2007</entry>
<entry>ADD</entry>
<entry>2008-04-01</entry>
<entry>35</entry>
<entry>2008-04-02</entry>
</row>
<row>
<entry>2007</entry>
<entry>MOD</entry>
<entry>2008-04-02</entry>
<entry>3500</entry>
<entry>null</entry>
</row>
<row>
<entry>2008</entry>
<entry>ADD</entry>
<entry>2009-04-01</entry>
<entry>3700</entry>
<entry>2009-07-01</entry>
</row>
<row>
<entry>2008</entry>
<entry>MOD</entry>
<entry>2009-07-01</entry>
<entry>4100</entry>
<entry>2010-02-01</entry>
</row>
<row>
<entry>2008</entry>
<entry>MOD</entry>
<entry>2010-02-01</entry>
<entry>4000</entry>
<entry>null</entry>
</row>
<row >
<entry>2009</entry>
<entry>ADD</entry>
<entry>2010-04-01</entry>
<entry>4500</entry>
<entry>null</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<section id="partitioning-example-column">
<title>Determining a suitable partitioning column</title>
<para>
To partition this data, the &apos;level of interestingness&apos; must be defined.
Consider the following:
<orderedlist>
<listitem>
<para>
For fiscal year 2006 there is only one revision. It has the oldest <emphasis>revision timestamp</emphasis>
of all audit rows, but should still be regarded as interesting because it is the latest modification
for this fiscal year in the salary table; its <emphasis>end revision timestamp</emphasis> is null.
</para>
<para>
Also note that it would be very unfortunate if in 2011 there would be an update of the salary for fiscal
year 2006 (which is possible in until at least 10 years after the fiscal year) and the audit
information would have been moved to a slow disk (based on the age of the
<emphasis>revision timestamp</emphasis>). Remember that in this case Envers will have to update
the <emphasis>end revision timestamp</emphasis> of the most recent audit row.
</para>
</listitem>
<listitem>
<para>
There are two revisions in the salary of fiscal year 2007 which both have nearly the same
<emphasis>revision timestamp</emphasis> and a different <emphasis>end revision timestamp</emphasis>.
On first sight it is evident that the first revision was a mistake and probably uninteresting.
The only interesting revision for 2007 is the one with <emphasis>end revision timestamp</emphasis> null.
</para>
</listitem>
</orderedlist>
Based on the above, it is evident that only the <emphasis>end revision timestamp</emphasis> is suitable for
audit table partitioning. The <emphasis>revision timestamp</emphasis> is not suitable.
</para>
</section>
<section id="partitioning-example-scheme">
<title>Determining a suitable partitioning scheme</title>
<para>
A possible partitioning scheme for the salary table would be as follows:
<orderedlist>
<listitem>
<para>
<emphasis>end revision timestamp</emphasis> year = 2008
</para>
<para>
This partition contains audit data that is not very (or no longer) interesting.
</para>
</listitem>
<listitem>
<para>
<emphasis>end revision timestamp</emphasis> year = 2009
</para>
<para>
This partition contains audit data that is potentially interesting.
</para>
</listitem>
<listitem>
<para>
<emphasis>end revision timestamp</emphasis> year >= 2010 or null
</para>
<para>
This partition contains the most interesting audit data.
</para>
</listitem>
</orderedlist>
</para>
<para>
This partitioning scheme also covers the potential problem of the update of the
<emphasis>end revision timestamp</emphasis>, which occurs if a row in the audited table is modified.
Even though Envers will update the <emphasis>end revision timestamp</emphasis> of the audit row to
the system date at the instant of modification, the audit row will remain in the same partition
(the &apos;extension bucket&apos;).
</para>
<para>
And sometime in 2011, the last partition (or &apos;extension bucket&apos;) is split into two new partitions:
<orderedlist>
<listitem>
<para>
<emphasis>end revision timestamp</emphasis> year = 2010
</para>
<para>
This partition contains audit data that is potentially interesting (in 2011).
</para>
</listitem>
<listitem>
<para>
<emphasis>end revision timestamp</emphasis> year >= 2011 or null
</para>
<para>
This partition contains the most interesting audit data and is the new &apos;extension bucket&apos;.
</para>
</listitem>
</orderedlist>
</para>
</section>
</section>
</chapter>

View File

@ -1,86 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<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 requires 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>
auditing of all mappings defined by the JPA specification
</para>
</listitem>
<listitem>
<para>
auditing of Hibernate mappings, which extend JPA, like custom types and
collections/maps of "simple" types (Strings, Integers, etc.)
(see also <xref linkend="exceptions"/>)
</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

@ -1,218 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="queries">
<title>Queries</title>
<para>
You can think of historic data as having two dimension. The first - horizontal -
is the state of the database at a given revision. Thus, you can
query for entities as they were at revision N. The second - vertical - are the
revisions, at which entities changed. Hence, you can query for revisions,
in which a given entity changed.
</para>
<para>
The queries in Envers are similar to
<ulink url="http://www.hibernate.org/hib_docs/v3/reference/en/html/querycriteria.html">Hibernate Criteria</ulink>,
so if you are common with them, using Envers queries will be much easier.
</para>
<para>
The main limitation of the current queries implementation is that you cannot
traverse relations. You can only specify constraints on the ids of the
related entities, and only on the "owning" side of the relation. This however
will be changed in future releases.
</para>
<para>
Please note, that queries on the audited data will be in many cases much slower
than corresponding queries on "live" data, as they involve correlated subselects.
</para>
<para>
In the future, queries will be improved both in terms of speed and possibilities, when using the valid-time
audit strategy, that is when storing both start and end revisions for entities. See
<xref linkend="configuration"/>.
</para>
<section id="entities-at-revision">
<title>Querying for entities of a class at a given revision</title>
<para>
The entry point for this type of queries is:
</para>
<programlisting><![CDATA[AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(MyEntity.class, revisionNumber);]]></programlisting>
<para>
You can then specify constraints, which should be met by the entities returned, by
adding restrictions, which can be obtained using the <literal>AuditEntity</literal>
factory class. For example, to select only entities, where the "name" property
is equal to "John":
</para>
<programlisting><![CDATA[query.add(AuditEntity.property("name").eq("John"));]]></programlisting>
<para>
And to select only entites that are related to a given entity:
</para>
<programlisting><![CDATA[query.add(AuditEntity.property("address").eq(relatedEntityInstance));
// or
query.add(AuditEntity.relatedId("address").eq(relatedEntityId));]]></programlisting>
<para>
You can limit the number of results, order them, and set aggregations and projections
(except grouping) in the usual way.
When your query is complete, you can obtain the results by calling the
<literal>getSingleResult()</literal> or <literal>getResultList()</literal> methods.
</para>
<para>
A full query, can look for example like this:
</para>
<programlisting><![CDATA[List personsAtAddress = getAuditReader().createQuery()
.forEntitiesAtRevision(Person.class, 12)
.addOrder(AuditEntity.property("surname").desc())
.add(AuditEntity.relatedId("address").eq(addressId))
.setFirstResult(4)
.setMaxResults(2)
.getResultList();]]></programlisting>
</section>
<section id="revisions-of-entity">
<title>Querying for revisions, at which entities of a given class changed</title>
<para>
The entry point for this type of queries is:
</para>
<programlisting><![CDATA[AuditQuery query = getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true);]]></programlisting>
<para>
You can add constraints to this query in the same way as to the previous one.
There are some additional possibilities:
</para>
<orderedlist>
<listitem>
<para>
using <literal>AuditEntity.revisionNumber()</literal> you can specify constraints, projections
and order on the revision number, in which the audited entity was modified
</para>
</listitem>
<listitem>
<para>
similarly, using <literal>AuditEntity.revisionProperty(propertyName)</literal> you can specify constraints,
projections and order on a property of the revision entity, corresponding to the revision
in which the audited entity was modified
</para>
</listitem>
<listitem>
<para>
<literal>AuditEntity.revisionType()</literal> gives you access as above to the type of
the revision (ADD, MOD, DEL).
</para>
</listitem>
</orderedlist>
<para>
Using these methods,
you can order the query results by revision number, set projection or constraint
the revision number to be greater or less than a specified value, etc. For example, the
following query will select the smallest revision number, at which entity of class
<literal>MyEntity</literal> with id <literal>entityId</literal> has changed, after revision
number 42:
</para>
<programlisting><![CDATA[Number revision = (Number) getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true)
.setProjection(AuditEntity.revisionNumber().min())
.add(AuditEntity.id().eq(entityId))
.add(AuditEntity.revisionNumber().gt(42))
.getSingleResult();]]></programlisting>
<para>
The second additional feature you can use in queries for revisions is the ability
to maximalize/minimize a property. For example, if you want to select the
revision, at which the value of the <literal>actualDate</literal> for a given entity
was larger then a given value, but as small as possible:
</para>
<programlisting><![CDATA[Number revision = (Number) getAuditReader().createQuery()
.forRevisionsOfEntity(MyEntity.class, false, true)
// We are only interested in the first revision
.setProjection(AuditEntity.revisionNumber().min())
.add(AuditEntity.property("actualDate").minimize()
.add(AuditEntity.property("actualDate").ge(givenDate))
.add(AuditEntity.id().eq(givenEntityId)))
.getSingleResult();
]]></programlisting>
<para>
The <literal>minimize()</literal> and <literal>maximize()</literal> methods return a criteria,
to which you can add constraints, which must be met by the entities with the
maximized/minimized properties.
</para>
<para>
You probably also noticed that there are two boolean parameters, passed when
creating the query. The first one, <literal>selectEntitiesOnly</literal>, is only valid when
you don't set an explicit projection. If true, the result of the query will be
a list of entities (which changed at revisions satisfying the specified
constraints).
</para>
<para>
If false, the result will be a list of three element arrays. The
first element will be the changed entity instance. The second will be an entity
containing revision data (if no custom entity is used, this will be an instance
of <literal>DefaultRevisionEntity</literal>). The third will be the type of the
revision (one of the values of the <literal>RevisionType</literal> enumeration:
ADD, MOD, DEL).
</para>
<para>
The second parameter, <literal>selectDeletedEntities</literal>, specifies if revisions,
in which the entity was deleted should be included in the results. If yes, such entities
will have the revision type DEL and all fields, except the id,
<literal>null</literal>.
</para>
</section>
</chapter>

View File

@ -1,175 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="quickstart">
<title>Quickstart</title>
<para>
If you're using JPA, when coniguring Hibernate (in <literal>persistence.xml</literal>), 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.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-update"
value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-delete"
value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.AuditEventListener" /&gt;
&lt;/properties&gt;
&lt;/persistence-unit&gt;</programlisting>
<para>
If you're using Hibernate directly, add the following to <literal>hibernate.cfg.xml</literal>:
</para>
<programlisting>
&lt;hibernate-configuration&gt;
&lt;session-factory&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="post-insert"/&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="post-update"/&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="post-delete"/&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-update"/&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-remove"/&gt;
&lt;listener class="org.hibernate.envers.event.AuditEventListener" type="post-collection-recreate"/&gt;
&lt;/session-factory&gt;
&lt;/hibernate-configuration&gt;
</programlisting>
<para>
The <literal>EJB3Post...EvenListener</literal>s are needed, so that ejb3 entity lifecycle callback
methods work (<literal>@PostPersist, @PostUpdate, @PostRemove</literal>.
</para>
<para>
Then, annotate your persistent class with <literal>@Audited</literal> - this will make all
properties audited. 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_AUD</literal> and <literal>Person_AUD</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 (history) of an entity using the <literal>AuditReader</literal> interface, which you
can obtain when having an open EntityManager.
</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

@ -1,180 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<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>
Please note that the revision entity must be a mapped Hibernate 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- or j.u.Date- 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>
When using a <literal>Date</literal>, instead of a <literal>long/Long</literal> for the revision timestamp,
take care not to use a mapping of the property which will loose precision (for example, using
<literal>@Temporal(DATE)</literal> is wrong, as it doesn't store the time information, so many of your
revisions will appear to happen at exactly the same time). A good choice is a
<literal>@Temporal(TIMESTAMP)</literal>.
</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>
Alternatively, you can use the <literal>getCurrentRevision</literal> method of the
<literal>AuditReader</literal> interface to obtain the current revision, and fill it with desired information.
The method has a <literal>persist</literal> parameter specifying, if the revision entity should be persisted
before returning. If set to <literal>true</literal>, the revision number will be available in the returned
revision entity (as it is normally generated by the database), but the revision entity will be persisted
regardless of wheter there are any audited entities changed. If set to <literal>false</literal>, the revision
number will be <literal>null</literal>, but the revision entity will be persisted only if some audited entities
have changed.
</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>

View File

@ -1,123 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="schema">
<title>Generating schema with Ant</title>
<para>
If you'd like to generate the database schema file with the Hibernate Tools Ant task,
you'll probably notice that the generated file doesn't contain definitions of audit
tables. To generate also the audit tables, you simply need to use
<literal>org.hibernate.tool.ant.EnversHibernateToolTask</literal> instead of the usual
<literal>org.hibernate.tool.ant.HibernateToolTask</literal>. The former class extends
the latter, and only adds generation of the version entities. So you can use the task
just as you used to.
</para>
<para>
For example:
</para>
<programlisting><![CDATA[<target name="schemaexport" depends="build-demo"
description="Exports a generated schema to DB and file">
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.EnversHibernateToolTask"
classpathref="build.demo.classpath"/>
<hibernatetool destdir=".">
<classpath>
<fileset refid="lib.hibernate" />
<path location="${build.demo.dir}" />
<path location="${build.main.dir}" />
</classpath>
<jpaconfiguration persistenceunit="ConsolePU" />
<hbm2ddl
drop="false"
create="true"
export="false"
outputfilename="versioning-ddl.sql"
delimiter=";"
format="true"/>
</hibernatetool>
</target>]]></programlisting>
<para>
Will generate the following schema:
</para>
<programlisting><![CDATA[
create table Address (
id integer generated by default as identity (start with 1),
flatNumber integer,
houseNumber integer,
streetName varchar(255),
primary key (id)
);
create table Address_AUD (
id integer not null,
REV integer not null,
flatNumber integer,
houseNumber integer,
streetName varchar(255),
REVTYPE tinyint,
primary key (id, REV)
);
create table Person (
id integer generated by default as identity (start with 1),
name varchar(255),
surname varchar(255),
address_id integer,
primary key (id)
);
create table Person_AUD (
id integer not null,
REV integer not null,
name varchar(255),
surname varchar(255),
REVTYPE tinyint,
address_id integer,
primary key (id, REV)
);
create table REVINFO (
REV integer generated by default as identity (start with 1),
REVTSTMP bigint,
primary key (REV)
);
alter table Person
add constraint FK8E488775E4C3EA63
foreign key (address_id)
references Address;
]]></programlisting>
</chapter>

View File

@ -1,104 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
]>
<chapter id="source">
<title>Building from source and testing</title>
<section id="source-checkout">
<title>Building from source</title>
<para>
Envers, as a module of Hibernate, uses the standard Hibernate build. So all the usual
build targets (compile, test, install) will work.
</para>
<para>
The public Hibernate Git repository is hosted at GitHub and can be browsed using
<ulink url="https://github.com/hibernate/hibernate-core">GitHub</ulink>.
The source can be checked out using either
<programlisting>
git clone https://github.com/hibernate/hibernate-core hibernate-core.git
git clone git://github.com/hibernate/hibernate-core.git
</programlisting>
</para>
</section>
<section id="source-contributing">
<title>Contributing</title>
<para>
If you want to contribute a fix or new feature, either:
<itemizedlist>
<listitem>
use the GitHub fork capability: clone, work on a branch, fork the repo on GitHub (fork button), push the work there and trigger a pull request (pull request button).
</listitem>
<listitem>
use the pure Git approach: clone, work on a branch, push to a public fork repo hosted somewhere, trigger a pull request
(<literal>git pull-request</literal>)
</listitem>
<listitem>
provide a good old patch file: clone the repo, create a patch with git format-patch or diff and attach the patch file to JIRA
</listitem>
</itemizedlist>
</para>
</section>
<section id="source-tests">
<title>Envers integration tests</title>
<para>
The tests use, by default, use a H2 in-memory database. The configuration
file can be found in <literal>src/test/resources/hibernate.test.cfg.xml</literal>.
</para>
<para>
The tests use TestNG, and can be found in the
<literal>org.hibernate.envers.test.integration</literal> package
(or rather, in subpackages of this package).
The tests aren't unit tests, as they don't test individual classes, but the behaviour
and interaction of many classes, hence the name of package.
</para>
<para>
A test normally consists of an entity (or two entities) that will be audited and extends the
<literal>AbstractEntityTest</literal> class, which has one abstract method:
<literal>configure(Ejb3Configuration)</literal>. The role of this method is to add the entities
that will be used in the test to the configuration.
</para>
<para>
The test data is in most cases created in the "initData" method (which is called once before
the tests from this class are executed), which normally creates a couple of revisions,
by persisting and updating entities. The tests first check if the revisions, in which
entities where modified are correct (the testRevisionCounts method), and if the historic
data is correct (the testHistoryOfXxx methods).
</para>
</section>
</chapter>

View File

@ -1,114 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<chapter id="tables">
<title>Generated tables and their content</title>
<para>
For each audited entity (that is, for each entity containing at least one audited field), an audit
table is created. By default, the audit table's name is created by adding a "_AUD" suffix to
the original name, but this can be overriden by specifing a different suffix/prefix
(see <xref linkend="configuration"/>) or on a per-entity basis using the
<literal>@AuditTable</literal> annotation.
</para>
<para>
The audit table has the following fields:
</para>
<orderedlist>
<listitem>
<para>
id of the original entity (this can be more then one column, if using an embedded or multiple id)
</para>
</listitem>
<listitem>
<para>
revision number - an integer
</para>
</listitem>
<listitem>
<para>
revision type - a small integer
</para>
</listitem>
<listitem>
<para>
audited fields from the original entity
</para>
</listitem>
</orderedlist>
<para>
The primary key of the audit table is the combination of the original id of the
entity and the revision number - there can be at most one historic entry for a given
entity instance at a given revision.
</para>
<para>
The current entity data is stored in the original table and in the audit table.
This is a duplication of data, however as this solution makes the query system much more
powerful, and as memory is cheap, hopefully this won't be a major drawback for the users.
A row in the audit table with entity id ID, revision N and data D means:
entity with id ID has data D from revision N upwards. Hence, if we want to find an
entity at revision M, we have to search for a row in the audit table, which has the
revision number smaller or equal to M, but as large as possible. If no such row is
found, or a row with a "deleted" marker is found, it means that the entity didn't
exist at that revision.
</para>
<para>
The "revision type" field can currently have three values: 0, 1, 2, which means,
respectively, ADD, MOD and DEL. A row with a revision of type DEL will only contain the
id of the entity and no data (all fields NULL), as it only serves as a marker saying
"this entity was deleted at that revision".
</para>
<para>
Additionaly, there is a "REVINFO" table generated, which contains only two fields:
the revision id and revision timestamp. A row is inserted into this table on each
new revision, that is, on each commit of a transaction, which changes audited data.
The name of this table can be configured, as well as additional content stored,
using the <literal>@RevisionEntity</literal> annotation, see <xref linkend="revisionlog"/>.
</para>
<para>
While global revisions are a good way to provide correct auditing of relations,
some people have pointed out that this may be a bottleneck in systems, where data
is very often modified. One viable solution is to introduce an option to have an
entity "locally revisioned", that is revisions would be created for it independently.
This wouldn't enable correct versioning of relations, but wouldn't also require the
"REVINFO" table. Another possibility if to have "revisioning groups", that is groups
of entities which share revision numbering. Each such group would have to consist
of one or more strongly connected component of the graph induced by relations between
entities. Your opinions on the subject are very welcome on the forum! :)
</para>
</chapter>

View File

@ -1,60 +0,0 @@
<?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" [
<!ENTITY % BOOK_ENTITIES SYSTEM "Hibernate_Envers_-_Easy_Entity_Auditing.ent">
%BOOK_ENTITIES;
]>
<legalnotice id="Legal_Notice">
<title>Legal Notice</title>
<para>
<address>
<street>1801 Varsity Drive</street>
<city>Raleigh</city>, <state>NC</state><postcode>27606-2072</postcode><country>USA</country>
<phone>Phone: +1 919 754 3700</phone>
<phone>Phone: 888 733 4281</phone>
<fax>Fax: +1 919 754 3701</fax>
<pob>PO Box 13588</pob><city>Research Triangle Park</city>, <state>NC</state><postcode>27709</postcode><country>USA</country>
</address>
</para>
<para>
Copyright <trademark class="copyright"/> 2007 by Red Hat, Inc. 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 <ulink url="http://www.gnu.org/licenses/lgpl-2.1.html">Lesser General Public License</ulink>, as published
by the Free Software Foundation.
</para>
<para>
Red Hat and the Red Hat "Shadow Man" logo are registered trademarks of Red Hat, Inc. in the United States and other countries.
</para>
<para>
All other trademarks referenced herein are the property of their respective owners.
</para>
<para>
The GPG fingerprint of the security@redhat.com key is:
</para>
<para>
CA 20 86 86 2B D6 9D FC 65 F6 EC C4 21 91 80 CD DB 42 A6 0E
</para>
</legalnotice>

View File

@ -1,6 +0,0 @@
# Config::Simple 4.59
# Wed Dec 9 09:53:51 2009
debug: 1
xml_lang: en-US
brand: jboss-community-hibernate