HHH-6036: Removing old Envers docs
This commit is contained in:
parent
e71762a313
commit
33cc3f3f62
|
@ -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.
|
|
|
@ -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>©rightYear;</year>
|
|
||||||
<holder>©rightHolder;</holder>
|
|
||||||
</copyright>
|
|
||||||
<xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<!-- include translators... -->
|
|
||||||
</bookinfo>
|
|
|
@ -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>©rightYear;</year>
|
|
||||||
<holder>©rightHolder;</holder>
|
|
||||||
</copyright>
|
|
||||||
<xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<!-- include translators... -->
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<toc/>
|
|
||||||
|
|
||||||
<xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<xi:include href="content/quickstart.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<xi:include href="content/example.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<xi:include href="content/revisionlog.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<xi:include href="content/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>
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<!ENTITY version "WORKING">
|
|
||||||
<!ENTITY today "TODAY">
|
|
||||||
<!ENTITY copyrightYear "2004">
|
|
||||||
<!ENTITY copyrightHolder "Red Hat Inc.">
|
|
||||||
<!ENTITY semi ";">
|
|
|
@ -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>©rightYear;</year>
|
|
||||||
<holder>©rightHolder;</holder>
|
|
||||||
</copyright>
|
|
||||||
<xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
||||||
<!- include translators... ->
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<toc/>
|
|
||||||
-->
|
|
||||||
<xi:include href="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>
|
|
||||||
|
|
|
@ -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><persistence-unit ...>
|
|
||||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
|
||||||
<class>...</class>
|
|
||||||
<properties>
|
|
||||||
<property name="hibernate.dialect" ... />
|
|
||||||
<!-- other hibernate properties -->
|
|
||||||
|
|
||||||
<property name="hibernate.ejb.event.post-insert"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-update"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-delete"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.pre-collection-update"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.pre-collection-remove"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-collection-recreate"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
|
|
||||||
<property name="org.hibernate.envers.versionsTableSuffix" value="_V" />
|
|
||||||
<property name="org.hibernate.envers.revisionFieldName" value="ver_rev" />
|
|
||||||
<!-- other envers properties -->
|
|
||||||
</properties>
|
|
||||||
</persistence-unit></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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><persistence-unit ...>
|
|
||||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
|
||||||
<class>...</class>
|
|
||||||
<properties>
|
|
||||||
<property name="hibernate.dialect" ... />
|
|
||||||
<!-- other hibernate properties -->
|
|
||||||
|
|
||||||
<!-- Envers listeners -->
|
|
||||||
|
|
||||||
<property name="org.hibernate.envers.auditTableSuffix" value="_versions" />
|
|
||||||
<property name="org.hibernate.envers.revisionFieldName" value="_revision" />
|
|
||||||
<property name="org.hibernate.envers.revisionTypeFieldName" value="_rev_type" />
|
|
||||||
<!-- other envers properties -->
|
|
||||||
</properties>
|
|
||||||
</persistence-unit></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>
|
|
|
@ -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 'increasing level of interestingness', 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 'increasing level of interestingness',
|
|
||||||
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 'level of interestingness' 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 'extension bucket').
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
And sometime in 2011, the last partition (or 'extension bucket') 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 'extension bucket'.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</orderedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
</chapter>
|
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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><persistence-unit ...>
|
|
||||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
|
||||||
<class>...</class>
|
|
||||||
<properties>
|
|
||||||
<property name="hibernate.dialect" ... />
|
|
||||||
<!-- other hibernate properties -->
|
|
||||||
|
|
||||||
<property name="hibernate.ejb.event.post-insert"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-update"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-delete"
|
|
||||||
value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.pre-collection-update"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.pre-collection-remove"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
<property name="hibernate.ejb.event.post-collection-recreate"
|
|
||||||
value="org.hibernate.envers.event.AuditEventListener" />
|
|
||||||
</properties>
|
|
||||||
</persistence-unit></programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
If you're using Hibernate directly, add the following to <literal>hibernate.cfg.xml</literal>:
|
|
||||||
</para>
|
|
||||||
<programlisting>
|
|
||||||
<hibernate-configuration>
|
|
||||||
<session-factory>
|
|
||||||
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-insert"/>
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-update"/>
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-delete"/>
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-update"/>
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-remove"/>
|
|
||||||
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-collection-recreate"/>
|
|
||||||
|
|
||||||
|
|
||||||
</session-factory>
|
|
||||||
</hibernate-configuration>
|
|
||||||
</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<Person> persons;
|
|
||||||
|
|
||||||
// add getters, setters, constructors, equals and hashCode here
|
|
||||||
}
|
|
||||||
</programlisting>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
And that's it! You create, modify and delete the entites as always. If you look
|
|
||||||
at the generated schema, you will notice that it is unchanged by adding auditing
|
|
||||||
for the Address and Person entities. Also, the data they hold is the same. There are,
|
|
||||||
however, two new tables - <literal>Address_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<T> cls, Object primaryKey, Number revision)</literal>
|
|
||||||
method returns an entity with the given primary key, with the data it contained at
|
|
||||||
the given revision. If the entity didn't exist at this revision, <literal>null</literal>
|
|
||||||
is returned. Only the audited properties will be set on the returned entity.
|
|
||||||
The rest will be <literal>null</literal>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
You can also get a list of revisions at which an entity was modified using the
|
|
||||||
<literal>getRevisions</literal> method, as well as retrieve the date,
|
|
||||||
at which a revision was created using the <literal>getRevisionDate</literal> method.
|
|
||||||
</para>
|
|
||||||
</chapter>
|
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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>
|
|
|
@ -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
|
|
Loading…
Reference in New Issue