Hibernate SVN: r14352 - core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-23 18:52:40 -0500 (Sat, 23 Feb 2008)
New Revision: 14352
Modified:
core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/MultiplexingCacheInstanceManager.java
Log:
Reduce use of "multiplexer" in names; use JGroups
Small Javadoc changes
Modified: core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/MultiplexingCacheInstanceManager.java
===================================================================
--- core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/MultiplexingCacheInstanceManager.java 2008-02-23 23:49:26 UTC (rev 14351)
+++ core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/MultiplexingCacheInstanceManager.java 2008-02-23 23:52:40 UTC (rev 14352)
@@ -46,9 +46,7 @@
/**
* Allows building separate {@link Cache} instances for each type of region, but
* supports using the JGroups multiplexer under the covers to re-use the same group
- * communication stack. <p/> todo : replace the prototype cache factory with
- * the equivalent JBoss Cache solution from
- * http://jira.jboss.com/jira/browse/JBCACHE-1156
+ * communication stack. <p/>
*
* @author Steve Ebersole
* @author Brian Stansberry
@@ -58,20 +56,20 @@
private static final Logger log = LoggerFactory.getLogger(MultiplexingCacheInstanceManager.class);
/**
- * Classpath or filesystem resource identifying containing JBoss Cache
+ * Classpath or filesystem resource containing JBoss Cache
* configurations the factory should use.
*
* @see #DEF_CACHE_FACTORY_RESOURCE
*/
public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.configs";
/**
- * Classpath or filesystem resource identifying containing JGroups protocol
+ * Classpath or filesystem resource containing JGroups protocol
* stack configurations the <code>org.jgroups.ChannelFactory</code>
* should use.
*
- * @see #DEF_MULTIPLEXER_RESOURCE
+ * @see #DEF_JGROUPS_RESOURCE
*/
- public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.multiplexer.stacks";
+ public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.jgroups.stacks";
/**
* Name of the configuration that should be used for entity caches.
@@ -110,7 +108,7 @@
* Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies
* the "jgroups-stacks.xml" file in this package.
*/
- public static final String DEF_MULTIPLEXER_RESOURCE = "org/hibernate/cache/jbc2/builder/jgroups-stacks.xml";
+ public static final String DEF_JGROUPS_RESOURCE = "org/hibernate/cache/jbc2/builder/jgroups-stacks.xml";
/**
* Default value for {@link #ENTITY_CACHE_RESOURCE_PROP}.
*/
@@ -280,7 +278,7 @@
if (buildCaches && jbcFactory == null) {
// See if the user configured a multiplexer stack
if (channelFactory == null) {
- String muxStacks = PropertiesHelper.getString(CHANNEL_FACTORY_RESOURCE_PROP, properties, DEF_MULTIPLEXER_RESOURCE);
+ String muxStacks = PropertiesHelper.getString(CHANNEL_FACTORY_RESOURCE_PROP, properties, DEF_JGROUPS_RESOURCE);
if (muxStacks != null) {
channelFactory = new JChannelFactory();
channelFactory.setMultiplexerConfig(muxStacks);
16 years, 9 months
Hibernate SVN: r14351 - core/trunk/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc2/builder.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-23 18:49:26 -0500 (Sat, 23 Feb 2008)
New Revision: 14351
Modified:
core/trunk/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc2/builder/jbc2-configs.xml
Log:
Use udp in all configs so we by default share a Channel
Use NullEvictionPolicy for timestamps
Tweak the default eviction configs
Modified: core/trunk/cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc2/builder/jbc2-configs.xml
===================================================================
(Binary files differ)
16 years, 9 months
Hibernate SVN: r14350 - in core/trunk/cache-jbosscache2/src: test/java/org/hibernate/test/cache/jbc2/query and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-23 18:47:41 -0500 (Sat, 23 Feb 2008)
New Revision: 14350
Modified:
core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java
Log:
Ensure that queries are segregated from entities/collections if they use the same region name
Modified: core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java
===================================================================
--- core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java 2008-02-23 00:15:59 UTC (rev 14349)
+++ core/trunk/cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java 2008-02-23 23:47:41 UTC (rev 14350)
@@ -43,8 +43,8 @@
public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter implements QueryResultsRegion {
public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.region.jbc2.query.localonly";
+ public static final String TYPE = "QUERY";
-
/**
* Whether we should set an option to disable propagation of changes around
* cluster.
@@ -134,7 +134,7 @@
@Override
protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
- return Fqn.fromString(escapeRegionName(regionName, regionPrefix));
+ return getTypeLastRegionFqn(regionName, regionPrefix, TYPE);
}
}
Modified: core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java
===================================================================
--- core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java 2008-02-23 00:15:59 UTC (rev 14349)
+++ core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java 2008-02-23 23:47:41 UTC (rev 14350)
@@ -36,6 +36,7 @@
import org.hibernate.cache.jbc2.BasicRegionAdapter;
import org.hibernate.cache.jbc2.CacheInstanceManager;
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
+import org.hibernate.cache.jbc2.query.QueryResultsRegionImpl;
import org.hibernate.cfg.Configuration;
import org.hibernate.test.cache.jbc2.AbstractGeneralDataRegionTestCase;
import org.hibernate.test.util.CacheTestUtil;
@@ -83,7 +84,7 @@
@Override
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
- return Fqn.fromString(BasicRegionAdapter.escapeRegionName(regionName, regionPrefix));
+ return BasicRegionAdapter.getTypeLastRegionFqn(regionName, regionPrefix, QueryResultsRegionImpl.TYPE);
}
public void testPutDoesNotBlockGetOptimistic() throws Exception {
16 years, 9 months
Hibernate SVN: r14349 - core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-22 19:15:59 -0500 (Fri, 22 Feb 2008)
New Revision: 14349
Modified:
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml
Log:
Minor fixes
Modified: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml 2008-02-22 23:26:44 UTC (rev 14348)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml 2008-02-23 00:15:59 UTC (rev 14349)
@@ -223,7 +223,7 @@
<para>
Specifies the JNDI name under which the JBoss Cache instance
to use is bound. Note that although this configuration property
- has the same name as the one used by <literal>SharedCacheInstanceManager</literal>,
+ has the same name as the one used by <literal>SharedJBossCacheRegionFactory</literal>,
the meaning here is different. Note also that in this class'
usage of the property, there is no default value -- the user
must specify the property.
@@ -309,8 +309,8 @@
<para>
Name of the configuration that should be used for query caches.
By default, tries to use the same cache as is used for
- entity caching. If there is no entity cache or it uses
- invalidation, the default value is <literal>local-query</literal>.
+ entity caching. If there is no entity cache, the default
+ value is <literal>local-query</literal>.
</para>
</listitem>
</varlistentry>
@@ -324,7 +324,7 @@
configurations. If you want to set
<literal>hibernate.cache.region.jbc2.configs</literal> and use your
own JBoss Cache configuration file, you can still take advantage of
- these defaults names; just name the configurations in your file
+ these default names; just name the configurations in your file
to match.
</para>
16 years, 9 months
Hibernate SVN: r14348 - core/trunk/documentation/manual/src/main/docbook/en-US/content.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-22 18:26:44 -0500 (Fri, 22 Feb 2008)
New Revision: 14348
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
Log:
[HHH-2555] Include JBoss Cache 2
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2008-02-22 23:24:53 UTC (rev 14347)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2008-02-22 23:26:44 UTC (rev 14348)
@@ -695,12 +695,19 @@
<entry></entry>
</row>
<row>
- <entry>JBoss TreeCache</entry>
+ <entry>JBoss Cache 1.x</entry>
<entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
<entry>clustered (ip multicast), transactional</entry>
<entry>yes (replication)</entry>
<entry>yes (clock sync req.)</entry>
</row>
+ <row>
+ <entry>JBoss Cache 2</entry>
+ <entry><literal>org.hibernate.cache.jbc2.JBossCacheRegionFactory</literal></entry>
+ <entry>clustered (ip multicast), transactional</entry>
+ <entry>yes (replication or invalidation)</entry>
+ <entry>yes (clock sync req.)</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -890,12 +897,19 @@
<entry></entry>
</row>
<row>
- <entry>JBoss TreeCache</entry>
+ <entry>JBoss Cache 1.x</entry>
<entry>yes</entry>
<entry></entry>
<entry></entry>
<entry>yes</entry>
</row>
+ <row>
+ <entry>JBoss Cache 2</entry>
+ <entry>yes</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>yes</entry>
+ </row>
</tbody>
</tgroup>
</table>
16 years, 9 months
Hibernate SVN: r14347 - in core/trunk/documentation: jbosscache2 and 6 other directories.
by hibernate-commits@lists.jboss.org
Author: bstansberry(a)jboss.com
Date: 2008-02-22 18:24:53 -0500 (Fri, 22 Feb 2008)
New Revision: 14347
Added:
core/trunk/documentation/jbosscache2/
core/trunk/documentation/jbosscache2/README
core/trunk/documentation/jbosscache2/pom.xml
core/trunk/documentation/jbosscache2/src/
core/trunk/documentation/jbosscache2/src/main/
core/trunk/documentation/jbosscache2/src/main/docbook/
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/Hibernate_JBC2_Reference.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/architecture.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/concepts.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/eviction.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/introduction.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/preface.xml
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/hibernate_logo_a.png
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/multi-cache.png
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/single-cache.png
core/trunk/documentation/jbosscache2/src/main/docbook/en-US/legal_notice.xml
Log:
[HHH-3127] Create reference guide for the Hibernate/JBC2 integration
Property changes on: core/trunk/documentation/jbosscache2
___________________________________________________________________
Name: svn:ignore
+ target
.project
.settings
Added: core/trunk/documentation/jbosscache2/README
===================================================================
--- core/trunk/documentation/jbosscache2/README (rev 0)
+++ core/trunk/documentation/jbosscache2/README 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,176 @@
+THE HIBERNATE DOCUMENTATION
+christian(a)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.
Property changes on: core/trunk/documentation/jbosscache2/README
___________________________________________________________________
Name: svn:executable
+ *
Added: core/trunk/documentation/jbosscache2/pom.xml
===================================================================
--- core/trunk/documentation/jbosscache2/pom.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/pom.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,86 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core-parent</artifactId>
+ <version>1</version>
+ </parent>
+
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-jbc2-manual</artifactId>
+ <version>3.3.0-SNAPSHOT</version>
+ <packaging>jdocbook</packaging>
+
+ <name>Hibernate/JBoss Cache 2 Reference Manual</name>
+ <description>The Hibernate / JBoss Cache 2 integration reference manual</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jboss.maven.plugins</groupId>
+ <artifactId>maven-jdocbook-plugin</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <extensions>true</extensions>
+ <dependencies>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-jdocbook-style</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ <type>jdocbook-style</type>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <sourceDocumentName>Hibernate_JBC2_Reference.xml</sourceDocumentName>
+ <masterTranslation>en-US</masterTranslation>
+ <translations>
+ <translation>es-ES</translation>
+ <translation>fr-FR</translation>
+ <translation>ja-JP</translation>
+ <translation>ko-KR</translation>
+ <translation>pt-BR</translation>
+ <translation>zh-CN</translation>
+ </translations>
+ <imageResource>
+ <directory>src/main/docbook/en-US</directory>
+ <excludes>
+ <exclude>*.xml</exclude>
+ <exclude>**/*.xml</exclude>
+ <exclude>*.zargo</exclude>
+ <exclude>**/*.zargo</exclude>
+ </excludes>
+ </imageResource>
+ <formats>
+ <format>
+ <formatName>pdf</formatName>
+ <stylesheetResource>classpath:/xslt/hibernate/pdf/main-pdf.xsl</stylesheetResource>
+ <finalName>hibernate_reference.pdf</finalName>
+ <profilingTypeName>two_pass</profilingTypeName>
+ </format>
+ <format>
+ <formatName>html_single</formatName>
+ <stylesheetResource>classpath:/xslt/hibernate/html/main-single.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ <profilingTypeName>two_pass</profilingTypeName>
+ </format>
+ <format>
+ <formatName>html</formatName>
+ <stylesheetResource>classpath:/xslt/hibernate/html/main-chunk.xsl</stylesheetResource>
+ <finalName>index.html</finalName>
+ <profilingTypeName>two_pass</profilingTypeName>
+ </format>
+ </formats>
+ <options>
+ <xincludeSupported>true</xincludeSupported>
+ <localeSeparator>-</localeSeparator>
+ <useRelativeImageUris>true</useRelativeImageUris>
+ </options>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/Hibernate_JBC2_Reference.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/Hibernate_JBC2_Reference.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/Hibernate_JBC2_Reference.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,61 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<!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.alpha1">
+ <!ENTITY copyrightYear "2008">
+ <!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
+]>
+
+<book>
+
+ <bookinfo>
+ <title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
+ <subtitle>Using JBoss Cache 2 as a Hibernate Second Level Cache</subtitle>
+ <releaseinfo>&versionNumber;</releaseinfo>
+ <productnumber>&versionNumber;</productnumber>
+ <issuenum>1</issuenum>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/hibernate_logo_a.png" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/hibernate_logo_a.png" depth="3cm" />
+ </imageobject>
+ </mediaobject>
+ <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/introduction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/concepts.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/eviction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</book>
+
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/architecture.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/architecture.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/architecture.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,293 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<chapter id="architecture">
+
+ <title>Architecture</title>
+
+ <para>
+ We've now gone through all the main concepts and the configuration
+ details; now we'll look a bit under the covers to understand a bit
+ more about the architectural design of the Hibernate/JBoss Cache
+ integration. Readers can skip this chapter if they aren't interested
+ in a look under the covers.
+ </para>
+
+ <sect1 id="architecture-interface" revision="1">
+ <title>Hibernate Interface to the Caching Subsystem</title>
+
+ <para>
+ The rest of Hibernate interacts with the Second Level Cache subsystem
+ via the <literal>org.hibernate.cache.RegionFactory</literal> interface.
+ What implementation of the interface is used is determined by the
+ value of the <literal>hibernate.cache.region.factory_class</literal>
+ configuration property. The interface itself is straightforward:
+ </para>
+
+ <programlisting><![CDATA[void start(Settings settings, Properties properties)
+ throws CacheException;
+
+void stop();
+
+boolean isMinimalPutsEnabledByDefault();
+
+long nextTimestamp();
+
+EntityRegion buildEntityRegion(String regionName,
+ Properties properties,
+ CacheDataDescription metadata)
+ throws CacheException;
+
+CollectionRegion buildCollectionRegion(String regionName,
+ Properties properties,
+ CacheDataDescription cdd)
+ throws CacheException;
+
+QueryResultsRegion buildQueryResultsRegion(String regionName,
+ Properties properties)
+ throws CacheException;
+
+TimestampsRegion buildTimestampsRegion(String regionName,
+ Properties properties)
+ throws CacheException;]]></programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The <literal>start</literal> method is invoked during
+ <literal>SessionFactory</literal> startup and allows the region
+ factory implementation to access all the configuration settings
+ and initialize itself. The <literal>stop</literal> method is
+ invoked during <literal>SessionFactory</literal> shutdown.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The various <literal>build***Region</literal> methods are invoked as
+ Hibernate detects it needs to cache different data. Hibernate can
+ invoke these methods multiple times, with different
+ <literal>regionName</literal> values; each call results in the
+ establishment of a separate area in the underlying JBoss Cache
+ instance(s). For example, if an application includes an
+ entity class <literal>org.example.Order</literal> and another entity
+ class <literal>org.example.LineItem</literal>, you would see two
+ calls to <literal>buildEntityRegion</literal>, one for the
+ <literal>Order</literal> class and one for the
+ <literal>LineItem</literal> class. (Note that it is possible, and
+ recommended, to configure one or more shared regions for entities,
+ collections and queries. See <xref linkend="eviction-organization"/>
+ for some examples.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ For each call to a <literal>build***Region</literal> method, the
+ region factory returns a region object implementing the
+ <literal>EntityRegion</literal>, <literal>CollectionRegion</literal>,
+ <literal>QueryResultsRegion</literal> or <literal>TimestampsRegion</literal>
+ interface. Each interface specifies the needed semantics for
+ caching the relevant type of data. Thereafter, the Hibernate core
+ invokes on that region object to manage reading and writing data
+ in the cache.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Next, we'll look at the architecture of how the JBoss Cache integration
+ implements these interfaces, first in the case where a single JBoss
+ Cache instance is used, next in the case where multiple instances are
+ desired.
+ </para>
+
+ </sect1>
+
+ <sect1 id="architecture-single-cache" revision="1">
+ <title>Single JBoss Cache Instance Architecture</title>
+
+ <para>
+ The following diagram illustrates the key elements involved when
+ a single JBoss Cache instance is used:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/single-cache.png" format="PNG" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/single-cache.png" format="PNG" align="center" />
+ </imageobject>
+ </mediaobject>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ For the single cache case, the user should specify
+ <literal>SharedJBossCacheRegionFactory</literal> as their
+ <literal>hibernate.cache.region.factory_class</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>As part of its startup process, te region factory delegates
+ responsibility for providing JBoss Cache instances to an
+ implementation of the
+ <literal>org.hibernate.cache.jbc2.CacheInstanceManager</literal>
+ interface. The region factory separately requests a JBoss Cache
+ instance for entities, one for collections, one for queries and one
+ for timestamps. Whether the <literal>CacheInstanceManager</literal>
+ provides the same underlying JBoss Cache instance for each
+ request or provides multiple caches is an implementation detail
+ of the <literal>CacheInstanceManager</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SharedJBossCacheRegionFactory</literal> creates an
+ instance of <literal>SharedCacheInstanceManager</literal> as
+ its <literal>CacheInstanceManager</literal>.
+ <literal>SharedCacheInstanceManager</literal> uses the JBoss Cache
+ configuration file specified by the user to create a single
+ <literal>org.jboss.cache.Cache</literal> instance, and provides
+ that same instance to the region factory when it requests the
+ cache for entities, collections, queries and timestamps.
+ <literal>SharedCacheInstanceManager</literal> also creates an
+ <literal>org.jgroups.ChannelFactory</literal> and passes it to
+ the <literal>Cache</literal>. The <literal>ChannelFactory</literal>
+ provides the cache with the <literal>org.jgroups.Channel</literal>
+ it uses for intra-cluster communication.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ At this point, the region factory has a reference to a cache
+ for entities, a reference to a cache for collections, one for
+ queries and one for timestamps. In this particular case, each
+ reference points to the same underlying <literal>Cache</literal>
+ instance. When core Hibernate invokes the
+ <literal>buildEntityRegion</literal> operation on the region
+ factory, it instantiates an implementation of the
+ <literal>EntityRegion</literal> interface that knows how to
+ interface with JBoss Cache, passing it a reference to its
+ entity cache. Same thing happens for collections, etc.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Core Hibernate invokes on the <literal>EntityRegion</literal>,
+ which in turn invokes read and write operations on the underlying
+ JBoss Cache. The cache uses its <literal>Channel</literal> to
+ propagate changes to its peers in the cluster.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When the <literal>SessionFactory</literal> shuts down, it
+ invokes <literal>stop()</literal> on the region factory, which
+ in turn ensures that the JBoss Cache instance is stopped and
+ destroyed (which in turn closes the JGroups channel).
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect1>
+
+ <sect1 id="architecture-cache-per-type" revision="1">
+ <title>Multiple JBoss Cache Instance Architecture</title>
+
+ <para>
+ The situation when multiple JBoss Cache instances are used is very
+ similar to the single cache case:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/multi-cache.png" format="PNG" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/multi-cache.png" format="PNG" align="center" />
+ </imageobject>
+ </mediaobject>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Here the user should specify
+ <literal>MultiplexedJBossCacheRegionFactory</literal> as their
+ <literal>hibernate.cache.region.factory_class</literal>. The
+ <literal>MultiplexedJBossCacheRegionFactory</literal> shares
+ almost all its code with <literal>SharedJBossCacheRegionFactory</literal>;
+ the main difference is it constructs a different <literal>CacheInstanceManager</literal>
+ implementation -- the <literal>MultiplexedCacheInstanceManager</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>MultiplexedCacheInstanceManager</literal> differs from
+ <literal>SharedCacheInstanceManager</literal> in that it does
+ not directly instantiate a cache. Rather, it creates an
+ instance of <literal>org.jboss.cache.CacheManager</literal>,
+ providing it with a <literal>ChannelFactory</literal> and the
+ location of the user-specified cache configuration file. The
+ <literal>CacheManager</literal> parses the configuration file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>MultiplexedCacheInstanceManager</literal> analyzes
+ Hibernate's configuration to determine the name of the desired
+ cache configuration for entities, collections, queries and
+ timestamps. See <xref linkend="sessionfactory-multiplexed"/> for
+ details. It then asks its <literal>CacheManager</literal> to
+ provide each needed cache. In the diagram, two different caches are needed:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>One, using the "optimistic-entity" configuration,
+ that is used for entities, collections and queries
+ </para>
+ </listitem>
+ </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para>Another, with the "timestamps-cache" configuration,
+ that is used for timestamps.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Both the "optimistic-entity" configuration and the "timestamps-cache"
+ configuration specify the use of the "udp" JGroups channel
+ configuration, so the <literal>CacheManager</literal>'s
+ <literal>ChannelFactory</literal> will ensure that they share
+ the underlying JGroups resources.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The way the region factory creates regions is exactly the same
+ as in the single JBoss Cache case; the only difference is the
+ region factory's internal reference to its timestamps cache
+ now points to a different cache object from the entity, collection
+ and query cache references.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/concepts.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/concepts.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/concepts.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,944 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<chapter id="concepts">
+
+ <title>Core Concepts</title>
+
+ <para>
+ This chapter focuses on some of the core concepts underlying how the
+ JBoss Cache-based implementation of the Hibernate Second Level Cache works.
+ There's a fair amount of detail, which certainly doesn't all need to be
+ mastered to use JBoss Cache with Hibernate. But, an understanding of some
+ of the basic concepts here will help a user understand what some of the
+ typical configurations discussed in the next chapter are all about.
+ </para>
+
+ <para>
+ If you want to skip the details for now, feel free to jump ahead to
+ <xref linkend="concepts-cache-matching-process"/>
+ </para>
+
+ <sect1 id="concepts-data-types" revision="1">
+ <title>Types of Cached Data</title>
+
+ <para>
+ The Second Level Cache can cache four different types of data: entities,
+ collections, query results and timestamps. Proper handling of each
+ of the types requires slightly different caching semantics. A major
+ improvement in Hibernate 3.3 is the addition of the
+ <literal>org.hibernate.cache.RegionFactory</literal> API, which
+ allows Hibernate to tell the caching integration layer what type
+ of data is being cached. Based on that knowledge, the cache integration
+ layer can apply the semantics appropriate to that type.
+ </para>
+
+ <sect2 id="concepts-data-types-entity" revision="1">
+ <title>Entities</title>
+ <para>
+ Entities are the most common type of data cached in the second level
+ cache. Entity caching requires the following semantics in a
+ clustered cache:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Newly created entities should only be stored on the node on
+ which they are created until the transaction in which they
+ were created commits. Until that transaction commits, the
+ cached entity should only be visible to that transaction.
+ After the transaction commits, cluster-wide the cache should
+ be in a "consistent" state. The cache is consistent if on
+ any node in the cluster, the new entity is either:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ stored in the cache, with all non-collection fields
+ matching what is in the database.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ not stored in the cache at all.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ Maintaining cache consistency basically requires that the
+ cluster-wide update messages that inform other nodes of
+ the changes made during a transaction be made
+ <emphasis>synchronously</emphasis> as part of the transaction
+ commit process. This means that the transaction thread will
+ block until the changes have been transmitted to all nodes
+ in the cluster, those nodes have updated their internal
+ state to reflect the changes, and have responded to the
+ originating node telling them of their success (or failure)
+ in doing so. JBoss Cache uses a 2 phase commit protocol, so
+ there will actually be 2 synchronous cluster-wide messages per
+ transaction commit. If any node in the cluster fails in the
+ initial prepare phase of the 2PC, the underlying transaction
+ will be rolled back and in the second phase JBoss
+ Cache will tell the other nodes in the cluster to revert
+ the change.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For existing entities that are modified in the course of a
+ transaction, the updated entity state should only be stored
+ on the node on which the modification occurred until the
+ transaction commits. Until that transaction commits, the
+ changed entity state should only be visible to that transaction.
+ After the transaction commits, cluster-wide the cache should
+ be in a "consistent" state, as described above.
+ </para>
+ <para>
+ Concurrent cache updates of the same entity anywhere in the
+ cluster should not be possible, as Hibernate will acquire
+ an exclusive lock on the database representation of the entity
+ before attempting to update the cache.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ A read of a cached entity holds a transaction scope read lock on
+ the relevant portion of cache. The presence of a read lock
+ held by one transaction should not prevent a concurrent read
+ by another transaction. Whether the presence of that read
+ lock prevents a concurrent write depends on whether the cache
+ is configured for READ_COMMITTED or REPEATABLE_READ semantics
+ and whether the cache is using optimistic locking. READ_COMMITTED
+ will allow a concurrent write to proceed; pessimistic locking
+ with REPEATABLE_READ will cause the write to block until the
+ transaction with the read lock commits. Optimistic locking
+ allows a REPEATABLE_READ semantic without forcing the writing
+ transaction to block.
+ </para>
+
+ <para>
+ A read of a cached entity does not result in any messages to
+ other nodes in the cluster or any cluster-wide read locks.
+ </para>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ The basic operation of storing an entity that has been directly
+ read from the database should have a <emphasis>fail-fast</emphasis>
+ semantic. This type of operation is referred to as a <emphasis>put</emphasis>
+ and is the most common type of operation. Basically, the
+ rules for handling new entities or entity updates discussed
+ above mean the cache's representation of an entity should
+ always match the database's. So, if a <literal>put</literal>
+ attempt encounters any existing copy of the entity in the cache,
+ it should assume that existing copy is either newer or the same
+ as what it is trying to store, and the <literal>put</literal>
+ attempt should promptly and silently abort, with no impact on
+ any ongoing transactions.
+ </para>
+
+ <para>
+ A <literal>put</literal> operation should not acquire any
+ long-lasting locks on the cache.
+ </para>
+
+ <para>
+ If the cache is configured to use replication, the replication
+ of the <literal>put</literal> should occur immediately, not
+ waiting for transaction commit and without the calling thread
+ needing to block waiting for responses from the other nodes
+ in the cluster. This is a "fire-and-forget" semantic that
+ JBoss Cache refers to as <emphasis>asynchronous replication</emphasis>.
+ When other nodes receive a replicated <literal>put</literal>,
+ they use the same fail-fast semantics as a local <literal>put</literal>
+ -- i.e. promptly and silently abort if the entity is already cached.
+ </para>
+
+ <para>
+ If the cache is configured to use invalidation, a
+ <literal>put</literal> should not result in any cluster-wide
+ message at all. The fact that one node in the cluster has
+ cached an entity should not invalidate another node's cache
+ of that same entity -- both caches are storing the same
+ information.
+ </para>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ A removal of an entity from the cache (i.e. to reflect a
+ DELETE from the underlying database) is basically a special
+ case of a modification; the removal should not be visible on
+ other nodes or to other transactions until the transaction that
+ did the remove commits. Cache consistency after commit means the
+ removed entity is no longer in the cache on any node in the
+ cluster.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="concepts-data-types-collection" revision="1">
+ <title>Collections</title>
+ <para>
+ Collection caching refers to the case where a cached entity has as
+ one of its fields a collection of other entities. Hibernate handles
+ this field specially in the second level cache; a special area in
+ the cache is created where the primary keys of the entities in the
+ collection are stored.
+ </para>
+
+ <para>
+ The management of collection caching is very similar to entity
+ caching, with a few differences:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ When a new entity is created that includes a collection,
+ no attempt is made to insert the collection into the cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When a transaction updates the contents of a collection,
+ no attempt is made to reflect the new contents of the collection
+ in the cache. Instead, the existing collection is simply
+ removed from the cache across the cluster, using the same
+ semantics as an entity removal.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ In essence, for collections Hibernate only supports cache reads and
+ the <literal>put</literal> operation, with any modification of the
+ collection resulting in cluster-wide invalidation of that collection
+ from the cache. If the collection field is accessed again, a new read from
+ the database will be done, followed by another cache <literal>put</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="concepts-data-types-queries" revision="1">
+ <title>Queries</title>
+
+ <para>
+ Hibernate supports caching of query results in the second level
+ cache. The HQL statement that comprised the query is cached (including
+ any parameter values) along with the primary keys of all entities
+ that comprise the result set.
+ </para>
+
+ <para>
+ The semantics of query caching are significantly different
+ from those of entity caching. A database row that reflects an
+ entity's state can be locked, with cache updates applied with that
+ lock in place. The semantics of entity caching take advantage of
+ this fact to help ensure cache consistency across the cluster.
+ There is no clear database analogue to a query result set that can
+ be efficiently locked to ensure consistency in the cache. As a result,
+ the fail-fast semantics used with the entity caching <literal>put</literal>
+ operation are not available; instead query caching has semantics
+ akin to an entity insert, including costly synchronous cluster
+ updates and the JBoss Cache two phase commit protocol. Furthermore,
+ Hibernate must agressively invalidate query results from the cache
+ any time any instance of one of the entity classes involved in the
+ query's WHERE clause changes. All such query results are invalidated,
+ even if the change made to the entity instance would not have affected
+ the query result. It is not performant for Hibernate to try to
+ determine if the entity change would have affected the query result,
+ so the safe choice is to invaldiate the query. See
+ <xref linkend="concepts-data-types-timestamps"/> for more on query
+ invalidation.
+ </para>
+
+ <para>
+ The effect of all this is that query caching is less likely to
+ provide a performance boost than entity/collection caching. Use it
+ with care and benchmark your application with it enabled and disabled.
+ Be careful about replicating query results; caching them locally
+ only on the node that executed the query will be more
+ performant unless the query is quite expensive, is very likely to
+ be repeated on other nodes, and is unlikely to be invalidated out
+ of the cache.<footnote><para>See the discussion of the
+ <literal>hibernate.cache.region.jbc2.query.localonly</literal>
+ property in <xref linkend="sessionfactory"/></para> for more on how
+ to only cache query results locally.</footnote>.
+ </para>
+
+ <para>
+ The JBoss Cache-based implementation of query caching adds a couple
+ of interesting semantics, both designed to ensure that query
+ cache operations don't block transactions from proceeding:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ The insertion of a query result into the cache is very much
+ like the insertion of a new entity. The difference is it
+ is possible for two transactions, possibly on different
+ nodes, to try to insert the same query at the same time.
+ (If this happened with entities, the database would throw
+ an exception with a primary key violation before any
+ caching work could start). This could lead to long delays
+ as the transactions compete for cache locks. To prevent
+ such delays, the cache integration layer will set a very
+ short (a few ms) lock timeout before attempting to cache a
+ query result. If there is any sort of locking conflict,
+ it will be detected quickly, and the attempt to cache the
+ result will be quietly abandonded.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A read of a query result does not result in any long-lasting
+ read lock in the cache. Thus, the fact that an uncommitted
+ transaction had read a query result does not prevent concurrent
+ transactions from subsequently invalidating that result and
+ caching a new result set. However, an insertion of a query result
+ into the cache will result in an exclusive write lock that
+ lasts until the transaction that did the insert commits; this
+ lock will prevent other transactions from reading the result.
+ Since the point of query caching is to improve performance,
+ blocking on a cache read for an extended period seems
+ suboptimal. So, the cache integration code will set a very
+ low lock acquisition timeout before attempting the read; if
+ there is a lock conflict, the read will silently fail,
+ resulting in a cache miss and a re-execution of the query
+ against the database.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-data-types-timestamps" revision="1">
+ <title>Timestamps</title>
+
+ <para>
+ Timestamp caching is an internal detail of query caching. As part of
+ each query result, Hibernate stores the timestamp of when the query
+ was executed. There is also a special area in the cache (the
+ <emphasis>timestamps cache</emphasis>) where, for each entity class,
+ the timestamp of the last update to any instance of that class is
+ stored. When a query result is read from the cache, its timestamp
+ is compared to the timestamps of all entities involved in the query.
+ If any entity has a later timestamp, the cached result is discarded
+ and a new query against the database is executed.
+ </para>
+
+ <para>
+ The semantics of of the timestamp cache are quite different from
+ those of the entity, collection and query caches.
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ For all nodes in the cluster, the contents of the timestamp
+ cache should be identical, with all timestamps represented.
+ For the other cache types, it is acceptable for some nodes
+ in the cluster to not store some data, as long as everyone
+ who does store an item stores the same thing. Not so with
+ timestamps -- everyone must store all timestamps. Using a
+ JBoss Cache configured for invalidation is not allowed for
+ the timestamps cache. Further, configuring JBoss Cache
+ eviction to remove old or infrequently used data from the
+ timestamps cache should not be done. Also, when a new node
+ joins a running cluster, it must acquire the current state of all
+ timestamps from another member, performing what is known as an
+ <emphasis>initial state transfer</emphasis>.
+ For other cache types, an initial state transfer is not
+ required.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A timestamp represents an entire entity class, not a single
+ instance. Thus it is quite likely that two concurrent
+ transactions will both attempt to update the same timestamp.
+ These updates need to be serialized, but no long lasting
+ exclusive lock on the timestamp is held.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ As soon as a timestamp is updated, the new value needs to be
+ propagated around the cluster. Waiting until the transaction
+ that changed the timestamp commits is inadequate. So, changes
+ to timestamps can be quite "chatty" in terms of how many
+ messages are sent around the cluster. Sending the timestamp
+ update messages synchronously would have a serious impact
+ on performance, and would quite likely result in
+ cluster-wide lock conflicts that would prevent transactions
+ from progressing for tens of seconds at a time. To mitigate
+ these issues, timestamp updates are sent asynchronously.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="concepts-cache-attributes" revision="1">
+ <title>Key JBoss Cache Behaviors</title>
+
+ <para>
+ JBoss Cache is a very flexible tool and includes a great number of
+ configuration options. See the <emphasis>JBoss Cache User Guide</emphasis>
+ for an in depth discussion of these options. Here we focus on the
+ main concepts that are most important to the Second Level Cache use case.
+ This discussion will focus on concepts; see <xref linkend="jbc-config"/> for
+ details on the actual configurations involved.
+ </para>
+
+ <sect2 id="concepts-cache-attr-repl" revision="1">
+ <title>Replication vs. Invalidation vs. Local Mode</title>
+
+ <para>
+ JBoss Cache provides three different choices for how a node in the
+ cluster should interact with the rest of the cluster when its local
+ state is updated:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Replication:</emphasis> The updated cache will
+ send its new state (e.g. the new values for an entity's fields)
+ to the other members of the cluster. This is heavy in terms
+ of the size of network traffic, since the new state needs to
+ be transmitted. It also has the effect forcing the data that
+ is cached in each node in the cluster to be the same, even if
+ the users accessing the various nodes are interested in
+ different data. So, if a user on node A reads an
+ <literal>Order</literal> entity with primary
+ key <literal>12343439485030</literal> from the database,
+ with replication that entity will be cached on every node
+ in the cluster, even though no other users are interested
+ in that particular <literal>Order</literal>.
+ </para>
+
+ <para>
+ Because of these downsides, replication is generally not the
+ best choice for entity, collection and query caching.
+ However, in a cluster <emphasis>replication is the only
+ valid choice for the timestamps cache</emphasis>.
+ </para>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ <emphasis>Invalidation:</emphasis> The updated cache will
+ send a message to the other members of the cluster telling
+ them that a particular piece of data (e.g. a particular entity)
+ has been modified. Upon receipt of this message, the other
+ nodes will remove this data from their local cache, if it
+ is stored there. Invalidation is lighter than replication
+ in terms of network traffic, since only the "id" of the
+ data needs to be transmitted, not the entire new state.
+ The downside to invalidation is that if the invalidated
+ data is needed again, it has to be re-read from the database.
+ However, in most cases data that many nodes in the cluster
+ all want to have in memory is not data that is frequently
+ changed.
+ </para>
+
+ <para>
+ Invalidation makes no sense for query caching; if it is
+ used for a query cache region the Hibernate/JBoss Cache
+ integration will detect this and switch any query cache
+ related calls to Local mode. Invalidation must not be used
+ for timestamp caching; Hibernate will throw an exception
+ during session factory startup if it finds that it is.
+ </para>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ <emphasis>Local:</emphasis> The updated cache does not even
+ know if there are any other nodes, and will not attempt
+ to update them. If JBoss Cache is used as a Second
+ Level Cache in a non-clustered environment, Local mode
+ should be used. <emphasis>If there is a cluster, Local
+ mode should never be used for entity, collection or
+ timestamp caching.</emphasis> Local mode can be used
+ for query caching in a cluster, since the replicated
+ timestamps cache will ensure that outdated cached queries
+ are not used. Often Local mode is the best choice for
+ query caching, as query results can be large and the cost
+ of replicating them high.
+ </para>
+
+ <para>
+ If the same underlying JBoss Cache instance is used for
+ the query cache and any of the other caches, the
+ <literal>SessionFactory</literal> can be configured to suppress
+ replication of the queries, essentially making the queries
+ operate in Local mode. This is done by adding the following
+ configuration:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.region.jbc2.query.localonly=true]]></programlisting>
+
+ <para>
+ If the JBoss Cache instance that the query cache is using
+ is configured for invalidation, setting this property isn't
+ even necessary; the Hibernate/JBoss Cache integration will
+ detect this condition and switch any query cache-related
+ calls to Local mode.
+ </para>
+
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="concepts-cache-attr-sync" revision="1">
+ <title>Synchronous vs. Asynchronous</title>
+
+ <para>
+ In JBoss Cache terms, <emphasis>synchronous</emphasis> vs.
+ <emphasis>asynchronous</emphasis> refers to whether a thread that
+ initiates a cluster-wide message blocks until that message has been
+ received, processed and acknowledged by the other members of the
+ cluster. Synchronous means the thread blocks; asynchronous means
+ the message is sent and the thread immediately returns; more of a
+ "fire and forget". An example of a message would be a set of cache
+ inserts, updates and removes sent out to the cluster as part of a
+ transaction commit.
+ </para>
+
+ <para>
+ In almost all cases, the cache should be configured to use synchronous
+ messages, as these are the only way to ensure data consistency
+ across the cluster. JBoss Cache supports programatically overriding
+ the default configured behavior on a per-call basis, so for the
+ special cases where sending a message asynchronously is appropriate,
+ the Hibernate/JBoss Cache integration code will force the call
+ to go asynchronously. So, configure your caches to use
+ synchronous messages.
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-cache-attr-lock" revision="1">
+ <title>Locking Scheme</title>
+
+ <para>
+ JBoss Cache supports both optimistic and pessimistic locking schemes.
+ See the <emphasis>JBoss Cache User Guide</emphasis> for an in depth
+ discussion of these options. In the Second Level Cache use case, the
+ main benefit of optimistic locking is that updates of cached entities
+ by one transaction do not block reads of the cached entity by other
+ transactions, yet REPEATABLE_READ semantics are preserved. Optimistic
+ locking has a higher level of runtime overhead, however.
+ </para>
+
+ <para>
+ If you are using optimistic locking and data versioning in Hibernate
+ for your entities, you should use it in the entity cache as well.
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-cache-attr-state" revision="1">
+ <title>Initial State Transfer</title>
+
+ <para>
+ When a new node joins a running cluster, it can request from an
+ existing member a copy of that member's current cache contents.
+ This process is known as an <emphasis>initial state transfer</emphasis>.
+ Doing an initial state transfer allows the new member to have a
+ "hot cache"; i.e. as user requests come in, data will already be
+ cached, helping avoid an initial set of reads from the database.
+ </para>
+
+ <para>
+ However, doing an initial state transfer comes at a cost. The node
+ providing the state needs to lock its entire tree, serialize it and
+ send it over the network. This could be a large amount of data and
+ the transfer could take a considerable period of time to process.
+ While the transfer is ongoing, the state provider is holding locks
+ on its cache, preventing any local or replicated updates from
+ proceeeding. All work around the cache can come to a halt for a period.
+ </para>
+
+ <para>
+ Because of this cost, we generally recommend avoiding initial state
+ transfers in the second level cache use case. The exception to this
+ is the timestamps cache. <emphasis>For the timestamps cache, an
+ initial state transfer is required.</emphasis>
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-cache-attr-eviction" revision="1">
+ <title>Cache Eviction</title>
+
+ <para>
+ <emphasis>Eviction</emphasis> refers to the process by which old,
+ relatively unused, or excessively voluminous data can be dropped
+ from the cache, allowing the cache to remain within a memory budget.
+ Generally, applications that use the Second Level Cache should
+ configure eviction. See <xref linkend="eviction"/> for details.
+ </para>
+ </sect2>
+
+ <sect2 id="concepts-cache-attr-misc" revision="1">
+ <title>Buddy Replication and Cache Loading</title>
+
+ <para>
+ <emphasis>Buddy replication</emphasis> refers to a JBoss Cache feature
+ whereby each node in the cluster replicates its cached data to a
+ limited number (often one) of "buddies" rather than to all nodes
+ in the cluster. <emphasis>Buddy replication should not be used in a
+ Second Level Cache</emphasis>. It is intended for use cases where
+ one node in the cluster "owns" some data , and just wants to make a
+ backup copy of the data to provide high availability. The data
+ (e.g. a web session) is never meant to be accessed simultaneously on
+ two different nodes in the cluster. Second Level Cache data does
+ not meet this "ownership" criteria; entities are meant to be
+ simultaneously usable by all nodes in the cluster.
+ </para>
+
+ <para>
+ <emphasis>Cache Loading</emphasis> refers to a JBoss Cache feature
+ whereby cached data can be persisted to disk. The persisted data
+ either serves as a highly available copy of the data in case of
+ a cluster restart, or as an overflow area for when the amount of
+ cached data exceeds an application's memory budget. <emphasis>Cache
+ loading should not be used in a Second Level Cache</emphasis>.
+ The underlying database from which the cached data comes already
+ serves the same functions; adding a cache loader to the mix is
+ just wasteful.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="concepts-cache-matching" revision="1">
+ <title>Matching JBC Behavior to Types of Data</title>
+
+ <para>
+ The preceding discussion has gone into a lot of detail about what
+ Hibernate wants to accomplish as it caches data, and what JBoss Cache
+ configuration options are available. What should be clear is that the
+ configurations that are best for caching one type of data are not
+ the best (and are sometimes completely incorrect) for other types.
+ Entities likely work best with synchronous invalidation; timestamps
+ <emphasis>require</emphasis> replication; query caching might do
+ best in local mode.
+ </para>
+
+ <para>
+ Prior to Hibernate 3.3 and JBoss Cache 2.1, the conflicting requirements
+ between the different cache types led to a real dilemna, particularly
+ if query caching was enabled. This conflict arose because all four
+ cache types needed to share a single underlying cache, with a single
+ configuration. If query caching was enabled, the requirements of the
+ timestamps cache basically forced use of synchronous replication,
+ which is the worst performing choice for the more critical
+ entity cache and is often inappropriate for the query cache.
+ </para>
+
+ <para>
+ With Hibernate 3.3 and JBoss Cache 2.1 it has become
+ possible, even easy, to use separate underlying JBoss Cache instances
+ for the different cache types. As a result, the entity cache can be
+ optimally configured for entities while the necessary configuration
+ for the timestamps cache is maintained.
+ </para>
+
+ <para>
+ There were three key changes that make this improvement possible:
+ </para>
+
+ <sect2 id="concepts-cache-matching-region-factory" revision="1">
+ <title>The <literal>RegionFactory</literal> Interface</title>
+
+ <para>
+ As mentioned previously, Hibernate 3.3 introduced the
+ <literal>RegionFactory</literal> API as its mechanism for managing
+ the Second Level Cache. This API makes it possible for implementations
+ to know at all times whether they are working with entities,
+ collections, queries or timestamps. That knowledge allows the
+ Hibernate/JBoss Cache integration layer to make the best use of the
+ various options JBoss Cache provides.
+ </para>
+
+ <para>
+ A Hibernate user doesn't need to understand the <literal>RegionFactory</literal>
+ API in any detail at all; the main point is internally it makes
+ possible independent management of the different cache types.
+ </para>
+ </sect2>
+
+ <sect2 id="concepts-cache-matching-cache-manager" revision="1">
+ <title>The <literal>CacheManager</literal> API</title>
+
+ <para>
+ The <literal>CacheManager</literal> API is a new feature of JBoss
+ Cache 2.1. It provides an API for managing multiple distinct
+ JBoss Cache instances in the same VM. Basically a
+ <literal>CacheManager</literal> is instantiated and provided a set
+ of <emphasis>named</emphasis> cache configurations. An application
+ like the Hibernate/JBoss Cache integration layer accesses the
+ <literal>CacheManager</literal> and asks for a cache configured with
+ a particular named configuration.
+ </para>
+
+ <para>
+ Again,a Hibernate user doesn't need to understand the
+ <literal>CacheManager</literal>; it's an internal detail. The thing
+ to understand is that the task of a Hibernate Second Level Cache user
+ is to:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Provide a set of named JBoss Cache configurations in an XML
+ file (or just use the default set included in the
+ <literal>jbc2-configs.xml</literal> file found in the
+ <literal>org.hibernate.cache.jbc2.builder</literal> package
+ in <literal>hibernate-jbosscache2.jar</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Tell Hibernate which cache configurations to use for entity,
+ collection, query and timestamp caching. In practice, this
+ can be quite simple, as there is a reasonable set of defaults.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </para>
+
+ <para>
+ See <xref linkend="configuration"/> for more on how to do this.
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-cache-matching-jgroups" revision="1">
+ <title>Sharable JGroups Resources</title>
+
+ <para>
+ JGroups is the group communication library JBoss Cache uses to send
+ messages around a cluster. Each cache has a JGroups
+ <literal>Channel</literal>; different channels
+ around the cluster that have the same name and compatible
+ configurations detect each other and form a group for message
+ transmission.
+ </para>
+
+ <para>
+ A <literal>Channel</literal> is a fairly heavy object, typically
+ using a good number of threads, several sockets and some good sized
+ network I/O buffers. Creating multiple different channels in the
+ same VM was therefore costly, and was an administrative burden as
+ well, since each channel would need separate configuration to use
+ different network addresses or ports. Architecturally, this
+ mitigated against having multiple JBoss Cache instances in an
+ application, since each would need its own <literal>Channel</literal>.
+ </para>
+
+ <para>
+ Added in JGroups 2.5 and much improved in the JGroups 2.6
+ series is the concept of sharable JGroups resources. Basically,
+ the heavyweight JGroups elements can be shared. An application
+ (e.g. the Hibernate/JBoss Cache integration layer) uses a JGroups
+ <literal>ChannelFactory</literal>. The <literal>ChannelFactory</literal>
+ is provided with a set of <emphasis>named</emphasis> channel
+ configurations. When a <literal>Channel</literal> is needed (e.g.
+ by a JBoss Cache instance), the application asks the
+ <literal>ChannelFactory</literal> for the channel by name. If
+ different callers ask for a channel with the same name, the
+ <literal>ChannelFactory</literal> ensures that they get
+ channels that share resources.
+ </para>
+
+ <para>
+ The effect of all this is that if a user wants to use four separate
+ JBoss Cache instances, one for entity caching, one for collection
+ caching, one for query caching and one for timestamp caching, those
+ four caches can all share the same underlying JGroups resources.
+ </para>
+
+ <para>
+ The task of a Hibernate Second Level Cache user is to:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Provide a set of named JGroups configurations in an XML file
+ (or just use the default set included in the
+ <literal>jgroups-stacks.xml</literal> file found in the
+ <literal>org.hibernate.cache.jbc2.builder</literal> package
+ in the <literal>hibernate-jbosscache2.jar</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Tell Hibernate where to find that set of configurations
+ on the classpath. See <xref linkend="sessionfactory"/> for
+ details on how to do this. This is not necessary if the
+ default set included in <literal>hibernate-jbosscache2.jar</literal>
+ is used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In the JBoss Cache configurations you are using specify
+ the name of the channel you want to use. This should be
+ one of the named configurations in the JGroups XML file.
+ The default set of JBoss Cache configurations found in the
+ <literal>hibernate-jbosscache2.jar</literal> already have
+ appropriate default choices. See <xref linkend="jbc-config-jgroups"/>
+ for details on how to set this if you don't wish to use the
+ defaults.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ See <xref linkend="jgroups-config"/> for more on JGroups.
+ </para>
+
+ </sect2>
+
+ <sect2 id="concepts-cache-matching-process" revision="1">
+ <title>Bringing It All Together</title>
+
+ <para>
+ So, we've seen that Hibernate caches up to four different types of
+ data (entities, collections, queries and timestamps) and that
+ Hibernate 3.3 + JBoss Cache 2 gives you the flexibility to use a
+ separate underlying JBoss Cache, with different behavior, for each
+ type. You can actually deploy four separate caches, one for each type.
+ </para>
+
+ <para>
+ In practice, four separate caches are unnecessary. For example,
+ entities and collection caching have similar enough semantics that
+ there is no reason not to share a JBoss Cache instance between them.
+ The queries can usually use the same cache as well. Similarly,
+ queries and timestamps can share a JBoss Cache instance configured
+ for replication, with the
+ <literal>hibernate.cache.region.jbc2.query.localonly=true</literal>
+ configuration letting you turn off replication for the queries if
+ you want to.
+ </para>
+
+ <para>
+ Here's a decision tree you can follow:
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Decide if you want to enable query caching.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Decide if you want to use invalidation or replication for
+ your entities and collections. Invalidation is generally
+ recommended for entities and collections.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If you want invalidation, and you want query
+ caching, you will need two JBoss Cache instances, one
+ with synchronous invalidation for the entities and collections,
+ and one with synchronous replication for the timestamps.
+ The queries will go in the timestamp cache if you want them
+ to replicate; they can go with the entities and collections
+ otherwise.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If you want invalidation but don't want query caching, you can
+ use a single JBoss Cache instance, configured for synchronous
+ invalidation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If you want replication, whether or not you want query caching,
+ you can use a single JBoss Cache instance, configured for
+ synchronous replication.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you are using query caching, from the above decision tree
+ you've either got your timestamps sharing a cache with other
+ data types, or they are by themselves. Either way,
+ the cache being used for timestamps <emphasis>must have
+ initial state transfer enabled</emphasis>. Now, if the timestamps
+ are sharing a cache with entities, collections or queries,
+ decide whether you want initial state transfer for that other
+ data. See <xref linkend="concepts-cache-attr-state"/>
+ for the implications of this. If you don't want initial state
+ transfer for the other data, you'll need to have a separate
+ cache for the timestamps.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Finally, if your queries are sharing a cache configured
+ for replication, decide if you want the cached query results
+ to replicate. (The timestamps cache <emphasis>must</emphasis>
+ replicate.) If not, you'll want to set the
+ <literal>hibernate.cache.region.jbc2.query.localonly=true</literal>
+ option when you configure your <literal>SessionFactory</literal>
+ </para>
+ </listitem>
+ </orderedlist>
+
+ </para>
+
+ <para>
+ Once you've made these decisions, you know whether you need just one
+ underlying JBoss Cache instance, or more than one.
+ Next we'll see how to actually configure the setup you've selected.
+ </para>
+ </sect2>
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/configuration.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,1052 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<chapter id="configuration">
+
+ <title>Configuration</title>
+
+ <para>
+ There are three main areas of configuration involved in using JBoss Cache
+ 2 for your Hibernate Second Level Cache: configuring the Hibernate
+ <literal>SessionFactory</literal>, configuring the underlying JBoss Cache
+ instance(s), and configuring the JGroups <literal>ChannelFactory</literal>.
+ If you use the standard JBoss Cache and JGroups configurations that ship
+ with the <literal>hibernate-jbosscache2.jar</literal>, then all you
+ need to worry about is the <literal>SessionFactory</literal> configuration.
+ </para>
+
+ <sect1 id="sessionfactory" revision="1">
+ <title>Configuring the Hibernate Session Factory</title>
+
+ <sect2 id="sessionfactory-overview" revision="1">
+ <title>Basics</title>
+
+ <para>
+ There are four basic steps to configuring the
+ <literal>SessionFactory</literal>:
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Tell Hibernate you whether to enable caching of entities and
+ collections. No need to set this property if you don't:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_second_level_cache=true]]></programlisting>
+
+ </listitem>
+
+ <listitem>
+ <para>
+ Tell Hibernate you want to enable caching of
+ query results. No need to set this property if you don't:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_query_cache=true]]></programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have enabled caching of query results, tell Hibernate if
+ you want to suppress costly replication of those results around
+ the cluster. No need to set this property if you want query
+ results replicated:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.region.jbc2.query.localonly=true]]></programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ Finally, you need to tell Hibernate what <literal>RegionFactory</literal>
+ implementation to use to manage your caches. You do this by
+ setting the <literal>hibernate.cache.region.factory_class</literal>
+ configuration option.
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.region.factory_class=
+ org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory]]></programlisting>
+
+ <para>
+ To determine the correct factory class, you must decide
+ whether you need just one underlying JBoss
+ Cache instance to support the different types of caching
+ you will be doing, or whether you need more than one. See
+ <xref linkend="concepts"/> and particularly
+ <xref linkend="concepts-cache-matching-process"/> for more
+ on how to make that decision. Once you know the answer,
+ see <xref linkend="sessionfactory-factories"/> to find the
+ factory class that best meets your needs.
+ </para>
+
+ <para>
+ Once you've specified your factory class, there may be
+ other factory-class-specific configurations you may
+ want to set. The available options are explained below.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </para>
+
+
+ </sect2>
+
+ <sect2 id="sessionfactory-factories" revision="1">
+ <title>Specifying the <literal>RegionFactory</literal> Implementation</title>
+
+ <para>
+ Hibernate 3.3 ships with the following <literal>RegionFactory</literal>
+ implementations that work with JBoss Cache 2. Select the
+ one that is appropriate to your needs and use it with
+ the <literal>hibernate.cache.region.factory_class</literal>
+ configuration option.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory</literal></term>
+ <listitem>
+ <para>
+ Instantiates a single JBoss Cache instance for use with all
+ cache data types (entities, collections, queries, timestamps).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.cache.jbc2.JndiSharedJBossCacheRegionFactory</literal></term>
+ <listitem>
+ <para>
+ Uses a single JBoss Cache instance for all cache data types.
+ However, does not instantiate the JBoss Cache instance itself;
+ instead looks for an existing cache in JNDI. This allows
+ sharing of a single JBoss Cache instance across multiple
+ Hibernate session factories running in the same environment.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory</literal></term>
+ <listitem>
+ <para>
+ Supports using multiple JBoss Cache instances with different
+ cache data types (entities, collections, queries, timestamps)
+ assigned to different JBoss Cache instances. Instantiates a
+ JBoss Cache <literal>CacheManager</literal> to manage the
+ JBoss Cache instances.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.cache.jbc2.JndiMultiplexedJBossCacheRegionFactory</literal></term>
+ <listitem>
+ <para>
+ Functions like <literal>JndiMultiplexedJBossCacheRegionFactory</literal>,
+ but instead of instantiating its own <literal>CacheManager</literal>
+ it looks for an existing one in JNDI. This allows
+ sharing of the various JBoss Cache instances across multiple
+ Hibernate session factories running in the same environment.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect2>
+
+ <sect2 id="sessionfactory-shared" revision="1">
+ <title>The <literal>SharedJBossCacheRegionFactory</literal></title>
+
+ <para>
+ The <literal>SharedJBossCacheRegionFactory</literal> supports a
+ number of additional configuration options:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.shared</literal></term>
+ <listitem>
+ <para>
+ Classpath or filesystem resource containing JBoss Cache
+ configuration settings the underlying cache should use.
+ Default value is <literal>treecache.xml</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.multiplexer.stacks</literal></term>
+ <listitem>
+ <para>
+ Classpath or filesystem resource containing JGroups protocol
+ stack configurations the <literal>ChannelFactory</literal>
+ should use. Default is
+ <literal>org/hibernate/cache/jbc2/builder/jgroups-stacks.xml</literal>,
+ a file found in the <literal>hibernate-jbosscache2.jar</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Note that the default <literal>treecache.xml</literal> file does
+ not exist; it is up to the user to provide it.
+ </para>
+ </sect2>
+
+ <sect2 id="sessionfactory-shared-jndi" revision="1">
+ <title>The <literal>JndiSharedJBossCacheRegionFactory</literal></title>
+
+ <para>
+ The <literal>JndiSharedJBossCacheRegionFactory</literal> supports an
+ additional configuration option:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.shared</literal></term>
+ <listitem>
+ <para>
+ Specifies the JNDI name under which the JBoss Cache instance
+ to use is bound. Note that although this configuration property
+ has the same name as the one used by <literal>SharedCacheInstanceManager</literal>,
+ the meaning here is different. Note also that in this class'
+ usage of the property, there is no default value -- the user
+ must specify the property.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ The <literal>JndiSharedJBossCacheRegionFactory</literal> requires
+ that the JBoss Cache instance is already bound in JNDI; it will
+ not create and bind one if it isn't. It is up to the the user
+ to ensure the cache is created and bound in JNDI before the
+ Hibernate <literal>SessionFactory</literal> is created.
+ </para>
+
+ </sect2>
+
+ <sect2 id="sessionfactory-multiplexed" revision="1">
+ <title>The <literal>MultiplexedJBossCacheRegionFactory</literal></title>
+
+ <para>
+ The <literal>MultiplexedJBossCacheRegionFactory</literal> supports a
+ number of additional configuration options:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.configs</literal></term>
+ <listitem>
+ <para>
+ Classpath or filesystem resource containing JBoss Cache
+ configurations the <literal>CacheManager</literal> should
+ use. Default is
+ <literal>org/hibernate/cache/jbc2/builder/jbc2-configs.xml</literal>,
+ a file found in the <literal>hibernate-jbosscache2.jar</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.multiplexer.stacks</literal></term>
+ <listitem>
+ <para>
+ Classpath or filesystem resource containing JGroups protocol
+ stack configurations the <literal>ChannelFactory</literal>
+ should use. Default is
+ <literal>org/hibernate/cache/jbc2/builder/jgroups-stacks.xml</literal>,
+ a file found in the <literal>hibernate-jbosscache2.jar</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.entity</literal></term>
+ <listitem>
+ <para>
+ Name of the configuration that should be used for entity caches.
+ Default value is <literal>optimistic-entity</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.collection</literal></term>
+ <listitem>
+ <para>
+ Name of the configuration that should be used for collection caches.
+ No default value, as by default we try to use the same JBoss Cache
+ instance that is used for entity caching.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.ts</literal></term>
+ <listitem>
+ <para>
+ Name of the configuration that should be used for timestamp caches.
+ Default value is <literal>timestamps-cache</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cfg.query</literal></term>
+ <listitem>
+ <para>
+ Name of the configuration that should be used for query caches.
+ By default, tries to use the same cache as is used for
+ entity caching. If there is no entity cache or it uses
+ invalidation, the default value is <literal>local-query</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Many of the default values name JBoss Cache configurations in the
+ standard <literal>jbc2-configs.xml</literal> file found in the
+ <literal>hibernate-jbosscache2.jar</literal>. See
+ <xref linkend="jbc-config-multiple-std"/> for details on those
+ configurations. If you want to set
+ <literal>hibernate.cache.region.jbc2.configs</literal> and use your
+ own JBoss Cache configuration file, you can still take advantage of
+ these defaults names; just name the configurations in your file
+ to match.
+ </para>
+
+ <para>
+ This is all looks a bit complex, so let's show what happens if you
+ just configure the defaults, with query caching enabled:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_second_level_cache=true
+hibernate.cache.use_query_cache=true
+hibernate.cache.region.factory_class=
+ org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory]]></programlisting>
+
+ <para>
+ You would end up using two JBoss Cache instances:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>One, for the entities, collection and queries, would use the
+ <literal>optimistic-entity</literal> configuration. This cache
+ would use optimistic locking, synchronous invalidation and would
+ disable initial state transfer.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The second, for timestamps, would use the
+ <literal>timestamps-cache</literal> configuration. This cache
+ would use pessimistic locking, asynchronous replication and would
+ enable initial state transfer.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ See <xref linkend="jbc-config-multiple-std"/> for more on these
+ standard cache configurations.
+ </para>
+
+ <para>
+ If you hadn't set <literal>hibernate.cache.use_query_cache=true</literal>
+ you'd just have the single <literal>optimistic-entity</literal> cache,
+ shared by the entities and collections.
+ </para>
+ </sect2>
+
+ <sect2 id="sessionfactory-multiplexed-jndi" revision="1">
+ <title>The <literal>JndiMultiplexedJBossCacheRegionFactory</literal></title>
+
+ <para>
+ The <literal>JndiMultiplexedJBossCacheRegionFactory</literal>
+ supports an additional configuration option:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>hibernate.cache.region.jbc2.cachefactory</literal></term>
+ <listitem>
+ <para>
+ Specifies the JNDI name under which the
+ <literal>CacheManager</literal> to use is bound.
+ There is no default value -- the user must specify the property.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ The <literal>JndiMultiplexedJBossCacheRegionFactory</literal> requires
+ that the JBoss Cache <literal>CacheManager</literal> is already
+ bound in JNDI; it will not create and bind one if it isn't. It is
+ up to the the user to ensure the cache is <literal>CacheManager</literal>
+ and bound in JNDI before the Hibernate <literal>SessionFactory</literal>
+ is created.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="jbc-config" revision="1">
+
+ <title>Configuring JBoss Cache</title>
+
+ <para>
+ JBoss Cache provides a great many different configuration options;
+ here we are just going to look at a few that are most relevant
+ to the Second Level Cache use case. Please see the
+ <emphasis>JBoss Cache User Guide</emphasis> for full details.
+ </para>
+
+ <sect2 id="jbc-config-single" revision="1">
+ <title>Configuring a Single Standalone Cache</title>
+
+ <para>
+ To configure a single standalone cache (i.e. for use by a
+ <literal>SharedJBossCacheRegionFactory</literal>), you need to
+ create a standard JBoss Cache XML configuration file and place
+ it on the classpath. See the <emphasis>JBoss Cache User Guide</emphasis>
+ and the JBoss Cache distribution for examples of JBoss Cache
+ configuration files.
+ </para>
+ <para>
+ If the resource path to your file is <literal>treecache.xml</literal>,
+ the <literal>SharedJBossCacheRegionFactory</literal> will find it
+ by default; otherwise you will need to use a configuration option
+ to tell it where it is. See <xref linkend="sessionfactory-shared"/>
+ for instruction on how to do that.
+ </para>
+ </sect2>
+
+ <sect2 id="jbc-config-multiple" revision="1">
+ <title>Managing Multiple Caches via a CacheManager</title>
+
+ <para>
+ If you are using <literal>MultiplexedJBossCacheRegionFactory</literal>
+ you will need to provide a set of JBoss Cache configurations for
+ its <literal>CacheManager</literal> to use. (Or, use the set in the
+ <literal>jbc2-configs.xml</literal> file that ships with
+ <literal>hibernate-jbosscache2.jar</literal>.) The XML file used
+ by a <literal>CacheManager</literal> is very similar to the
+ usual config file used by a standalone cache; the biggest
+ difference is it can include multiple, named, configurations.
+ The format looks like this:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+
+<cache-configs>
+
+ <!-- A config appropriate for entity/collection caching. -->
+ <cache-config name="optimistic-entity">
+
+ <!-- Node locking scheme -->
+ <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+ ..... other configuration attributes
+
+ </cache-config>
+
+
+ <!-- A config appropriate for entity/collection caching that
+ uses pessimistic locking -->
+ <cache-config name="pessimistic-entity">
+
+ <!-- Node locking scheme -->
+ <attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
+
+ ..... other configuration attributes
+
+ </cache-config>
+
+</cache-configs>]]></programlisting>
+
+ <para>
+ Each <literal><cache-config></literal> element contains a complete
+ cache configuration, with the same contents as what you would place in
+ the <literal><mbean></literal> element in a standalone cache
+ configuration file. The <literal>name</literal> attribute on the
+ <literal><cache-config></literal> element provides the identifier
+ for the configuration; users of the <literal>CacheManager</literal>
+ will provide this name when requesting a JBoss Cache instance that uses
+ this configuration.
+ </para>
+
+ </sect2>
+
+ <sect2 id="jbc-config-detail" revision="1">
+ <title>JBoss Cache Configuration Details</title>
+
+ <para>
+ Let's look at how to specify a few of the JBoss Cache configuration
+ options that are most relevant to the Hibernate use case.
+ </para>
+
+ <sect3 id="jbc-config-mode" revision="1">
+ <title>CacheMode</title>
+
+ <para>
+ The JBoss Cache <emphasis>CacheMode</emphasis> attribute
+ encapsulates whether the cache uses replication, invalidation or
+ local mode, as well as whether messages should be synchronous
+ or asynchronous. See <xref linkend="concepts-cache-attr-repl"/>
+ and <xref linkend="concepts-cache-attr-sync"/> for a discussion of
+ these concepts.
+ </para>
+
+ <para>
+ The CacheMode is configured as follows:
+ </para>
+
+ <programlisting><![CDATA[<!-- Legal modes are LOCAL
+ REPL_ASYNC
+ REPL_SYNC
+ INVALIDATION_ASYNC
+ INVALIDATION_SYNC
+-->
+<attribute name="CacheMode">INVALIDATION_SYNC</attribute>]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="jbc-config-locking" revision="1">
+ <title>NodeLockingScheme</title>
+
+ <para>
+ The JBoss Cache <emphasis>NodeLockingScheme</emphasis> attribute
+ configures whether optimistic locking or pessimistic locking
+ should be used. See <xref linkend="concepts-cache-attr-lock"/>
+ for a discussion of locking.
+ </para>
+
+ <para>
+ The NodeLockingScheme is configured as follows:
+ </para>
+
+ <programlisting><![CDATA[<!-- Node locking scheme:
+ OPTIMISTIC
+ PESSIMISTIC (default)
+-->
+<attribute name="NodeLockingScheme">OPTIMISTIC</attribute>]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="jbc-config-jgroups" revision="1">
+ <title>JGroups <literal>Channel</literal> Configuration</title>
+
+ <para>
+ Each JBoss Cache instance (except those with CacheMode
+ LOCAL) will need a JGroups <literal>Channel</literal>. The cache
+ configuration needs to tell JGroups how to set up the channel's
+ protocol stack. This is configured as follows:
+ </para>
+
+ <programlisting><![CDATA[<attribute name="MultiplexerStack">udp</attribute>]]></programlisting>
+
+ <para>
+ An alternate approach is to include the full protocol stack
+ configuration in the JBoss Cache configuration:
+ </para>
+
+ <programlisting><![CDATA[<!-- JGroups protocol stack properties. -->
+<attribute name="ClusterConfig">
+ <config>
+ <UDP mcast_addr="228.10.10.10"
+ mcast_port="45588"
+ tos="8"
+
+ ... many more details
+
+ <pbcast.STATE_TRANSFER/>
+ <pbcast.FLUSH timeout="0"/>
+ </config>
+</attribute>]]></programlisting>
+
+ <para>
+ See <xref linkend="jgroups-config"/> for more on JGroups configuration.
+ </para>
+ </sect3>
+
+
+ <sect3 id="jbc-config-statetransfer" revision="1">
+ <title>Initial State Transfer</title>
+
+ <para>
+ See <xref linkend="concepts-cache-attr-state"/> for a discussion
+ of the concept of initial state transfer.
+ </para>
+ <para>
+ Initial State Transfer is configured as follows:
+ </para>
+
+ <programlisting><![CDATA[<!-- Whether or not to fetch state on joining a cluster. -->
+<attribute name="FetchInMemoryState">false</attribute>]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="jbc-config-marshalling" revision="1">
+ <title>Region-Based Marshalling</title>
+
+ <para>
+ JBoss Cache includes a feature called <emphasis>Region Based
+ Marshalling</emphasis> that helps ensure the correct
+ classloader is in place when objects are serialized and
+ deserialized as part of replication and invalidation
+ messages. This feature adds some overhead, but it allows
+ your cache to work in complex classloading environments
+ such as those found in many application servers. It can be
+ disabled if your application meets the following criteria:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ No cached entities use custom types (i.e. types persisted as
+ BLOBs or CLOBs or as a Hibernate UserType) in their
+ fields, and no entities use complex primary keys.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>OR</emphasis> all custom types and complex
+ primary key types are visible to the classloader that
+ loads JGroups.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Region based marshalling is configured as follows:
+ </para>
+
+ <programlisting><![CDATA[<!--
+ Whether to use marshalling or not. Default is "false".
+-->
+<attribute name="UseRegionBasedMarshalling">true</attribute>
+<!-- Must match the value of "UseRegionBasedMarshalling" -->
+<attribute name="InactiveOnStartup">true</attribute>]]></programlisting>
+
+ <para>
+ Region based marshalling is enabled in the standard cache
+ configurations that ship with
+ <literal>hibernate-jbosscache2.jar</literal>
+ </para>
+ </sect3>
+
+ <sect3 id="jbc-config-eviction" revision="1">
+ <title>Eviction</title>
+
+ <para>
+ This topic deserves a chapter of it's own. See
+ <xref linkend="eviction"/>.
+ </para>
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="jbc-config-multiple-std" revision="1">
+ <title>Standard JBoss Cache Configurations</title>
+
+ <para>
+ Hibernate ships with a number of standard JBoss Cache configurations
+ in the <literal>hibernate-jbosscache2.jar</literal>'s
+ <literal>jbc2-configs.xml</literal> file. The following table
+ highlights the key features of each configuration.
+ </para>
+
+ <table frame="topbot">
+ <title>Standard JBoss Cache Configurations</title>
+ <tgroup cols="6">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <colspec colname="c3" colwidth="1*"/>
+ <colspec colname="c4" colwidth="2*"/>
+ <colspec colname="c5" colwidth="1*"/>
+ <colspec colname="c6" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Valid For</entry>
+ <entry>Optimal For</entry>
+ <entry>CacheMode</entry>
+ <entry>Locking</entry>
+ <entry>State Transfer</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <property>optimistic-entity</property>
+ </entry>
+ <entry>
+ <property>E/C/Q</property>
+ </entry>
+ <entry>
+ <property>E/C/Q</property>
+ </entry>
+ <entry>
+ <property>INVALIDATION_SYNC</property>
+ </entry>
+ <entry>
+ <property>OPTIMISTIC</property>
+ </entry>
+ <entry>
+ <para>no</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>pessimistic-entity</property>
+ </entry>
+ <entry>
+ <property>E/C/Q</property>
+ </entry>
+ <entry>
+ <property>E/C/Q</property>
+ </entry>
+ <entry>
+ <property>INVALIDATION_SYNC</property>
+ </entry>
+ <entry>
+ <property>PESSIMISTIC</property>
+ </entry>
+ <entry>
+ <para>no</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>local-query</property>
+ </entry>
+ <entry>
+ <property>Q</property>
+ </entry>
+ <entry>
+ <property>Q</property>
+ </entry>
+ <entry>
+ <property>LOCAL</property>
+ </entry>
+ <entry>
+ <property>PESSIMISTIC</property>
+ </entry>
+ <entry>
+ <para>no</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>replicated-query</property>
+ </entry>
+ <entry>
+ <property>Q</property>
+ </entry>
+ <entry>
+ <property>--</property>
+ </entry>
+ <entry>
+ <property>LOCAL</property>
+ </entry>
+ <entry>
+ <property>OPTIMISTIC</property>
+ </entry>
+ <entry>
+ <para>no</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>timestamps-cache</property>
+ </entry>
+ <entry>
+ <property>T</property>
+ </entry>
+ <entry>
+ <property>T</property>
+ </entry>
+ <entry>
+ <property>REPL_ASYNC</property>
+ </entry>
+ <entry>
+ <property>PESSIMISTIC</property>
+ </entry>
+ <entry>
+ <para>yes</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>optimistic-shared</property>
+ </entry>
+ <entry>
+ <property>E/C/Q/T</property>
+ </entry>
+ <entry>
+ <property>--</property>
+ </entry>
+ <entry>
+ <property>REPL_SYNC</property>
+ </entry>
+ <entry>
+ <property>OPTIMISTIC</property>
+ </entry>
+ <entry>
+ <para>yes</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>pessimistic-shared</property>
+ </entry>
+ <entry>
+ <property>E/C/Q/T</property>
+ </entry>
+ <entry>
+ <property>--</property>
+ </entry>
+ <entry>
+ <property>REPL_SYNC</property>
+ </entry>
+ <entry>
+ <property>PESSIMISTIC</property>
+ </entry>
+ <entry>
+ <para>yes</para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ A few notes on the above table:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Valid For</emphasis> and <emphasis>Optimal For</emphasis>
+ describe the suitability of the configuration for the four types
+ of data -- Entities, Collections, Queries and Timestamps.
+ </para>
+ </listitem>
+ <listitem>
+ <para><emphasis>State Transfer</emphasis> indicates whether an
+ initial state transfer will be performed when a cache region is
+ activated.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Each of the configurations uses the <literal>udp</literal> JGroups
+ protocol stack configuration (except <literal>local-query</literal>,
+ which doesn't use JGroups at all). Since they all use the same
+ stack, if more than one of these caches is created they will share
+ their JGroups resources. See <xref linkend="jgroups-config-std"/>
+ for a description of the standard stacks.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ These standard configurations are a good choice for many applications.
+ The primary reason users may want to use their own configurations is
+ to support more complex eviction setups. See <xref linkend="eviction"/>
+ for more on the kinds of things you can do with eviction.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="jgroups-config" revision="1">
+ <title>JGroups Configuration</title>
+
+ <para>
+ JGroups configuration is a complex area that goes well beyond the scope
+ of this document. Users interested in exploring the details are
+ encouraged to visit the JGroups website at http://www.jgroups.org as
+ well as the JGroups wiki page at jboss.com.
+ </para>
+
+ <para>
+ The <literal>jgroups-stacks.xml</literal> file found in the
+ <literal>org.hibernate.cache.jbc2.builder</literal> package
+ in the <literal>hibernate-jbosscache2.jar</literal> provides a good
+ set of standard JGroups configurations; these should be suitable for
+ most needs. If you need to create your own configuration set, we
+ recommend that you start with this file as a base.
+ </para>
+
+ <sect2 id="jgroups-config-transport" revision="1">
+ <title>Transport -- UDP vs. TCP</title>
+
+ <para>
+ The JGroups <emphasis>transport</emphasis> refers to the mechanism
+ JGroups uses for sending messages to the group members. Choosing
+ which transport to use is the main JGroups-related decision users
+ will need to make. There are three transport types:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>UDP</emphasis> -- uses UDP multicast for transmitting
+ messages to all members of the group. Multicast is efficient for the
+ Second Level Cache use case, particularly with larger clusters,
+ since maintaining cache consistency means many messages need to
+ be sent to all members. UDP-based channel configurations are
+ used in the JBoss Cache configurations in the standard
+ <literal>jbc2-configs.xml</literal> file that ships with
+ Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>TCP</emphasis> -- uses multiple TCP unicasts
+ for transmitting messages to all members of the group. Less
+ efficient for the Second Level Cache use case, particularly as
+ clusters get larger, i.e. over 4 to 6 nodes. However, in some
+ network environments UDP multicast is not an option, in which
+ case TCP is available.
+ </para>
+
+ <para>
+ If a TCP-based channel is used, there are a couple of options
+ available for how a channel "discovers" the other members in
+ the group when it first starts.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>TCP + TCPPING</emphasis> -- here a static
+ list of all the possible nodes in the cluster
+ must be provided. The TCPPING "discovery" protocol uses
+ that static list to probe for available peers, using
+ TCP messages. The downside here is the need to provide
+ and maintain the static list. The upside, for multicast-averse
+ environments, is all communication uses TCP.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>TCP + MPING</emphasis> -- here the MPING
+ "discovery" protocol uses UDP multicast to probe for
+ available peers; once they are detected all regular
+ message traffic uses TCP. The downside here, for the
+ multicast-averse, is that multicast is used. The upside
+ is there is no need for a static configuration of all
+ possible peers.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The TCP-based configurations in the
+ <literal>jgroups-stacks.xml</literal> file found in
+ <literal>hibernate-jbosscache2.jar</literal> all use
+ TCP + MPING. This is because there is no way for the
+ Hibernate authors to provide a meaningful static
+ configuration for TCPPING. If you want to use TCP + TCPPING
+ you will need to provide your own JGroups configuration file.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>TUNNEL</emphasis> -- a specialized protocol designed
+ for cases where cluster members need to communicate across
+ firewalls. See the JGroups documentation for details.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="jgroups-config-std" revision="1">
+ <title>Standard JGroups Configurations</title>
+
+ <para>
+ By default the Second Level Cache will use JGroups configurations
+ found in the <literal>jgroups-stacks.xml</literal> file included in
+ <literal>hibernate-jbosscache2.jar</literal>. Following are their
+ names and a brief description of each:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>udp</literal></term>
+ <listitem>
+ <para>
+ UDP multicast-based config; appropriate for all cache types.
+ Includes JGroups flow control (FC) which is needed for caches
+ that send significant numbers of asynchronous messages (i.e.
+ timestamp caches and entity/collection caches configured for
+ replication instead of invalidation). If you're not sure and
+ want to use UDP multicast, this is the best choice.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>udp-sync</literal></term>
+ <listitem>
+ <para>
+ UDP multicast-based config that omits JGroups flow control
+ (FC). Optimal for caches that send little or no asynchronous
+ messages, i.e. entity/collection caches configured for invalidation.
+ Unsuitable for timestamp caches or entity/collection caches
+ configured for replication.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tcp</literal></term>
+ <listitem>
+ <para>
+ TCP-based config with UDP multicast discovery (MPING).
+ Includes JGroups flow control (FC); see <literal>udp</literal>
+ above for the significance of that.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tcp-sync</literal></term>
+ <listitem>
+ <para>
+ TCP-based config with UDP multicast discovery (MPING).
+ Omits JGroups flow control (FC); see
+ <literal>udp-sync</literal> above for the significance of that.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tunnel</literal></term>
+ <listitem>
+ <para>
+ Uses a specialized protocol designed for cases where cluster
+ members need to communicate across firewalls. See the JGroups
+ documentation for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/eviction.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/eviction.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/eviction.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,661 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<chapter id="eviction">
+
+ <title>Cache Eviction</title>
+
+ <sect1 id="eviction-overview" revision="1">
+ <title>Overview</title>
+
+ <para>
+ <emphasis>Eviction</emphasis> refers to the process by which old,
+ relatively unused, or excessively voluminous data can be dropped
+ from the cache, allowing the cache to remain within a memory budget.
+ Generally, applications that use the Second Level Cache should
+ configure eviction, unless only a relatively small amount of
+ reference data is cached. This chapter provides a brief overview
+ of how JBoss Cache eviction works, and then explains how to configure
+ eviction to effectively manage the data stored in a Hibernate Second
+ Level Cache. A basic understanding of JBoss Cache eviction and of
+ concepts like FQNs is assumed; see the <emphasis>JBoss Cache User Guide</emphasis>
+ for more information.
+ </para>
+
+ <sect2 id="eviction-overview-process" revision="1">
+ <title>The Eviction Process</title>
+
+ <para>
+ The JBoss Cache eviction process is fairly straightforward. Whenever
+ a node in a cache read or written to, added or removed, the cache
+ finds the <emphasis>eviction region</emphasis> (see below) that
+ contains the node and passes an <emphasis>eviction event</emphasis>
+ object to the <emphasis>eviction policy</emphasis> (see below)
+ associated with the region. The eviction policy uses the stream of
+ events it receives to track activity in the region. Periodically,
+ a background thread runs and contacts each region's eviction
+ policy. The policy uses its knowledge of the activity in the region,
+ along with any configuration it was provided at startup, to determine
+ which if any cache nodes should be evicted from memory. It then
+ tells the cache to evict those nodes. Evicting a node means
+ dropping it from the cache's in-memory state. The eviction only
+ occurs on that cache instance; there is no cluster-wide eviction.
+ </para>
+
+ <para>
+ An important point to understand is that eviction proceeds
+ independently on each peer in the cluster, with what gets
+ evicted depending on the activity on that peer. There is no
+ "global eviction" where JBoss Cache removes a piece of data in
+ every peer in the cluster in order to keep memory usage inside
+ a budget. The Hibernate/JBC integration layer may remove some
+ data globally, but that isn't done for the kind of memory
+ management reasons we're discussing in this chapter.
+ </para>
+
+ <para>
+ An effect of this is that even if a cache is configured for
+ replication, if eviction is enabled the contents of a cache will
+ be different between peers in the cluster; some may have evicted
+ some data, while others will have evicted different data. What
+ gets evicted is driven by what data is accessed by users on each
+ peer.
+ </para>
+
+ <para>
+ Controlling when data is evicted from the cache is a matter
+ of setting up appropriate eviction regions and configuring
+ appropriate eviction policies for each region.
+ </para>
+
+ </sect2>
+
+ <sect2 id="eviction-overview-regions" revision="1">
+ <title>Eviction Regions</title>
+
+ <para>
+ JBoss Cache stores its data in a set of nodes organized in a tree
+ structure. An eviction region is a just a portion of the tree
+ to which an eviction policy has been assigned. The name of the
+ region is the FQN of the topmost node in that portion of the tree.
+ An eviction configuration always needs to include a special region
+ named <literal>_default_</literal>; this region is rooted in the
+ root node of the tree and includes all nodes not covered by
+ other regions.
+ </para>
+ <para>
+ It's possible to define regions that overlap. In other words, one
+ region can be defined for <emphasis>/a/b/c</emphasis>, and another
+ defined for <emphasis>/a/b/c/d</emphasis> (which is just the
+ <emphasis>d</emphasis> subtree of the <emphasis>/a/b/c</emphasis>
+ sub-tree). The algorithm that assigns eviction events to eviction
+ regions handles scenarios like this consistently by always choosing
+ the first region it encounters. So, if the algorithm needed to
+ decide how to handle an event affecting <emphasis>/a/b/c/d/e</emphasis>,
+ it would start from there and work its way up the tree until it
+ hits the first defined region - in this case <emphasis>/a/b/c/d</emphasis>.
+ </para>
+ </sect2>
+
+ <sect2 id="eviction-overview-policies" revision="1">
+ <title>Eviction Policies</title>
+
+ <para>
+ An <emphasis>Eviction Policy</emphasis> is a class that knows how
+ to handle eviction events to track the activity in its region.
+ It may have a specialized set of configuration properties that
+ give it rules for when a particular node in the region should be
+ evicted. It can then use that configuration and its knowledge of
+ activity in the region to to determine what nodes to evict.
+ </para>
+
+ <para>
+ JBoss Cache ships with a number of eviction policies. See the
+ <emphasis>JBoss Cache User Guide</emphasis> for a discussion of
+ all of them. Here we are going to focus on just two.
+ </para>
+
+ <sect3 id="eviction-overview-policies-lru" revision="1">
+ <title>The <literal>LRUPolicy</literal></title>
+
+ <para>
+ The <literal>org.jboss.cache.eviction.LRUPolicy</literal> evicts
+ nodes that have been Least Recently Used. It has the following
+ configuration parameters:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <literal>maxNodes</literal>
+ - This is the maximum number of nodes allowed in this region.
+ 0 denotes no limit. If the region has more nodes than this,
+ the least recently used nodes will be evicted until the number
+ of nodes equals this limit.
+ </listitem>
+
+ <listitem>
+ <literal>timeToLiveSeconds</literal>
+ - The amount of time a node is not written to or read (in seconds)
+ before the node should be evicted. 0 denotes no limit. Nodes that
+ exceed this limit will be evicted whether or not a
+ <literal>maxNodes</literal> limit has been breached.
+ </listitem>
+
+ <listitem>
+ <literal>maxAgeSeconds</literal>
+ - Lifespan of a node (in seconds) regardless of idle time before
+ the node is swept away. 0 denotes no limit. Nodes that
+ exceed this limit will be evicted whether or not a
+ <literal>maxNodes</literal> or <literal>timeToLiveSeconds</literal>
+ limit has been breached.
+ </listitem>
+
+ <listitem>
+ <literal>minTimeToLiveSeconds</literal>
+ - the minimum amount of time a node must be allowed to live after
+ being accessed before it is allowed to be considered for eviction.
+ 0 denotes that this feature is disabled, which is the default value.
+ Should be set to a value less than <literal>timeToLiveSeconds</literal>.
+ It is recommended that this be set to a value slightly greater
+ than the maximum amount of time a transaction that affects the
+ region should take to complete. Configuring this is particularly
+ important when optimistic locking is used in conjunction with
+ invalidation.
+ </listitem>
+ </itemizedlist>
+ </sect3>
+
+ <sect3 id="eviction-overview-policies-null" revision="1">
+ <title>The <literal>NullEvictionPolicy</literal></title>
+
+ <para>
+ The <literal>org.jboss.cache.eviction.NullEvictionPolicy</literal>
+ is a simple policy that very efficiently does ... nothing. It
+ is used to efficiently short-circuit eviction handling for regions
+ where you don't want objects to be evicted (e.g. the timestamps
+ cache, which should <emphasis>never</emphasis> have data
+ evicted). Since the <literal>NullEvictionPolicy</literal> doesn't
+ actually evict anything, it doesn't take any configuration parameters.
+ </para>
+ </sect3>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="eviction-organization" revision="1">
+ <title>Organization of Data in the Cache</title>
+
+ <para>
+ In order to understand how to configure eviction, you need to
+ understand how Hibernate organizes data in the cache.
+ </para>
+
+ <sect2 id="eviction-organization-elements" revision="1">
+ <title>Region Prefix and Region Name</title>
+
+ <para>
+ All FQNs in a second level cache include two elements:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A <emphasis>Region Prefix</emphasis>, which is simply
+ any value assigned to the
+ <literal>hibernate.cache.region_prefix</literal> Hibernate
+ configuration property. If no Region Prefix is set, this
+ portion of the FQN is omitted.
+ </para>
+ <para>
+ If different session factories are sharing the same underlying
+ JBoss Cache instance(s) it is <emphasis>strongly encouraged</emphasis>
+ that a distinct Region Prefix be assigned to each. This will
+ help ensure that the different session factories cache their
+ data in different subtrees in JBoss Cache.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A <emphasis>Region Name</emphasis>, which is either
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ any value assigned to a <literal><cache></literal> element's
+ <literal>region</literal> attribute in a class or collection mapping.
+ See <xref linkend="eviction-organization-entity"/> for
+ an example.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Any value assigned to a Hibernate <literal>Query</literal>
+ object's <literal>cacheRegion</literal> property. See
+ <xref linkend="eviction-organization-query"/> for an
+ example.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <emphasis>escaped class name</emphasis> of the type
+ being cached. An <emphasis>escaped class name</emphasis>
+ is simply a fully-qualified class name with any
+ <literal>.</literal> replaced with a <literal>/</literal>
+ -- for example <literal>org/example/Foo</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="eviction-organization-entity" revision="1">
+ <title>Entities</title>
+
+ <para>
+ The FQN for the cache region where entities of a particular class
+ is stored is derived as follows:
+ </para>
+ <para>
+ <literal>/</literal> + <emphasis>Region Prefix</emphasis> + <literal>/</literal>
+ + <emphasis>Region Name</emphasis> + <literal>/ENTITY</literal>
+ </para>
+
+ <para>
+ If no region prefix was specified, the leading <literal>/</literal> and
+ <emphasis>Region Prefix</emphasis> is not included in the FQN.
+ So, if <literal>hibernate.cache.region_prefix</literal> was set to
+ "appA" and a class was mapped like this:
+ </para>
+
+ <programlisting><![CDATA[<class name="org.example.Foo">
+ <cache usage="transactional" region="foo_region"/>
+ ....
+</class>]]></programlisting>
+
+ <para>
+ The FQN of the region where <literal>Foo</literal> entities
+ would be cached is <literal>/appA/foo_region/ENTITY</literal>.
+ </para>
+
+ <para>
+ If the class mapping does not include a <literal>region</literal>
+ attribute, the region name is based on the name of the entity
+ class, e.g.
+ </para>
+
+ <programlisting><![CDATA[<class name="org.example.Bar">
+ <cache usage="transactional"/>
+ ....
+</class>]]></programlisting>
+
+ <para>
+ the FQN of the region where <literal>Bar</literal> entities
+ would be cached is <literal>/appA/org/example/Bar/ENTITY</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="eviction-organization-coll" revision="1">
+ <title>Collections</title>
+
+ <para>
+ The FQN for the cache region where entities of a particular class
+ is stored is derived as follows:
+ </para>
+ <para>
+ <literal>/</literal> + <emphasis>Region Prefix</emphasis> + <literal>/</literal>
+ + <emphasis>Region Name</emphasis> + <literal>/COLL</literal>
+ </para>
+
+ <para>
+ So, let's say our example <literal>Foo</literal> entity
+ included a collection field <literal>bars</literal> that
+ we wanted to cache:
+ </para>
+
+ <programlisting><![CDATA[<class name="org.example.Foo">
+ <cache usage="transactional"/>
+ ....
+ <one-to-many name="bars" class="org.example.Bar">
+ <cache usage="transactional" region="foo_region"/>
+ </one-to-many>
+</class>]]></programlisting>
+
+ <para>
+ The FQN of the region where the collection would be cached
+ would be
+ <literal>/appA/foo_region/COLL</literal>.
+ </para>
+
+ <para>
+ If the collection's <literal><cache></literal> element
+ did not include a <literal>region</literal>, the FQN would be
+ <literal>/appA/org/example/Foo/COLL</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="eviction-organization-query" revision="1">
+ <title>Queries</title>
+
+ <para>
+ Queries follow this pattern:
+ </para>
+
+ <para>
+ <literal>/</literal> + <emphasis>Region Prefix</emphasis> + <literal>/</literal>
+ + <emphasis>Region Name</emphasis> + <literal>/QUERY</literal>
+ </para>
+
+ <para>
+ Say we had the following query (again with a region prefix set to
+ "appA"):
+ </para>
+
+ <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog " +
+ "where blog.blogger = :blogger")
+ .setEntity("blogger", blogger)
+ .setMaxResults(15)
+ .setCacheable(true)
+ .setCacheRegion("frontpages")
+ .list();]]></programlisting>
+
+ <para>
+ The FQN of the region where this query's results would be cached
+ would be <literal>/appA/frontpages/QUERY</literal>.
+ </para>
+
+ <para>
+ If the call to <literal>setCacheRegion("frontpages")</literal>
+ were ommitted, the <emphasis>Region Name</emphasis> portion of
+ the FQN would be based on a Hibernate class:
+ <literal>/appA/org/hibernate/cache/StandardQueryCache/QUERY</literal>
+ </para>
+ </sect2>
+
+ <sect2 id="eviction-organization-timestamps" revision="1">
+ <title>Timestamps</title>
+
+ <para>
+ Timestamps follow this pattern:
+ </para>
+
+ <para>
+ <literal>/TS/</literal> + <emphasis>Region Prefix</emphasis> +
+ <literal>/org/hibernate/cache/UpdateTimestampsCache</literal>
+ </para>
+
+ <para>
+ again with a <literal>/</literal> and the <emphasis>Region Prefix</emphasis>
+ portion omitted if no region prefix was set.
+ </para>
+
+ <para>
+ Note that in the timestamps case the special constant ("TS") comes
+ at the start of the FQN rather than the end. This makes it easier
+ to ensure that eviction is never enabled for the timestamps region.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="eviction-organization-example" revision="1">
+ <title>Example Configuration</title>
+
+ <para>
+ So far we've been looking at things in the abstract; let's see an
+ example of how this comes together. In this example, imagine we
+ have a Hibernate application with the following characteristics.
+
+ <itemizedlist>
+ <listitem>
+ <para>Query caching is enabled.</para>
+ </listitem>
+ <listitem>
+ <para>
+ There is a region prefix set as part of the Hibernate
+ configuration: <literal>hibernate.cache.region_prefix==appA</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Some cachable entities and collections have a region
+ name of "reference" set in their Hibernate mapping.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Some cachable queries have the "reference" region name
+ set when they are created.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Other cachable entities and collections in the
+ <literal>org.example.hibernate</literal> package don't have a
+ region name set in their Hibernate mapping.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Other cachable queries don't have a region name set when they
+ are created.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ Let's see a possible eviction configuration for this scenario:
+ </para>
+
+ <programlisting><![CDATA[<attribute name="EvictionPolicyConfig">
+ <config>
+
+ <attribute name="wakeUpIntervalSeconds">5</attribute>
+ <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+
+ <!--
+ Default region to pick up anything we miss in the more specific
+ regions below.
+ -->
+ <region name="/_default_">
+ <attribute name="maxNodes">500</attribute>
+ <attribute name="timeToLiveSeconds">300</attribute>
+ <attribute name="minTimeToLiveSeconds">120</attribute>
+ </region>
+
+ <!-- Don't ever evict modification timestamps -->
+ <region name="/TS"
+ policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+
+ <!-- Reference data -->
+ <region name="/appA/reference">
+ <!-- Keep all reference data if it's being used -->
+ <attribute name="maxNodes">0</attribute>
+ <!-- Keep it around a long time (4 hours) -->
+ <attribute name="timeToLiveSeconds">14400</attribute>
+ <attribute name="minTimeToLiveSeconds">120</attribute>
+ </region>
+
+ <!-- Be more aggressive about queries on reference data -->
+ <region name="/appA/reference/QUERY">
+ <attribute name="maxNodes">200</attribute>
+ <attribute name="timeToLiveSeconds">1000</attribute>
+ <attribute name="minTimeToLiveSeconds">120</attribute>
+ </region>
+
+ <!--
+ Lots of entity instances from this package, but different
+ users are unlikely to share them. So, we can cache
+ a lot, but evict unused ones pretty quickly.
+ -->
+ <region name="/appA/org/example/hibernate">
+ <attribute name="maxNodes">50000</attribute>
+ <attribute name="timeToLiveSeconds">1200</attribute>
+ <attribute name="minTimeToLiveSeconds">120</attribute>
+ </region>
+
+ <!-- Clean up misc queries very promptly -->
+ <region name="/appA/org/hibernate/cache/StandardQueryCache">
+ <attribute name="maxNodes">200</attribute>
+ <attribute name="timeToLiveSeconds">240</attribute>
+ <attribute name="minTimeToLiveSeconds">120</attribute>
+ </region>
+
+ </config>
+</attribute>]]></programlisting>
+
+ <para>
+ Notes on the above:
+
+ <itemizedlist>
+ <listitem>
+ <para>The <literal>wakeUpIntervalSeconds</literal> configuration
+ controls how often the background eviction process kicks
+ in to evict nodes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>The first <literal>policyClass</literal> configuration
+ sets the default eviction policy class to use for each region.
+ Here we want to use the standard <literal>LRUPolicy</literal>
+ This can be overridden on a per-region basis, as is done
+ here for the <literal>/TS</literal> region.</para>
+ </listitem>
+ <listitem>
+ <para>We set up a <literal>/_default_</literal> region. Having
+ such a region is a requirement if eviction is used. Here we
+ don't expect any data to end up in this default region, but
+ if by mistake someone adds a new entity type that doesn't fall
+ into one of our other regions, we may not have a large memory
+ budget for it so we evict fairly agressively.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Evicting timestamps is forbidden, so we add a
+ <literal>/TS</literal> region that disables it. Here we
+ see how to override the default eviction policy.</para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>/appA/reference</literal> region covers our
+ reference data entities and collections. This is our most
+ likely to be reused data, so we configure the cache to be
+ very slow to evict it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The queries related to our reference data are less likely to
+ be reused, and may take up a lot of memory, so we override the
+ <literal>/appA/reference</literal> region with a
+ <literal>/appA/reference/QUERY</literal> region that is more
+ agressive about eviction.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The <literal>org.example.hibernate</literal> package includes a
+ lot of entity classes like <literal>Order</literal>, where
+ there are hundreds of thousands of records in the database.
+ These are unlikely to be reused across users, but we have a lot
+ of users and want to be able to cache many of them so a user
+ can have fast access to his or her data during the
+ course of their interaction with the system. So we create a
+ <literal>/appA/org/example/hibernate</literal> region
+ with a high <literal>maxNodes</literal> value but a fairly
+ low <literal>timeToLiveSeconds</literal>. The low time-to-live
+ ensures an <literal>Order</literal> is evicted quickly once a
+ user is done with it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Finally, cacheable queries that aren't assigned to
+ to the <literal>reference</literal> region will end up in
+ <literal>/appA/org/hibernate/cache/StandardQueryCache</literal>.
+ We've elected not to keep these around long at all.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+
+ <sect1 id="eviction-organization-best" revision="1">
+ <title>Best Practices</title>
+
+ <para>
+ Some best practices to follow:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Set <literal>hibernate.cache.region_prefix</literal> in your
+ configuration. It makes it simple to ensure the different session
+ factories don't step on each other if they share a JBoss Cache
+ instance.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Always set up an eviction region for the <literal>/TS</literal>
+ FQN that uses the <literal>NullEvictionPolicy</literal>. This
+ will ensure that timestamps never get evicted. Even if you are
+ not doing query caching or aren't caching timestamps in a
+ particular cache, this is still a good practice, as it costs
+ almost nothing and helps to ensure that timestamp eviction doesn't
+ slip in unnoticed later.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Assign a region to your entities, collections and queries rather
+ than relying on class names to compose the FQN. It makes
+ it easier to set up eviction, and helps prevent your eviction
+ setup breaking if class names are refactored.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Assign a different region name to your entities, collections or
+ queries that have different desirable eviction characteristics.
+ Put objects like often used reference data in one region, data
+ probably only accessed by a single user in another. Aggressively
+ evict the latter region; be less agressive with the former if
+ you evict it at all.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In some cases, there is an external application (i.e. outside
+ of Hibernate's control) that can modify data in the database.
+ Generally, a Second Level Cache should not be used in this sort
+ of case, since it can result in data in the cache being out of
+ date with respect to the database. But sometimes application
+ designers can tolerate having out of date data in the cache. In
+ this sort of situation, use an <literal>LRUPolicy</literal> with
+ a fairly low <literal>maxAgeSeconds</literal>. This will ensure
+ that out-of-date data eventually gets flushed from the cache.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/introduction.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/introduction.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,182 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<chapter id="introduction">
+
+ <title>Introduction</title>
+
+ <sect1 id="introduction-overview" revision="1">
+ <title>Overview</title>
+
+ <para>
+ JBoss Cache is a tree-structured, clustered, transactional cache. It
+ includes support for maintaining cache consistency across multiple
+ cache instances running in a cluster. It integrates with JTA transaction
+ managers, supporting transaction-scoped locking of cache elements and
+ automatic rollback of cache changes upon transaction rollback. It
+ supports both pessimistic and optimistic locking, with the tree-structure
+ of the cache allowing maximum concurrency.
+ </para>
+
+ <para>
+ All of these features make JBoss Cache an excellent choice for use as a
+ Hibernate <emphasis>Second Level Cache</emphasis>, particularly in
+ a clustered environment. A Hibernate <literal>Session</literal> is a
+ transaction-scoped cache of persistent data -- data accessed via the
+ <literal>Session</literal> is cached in the <literal>Session</literal>
+ for the duration of the current transaction, and then is cleared. A
+ <emphasis>Second Level Cache</emphasis> is an optional cluster or
+ JVM-level cache whose contents are maintained beyond the life of a
+ transaction and whose contents can be shared across transactions.
+ Use of a Second Level Cache is configured as part of the configuration
+ of the Hibernate <literal>SessionFactory</literal>. If a Second Level
+ Cache is enabled, caching of an instance of a particular
+ entity class or of results of a particular query can be configured on
+ a class-by-class, collection-by-collection and query-by-query basis.
+ See the <emphasis>Hibernate Reference Documentation</emphasis> for more
+ on Second Level Cache basics and how to configure entity classes,
+ collections and queries for caching.
+ </para>
+
+ <para>
+ The JBoss Cache Second Level Cache integration supports the
+ <literal>transactional</literal> and <literal>read only</literal>
+ <emphasis>cache concurrency strategies</emphasis> discussed in the
+ <emphasis>Hibernate Reference Documentation</emphasis>. It supports
+ query caching and is, of course, cluster safe.
+ </para>
+ </sect1>
+
+ <sect1 id="introduction-requirements" revision="1">
+ <title>Requirements</title>
+
+ <para>
+ Second level caching with JBoss Cache 2 requires the use of JBoss
+ Cache 2.1.0 or later. The core JBoss Cache project is used; the
+ related PojoCache project/library is not needed. The following jars,
+ included with the JBoss Cache distribution, need to be on the classpath:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>jbosscache-core.jar</para></listitem>
+ <listitem><para>commons-logging.jar</para></listitem>
+ <listitem><para>jboss-common-core.jar</para></listitem>
+ <listitem><para>jgroups.jar</para></listitem>
+ </itemizedlist>
+
+ <para>
+ JBoss Cache also needs to have the classes in the
+ <literal>javax.transaction</literal> package on the classpath,
+ but those are already included in the Hibernate distribution.
+ </para>
+
+ <para>
+ The <literal>hibernate-jbosscache2.jar</literal> that is included with
+ the Hibernate distribution also needs to be on the classpath.
+ </para>
+
+ <para>
+ A JBoss Cache configuration file, and usually a JGroups configuration
+ file<footnote><para><ulink url="http://labs.jboss.org/jgroups">JGroups</ulink>
+ is the group communication library used by JBoss Cache for intra-cluster
+ communication.</para></footnote>, need to be on the classpath. The
+ <literal>hibernate-jbosscache2.jar</literal> includes standard
+ configuration files in the <literal>org.hibernate.cache.jbc2.builder</literal>
+ package. The <literal>jbc2-configs.xml</literal> file is for JBoss
+ Cache and the <literal>jgroups-stacks.xml</literal> file is for JGroups.
+ See <xref linkend="jbc-config"/> and <xref linkend="jgroups-config"/>
+ for more details on these files. Users can create their own versions
+ and tell the <literal>SessionFactory</literal> to use them; see
+ <xref linkend="sessionfactory"/> for details.
+ </para>
+
+ </sect1>
+
+ <sect1 id="introduction-configuration" revision="1">
+ <title>Configuration Basics</title>
+
+ <para>
+ The key steps in using JBoss Cache as a second level cache are to:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Tell Hibernate in your <literal>SessionFactory</literal>
+ configuration that you want to use JBoss Cache 2 as your
+ Second Level Cache implementation:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.region.factory_class=
+ org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory]]></programlisting>
+
+ <para>
+ There are a number of values that can be provided for the
+ <literal>hibernate.cache.region.factory_class</literal>
+ property, depending on how you want the JBoss Cache integration
+ to work. Based on what factory class you specify, there are
+ additional detail configuration properties you can add to further
+ control that factory. However, simply specifying the
+ <literal>MultiplexedJBossCacheRegionFactory</literal> shown
+ above provides a reasonable set of default values useful for
+ many applications. See <xref linkend="sessionfactory-factories"/>
+ for more details.
+ </para>
+
+ <para>
+ Do not set the legacy <literal>hibernate.cache.provider_class</literal>
+ property when using JBoss Cache 2. That is a legacy property
+ from before Hibernate 3.3's redesign of second level caching
+ internals. It will not work with JBoss Cache 2.
+ </para>
+
+ </listitem>
+ <listitem>
+ <para>
+ Tell Hibernate you want to enable caching of entities and
+ collections. No need to set this property if you don't:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_second_level_cache=true]]></programlisting>
+ </listitem>
+ <listitem>
+ <para>
+ Tell Hibernate you want to enable caching of
+ query results. No need to set this property if you don't:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_query_cache=true]]></programlisting>
+ </listitem>
+ <listitem>
+ <para>
+ If you have enabled caching of query results, tell Hibernate if
+ you want to suppress costly replication of those results around
+ the cluster. No need to set this property if you want query
+ results replicated:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.region.jbc2.query.localonly=true]]></programlisting>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ See <xref linkend="configuration"/> for full details on configuration.
+ </para>
+ </sect1>
+
+</chapter>
\ No newline at end of file
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/preface.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/preface.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/content/preface.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,166 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+
+<preface id="preface" revision="1">
+ <title>Preface</title>
+
+ <para>
+ This document is focused on the use of the
+ <ulink url="http://labs.jboss.org/jbosscache">JBoss Cache</ulink>
+ clustered transactional caching library as a tool for caching data in
+ a Hibernate-based application.
+ </para>
+
+ <para>
+ Working with object-oriented software and a relational database can be cumbersome
+ and time consuming in today's enterprise environments. Hibernate is an object/relational
+ mapping tool for Java environments. The term object/relational mapping (ORM) refers to
+ the technique of mapping a data representation from an object model to a relational
+ data model with a SQL-based schema.
+ </para>
+
+ <para>
+ Hibernate not only takes care of the mapping from Java classes to
+ database tables (and from Java data types to SQL data types), but also provides data
+ query and retrieval facilities and can significantly reduce development time otherwise
+ spent with manual data handling in SQL and JDBC.
+ </para>
+
+ <para>
+ In any application that works with a relational database, caching data
+ retrieved from the database can potentially improve application performance.
+ Hibernate provides a number of facilities for caching data on the
+ database client side, i.e. in the Java process in which Hibernate is
+ running. The primary facility is the Hibernate <literal>Session</literal>
+ itself, which maintains a transaction-scoped cache of persistent data.
+ If you wish to cache data beyond the scope of a transaction, it is
+ possible to configure a cluster or JVM-level (technically a
+ <literal>SessionFactory</literal>-level) cache on a class-by-class,
+ collection-by-collection and query-by-query basis. This type of cache
+ is referred to as a <emphasis>Second Level Cache</emphasis>.
+ </para>
+
+ <para>
+ Hibernate provides a pluggable architecture for implementing its
+ Second Level Cache, allowing it to integrate with a number of third-party
+ caching libraries. This document is focused on the use of the
+ <ulink url="http://labs.jboss.org/jbosscache">JBoss Cache</ulink>
+ clustered transactional caching library as an implementation of
+ the Second Level Cache. It specifically focuses on JBoss Cache 2.
+ </para>
+
+ <para>
+ If you are new to Hibernate and Object/Relational Mapping or even Java,
+ please follow these steps:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Read the <emphasis>Hibernate Reference Documentation</emphasis>,
+ particularly the <emphasis>Introduction</emphasis> and
+ <emphasis>Architecture</emphasis> sections.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Have a look at the <literal>eg/</literal> directory in the Hibernate
+ distribution, it contains a simple standalone application. Copy your
+ JDBC driver to the <literal>lib/</literal> directory and edit
+ <literal>etc/hibernate.properties</literal>, specifying correct values for
+ your database. From a command prompt in the distribution directory,
+ type <literal>ant eg</literal> (using Ant), or under Windows, type
+ <literal>build eg</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use the <emphasis>Hibernate Reference Documentation</emphasis>
+ as your primary source of information.
+ Consider reading <emphasis>Java Persistence with Hibernate</emphasis>
+ (http://www.manning.com/bauer2) if you need more help with application
+ design or if you prefer a step-by-step tutorial. Also visit
+ http://caveatemptor.hibernate.org and download the example application
+ for Java Persistence with Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ FAQs are answered on the Hibernate website.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Third party demos, examples, and tutorials are linked on the Hibernate
+ website.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The Community Area on the Hibernate website is a good resource for
+ design patterns and various integration solutions (Tomcat, JBoss AS,
+ Struts, EJB, etc.).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ If you are new to the Hibernate Second Level Cache or to JBoss Cache,
+ please follow these steps:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Read the <emphasis>Hibernate Reference Documentation</emphasis>,
+ particularly the <emphasis>Second Level Cache</emphasis> and
+ <emphasis>Configuration</emphasis> sections.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Read the
+ <ulink url="http://labs.jboss.org/jbosscache/docs/index.html">JBoss Cache User Guide, Core Edition</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use this guide as your primary source of information on the
+ usage of JBoss Cache 2 as a Hibernate Second Level Cache.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ If you have questions, use the user forum linked on the Hibernate website.
+ The user forum on the JBoss Cache website is also useful.
+ We also provide a JIRA issue tracking system for bug reports and feature requests. If you
+ are interested in the development of Hibernate, join the developer mailing list. If
+ you are interested in translating this documentation into your language, contact us
+ on the developer mailing list.
+ </para>
+
+ <para>
+ Commercial development support, production support, and training for Hibernate is
+ available through Red Hat Inc. (see http://www.hibernate.org/SupportTraining/).
+ Hibernate is a Professional Open Source project and a critical component of the
+ JBoss Enterprise Middleware System (JEMS) suite of products.
+ </para>
+
+</preface>
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/hibernate_logo_a.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/hibernate_logo_a.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/multi-cache.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/multi-cache.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/single-cache.png
===================================================================
(Binary files differ)
Property changes on: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/images/single-cache.png
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: core/trunk/documentation/jbosscache2/src/main/docbook/en-US/legal_notice.xml
===================================================================
--- core/trunk/documentation/jbosscache2/src/main/docbook/en-US/legal_notice.xml (rev 0)
+++ core/trunk/documentation/jbosscache2/src/main/docbook/en-US/legal_notice.xml 2008-02-22 23:24:53 UTC (rev 14347)
@@ -0,0 +1,52 @@
+<?xml version='1.0' encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2008, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ 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, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Brian Stansberry
+ -->
+<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<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"/> 2008 by Red Hat, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, V1.0 or later (the latest version is presently available at <ulink url="http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>).
+ </para>
+ <para>
+ Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
+ </para>
+ <para>
+ Distribution of the work or derivative of the work in any standard (paper) book form for commercial purposes is prohibited unless prior permission is obtained from the copyright holder.
+ </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(a)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>
16 years, 9 months
Hibernate SVN: r14346 - in core/trunk/testsuite/src/test/java/org/hibernate/test: manytomanyassociationclass and 4 other directories.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2008-02-20 12:58:09 -0500 (Wed, 20 Feb 2008)
New Revision: 14346
Added:
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
Log:
HHH-2801 : added tests for removing and adding equal element to many-to-many with association class
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,271 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+/**
+ * Abstract class for tests on many-to-many association using an association class.
+ *
+ * @author Gail Badner
+ */
+public abstract class AbstractManyToManyAssociationClassTest extends FunctionalTestCase {
+ private User user;
+ private Group group;
+ private Membership membership;
+
+ public AbstractManyToManyAssociationClassTest(String string) {
+ super( string );
+ }
+
+ public abstract String[] getMappings();
+
+ public abstract Membership createMembership(String name);
+
+ protected void prepareTest() {
+ Session s = openSession();
+ s.beginTransaction();
+ user = new User( "user" );
+ group = new Group( "group" );
+ s.save( user );
+ s.save( group );
+ membership = createMembership( "membership");
+ addMembership( user, group, membership );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ protected void cleanupTest() {
+ if ( getSessions() != null ) {
+ Session s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete from " + membership.getClass().getName() );
+ s.createQuery( "delete from User" );
+ s.createQuery( "delete from Group" );
+ s.getTransaction().commit();
+ s.close();
+ }
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public Membership getMembership() {
+ return membership;
+ }
+
+ public void testRemoveAndAddSameElement() {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddEqualElement() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddEqualCollection() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ user.setMemberships( new HashSet() );
+ group.setMemberships( new HashSet() );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddSameElementNonKeyModified() {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+
+ }
+
+ public void testRemoveAndAddEqualElementNonKeyModified() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testDeleteDetached() {
+ Session s = openSession();
+ s.beginTransaction();
+ s.delete( user );
+ s.delete( group );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ assertNull( s.get( User.class, user.getId() ) );
+ assertNull( s.get( Group.class , group.getId() ) );
+ assertNull( s.get( membership.getClass(), membership.getId() ) );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void deleteMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ u.getMemberships().remove( ug );
+ g.getMemberships().remove( ug );
+ ug.setUser( null );
+ ug.setGroup( null );
+ }
+
+ public void addMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ ug.setUser( u );
+ ug.setGroup( g );
+ u.getMemberships().add( ug );
+ g.getMemberships().add( ug );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Group.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,90 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gail Badner
+ */
+public class Group {
+ private Long id;
+ private String name;
+ private Set memberships = new HashSet();
+
+ public Group() {
+ }
+
+ public Group(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getMemberships() {
+ return memberships;
+ }
+
+ public void setMemberships(Set memberships) {
+ this.memberships = memberships;
+ }
+
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof Group ) {
+ Group grp = ( Group ) obj;
+ if ( grp.getName() != null && name != null ) {
+ return grp.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,48 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.manytomanyassociationclass.compositeid.ManyToManyAssociationClassCompositeIdTest;
+import org.hibernate.test.manytomanyassociationclass.surrogateid.assigned.ManyToManyAssociationClassAssignedIdTest;
+import org.hibernate.test.manytomanyassociationclass.surrogateid.generated.ManyToManyAssociationClassGeneratedIdTest;
+
+/**
+ * Tests on many-to-many association using an association class with a composite ID containing
+ * the IDs from the associated entities.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite( "Many-to-many with associaiton class tests" );
+ suite.addTest( ManyToManyAssociationClassCompositeIdTest.suite() );
+ suite.addTest( ManyToManyAssociationClassAssignedIdTest.suite() );
+ suite.addTest( ManyToManyAssociationClassGeneratedIdTest.suite() );
+ return suite;
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/Membership.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.io.Serializable;
+
+/**
+ * Models a user's membership in a group.
+ *
+ * @author Gail Badner
+ */
+public class Membership {
+ private Serializable id;
+ private String name;
+ private User user;
+ private Group group;
+
+ public Membership() {
+ }
+
+ public Membership(Serializable id) {
+ this.id = id;
+ }
+
+ public Membership(String name) {
+ this.name = name;
+ }
+
+ public Membership(Serializable id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Serializable getId() {
+ return id;
+ }
+
+ public void setId(Serializable id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof Membership ) {
+ Membership mem = ( Membership ) obj;
+ if ( mem.getName() != null && name != null ) {
+ return mem.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/User.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gail Badner
+ */
+public class User {
+ private Long id;
+ private String name;
+ private Set memberships = new HashSet();
+
+ public User() {
+ }
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getMemberships() {
+ return memberships;
+ }
+
+ public void setMemberships(Set memberships) {
+ this.memberships = memberships;
+ }
+
+ public void addGroupMembership(Group group) {
+ if ( group == null ) {
+ throw new IllegalArgumentException( "group cannot be null" );
+ }
+ }
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof User ) {
+ User user = ( User ) obj;
+ if ( user.getName() != null && name != null ) {
+ return user.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.compositeid;
+
+import junit.framework.Test;
+
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a composite ID containing
+ * the IDs from the associated entities.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassCompositeIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassCompositeIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/compositeid/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassCompositeIdTest.class );
+ }
+
+ public Membership createMembership( String name ) {
+ return new MembershipWithCompositeId( name );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass.compositeid">
+
+ <class name="org.hibernate.test.manytomanyassociationclass.User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="MembershipWithCompositeId"/>
+ </set>
+ </class>
+
+ <class name="org.hibernate.test.manytomanyassociationclass.Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="MembershipWithCompositeId"/>
+ </set>
+ </class>
+
+ <class name="MembershipWithCompositeId" table="HB_MEMBERSHIP">
+ <composite-id name="id"
+ class="MembershipWithCompositeId$Id">
+ <key-property name="userId" type="long" column="USER_ID"/>
+ <key-property name="groupId" type="long" column="GROUP_ID"/>
+ </composite-id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user" class="org.hibernate.test.manytomanyassociationclass.User"
+ not-null="true" unique-key="UK_MEMBERSHIP"
+ insert="false" update="false"/>
+ <many-to-one column="GROUP_ID" name="group" class="org.hibernate.test.manytomanyassociationclass.Group"
+ not-null="true" unique-key="UK_MEMBERSHIP"
+ insert="false" update="false"/>
+ </class>
+
+</hibernate-mapping>
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,101 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.compositeid;
+
+import java.io.Serializable;
+
+import org.hibernate.test.manytomanyassociationclass.Group;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.test.manytomanyassociationclass.User;
+
+/**
+ * Models a user's membership in a group.
+ *
+ * @author Gail Badner
+ */
+public class MembershipWithCompositeId extends Membership {
+
+ public static class Id implements Serializable {
+ private Long userId;
+ private Long groupId;
+
+ public Id() {
+ }
+
+ public Id(Long userId, Long groupId) {
+ this.userId = userId;
+ this.groupId = groupId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public Long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(Long groupId) {
+ this.groupId = groupId;
+ }
+
+ public boolean equals(Object o) {
+ if ( o != null && o instanceof Id ) {
+ Id that = ( Id ) o;
+ return this.userId.equals( that.userId ) &&
+ this.groupId.equals( that.groupId );
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return userId.hashCode() + groupId.hashCode();
+ }
+ }
+
+ public MembershipWithCompositeId() {
+ super( new Id() );
+ }
+
+ public MembershipWithCompositeId(String name) {
+ super( new Id(), name );
+ }
+
+ public void setGroup(Group group) {
+ ( (Id) getId() ).setGroupId( ( group == null ? null : group.getId() ) );
+ super.setGroup( group );
+ }
+
+ public void setUser(User user) {
+ ( (Id) getId() ).setUserId( user == null ? null : user.getId() );
+ super.setUser( user );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.surrogateid.assigned;
+
+import junit.framework.Test;
+
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a surrogate ID that is assigned.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassAssignedIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassAssignedIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassAssignedIdTest.class );
+ }
+
+ public Membership createMembership(String name) {
+ return new Membership( new Long( 1000 ), name );
+ }
+}
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass">
+
+ <class name="User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Membership" table="HB_MEMBERSHIP">
+ <id name="id" column="ID" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user" class="User" not-null="true" unique-key="UK_MEMBERSHIP"/>
+ <many-to-one column="GROUP_ID" name="group" class="Group" not-null="true" unique-key="UK_MEMBERSHIP"/>
+ </class>
+
+</hibernate-mapping>
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,134 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.surrogateid.generated;
+
+import java.util.HashSet;
+
+import junit.framework.Test;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a surrogate ID that is generated.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassGeneratedIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassGeneratedIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassGeneratedIdTest.class );
+ }
+
+ public Membership createMembership(String name) {
+ return new Membership( name );
+ }
+
+ public void testRemoveAndAddEqualElement() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+
+ public void testRemoveAndAddEqualCollection() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ getUser().setMemberships( new HashSet() );
+ getGroup().setMemberships( new HashSet() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+
+ public void testRemoveAndAddEqualElementNonKeyModified() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ Membership membershipNew = createMembership( "membership" );
+ addMembership( getUser(), getGroup(), membershipNew );
+ membershipNew.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+}
\ No newline at end of file
Added: core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml (rev 0)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml 2008-02-20 17:58:09 UTC (rev 14346)
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass">
+
+ <class name="User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Membership" table="HB_MEMBERSHIP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user"
+ class="User"
+ not-null="true" unique-key="UK_MEMBERSHIP"/>
+ <many-to-one column="GROUP_ID" name="group"
+ class="Group"
+ not-null="true" unique-key="UK_MEMBERSHIP"/>
+ </class>
+
+</hibernate-mapping>
16 years, 9 months
Hibernate SVN: r14345 - in core/branches/Branch_3_2/test/org/hibernate/test: manytomanyassociationclass and 4 other directories.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2008-02-20 12:57:19 -0500 (Wed, 20 Feb 2008)
New Revision: 14345
Added:
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Group.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Membership.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/User.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
Modified:
core/branches/Branch_3_2/test/org/hibernate/test/AllTests.java
Log:
HHH-2801 : added tests for removing and adding equal element to many-to-many with association class
Modified: core/branches/Branch_3_2/test/org/hibernate/test/AllTests.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/AllTests.java 2008-02-20 17:14:31 UTC (rev 14344)
+++ core/branches/Branch_3_2/test/org/hibernate/test/AllTests.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -87,6 +87,7 @@
import org.hibernate.test.legacy.StatisticsTest;
import org.hibernate.test.lob.LobSuite;
import org.hibernate.test.manytomany.ManyToManyTest;
+import org.hibernate.test.manytomanyassociationclass.ManyToManyAssociationClassSuite;
import org.hibernate.test.map.MapIndexFormulaTest;
import org.hibernate.test.mapcompelem.MapCompositeElementTest;
import org.hibernate.test.mapelemformula.MapElementFormulaTest;
@@ -230,6 +231,7 @@
suite.addTest( MixedTest.suite() );
suite.addTest( OneToManyTest.suite() );
suite.addTest( ManyToManyTest.suite() );
+ suite.addTest( ManyToManyAssociationClassSuite.suite() );
suite.addTest( OneToOneSuite.suite() );
suite.addTest( OptimisticLockTest.suite() );
suite.addTest( PropertyRefSuite.suite() );
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/AbstractManyToManyAssociationClassTest.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,271 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+
+/**
+ * Abstract class for tests on many-to-many association using an association class.
+ *
+ * @author Gail Badner
+ */
+public abstract class AbstractManyToManyAssociationClassTest extends FunctionalTestCase {
+ private User user;
+ private Group group;
+ private Membership membership;
+
+ public AbstractManyToManyAssociationClassTest(String string) {
+ super( string );
+ }
+
+ public abstract String[] getMappings();
+
+ public abstract Membership createMembership(String name);
+
+ protected void prepareTest() {
+ Session s = openSession();
+ s.beginTransaction();
+ user = new User( "user" );
+ group = new Group( "group" );
+ s.save( user );
+ s.save( group );
+ membership = createMembership( "membership");
+ addMembership( user, group, membership );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ protected void cleanupTest() {
+ if ( getSessions() != null ) {
+ Session s = openSession();
+ s.beginTransaction();
+ s.createQuery( "delete from " + membership.getClass().getName() );
+ s.createQuery( "delete from User" );
+ s.createQuery( "delete from Group" );
+ s.getTransaction().commit();
+ s.close();
+ }
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public Membership getMembership() {
+ return membership;
+ }
+
+ public void testRemoveAndAddSameElement() {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddEqualElement() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddEqualCollection() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ user.setMemberships( new HashSet() );
+ group.setMemberships( new HashSet() );
+ addMembership( user, group, membership );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testRemoveAndAddSameElementNonKeyModified() {
+ deleteMembership( user, group, membership );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+
+ }
+
+ public void testRemoveAndAddEqualElementNonKeyModified() {
+ deleteMembership( user, group, membership );
+ membership = createMembership( "membership" );
+ addMembership( user, group, membership );
+ membership.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ s.merge( user );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ user = ( User ) s.get( User.class, user.getId() );
+ group = ( Group ) s.get( Group.class, group.getId() );
+ membership = ( Membership ) s.get( membership.getClass(), membership.getId() );
+ assertEquals( "user", user.getName() );
+ assertEquals( "group", group.getName() );
+ assertEquals( "membership1", membership.getName() );
+ assertEquals( 1, user.getMemberships().size() );
+ assertEquals( 1, group.getMemberships().size() );
+ assertSame( membership, user.getMemberships().iterator().next() );
+ assertSame( membership, group.getMemberships().iterator().next() );
+ assertSame( user, membership.getUser() );
+ assertSame( group, membership.getGroup() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testDeleteDetached() {
+ Session s = openSession();
+ s.beginTransaction();
+ s.delete( user );
+ s.delete( group );
+ s.getTransaction().commit();
+ s.close();
+
+ s = openSession();
+ s.beginTransaction();
+ assertNull( s.get( User.class, user.getId() ) );
+ assertNull( s.get( Group.class , group.getId() ) );
+ assertNull( s.get( membership.getClass(), membership.getId() ) );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void deleteMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ u.getMemberships().remove( ug );
+ g.getMemberships().remove( ug );
+ ug.setUser( null );
+ ug.setGroup( null );
+ }
+
+ public void addMembership(User u, Group g, Membership ug) {
+ if ( u == null || g == null ) {
+ throw new IllegalArgumentException();
+ }
+ ug.setUser( u );
+ ug.setGroup( g );
+ u.getMemberships().add( ug );
+ g.getMemberships().add( ug );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Group.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Group.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Group.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,90 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gail Badner
+ */
+public class Group {
+ private Long id;
+ private String name;
+ private Set memberships = new HashSet();
+
+ public Group() {
+ }
+
+ public Group(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getMemberships() {
+ return memberships;
+ }
+
+ public void setMemberships(Set memberships) {
+ this.memberships = memberships;
+ }
+
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof Group ) {
+ Group grp = ( Group ) obj;
+ if ( grp.getName() != null && name != null ) {
+ return grp.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/ManyToManyAssociationClassSuite.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,48 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.manytomanyassociationclass.compositeid.ManyToManyAssociationClassCompositeIdTest;
+import org.hibernate.test.manytomanyassociationclass.surrogateid.assigned.ManyToManyAssociationClassAssignedIdTest;
+import org.hibernate.test.manytomanyassociationclass.surrogateid.generated.ManyToManyAssociationClassGeneratedIdTest;
+
+/**
+ * Tests on many-to-many association using an association class with a composite ID containing
+ * the IDs from the associated entities.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite( "Many-to-many with associaiton class tests" );
+ suite.addTest( ManyToManyAssociationClassCompositeIdTest.suite() );
+ suite.addTest( ManyToManyAssociationClassAssignedIdTest.suite() );
+ suite.addTest( ManyToManyAssociationClassGeneratedIdTest.suite() );
+ return suite;
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Membership.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Membership.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/Membership.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,109 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.io.Serializable;
+
+/**
+ * Models a user's membership in a group.
+ *
+ * @author Gail Badner
+ */
+public class Membership {
+ private Serializable id;
+ private String name;
+ private User user;
+ private Group group;
+
+ public Membership() {
+ }
+
+ public Membership(Serializable id) {
+ this.id = id;
+ }
+
+ public Membership(String name) {
+ this.name = name;
+ }
+
+ public Membership(Serializable id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public Serializable getId() {
+ return id;
+ }
+
+ public void setId(Serializable id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public Group getGroup() {
+ return group;
+ }
+
+ public void setGroup(Group group) {
+ this.group = group;
+ }
+
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof Membership ) {
+ Membership mem = ( Membership ) obj;
+ if ( mem.getName() != null && name != null ) {
+ return mem.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/User.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/User.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/User.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,95 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Gail Badner
+ */
+public class User {
+ private Long id;
+ private String name;
+ private Set memberships = new HashSet();
+
+ public User() {
+ }
+
+ public User(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getMemberships() {
+ return memberships;
+ }
+
+ public void setMemberships(Set memberships) {
+ this.memberships = memberships;
+ }
+
+ public void addGroupMembership(Group group) {
+ if ( group == null ) {
+ throw new IllegalArgumentException( "group cannot be null" );
+ }
+ }
+ public boolean equals(Object obj) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj instanceof User ) {
+ User user = ( User ) obj;
+ if ( user.getName() != null && name != null ) {
+ return user.getName().equals( name );
+ }
+ else {
+ return super.equals( obj );
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return ( name == null ? super.hashCode() : name.hashCode() );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/ManyToManyAssociationClassCompositeIdTest.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,55 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.compositeid;
+
+import junit.framework.Test;
+
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a composite ID containing
+ * the IDs from the associated entities.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassCompositeIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassCompositeIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/compositeid/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassCompositeIdTest.class );
+ }
+
+ public Membership createMembership( String name ) {
+ return new MembershipWithCompositeId( name );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/Mappings.hbm.xml 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass.compositeid">
+
+ <class name="org.hibernate.test.manytomanyassociationclass.User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="MembershipWithCompositeId"/>
+ </set>
+ </class>
+
+ <class name="org.hibernate.test.manytomanyassociationclass.Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="MembershipWithCompositeId"/>
+ </set>
+ </class>
+
+ <class name="MembershipWithCompositeId" table="HB_MEMBERSHIP">
+ <composite-id name="id"
+ class="MembershipWithCompositeId$Id">
+ <key-property name="userId" type="long" column="USER_ID"/>
+ <key-property name="groupId" type="long" column="GROUP_ID"/>
+ </composite-id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user" class="org.hibernate.test.manytomanyassociationclass.User"
+ not-null="true" unique-key="UK_MEMBERSHIP"
+ insert="false" update="false"/>
+ <many-to-one column="GROUP_ID" name="group" class="org.hibernate.test.manytomanyassociationclass.Group"
+ not-null="true" unique-key="UK_MEMBERSHIP"
+ insert="false" update="false"/>
+ </class>
+
+</hibernate-mapping>
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/compositeid/MembershipWithCompositeId.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,101 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.compositeid;
+
+import java.io.Serializable;
+
+import org.hibernate.test.manytomanyassociationclass.Group;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.test.manytomanyassociationclass.User;
+
+/**
+ * Models a user's membership in a group.
+ *
+ * @author Gail Badner
+ */
+public class MembershipWithCompositeId extends Membership {
+
+ public static class Id implements Serializable {
+ private Long userId;
+ private Long groupId;
+
+ public Id() {
+ }
+
+ public Id(Long userId, Long groupId) {
+ this.userId = userId;
+ this.groupId = groupId;
+ }
+
+ public Long getUserId() {
+ return userId;
+ }
+
+ public void setUserId(Long userId) {
+ this.userId = userId;
+ }
+
+ public Long getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(Long groupId) {
+ this.groupId = groupId;
+ }
+
+ public boolean equals(Object o) {
+ if ( o != null && o instanceof Id ) {
+ Id that = ( Id ) o;
+ return this.userId.equals( that.userId ) &&
+ this.groupId.equals( that.groupId );
+ }
+ else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return userId.hashCode() + groupId.hashCode();
+ }
+ }
+
+ public MembershipWithCompositeId() {
+ super( new Id() );
+ }
+
+ public MembershipWithCompositeId(String name) {
+ super( new Id(), name );
+ }
+
+ public void setGroup(Group group) {
+ ( (Id) getId() ).setGroupId( ( group == null ? null : group.getId() ) );
+ super.setGroup( group );
+ }
+
+ public void setUser(User user) {
+ ( (Id) getId() ).setUserId( user == null ? null : user.getId() );
+ super.setUser( user );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/ManyToManyAssociationClassAssignedIdTest.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.surrogateid.assigned;
+
+import junit.framework.Test;
+
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a surrogate ID that is assigned.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassAssignedIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassAssignedIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassAssignedIdTest.class );
+ }
+
+ public Membership createMembership(String name) {
+ return new Membership( new Long( 1000 ), name );
+ }
+}
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/assigned/Mappings.hbm.xml 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass">
+
+ <class name="User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Membership" table="HB_MEMBERSHIP">
+ <id name="id" column="ID" type="long">
+ <generator class="assigned"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user" class="User" not-null="true" unique-key="UK_MEMBERSHIP"/>
+ <many-to-one column="GROUP_ID" name="group" class="Group" not-null="true" unique-key="UK_MEMBERSHIP"/>
+ </class>
+
+</hibernate-mapping>
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/ManyToManyAssociationClassGeneratedIdTest.java 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,134 @@
+/*
+ * 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
+ *
+ */
+package org.hibernate.test.manytomanyassociationclass.surrogateid.generated;
+
+import java.util.HashSet;
+
+import junit.framework.Test;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.hibernate.test.manytomanyassociationclass.AbstractManyToManyAssociationClassTest;
+import org.hibernate.test.manytomanyassociationclass.Membership;
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * Tests on many-to-many association using an association class with a surrogate ID that is generated.
+ *
+ * @author Gail Badner
+ */
+public class ManyToManyAssociationClassGeneratedIdTest extends AbstractManyToManyAssociationClassTest {
+ public ManyToManyAssociationClassGeneratedIdTest(String string) {
+ super( string );
+ }
+
+ public String[] getMappings() {
+ return new String[] { "manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml" };
+ }
+
+ public static Test suite() {
+ return new FunctionalTestClassTestSuite( ManyToManyAssociationClassGeneratedIdTest.class );
+ }
+
+ public Membership createMembership(String name) {
+ return new Membership( name );
+ }
+
+ public void testRemoveAndAddEqualElement() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+
+ public void testRemoveAndAddEqualCollection() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ getUser().setMemberships( new HashSet() );
+ getGroup().setMemberships( new HashSet() );
+ addMembership( getUser(), getGroup(), createMembership( "membership" ) );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+
+ public void testRemoveAndAddEqualElementNonKeyModified() {
+ deleteMembership( getUser(), getGroup(), getMembership() );
+ Membership membershipNew = createMembership( "membership" );
+ addMembership( getUser(), getGroup(), membershipNew );
+ membershipNew.setName( "membership1" );
+
+ Session s = openSession();
+ s.beginTransaction();
+ try {
+ // The new membership is transient (it has a null surrogate ID), so
+ // Hibernate assumes that it should be added to the collection.
+ // Inserts are done before deletes, so a ConstraintViolationException
+ // will be thrown on the insert because the unique constraint on the
+ // user and group IDs in the join table is violated. See HHH-2801.
+ s.merge( getUser() );
+ fail( "should have failed because inserts are before deletes");
+ }
+ catch( ConstraintViolationException ex ) {
+ // expected
+ s.getTransaction().rollback();
+ }
+ finally {
+ s.close();
+ }
+ }
+}
\ No newline at end of file
Added: core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml
===================================================================
--- core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml (rev 0)
+++ core/branches/Branch_3_2/test/org/hibernate/test/manytomanyassociationclass/surrogateid/generated/Mappings.hbm.xml 2008-02-20 17:57:19 UTC (rev 14345)
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ 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
+ ~
+ -->
+
+<hibernate-mapping package="org.hibernate.test.manytomanyassociationclass">
+
+ <class name="User" table="HB_USER">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="USER_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Group" table="HB_GROUP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <set name="memberships" cascade="all, delete-orphan" inverse="true" lazy="true">
+ <key column="GROUP_ID"/>
+ <one-to-many class="Membership"/>
+ </set>
+ </class>
+
+ <class name="Membership" table="HB_MEMBERSHIP">
+ <id name="id" column="ID" type="long">
+ <generator class="native"/>
+ </id>
+ <property name="name" column="NAME" type="string" length="40" not-null="true"/>
+ <many-to-one column="USER_ID" name="user"
+ class="User"
+ not-null="true" unique-key="UK_MEMBERSHIP"/>
+ <many-to-one column="GROUP_ID" name="group"
+ class="Group"
+ not-null="true" unique-key="UK_MEMBERSHIP"/>
+ </class>
+
+</hibernate-mapping>
16 years, 9 months
Hibernate SVN: r14344 - in annotations/trunk: src/java/org/hibernate/annotations and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-02-20 12:14:31 -0500 (Wed, 20 Feb 2008)
New Revision: 14344
Added:
annotations/trunk/src/java/org/hibernate/annotations/GenericGenerators.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/Monkey.java
Modified:
annotations/trunk/doc/reference/en/modules/entity.xml
annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java
annotations/trunk/src/test/org/hibernate/test/annotations/id/package-info.java
Log:
ANN-442 add @GenericGenerators (Paul Cowan)
Modified: annotations/trunk/doc/reference/en/modules/entity.xml
===================================================================
--- annotations/trunk/doc/reference/en/modules/entity.xml 2008-02-20 13:46:43 UTC (rev 14343)
+++ annotations/trunk/doc/reference/en/modules/entity.xml 2008-02-20 17:14:31 UTC (rev 14344)
@@ -2394,10 +2394,11 @@
public class Carrot extends Vegetable { ... }</programlisting></para>
</sect2>
- <sect2 id="entity-hibspec-identifier" label="Identifier" revision="1">
+ <sect2 id="entity-hibspec-identifier" label="Identifier" revision="2">
<title>Identifier</title>
<para><literal><literal>@org.hibernate.annotations.GenericGenerator</literal>
+ and <literal>@org.hibernate.annotations.GenericGenerators</literal>
allows you to define an Hibernate specific id
generator.</literal></para>
@@ -2420,16 +2421,23 @@
some parameters through the <literal>parameters</literal>
attribute.</para>
- <para>Contrary to its standard counterpart,
- <literal>@GenericGenerator</literal> can be used in package level
- annotations, making it an application level generator (just like if it
- were in a JPA XML file).</para>
+ <para>Contrary to their standard counterpart,
+ <literal>@GenericGenerator</literal> and <literal>@GenericGenerators</literal>
+ can be used in package level annotations, making them application level generators
+ (just like if they were in a JPA XML file).</para>
- <programlisting>@GenericGenerator(name="hibseq", strategy = "seqhilo",
- parameters = {
- @Parameter(name="max_lo", value = "5"),
- @Parameter(name="sequence", value="heybabyhey")
- }
+ <programlisting>@GenericGenerators(
+ {
+ @GenericGenerator(
+ name="hibseq",
+ strategy = "seqhilo",
+ parameters = {
+ @Parameter(name="max_lo", value = "5"),
+ @Parameter(name="sequence", value="heybabyhey")
+ }
+ ),
+ @GenericGenerator(...)
+ }
)
package org.hibernate.test.model</programlisting>
</sect2>
Added: annotations/trunk/src/java/org/hibernate/annotations/GenericGenerators.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/annotations/GenericGenerators.java (rev 0)
+++ annotations/trunk/src/java/org/hibernate/annotations/GenericGenerators.java 2008-02-20 17:14:31 UTC (rev 14344)
@@ -0,0 +1,21 @@
+//$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Array of generic generator definitions
+ *
+ * @author Paul Cowan
+ */
+@Target({PACKAGE, TYPE})
+@Retention(RUNTIME)
+public @interface GenericGenerators {
+ GenericGenerator[] value();
+}
+
Modified: annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
--- annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java 2008-02-20 13:46:43 UTC (rev 14343)
+++ annotations/trunk/src/java/org/hibernate/cfg/AnnotationBinder.java 2008-02-20 17:14:31 UTC (rev 14344)
@@ -96,6 +96,7 @@
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import org.hibernate.annotations.Where;
+import org.hibernate.annotations.GenericGenerators;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
@@ -233,17 +234,31 @@
mappings.addGenerator( idGen );
}
- if ( pckg.isAnnotationPresent( GenericGenerator.class ) ) {
- GenericGenerator ann = pckg.getAnnotation( GenericGenerator.class );
- IdGenerator idGen = buildIdGenerator( ann, mappings );
- mappings.addGenerator( idGen );
- }
+ bindGenericGenerators(pckg, mappings);
bindQueries( pckg, mappings );
bindFilterDefs( pckg, mappings );
bindTypeDefs( pckg, mappings );
BinderHelper.bindAnyMetaDefs( pckg, mappings );
}
+ private static void bindGenericGenerators(XAnnotatedElement annotatedElement, ExtendedMappings mappings) {
+ GenericGenerator defAnn = annotatedElement.getAnnotation( GenericGenerator.class );
+ GenericGenerators defsAnn = annotatedElement.getAnnotation( GenericGenerators.class );
+ if ( defAnn != null ) {
+ bindGenericGenerator( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for (GenericGenerator def : defsAnn.value() ) {
+ bindGenericGenerator( def, mappings );
+ }
+ }
+ }
+
+ private static void bindGenericGenerator(GenericGenerator def, ExtendedMappings mappings) {
+ IdGenerator idGen = buildIdGenerator( def, mappings );
+ mappings.addGenerator( idGen );
+ }
+
private static void bindQueries(XAnnotatedElement annotatedElement, ExtendedMappings mappings) {
{
SqlResultSetMapping ann = annotatedElement.getAnnotation( SqlResultSetMapping.class );
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java 2008-02-20 13:46:43 UTC (rev 14343)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/IdTest.java 2008-02-20 17:14:31 UTC (rev 14344)
@@ -41,6 +41,21 @@
}
+ /*
+ * Ensures that GenericGenerator annotations wrapped inside a GenericGenerators holder are
+ * bound correctly
+ */
+ public void testGenericGenerators() throws Exception {
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+ Monkey monkey = new Monkey();
+ s.persist( monkey );
+ s.flush();
+ assertNotNull(monkey.getId());
+ tx.rollback();
+ s.close();
+ }
+
public void testTableGenerator() throws Exception {
Session s = openSession();
Transaction tx = s.beginTransaction();
@@ -264,7 +279,8 @@
SoundSystem.class,
Furniture.class,
GoalKeeper.class,
- BreakDance.class
+ BreakDance.class,
+ Monkey.class
};
}
Added: annotations/trunk/src/test/org/hibernate/test/annotations/id/Monkey.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/Monkey.java (rev 0)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/Monkey.java 2008-02-20 17:14:31 UTC (rev 14344)
@@ -0,0 +1,24 @@
+//$
+package org.hibernate.test.annotations.id;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * @author Paul Cowan
+ */
+@Entity
+public class Monkey {
+ private String id;
+
+ @Id
+ @GeneratedValue(generator = "system-uuid-2")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+}
Modified: annotations/trunk/src/test/org/hibernate/test/annotations/id/package-info.java
===================================================================
--- annotations/trunk/src/test/org/hibernate/test/annotations/id/package-info.java 2008-02-20 13:46:43 UTC (rev 14343)
+++ annotations/trunk/src/test/org/hibernate/test/annotations/id/package-info.java 2008-02-20 17:14:31 UTC (rev 14344)
@@ -3,7 +3,9 @@
* Test package for metatata facilities
* It contains an example of package level metadata
*/
+(a)org.hibernate.annotations.GenericGenerator(name = "system-uuid", strategy = "uuid")
+(a)org.hibernate.annotations.GenericGenerators(
+ @org.hibernate.annotations.GenericGenerator(name = "system-uuid-2", strategy = "uuid")
+)
+package org.hibernate.test.annotations.id;
-(a)org.hibernate.annotations.GenericGenerator(name = "system-uuid",
- strategy = "uuid") package org.hibernate.test.annotations.id;
-
16 years, 9 months
Hibernate SVN: r14343 - search/tags.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2008-02-20 08:46:43 -0500 (Wed, 20 Feb 2008)
New Revision: 14343
Added:
search/tags/v3_0_1_GA/
Log:
Hibernate Search release 3.0.1.GA
Copied: search/tags/v3_0_1_GA (from rev 14342, search/trunk)
16 years, 9 months