Hibernate SVN: r19955 - search/trunk.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-15 05:27:56 -0400 (Thu, 15 Jul 2010)
New Revision: 19955
Modified:
search/trunk/pom.xml
Log:
HSEARCH-559 Aligned slf4j version with Core
Modified: search/trunk/pom.xml
===================================================================
--- search/trunk/pom.xml 2010-07-14 19:31:59 UTC (rev 19954)
+++ search/trunk/pom.xml 2010-07-15 09:27:56 UTC (rev 19955)
@@ -127,7 +127,7 @@
</mailingLists>
<properties>
- <slf4jVersion>1.5.8</slf4jVersion>
+ <slf4jVersion>1.6.1</slf4jVersion>
<luceneVersion>2.9.2</luceneVersion>
<hibernateVersion>3.6.0-SNAPSHOT</hibernateVersion>
<hibernateCommonsAnnotationVersion>3.2.0.Final</hibernateCommonsAnnotationVersion>
14 years, 4 months
Hibernate SVN: r19954 - core/trunk/documentation/manual/src/main/docbook/en-US/content.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-14 15:31:59 -0400 (Wed, 14 Jul 2010)
New Revision: 19954
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
Log:
HHH-5379 Added CascadeTypes for annotations
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml
===================================================================
--- core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-14 18:59:15 UTC (rev 19953)
+++ core/trunk/documentation/manual/src/main/docbook/en-US/content/session_api.xml 2010-07-14 19:31:59 UTC (rev 19954)
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@@ -22,273 +22,237 @@
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
-
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
-
]>
-
<chapter id="objectstate">
- <title>Working with objects</title>
+ <title>Working with objects</title>
- <para>
- Hibernate is a full object/relational mapping solution that not only shields
- the developer from the details of the underlying database management
- system, but also offers <emphasis>state management</emphasis> of objects. This is,
- contrary to the management of SQL <literal>statements</literal> in common JDBC/SQL
- persistence layers, a natural object-oriented view of persistence in Java
- applications.
- </para>
+ <para>Hibernate is a full object/relational mapping solution that not only
+ shields the developer from the details of the underlying database management
+ system, but also offers <emphasis>state management</emphasis> of objects.
+ This is, contrary to the management of SQL <literal>statements</literal> in
+ common JDBC/SQL persistence layers, a natural object-oriented view of
+ persistence in Java applications.</para>
- <para>
- In other words, Hibernate application developers should always think about the
- <emphasis>state</emphasis> of their objects, and not necessarily about the
- execution of SQL statements. This part is taken care of by Hibernate and is only
- relevant for the application developer when tuning the performance of the system.
- </para>
+ <para>In other words, Hibernate application developers should always think
+ about the <emphasis>state</emphasis> of their objects, and not necessarily
+ about the execution of SQL statements. This part is taken care of by
+ Hibernate and is only relevant for the application developer when tuning the
+ performance of the system.</para>
- <section id="objectstate-overview">
- <title>Hibernate object states</title>
+ <section id="objectstate-overview">
+ <title>Hibernate object states</title>
- <para>
- Hibernate defines and supports the following object states:
- </para>
+ <para>Hibernate defines and supports the following object states:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Transient</emphasis> - an object is transient if it has just
- been instantiated using the <literal>new</literal> operator, and it
- is not associated with a Hibernate <literal>Session</literal>. It has no
- persistent representation in the database and no identifier value has been
- assigned. Transient instances will be destroyed by the garbage collector if
- the application does not hold a reference anymore. Use the Hibernate
- <literal>Session</literal> to make an object persistent (and let Hibernate
- take care of the SQL statements that need to be executed for this transition).
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Persistent</emphasis> - a persistent instance has a representation
- in the database and an identifier value. It might just have been saved or loaded,
- however, it is by definition in the scope of a <literal>Session</literal>.
- Hibernate will detect any changes made to an object in persistent state and
- synchronize the state with the database when the unit of work completes.
- Developers do not execute manual <literal>UPDATE</literal> statements, or
- <literal>DELETE</literal> statements when an object should be made transient.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Detached</emphasis> - a detached instance is an object that has been
- persistent, but its <literal>Session</literal> has been closed. The reference
- to the object is still valid, of course, and the detached instance might even
- be modified in this state. A detached instance can be reattached to a new
- <literal>Session</literal> at a later point in time, making it (and all the
- modifications) persistent again. This feature enables a programming model for
- long running units of work that require user think-time. We call them
- <emphasis>application transactions</emphasis>, i.e., a unit of work from the
- point of view of the user.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Transient</emphasis> - an object is transient if it
+ has just been instantiated using the <literal>new</literal> operator,
+ and it is not associated with a Hibernate <literal>Session</literal>.
+ It has no persistent representation in the database and no identifier
+ value has been assigned. Transient instances will be destroyed by the
+ garbage collector if the application does not hold a reference
+ anymore. Use the Hibernate <literal>Session</literal> to make an
+ object persistent (and let Hibernate take care of the SQL statements
+ that need to be executed for this transition).</para>
+ </listitem>
- <para>
- We will now discuss the states and state transitions (and the Hibernate methods that
- trigger a transition) in more detail.
- </para>
+ <listitem>
+ <para><emphasis>Persistent</emphasis> - a persistent instance has a
+ representation in the database and an identifier value. It might just
+ have been saved or loaded, however, it is by definition in the scope
+ of a <literal>Session</literal>. Hibernate will detect any changes
+ made to an object in persistent state and synchronize the state with
+ the database when the unit of work completes. Developers do not
+ execute manual <literal>UPDATE</literal> statements, or
+ <literal>DELETE</literal> statements when an object should be made
+ transient.</para>
+ </listitem>
- </section>
+ <listitem>
+ <para><emphasis>Detached</emphasis> - a detached instance is an object
+ that has been persistent, but its <literal>Session</literal> has been
+ closed. The reference to the object is still valid, of course, and the
+ detached instance might even be modified in this state. A detached
+ instance can be reattached to a new <literal>Session</literal> at a
+ later point in time, making it (and all the modifications) persistent
+ again. This feature enables a programming model for long running units
+ of work that require user think-time. We call them
+ <emphasis>application transactions</emphasis>, i.e., a unit of work
+ from the point of view of the user.</para>
+ </listitem>
+ </itemizedlist>
- <section id="objectstate-makingpersistent" revision="1">
- <title>Making objects persistent</title>
+ <para>We will now discuss the states and state transitions (and the
+ Hibernate methods that trigger a transition) in more detail.</para>
+ </section>
- <para>
- Newly instantiated instances of a persistent class are considered
- <emphasis>transient</emphasis> by Hibernate. We can make a transient
- instance <emphasis>persistent</emphasis> by associating it with a
- session:
- </para>
+ <section id="objectstate-makingpersistent" revision="1">
+ <title>Making objects persistent</title>
- <programlisting role="JAVA"><![CDATA[DomesticCat fritz = new DomesticCat();
+ <para>Newly instantiated instances of a persistent class are considered
+ <emphasis>transient</emphasis> by Hibernate. We can make a transient
+ instance <emphasis>persistent</emphasis> by associating it with a
+ session:</para>
+
+ <programlisting role="JAVA">DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
-Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+Long generatedId = (Long) sess.save(fritz);</programlisting>
- <para>
- If <literal>Cat</literal> has a generated identifier, the identifier is
- generated and assigned to the <literal>cat</literal> when <literal>save()</literal>
- is called. If <literal>Cat</literal> has an <literal>assigned</literal>
- identifier, or a composite key, the identifier should be assigned to
- the <literal>cat</literal> instance before calling <literal>save()</literal>.
- You can also use <literal>persist()</literal> instead of <literal>save()</literal>,
- with the semantics defined in the EJB3 early draft.
- </para>
+ <para>If <literal>Cat</literal> has a generated identifier, the identifier
+ is generated and assigned to the <literal>cat</literal> when
+ <literal>save()</literal> is called. If <literal>Cat</literal> has an
+ <literal>assigned</literal> identifier, or a composite key, the identifier
+ should be assigned to the <literal>cat</literal> instance before calling
+ <literal>save()</literal>. You can also use <literal>persist()</literal>
+ instead of <literal>save()</literal>, with the semantics defined in the
+ EJB3 early draft.</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>persist()</literal> makes a transient instance persistent.
- However, it does not guarantee that the identifier value will be assigned to
- the persistent instance immediately, the assignment might happen at flush time.
- <literal>persist()</literal> also guarantees that it will not execute an
- <literal>INSERT</literal> statement if it is called outside of transaction
- boundaries. This is useful in long-running conversations with an extended
- Session/persistence context.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>save()</literal> does guarantee to return an identifier. If an INSERT
- has to be executed to get the identifier ( e.g. "identity" generator, not
- "sequence"), this INSERT happens immediately, no matter if you are inside or
- outside of a transaction. This is problematic in a long-running conversation
- with an extended Session/persistence context.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>persist()</literal> makes a transient instance
+ persistent. However, it does not guarantee that the identifier value
+ will be assigned to the persistent instance immediately, the
+ assignment might happen at flush time. <literal>persist()</literal>
+ also guarantees that it will not execute an <literal>INSERT</literal>
+ statement if it is called outside of transaction boundaries. This is
+ useful in long-running conversations with an extended
+ Session/persistence context.</para>
+ </listitem>
- <para>
- Alternatively, you can assign the identifier using an overloaded version
- of <literal>save()</literal>.
- </para>
+ <listitem>
+ <para><literal>save()</literal> does guarantee to return an
+ identifier. If an INSERT has to be executed to get the identifier (
+ e.g. "identity" generator, not "sequence"), this INSERT happens
+ immediately, no matter if you are inside or outside of a transaction.
+ This is problematic in a long-running conversation with an extended
+ Session/persistence context.</para>
+ </listitem>
+ </itemizedlist>
-<programlisting role="JAVA"><![CDATA[DomesticCat pk = new DomesticCat();
+ <para>Alternatively, you can assign the identifier using an overloaded
+ version of <literal>save()</literal>.</para>
+
+ <programlisting role="JAVA">DomesticCat pk = new DomesticCat();
pk.setColor(Color.TABBY);
pk.setSex('F');
pk.setName("PK");
pk.setKittens( new HashSet() );
pk.addKitten(fritz);
-sess.save( pk, new Long(1234) );]]></programlisting>
-
- <para>
- If the object you make persistent has associated objects (e.g. the
- <literal>kittens</literal> collection in the previous example),
- these objects can be made persistent in any order you like unless you
- have a <literal>NOT NULL</literal> constraint upon a foreign key column.
- There is never a risk of violating foreign key constraints. However, you
- might violate a <literal>NOT NULL</literal> constraint if you
- <literal>save()</literal> the objects in the wrong order.
- </para>
-
- <para>
- Usually you do not bother with this detail, as you will normally use Hibernate's
- <emphasis>transitive persistence</emphasis> feature to save the associated
- objects automatically. Then, even <literal>NOT NULL</literal>
- constraint violations do not occur - Hibernate will take care of everything.
- Transitive persistence is discussed later in this chapter.
- </para>
-
- </section>
+sess.save( pk, new Long(1234) );</programlisting>
- <section id="objectstate-loading">
- <title>Loading an object</title>
+ <para>If the object you make persistent has associated objects (e.g. the
+ <literal>kittens</literal> collection in the previous example), these
+ objects can be made persistent in any order you like unless you have a
+ <literal>NOT NULL</literal> constraint upon a foreign key column. There is
+ never a risk of violating foreign key constraints. However, you might
+ violate a <literal>NOT NULL</literal> constraint if you
+ <literal>save()</literal> the objects in the wrong order.</para>
- <para>
- The <literal>load()</literal> methods of <literal>Session</literal> provide
- a way of retrieving a persistent instance if you know its identifier.
- <literal>load()</literal> takes a class object and loads the state into
- a newly instantiated instance of that class in a persistent state.
- </para>
+ <para>Usually you do not bother with this detail, as you will normally use
+ Hibernate's <emphasis>transitive persistence</emphasis> feature to save
+ the associated objects automatically. Then, even <literal>NOT
+ NULL</literal> constraint violations do not occur - Hibernate will take
+ care of everything. Transitive persistence is discussed later in this
+ chapter.</para>
+ </section>
- <programlisting role="JAVA"><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+ <section id="objectstate-loading">
+ <title>Loading an object</title>
-<programlisting role="JAVA"><![CDATA[// you need to wrap primitive identifiers
+ <para>The <literal>load()</literal> methods of <literal>Session</literal>
+ provide a way of retrieving a persistent instance if you know its
+ identifier. <literal>load()</literal> takes a class object and loads the
+ state into a newly instantiated instance of that class in a persistent
+ state.</para>
+
+ <programlisting role="JAVA">Cat fritz = (Cat) sess.load(Cat.class, generatedId);</programlisting>
+
+ <programlisting role="JAVA">// you need to wrap primitive identifiers
long id = 1234;
-DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );</programlisting>
- <para>
- Alternatively, you can load state into a given instance:
- </para>
+ <para>Alternatively, you can load state into a given instance:</para>
-<programlisting role="JAVA"><![CDATA[Cat cat = new DomesticCat();
+ <programlisting role="JAVA">Cat cat = new DomesticCat();
// load pk's state into cat
sess.load( cat, new Long(pkId) );
-Set kittens = cat.getKittens();]]></programlisting>
+Set kittens = cat.getKittens();</programlisting>
- <para>
- Be aware that <literal>load()</literal> will throw an unrecoverable exception if
- there is no matching database row. If the class is mapped with a proxy,
- <literal>load()</literal> just returns an uninitialized proxy and does not
- actually hit the database until you invoke a method of the proxy. This
- is useful if you wish to create an association to an object
- without actually loading it from the database. It also allows multiple
- instances to be loaded as a batch if <literal>batch-size</literal> is
- defined for the class mapping.
- </para>
-
- <para>
- If you are not certain that a matching row exists, you should use the
- <literal>get()</literal> method which hits the database immediately and
- returns null if there is no matching row.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+ <para>Be aware that <literal>load()</literal> will throw an unrecoverable
+ exception if there is no matching database row. If the class is mapped
+ with a proxy, <literal>load()</literal> just returns an uninitialized
+ proxy and does not actually hit the database until you invoke a method of
+ the proxy. This is useful if you wish to create an association to an
+ object without actually loading it from the database. It also allows
+ multiple instances to be loaded as a batch if
+ <literal>batch-size</literal> is defined for the class mapping.</para>
+
+ <para>If you are not certain that a matching row exists, you should use
+ the <literal>get()</literal> method which hits the database immediately
+ and returns null if there is no matching row.</para>
+
+ <programlisting role="JAVA">Cat cat = (Cat) sess.get(Cat.class, id);
if (cat==null) {
cat = new Cat();
sess.save(cat, id);
}
-return cat;]]></programlisting>
+return cat;</programlisting>
- <para>
- You can even load an object using an SQL <literal>SELECT ... FOR UPDATE</literal>,
- using a <literal>LockMode</literal>. See the API documentation for more information.
- </para>
+ <para>You can even load an object using an SQL <literal>SELECT ... FOR
+ UPDATE</literal>, using a <literal>LockMode</literal>. See the API
+ documentation for more information.</para>
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
-
- <para>
- Any associated instances or contained collections will
- <emphasis>not</emphasis> be selected <literal>FOR UPDATE</literal>, unless you decide
- to specify <literal>lock</literal> or <literal>all</literal> as a
- cascade style for the association.
- </para>
-
- <para>
- It is possible to re-load an object and all its collections at any time, using the
- <literal>refresh()</literal> method. This is useful when database triggers are used to
- initialize some of the properties of the object.
- </para>
-
- <programlisting role="JAVA"><![CDATA[sess.save(cat);
-sess.flush(); //force the SQL INSERT
-sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+ <programlisting role="JAVA">Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);</programlisting>
- <para>
- How much does Hibernate load
- from the database and how many SQL <literal>SELECT</literal>s will it use? This
- depends on the <emphasis>fetching strategy</emphasis>. This is explained in
- <xref linkend="performance-fetching"/>.
- </para>
+ <para>Any associated instances or contained collections will
+ <emphasis>not</emphasis> be selected <literal>FOR UPDATE</literal>, unless
+ you decide to specify <literal>lock</literal> or <literal>all</literal> as
+ a cascade style for the association.</para>
- </section>
+ <para>It is possible to re-load an object and all its collections at any
+ time, using the <literal>refresh()</literal> method. This is useful when
+ database triggers are used to initialize some of the properties of the
+ object.</para>
- <section id="objectstate-querying" revision="1">
- <title>Querying</title>
+ <programlisting role="JAVA">sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)</programlisting>
- <para>
- If you do not know the identifiers of the objects you are looking for,
- you need a query. Hibernate supports an easy-to-use but powerful object
- oriented query language (HQL). For programmatic query creation, Hibernate
- supports a sophisticated Criteria and Example query feature (QBC and QBE).
- You can also express your query in the native SQL of your database, with
- optional support from Hibernate for result set conversion into objects.
- </para>
+ <para>How much does Hibernate load from the database and how many SQL
+ <literal>SELECT</literal>s will it use? This depends on the
+ <emphasis>fetching strategy</emphasis>. This is explained in <xref
+ linkend="performance-fetching" />.</para>
+ </section>
- <section id="objectstate-querying-executing" revision="1">
- <title>Executing queries</title>
+ <section id="objectstate-querying" revision="1">
+ <title>Querying</title>
- <para>
- HQL and native SQL queries are represented with an instance of <literal>org.hibernate.Query</literal>.
- This interface offers methods for parameter binding, result set handling, and for the execution
- of the actual query. You always obtain a <literal>Query</literal> using the current
- <literal>Session</literal>:
- </para>
+ <para>If you do not know the identifiers of the objects you are looking
+ for, you need a query. Hibernate supports an easy-to-use but powerful
+ object oriented query language (HQL). For programmatic query creation,
+ Hibernate supports a sophisticated Criteria and Example query feature (QBC
+ and QBE). You can also express your query in the native SQL of your
+ database, with optional support from Hibernate for result set conversion
+ into objects.</para>
- <programlisting role="JAVA"><![CDATA[List cats = session.createQuery(
- "from Cat as cat where cat.birthdate < ?")
+ <section id="objectstate-querying-executing" revision="1">
+ <title>Executing queries</title>
+
+ <para>HQL and native SQL queries are represented with an instance of
+ <literal>org.hibernate.Query</literal>. This interface offers methods
+ for parameter binding, result set handling, and for the execution of the
+ actual query. You always obtain a <literal>Query</literal> using the
+ current <literal>Session</literal>:</para>
+
+ <programlisting role="JAVA">List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
.setDate(0, date)
.list();
@@ -309,35 +273,32 @@
Query mothersWithKittens = (Cat) session.createQuery(
"select mother from Cat as mother left join fetch mother.kittens");
-Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+Set uniqueMothers = new HashSet(mothersWithKittens.list());</programlisting>
- <para>
- A query is usually executed by invoking <literal>list()</literal>. The
- result of the query will be loaded completely into a collection in memory.
- Entity instances retrieved by a query are in a persistent state. The
- <literal>uniqueResult()</literal> method offers a shortcut if you
- know your query will only return a single object. Queries that
- make use of eager fetching of collections usually return duplicates of
- the root objects, but with their collections initialized. You can filter
- these duplicates through a <literal>Set</literal>.
- </para>
+ <para>A query is usually executed by invoking <literal>list()</literal>.
+ The result of the query will be loaded completely into a collection in
+ memory. Entity instances retrieved by a query are in a persistent state.
+ The <literal>uniqueResult()</literal> method offers a shortcut if you
+ know your query will only return a single object. Queries that make use
+ of eager fetching of collections usually return duplicates of the root
+ objects, but with their collections initialized. You can filter these
+ duplicates through a <literal>Set</literal>.</para>
- <section id="objectstate-querying-executing-iterate">
- <title>Iterating results</title>
+ <section id="objectstate-querying-executing-iterate">
+ <title>Iterating results</title>
- <para>
- Occasionally, you might be able to achieve better performance by
- executing the query using the <literal>iterate()</literal> method.
- This will usually be the case if you expect that the actual
- entity instances returned by the query will already be in the session
- or second-level cache. If they are not already cached,
- <literal>iterate()</literal> will be slower than <literal>list()</literal>
- and might require many database hits for a simple query, usually
- <emphasis>1</emphasis> for the initial select which only returns identifiers,
- and <emphasis>n</emphasis> additional selects to initialize the actual instances.
- </para>
+ <para>Occasionally, you might be able to achieve better performance by
+ executing the query using the <literal>iterate()</literal> method.
+ This will usually be the case if you expect that the actual entity
+ instances returned by the query will already be in the session or
+ second-level cache. If they are not already cached,
+ <literal>iterate()</literal> will be slower than
+ <literal>list()</literal> and might require many database hits for a
+ simple query, usually <emphasis>1</emphasis> for the initial select
+ which only returns identifiers, and <emphasis>n</emphasis> additional
+ selects to initialize the actual instances.</para>
- <programlisting role="JAVA"><![CDATA[// fetch ids
+ <programlisting role="JAVA">// fetch ids
Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
while ( iter.hasNext() ) {
Qux qux = (Qux) iter.next(); // fetch the object
@@ -348,18 +309,16 @@
// dont need to process the rest
break;
}
-}]]></programlisting>
- </section>
-
- <section id="objectstate-querying-executing-tuples">
- <title>Queries that return tuples</title>
+}</programlisting>
+ </section>
- <para>
- Hibernate queries sometimes return tuples of objects. Each tuple
- is returned as an array:
- </para>
+ <section id="objectstate-querying-executing-tuples">
+ <title>Queries that return tuples</title>
- <programlisting role="JAVA"><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+ <para>Hibernate queries sometimes return tuples of objects. Each tuple
+ is returned as an array:</para>
+
+ <programlisting role="JAVA">Iterator kittensAndMothers = sess.createQuery(
"select kitten, mother from Cat kitten join kitten.mother mother")
.list()
.iterator();
@@ -369,20 +328,18 @@
Cat kitten = (Cat) tuple[0];
Cat mother = (Cat) tuple[1];
....
-}]]></programlisting>
+}</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-scalar" revision="1">
+ <title>Scalar results</title>
- <section id="objectstate-querying-executing-scalar" revision="1">
- <title>Scalar results</title>
+ <para>Queries can specify a property of a class in the
+ <literal>select</literal> clause. They can even call SQL aggregate
+ functions. Properties or aggregates are considered "scalar" results
+ and not entities in persistent state.</para>
- <para>
- Queries can specify a property of a class in the <literal>select</literal> clause.
- They can even call SQL aggregate functions. Properties or aggregates are considered
- "scalar" results and not entities in persistent state.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Iterator results = sess.createQuery(
+ <programlisting role="JAVA">Iterator results = sess.createQuery(
"select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
"group by cat.color")
.list()
@@ -394,92 +351,79 @@
Date oldest = (Date) row[1];
Integer count = (Integer) row[2];
.....
-}]]></programlisting>
+}</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-parameters">
+ <title>Bind parameters</title>
- <section id="objectstate-querying-executing-parameters">
- <title>Bind parameters</title>
+ <para>Methods on <literal>Query</literal> are provided for binding
+ values to named parameters or JDBC-style <literal>?</literal>
+ parameters. <emphasis>Contrary to JDBC, Hibernate numbers parameters
+ from zero.</emphasis> Named parameters are identifiers of the form
+ <literal>:name</literal> in the query string. The advantages of named
+ parameters are as follows:</para>
- <para>
- Methods on <literal>Query</literal> are provided for binding values to
- named parameters or JDBC-style <literal>?</literal> parameters.
- <emphasis>Contrary to JDBC, Hibernate numbers parameters from zero.</emphasis>
- Named parameters are identifiers of the form <literal>:name</literal> in
- the query string. The advantages of named parameters are as follows:
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>named parameters are insensitive to the order they occur in
+ the query string</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- named parameters are insensitive to the order they occur in the
- query string
- </para>
- </listitem>
- <listitem>
- <para>
- they can occur multiple times in the same query
- </para>
- </listitem>
- <listitem>
- <para>
- they are self-documenting
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>they can occur multiple times in the same query</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[//named parameter (preferred)
+ <listitem>
+ <para>they are self-documenting</para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting role="JAVA">//named parameter (preferred)
Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
q.setString("name", "Fritz");
-Iterator cats = q.iterate();]]></programlisting>
+Iterator cats = q.iterate();</programlisting>
- <programlisting role="JAVA"><![CDATA[//positional parameter
+ <programlisting role="JAVA">//positional parameter
Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
q.setString(0, "Izi");
-Iterator cats = q.iterate();]]></programlisting>
+Iterator cats = q.iterate();</programlisting>
- <programlisting role="JAVA"><![CDATA[//named parameter list
+ <programlisting role="JAVA">//named parameter list
List names = new ArrayList();
names.add("Izi");
names.add("Fritz");
Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
q.setParameterList("namesList", names);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-pagination">
+ <title>Pagination</title>
- <section id="objectstate-querying-executing-pagination">
- <title>Pagination</title>
+ <para>If you need to specify bounds upon your result set, that is, the
+ maximum number of rows you want to retrieve and/or the first row you
+ want to retrieve, you can use methods of the <literal>Query</literal>
+ interface:</para>
- <para>
- If you need to specify bounds upon your result set, that is, the maximum number of rows
- you want to retrieve and/or the first row you want to retrieve, you can
- use methods of the <literal>Query</literal> interface:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+ <programlisting role="JAVA">Query q = sess.createQuery("from DomesticCat cat");
q.setFirstResult(20);
q.setMaxResults(10);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
- <para>
- Hibernate knows how to translate this limit query into the native
- SQL of your DBMS.
- </para>
+ <para>Hibernate knows how to translate this limit query into the
+ native SQL of your DBMS.</para>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-scrolling">
+ <title>Scrollable iteration</title>
- <section id="objectstate-querying-executing-scrolling">
- <title>Scrollable iteration</title>
+ <para>If your JDBC driver supports scrollable
+ <literal>ResultSet</literal>s, the <literal>Query</literal> interface
+ can be used to obtain a <literal>ScrollableResults</literal> object
+ that allows flexible navigation of the query results.</para>
- <para>
- If your JDBC driver supports scrollable <literal>ResultSet</literal>s, the
- <literal>Query</literal> interface can be used to obtain a
- <literal>ScrollableResults</literal> object that allows flexible
- navigation of the query results.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+ <programlisting role="JAVA">Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
"order by cat.name");
ScrollableResults cats = q.scroll();
if ( cats.first() ) {
@@ -496,215 +440,188 @@
pageOfCats = new ArrayList();
cats.beforeFirst();
int i=0;
- while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
}
-cats.close()]]></programlisting>
+cats.close()</programlisting>
- <para>
- Note that an open database connection and cursor is required for this
- functionality. Use <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
- if you need offline pagination functionality.
- </para>
+ <para>Note that an open database connection and cursor is required for
+ this functionality. Use
+ <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+ if you need offline pagination functionality.</para>
+ </section>
- </section>
+ <section id="objectstate-querying-executing-named" revision="1">
+ <title>Externalizing named queries</title>
- <section id="objectstate-querying-executing-named" revision="1">
- <title>Externalizing named queries</title>
+ <para>You can also define named queries in the mapping document.
+ Remember to use a <literal>CDATA</literal> section if your query
+ contains characters that could be interpreted as markup.</para>
- <para>
- You can also define named queries in the mapping document. Remember to use a
- <literal>CDATA</literal> section if your query contains characters that could
- be interpreted as markup.
- </para>
-
- <programlisting role="XML"><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
+ <programlisting role="XML"><query name="ByNameAndMaximumWeight"><![CDATA[
from eg.DomesticCat as cat
where cat.name = ?
- and cat.weight > ?
-] ]></query>]]></programlisting>
+ and cat.weight > ?
+] ]></query></programlisting>
- <para>
- Parameter binding and executing is done programatically:
- </para>
+ <para>Parameter binding and executing is done programatically:</para>
- <programlisting role="JAVA"><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
+ <programlisting role="JAVA">Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name);
q.setInt(1, minWeight);
-List cats = q.list();]]></programlisting>
+List cats = q.list();</programlisting>
- <para>
- The actual program code is independent of the query language that
- is used. You can also define native SQL queries in metadata, or migrate
- existing queries to Hibernate by placing them in mapping files.
- </para>
+ <para>The actual program code is independent of the query language
+ that is used. You can also define native SQL queries in metadata, or
+ migrate existing queries to Hibernate by placing them in mapping
+ files.</para>
- <para>
- Also note that a query declaration inside a <literal><hibernate-mapping></literal>
- element requires a global unique name for the query, while a query declaration inside a
- <literal><class></literal> element is made unique automatically by prepending the
- fully qualified name of the class. For example
- <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
- </para>
+ <para>Also note that a query declaration inside a
+ <literal><hibernate-mapping></literal> element requires a global
+ unique name for the query, while a query declaration inside a
+ <literal><class></literal> element is made unique automatically
+ by prepending the fully qualified name of the class. For example
+ <literal>eg.Cat.ByNameAndMaximumWeight</literal>.</para>
+ </section>
+ </section>
- </section>
+ <section id="objectstate-filtering" revision="1">
+ <title>Filtering collections</title>
- </section>
+ <para>A collection <emphasis>filter</emphasis> is a special type of
+ query that can be applied to a persistent collection or array. The query
+ string can refer to <literal>this</literal>, meaning the current
+ collection element.</para>
- <section id="objectstate-filtering" revision="1">
- <title>Filtering collections</title>
- <para>
- A collection <emphasis>filter</emphasis> is a special type of query that can be applied to
- a persistent collection or array. The query string can refer to <literal>this</literal>,
- meaning the current collection element.
- </para>
-
- <programlisting role="JAVA"><![CDATA[Collection blackKittens = session.createFilter(
+ <programlisting role="JAVA">Collection blackKittens = session.createFilter(
pk.getKittens(),
"where this.color = ?")
.setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
.list()
-);]]></programlisting>
-
- <para>
- The returned collection is considered a bag that is a copy of the given
- collection. The original collection is not modified. This is contrary to
- the implication of the name "filter", but consistent with expected behavior.
- </para>
+);</programlisting>
- <para>
- Observe that filters do not require a <literal>from</literal> clause, although they can have
- one if required. Filters are not limited to returning the collection elements themselves.
- </para>
+ <para>The returned collection is considered a bag that is a copy of the
+ given collection. The original collection is not modified. This is
+ contrary to the implication of the name "filter", but consistent with
+ expected behavior.</para>
- <programlisting role="JAVA"><![CDATA[Collection blackKittenMates = session.createFilter(
+ <para>Observe that filters do not require a <literal>from</literal>
+ clause, although they can have one if required. Filters are not limited
+ to returning the collection elements themselves.</para>
+
+ <programlisting role="JAVA">Collection blackKittenMates = session.createFilter(
pk.getKittens(),
"select this.mate where this.color = eg.Color.BLACK.intValue")
- .list();]]></programlisting>
+ .list();</programlisting>
- <para>
- Even an empty filter query is useful, e.g. to load a subset of elements in a
- large collection:
- </para>
+ <para>Even an empty filter query is useful, e.g. to load a subset of
+ elements in a large collection:</para>
- <programlisting role="JAVA"><![CDATA[Collection tenKittens = session.createFilter(
+ <programlisting role="JAVA">Collection tenKittens = session.createFilter(
mother.getKittens(), "")
.setFirstResult(0).setMaxResults(10)
- .list();]]></programlisting>
+ .list();</programlisting>
+ </section>
- </section>
+ <section id="objecstate-querying-criteria" revision="1">
+ <title>Criteria queries</title>
- <section id="objecstate-querying-criteria" revision="1">
- <title>Criteria queries</title>
+ <para>HQL is extremely powerful, but some developers prefer to build
+ queries dynamically using an object-oriented API, rather than building
+ query strings. Hibernate provides an intuitive
+ <literal>Criteria</literal> query API for these cases:</para>
- <para>
- HQL is extremely powerful, but some developers prefer to build queries dynamically
- using an object-oriented API, rather than building query strings. Hibernate provides
- an intuitive <literal>Criteria</literal> query API for these cases:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+ <programlisting role="JAVA">Criteria crit = session.createCriteria(Cat.class);
crit.add( Restrictions.eq( "color", eg.Color.BLACK ) );
crit.setMaxResults(10);
-List cats = crit.list();]]></programlisting>
-
- <para>
- The <literal>Criteria</literal> and the associated <literal>Example</literal>
- API are discussed in more detail in <xref linkend="querycriteria"/>.
- </para>
+List cats = crit.list();</programlisting>
- </section>
+ <para>The <literal>Criteria</literal> and the associated
+ <literal>Example</literal> API are discussed in more detail in <xref
+ linkend="querycriteria" />.</para>
+ </section>
- <section id="objectstate-querying-nativesql" revision="2">
- <title>Queries in native SQL</title>
+ <section id="objectstate-querying-nativesql" revision="2">
+ <title>Queries in native SQL</title>
- <para>
- You can express a query in SQL, using <literal>createSQLQuery()</literal> and
- let Hibernate manage the mapping from result sets to objects.
- You can at any time call <literal>session.connection()</literal> and
- use the JDBC <literal>Connection</literal> directly. If you choose to use the
- Hibernate API, you must enclose SQL aliases in braces:
- </para>
+ <para>You can express a query in SQL, using
+ <literal>createSQLQuery()</literal> and let Hibernate manage the mapping
+ from result sets to objects. You can at any time call
+ <literal>session.connection()</literal> and use the JDBC
+ <literal>Connection</literal> directly. If you choose to use the
+ Hibernate API, you must enclose SQL aliases in braces:</para>
- <programlisting role="JAVA"><![CDATA[List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
+ <programlisting role="JAVA">List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
-.list();]]></programlisting>
-
- <programlisting role="JAVA"><![CDATA[List cats = session.createSQLQuery(
+.list();</programlisting>
+
+ <programlisting role="JAVA">List cats = session.createSQLQuery(
"SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
"{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
- "FROM CAT {cat} WHERE ROWNUM<10")
+ "FROM CAT {cat} WHERE ROWNUM<10")
.addEntity("cat", Cat.class)
-.list()]]></programlisting>
+.list()</programlisting>
- <para>
- SQL queries can contain named and positional parameters, just like Hibernate queries.
- More information about native SQL queries in Hibernate can be found in
- <xref linkend="querysql"/>.
- </para>
-
- </section>
-
+ <para>SQL queries can contain named and positional parameters, just like
+ Hibernate queries. More information about native SQL queries in
+ Hibernate can be found in <xref linkend="querysql" />.</para>
</section>
+ </section>
- <section id="objectstate-modifying" revision="1">
- <title>Modifying persistent objects</title>
+ <section id="objectstate-modifying" revision="1">
+ <title>Modifying persistent objects</title>
- <para>
- <emphasis>Transactional persistent instances</emphasis> (i.e. objects loaded, saved, created or
- queried by the <literal>Session</literal>) can be manipulated by the application,
- and any changes to persistent state will be persisted when the <literal>Session</literal>
- is <emphasis>flushed</emphasis>. This is discussed later in this chapter. There is no need
- to call a particular method (like <literal>update()</literal>, which has a different
- purpose) to make your modifications persistent. The most straightforward way to update
- the state of an object is to <literal>load()</literal> it
- and then manipulate it directly while the <literal>Session</literal> is open:
- </para>
+ <para><emphasis>Transactional persistent instances</emphasis> (i.e.
+ objects loaded, saved, created or queried by the
+ <literal>Session</literal>) can be manipulated by the application, and any
+ changes to persistent state will be persisted when the
+ <literal>Session</literal> is <emphasis>flushed</emphasis>. This is
+ discussed later in this chapter. There is no need to call a particular
+ method (like <literal>update()</literal>, which has a different purpose)
+ to make your modifications persistent. The most straightforward way to
+ update the state of an object is to <literal>load()</literal> it and then
+ manipulate it directly while the <literal>Session</literal> is
+ open:</para>
- <programlisting role="JAVA"><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+ <programlisting role="JAVA">DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
cat.setName("PK");
-sess.flush(); // changes to cat are automatically detected and persisted]]></programlisting>
+sess.flush(); // changes to cat are automatically detected and persisted</programlisting>
- <para>
- Sometimes this programming model is inefficient, as it requires in the same session both an SQL
- <literal>SELECT</literal> to load an object and an SQL <literal>UPDATE</literal>
- to persist its updated state. Hibernate offers an
- alternate approach by using detached instances.
- </para>
+ <para>Sometimes this programming model is inefficient, as it requires in
+ the same session both an SQL <literal>SELECT</literal> to load an object
+ and an SQL <literal>UPDATE</literal> to persist its updated state.
+ Hibernate offers an alternate approach by using detached instances.</para>
- <important><para>
- Hibernate does not offer its own API for direct execution of
- <literal>UPDATE</literal> or <literal>DELETE</literal> statements. Hibernate is a
- <emphasis>state management</emphasis> service, you do not have to think in
- <emphasis>statements</emphasis> to use it. JDBC is a perfect API for executing
- SQL statements, you can get a JDBC <literal>Connection</literal> at any time
- by calling <literal>session.connection()</literal>. Furthermore, the notion
- of mass operations conflicts with object/relational mapping for online
- transaction processing-oriented applications. Future versions of Hibernate
- can, however, provide special mass operation functions. See <xref linkend="batch"/>
- for some possible batch operation tricks.
- </para>
-</important>
+ <important>
+ <para>Hibernate does not offer its own API for direct execution of
+ <literal>UPDATE</literal> or <literal>DELETE</literal> statements.
+ Hibernate is a <emphasis>state management</emphasis> service, you do not
+ have to think in <emphasis>statements</emphasis> to use it. JDBC is a
+ perfect API for executing SQL statements, you can get a JDBC
+ <literal>Connection</literal> at any time by calling
+ <literal>session.connection()</literal>. Furthermore, the notion of mass
+ operations conflicts with object/relational mapping for online
+ transaction processing-oriented applications. Future versions of
+ Hibernate can, however, provide special mass operation functions. See
+ <xref linkend="batch" /> for some possible batch operation
+ tricks.</para>
+ </important>
+ </section>
- </section>
+ <section id="objectstate-detached" revision="2">
+ <title>Modifying detached objects</title>
- <section id="objectstate-detached" revision="2">
- <title>Modifying detached objects</title>
+ <para>Many applications need to retrieve an object in one transaction,
+ send it to the UI layer for manipulation, then save the changes in a new
+ transaction. Applications that use this kind of approach in a
+ high-concurrency environment usually use versioned data to ensure
+ isolation for the "long" unit of work.</para>
- <para>
- Many applications need to retrieve an object in one transaction, send it to the
- UI layer for manipulation, then save the changes in a new transaction.
- Applications that use this kind of approach in a high-concurrency environment
- usually use versioned data to ensure isolation for the "long" unit of work.
- </para>
+ <para>Hibernate supports this model by providing for reattachment of
+ detached instances using the <literal>Session.update()</literal> or
+ <literal>Session.merge()</literal> methods:</para>
- <para>
- Hibernate supports this model by providing for reattachment of detached instances
- using the <literal>Session.update()</literal> or <literal>Session.merge()</literal>
- methods:
- </para>
-
- <programlisting role="JAVA"><![CDATA[// in the first session
+ <programlisting role="JAVA">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);
@@ -714,66 +631,57 @@
// later, in a new session
secondSession.update(cat); // update cat
-secondSession.update(mate); // update mate]]></programlisting>
+secondSession.update(mate); // update mate</programlisting>
- <para>
- If the <literal>Cat</literal> with identifier <literal>catId</literal> had already
- been loaded by <literal>secondSession</literal> when the application tried to
- reattach it, an exception would have been thrown.
- </para>
+ <para>If the <literal>Cat</literal> with identifier
+ <literal>catId</literal> had already been loaded by
+ <literal>secondSession</literal> when the application tried to reattach
+ it, an exception would have been thrown.</para>
- <para>
- Use <literal>update()</literal> if you are certain that the session does
- not contain an already persistent instance with the same identifier. Use
- <literal>merge()</literal> if you want to merge your modifications at any time
- without consideration of the state of the session. In other words, <literal>update()</literal>
- is usually the first method you would call in a fresh session, ensuring that
- the reattachment of your detached instances is the first operation that is executed.
- </para>
+ <para>Use <literal>update()</literal> if you are certain that the session
+ does not contain an already persistent instance with the same identifier.
+ Use <literal>merge()</literal> if you want to merge your modifications at
+ any time without consideration of the state of the session. In other
+ words, <literal>update()</literal> is usually the first method you would
+ call in a fresh session, ensuring that the reattachment of your detached
+ instances is the first operation that is executed.</para>
- <para>
- The application should individually <literal>update()</literal> detached instances
- that are reachable from the given detached instance <emphasis>only</emphasis> if it wants
- their state to be updated. This can be automated using <emphasis>transitive
- persistence</emphasis>. See <xref linkend="objectstate-transitive"/> for more information.
- </para>
+ <para>The application should individually <literal>update()</literal>
+ detached instances that are reachable from the given detached instance
+ <emphasis>only</emphasis> if it wants their state to be updated. This can
+ be automated using <emphasis>transitive persistence</emphasis>. See <xref
+ linkend="objectstate-transitive" /> for more information.</para>
- <para>
- The <literal>lock()</literal> method also allows an application to reassociate
- an object with a new session. However, the detached instance has to be unmodified.
- </para>
+ <para>The <literal>lock()</literal> method also allows an application to
+ reassociate an object with a new session. However, the detached instance
+ has to be unmodified.</para>
- <programlisting role="JAVA"><![CDATA[//just reassociate:
+ <programlisting role="JAVA">//just reassociate:
sess.lock(fritz, LockMode.NONE);
//do a version check, then reassociate:
sess.lock(izi, LockMode.READ);
//do a version check, using SELECT ... FOR UPDATE, then reassociate:
-sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+sess.lock(pk, LockMode.UPGRADE);</programlisting>
- <para>
- Note that <literal>lock()</literal> can be used with various
- <literal>LockMode</literal>s. See the API documentation and the
- chapter on transaction handling for more information. Reattachment is not
- the only usecase for <literal>lock()</literal>.
- </para>
+ <para>Note that <literal>lock()</literal> can be used with various
+ <literal>LockMode</literal>s. See the API documentation and the chapter on
+ transaction handling for more information. Reattachment is not the only
+ usecase for <literal>lock()</literal>.</para>
- <para>
- Other models for long units of work are discussed in <xref linkend="transactions-optimistic"/>.
- </para>
+ <para>Other models for long units of work are discussed in <xref
+ linkend="transactions-optimistic" />.</para>
+ </section>
- </section>
+ <section id="objectstate-saveorupdate">
+ <title>Automatic state detection</title>
- <section id="objectstate-saveorupdate">
- <title>Automatic state detection</title>
+ <para>Hibernate users have requested a general purpose method that either
+ saves a transient instance by generating a new identifier or
+ updates/reattaches the detached instances associated with its current
+ identifier. The <literal>saveOrUpdate()</literal> method implements this
+ functionality.</para>
- <para>
- Hibernate users have requested a general purpose method that either saves a
- transient instance by generating a new identifier or updates/reattaches
- the detached instances associated with its current identifier.
- The <literal>saveOrUpdate()</literal> method implements this functionality.
- </para>
-
- <programlisting role="JAVA"><![CDATA[// in the first session
+ <programlisting role="JAVA">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catID);
// in a higher tier of the application
@@ -782,157 +690,129 @@
// later, in a new session
secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
-secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)]]></programlisting>
+secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)</programlisting>
- <para>
- The usage and semantics of <literal>saveOrUpdate()</literal> seems to be confusing
- for new users. Firstly, so long as you are not trying to use instances from one session
- in another new session, you should not need to use <literal>update()</literal>,
- <literal>saveOrUpdate()</literal>, or <literal>merge()</literal>. Some whole
- applications will never use either of these methods.
- </para>
+ <para>The usage and semantics of <literal>saveOrUpdate()</literal> seems
+ to be confusing for new users. Firstly, so long as you are not trying to
+ use instances from one session in another new session, you should not need
+ to use <literal>update()</literal>, <literal>saveOrUpdate()</literal>, or
+ <literal>merge()</literal>. Some whole applications will never use either
+ of these methods.</para>
- <para>
- Usually <literal>update()</literal> or <literal>saveOrUpdate()</literal> are used in
- the following scenario:
- </para>
+ <para>Usually <literal>update()</literal> or
+ <literal>saveOrUpdate()</literal> are used in the following
+ scenario:</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- the application loads an object in the first session
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed up to the UI tier
- </para>
- </listitem>
- <listitem>
- <para>
- some modifications are made to the object
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed back down to the business logic tier
- </para>
- </listitem>
- <listitem>
- <para>
- the application persists these modifications by calling
- <literal>update()</literal> in a second session
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>the application loads an object in the first session</para>
+ </listitem>
- <para>
- <literal>saveOrUpdate()</literal> does the following:
- </para>
+ <listitem>
+ <para>the object is passed up to the UI tier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if the object is already persistent in this session, do nothing
- </para>
- </listitem>
- <listitem>
- <para>
- if another object associated with the session has the same identifier,
- throw an exception
- </para>
- </listitem>
- <listitem>
- <para>
- if the object has no identifier property, <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object's identifier has the value assigned to a newly instantiated
- object, <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object is versioned by a <literal><version></literal> or
- <literal><timestamp></literal>, and the version property value
- is the same value assigned to a newly instantiated object,
- <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- otherwise <literal>update()</literal> the object
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>some modifications are made to the object</para>
+ </listitem>
- <para>
- and <literal>merge()</literal> is very different:
- </para>
+ <listitem>
+ <para>the object is passed back down to the business logic tier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if there is a persistent instance with the same identifier currently
- associated with the session, copy the state of the given object onto
- the persistent instance
- </para>
- </listitem>
- <listitem>
- <para>
- if there is no persistent instance currently associated with the session,
- try to load it from the database, or create a new persistent instance
- </para>
- </listitem>
- <listitem>
- <para>
- the persistent instance is returned
- </para>
- </listitem>
- <listitem>
- <para>
- the given instance does not become associated with the session, it
- remains detached
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>the application persists these modifications by calling
+ <literal>update()</literal> in a second session</para>
+ </listitem>
+ </itemizedlist>
- </section>
+ <para><literal>saveOrUpdate()</literal> does the following:</para>
- <section id="objectstate-deleting" revision="1">
- <title>Deleting persistent objects</title>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>if the object is already persistent in this session, do
+ nothing</para>
+ </listitem>
- <para>
- <literal>Session.delete()</literal> will remove an object's state from the database.
- Your application, however, can still hold a reference to a deleted object.
- It is best to think of <literal>delete()</literal> as making a persistent instance,
- transient.
- </para>
+ <listitem>
+ <para>if another object associated with the session has the same
+ identifier, throw an exception</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[sess.delete(cat);]]></programlisting>
+ <listitem>
+ <para>if the object has no identifier property,
+ <literal>save()</literal> it</para>
+ </listitem>
- <para>
- You can delete objects in any order, without risk of foreign key
- constraint violations. It is still possible to violate a <literal>NOT
- NULL</literal> constraint on a foreign key column by deleting objects in
- the wrong order, e.g. if you delete the parent, but forget to delete the
- children.
- </para>
+ <listitem>
+ <para>if the object's identifier has the value assigned to a newly
+ instantiated object, <literal>save()</literal> it</para>
+ </listitem>
- </section>
-
- <section id="objectstate-replicating" revision="1">
- <title>Replicating object between two different datastores</title>
-
- <para>
- It is sometimes useful to be able to take a graph of persistent instances
- and make them persistent in a different datastore, without regenerating identifier
- values.
- </para>
-
- <programlisting role="JAVA"><![CDATA[//retrieve a cat from one database
+ <listitem>
+ <para>if the object is versioned by a
+ <literal><version></literal> or
+ <literal><timestamp></literal>, and the version property value
+ is the same value assigned to a newly instantiated object,
+ <literal>save()</literal> it</para>
+ </listitem>
+
+ <listitem>
+ <para>otherwise <literal>update()</literal> the object</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>and <literal>merge()</literal> is very different:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>if there is a persistent instance with the same identifier
+ currently associated with the session, copy the state of the given
+ object onto the persistent instance</para>
+ </listitem>
+
+ <listitem>
+ <para>if there is no persistent instance currently associated with the
+ session, try to load it from the database, or create a new persistent
+ instance</para>
+ </listitem>
+
+ <listitem>
+ <para>the persistent instance is returned</para>
+ </listitem>
+
+ <listitem>
+ <para>the given instance does not become associated with the session,
+ it remains detached</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+
+ <section id="objectstate-deleting" revision="1">
+ <title>Deleting persistent objects</title>
+
+ <para><literal>Session.delete()</literal> will remove an object's state
+ from the database. Your application, however, can still hold a reference
+ to a deleted object. It is best to think of <literal>delete()</literal> as
+ making a persistent instance, transient.</para>
+
+ <programlisting role="JAVA">sess.delete(cat);</programlisting>
+
+ <para>You can delete objects in any order, without risk of foreign key
+ constraint violations. It is still possible to violate a <literal>NOT
+ NULL</literal> constraint on a foreign key column by deleting objects in
+ the wrong order, e.g. if you delete the parent, but forget to delete the
+ children.</para>
+ </section>
+
+ <section id="objectstate-replicating" revision="1">
+ <title>Replicating object between two different datastores</title>
+
+ <para>It is sometimes useful to be able to take a graph of persistent
+ instances and make them persistent in a different datastore, without
+ regenerating identifier values.</para>
+
+ <programlisting role="JAVA">//retrieve a cat from one database
Session session1 = factory1.openSession();
Transaction tx1 = session1.beginTransaction();
Cat cat = session1.get(Cat.class, catId);
@@ -944,140 +824,117 @@
Transaction tx2 = session2.beginTransaction();
session2.replicate(cat, ReplicationMode.LATEST_VERSION);
tx2.commit();
-session2.close();]]></programlisting>
+session2.close();</programlisting>
- <para>
- The <literal>ReplicationMode</literal> determines how <literal>replicate()</literal>
- will deal with conflicts with existing rows in the database:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>ReplicationMode.IGNORE</literal>: ignores the object when there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.OVERWRITE</literal>: overwrites any existing database
- row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.EXCEPTION</literal>: throws an exception if there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.LATEST_VERSION</literal>: overwrites the row if its
- version number is earlier than the version number of the object, or ignore
- the object otherwise
- </para>
- </listitem>
- </itemizedlist>
+ <para>The <literal>ReplicationMode</literal> determines how
+ <literal>replicate()</literal> will deal with conflicts with existing rows
+ in the database:</para>
- <para>
- Usecases for this feature include reconciling data entered into different database
- instances, upgrading system configuration information during product upgrades,
- rolling back changes made during non-ACID transactions and more.
- </para>
-
- </section>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>ReplicationMode.IGNORE</literal>: ignores the object
+ when there is an existing database row with the same identifier</para>
+ </listitem>
- <section id="objectstate-flushing">
- <title>Flushing the Session</title>
+ <listitem>
+ <para><literal>ReplicationMode.OVERWRITE</literal>: overwrites any
+ existing database row with the same identifier</para>
+ </listitem>
- <para>
- Sometimes the <literal>Session</literal> will execute the SQL statements
- needed to synchronize the JDBC connection's state with the state of objects held in
- memory. This process, called <emphasis>flush</emphasis>, occurs by default at the following
- points:
- </para>
+ <listitem>
+ <para><literal>ReplicationMode.EXCEPTION</literal>: throws an
+ exception if there is an existing database row with the same
+ identifier</para>
+ </listitem>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- before some query executions
- </para>
- </listitem>
- <listitem>
- <para>
- from <literal>org.hibernate.Transaction.commit()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- from <literal>Session.flush()</literal>
- </para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para><literal>ReplicationMode.LATEST_VERSION</literal>: overwrites
+ the row if its version number is earlier than the version number of
+ the object, or ignore the object otherwise</para>
+ </listitem>
+ </itemizedlist>
- <para>
- The SQL statements are issued in the following order:
- </para>
+ <para>Usecases for this feature include reconciling data entered into
+ different database instances, upgrading system configuration information
+ during product upgrades, rolling back changes made during non-ACID
+ transactions and more.</para>
+ </section>
- <orderedlist spacing="compact">
- <listitem>
- <para>
- all entity insertions in the same order the corresponding objects
- were saved using <literal>Session.save()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- all entity updates
- </para>
- </listitem>
- <listitem>
- <para>
- all collection deletions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection element deletions, updates and insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all entity deletions in the same order the corresponding objects
- were deleted using <literal>Session.delete()</literal>
- </para>
- </listitem>
- </orderedlist>
+ <section id="objectstate-flushing">
+ <title>Flushing the Session</title>
- <para>
- An exception is that objects using <literal>native</literal> ID generation are
- inserted when they are saved.
- </para>
+ <para>Sometimes the <literal>Session</literal> will execute the SQL
+ statements needed to synchronize the JDBC connection's state with the
+ state of objects held in memory. This process, called
+ <emphasis>flush</emphasis>, occurs by default at the following
+ points:</para>
- <para>
- Except when you explicitly <literal>flush()</literal>, there are absolutely no
- guarantees about <emphasis>when</emphasis> the <literal>Session</literal> executes
- the JDBC calls, only the <emphasis>order</emphasis> in which they are executed.
- However, Hibernate does guarantee that the <literal>Query.list(..)</literal>
- will never return stale or incorrect data.
- </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>before some query executions</para>
+ </listitem>
- <para>
- It is possible to change the default behavior so that flush occurs less frequently.
- The <literal>FlushMode</literal> class defines three different modes: only flush
- at commit time when the Hibernate <literal>Transaction</literal> API
- is used, flush automatically using the explained routine, or never flush unless
- <literal>flush()</literal> is called explicitly. The last mode is useful for long running
- units of work, where a <literal>Session</literal> is kept open and disconnected for
- a long time (see <xref linkend="transactions-optimistic-longsession"/>).
- </para>
+ <listitem>
+ <para>from
+ <literal>org.hibernate.Transaction.commit()</literal></para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[sess = sf.openSession();
+ <listitem>
+ <para>from <literal>Session.flush()</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The SQL statements are issued in the following order:</para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>all entity insertions in the same order the corresponding
+ objects were saved using <literal>Session.save()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>all entity updates</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection deletions</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection element deletions, updates and insertions</para>
+ </listitem>
+
+ <listitem>
+ <para>all collection insertions</para>
+ </listitem>
+
+ <listitem>
+ <para>all entity deletions in the same order the corresponding objects
+ were deleted using <literal>Session.delete()</literal></para>
+ </listitem>
+ </orderedlist>
+
+ <para>An exception is that objects using <literal>native</literal> ID
+ generation are inserted when they are saved.</para>
+
+ <para>Except when you explicitly <literal>flush()</literal>, there are
+ absolutely no guarantees about <emphasis>when</emphasis> the
+ <literal>Session</literal> executes the JDBC calls, only the
+ <emphasis>order</emphasis> in which they are executed. However, Hibernate
+ does guarantee that the <literal>Query.list(..)</literal> will never
+ return stale or incorrect data.</para>
+
+ <para>It is possible to change the default behavior so that flush occurs
+ less frequently. The <literal>FlushMode</literal> class defines three
+ different modes: only flush at commit time when the Hibernate
+ <literal>Transaction</literal> API is used, flush automatically using the
+ explained routine, or never flush unless <literal>flush()</literal> is
+ called explicitly. The last mode is useful for long running units of work,
+ where a <literal>Session</literal> is kept open and disconnected for a
+ long time (see <xref
+ linkend="transactions-optimistic-longsession" />).</para>
+
+ <programlisting role="JAVA">sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
@@ -1090,188 +947,245 @@
// change to izi is not flushed!
...
tx.commit(); // flush occurs
-sess.close();]]></programlisting>
+sess.close();</programlisting>
- <para>
- During flush, an exception might occur (e.g. if a DML operation violates a constraint).
- Since handling exceptions involves some understanding of Hibernate's transactional
- behavior, we discuss it in <xref linkend="transactions"/>.
- </para>
+ <para>During flush, an exception might occur (e.g. if a DML operation
+ violates a constraint). Since handling exceptions involves some
+ understanding of Hibernate's transactional behavior, we discuss it in
+ <xref linkend="transactions" />.</para>
+ </section>
- </section>
+ <section id="objectstate-transitive" revision="1">
+ <title>Transitive persistence</title>
- <section id="objectstate-transitive" revision="1">
- <title>Transitive persistence</title>
+ <para>It is quite cumbersome to save, delete, or reattach individual
+ objects, especially if you deal with a graph of associated objects. A
+ common case is a parent/child relationship. Consider the following
+ example:</para>
- <para>
- It is quite cumbersome to save, delete, or reattach individual objects,
- especially if you deal with a graph of associated objects. A common case is
- a parent/child relationship. Consider the following example:
- </para>
+ <para>If the children in a parent/child relationship would be value typed
+ (e.g. a collection of addresses or strings), their life cycle would depend
+ on the parent and no further action would be required for convenient
+ "cascading" of state changes. When the parent is saved, the value-typed
+ child objects are saved and when the parent is deleted, the children will
+ be deleted, etc. This works for operations such as the removal of a child
+ from the collection. Since value-typed objects cannot have shared
+ references, Hibernate will detect this and delete the child from the
+ database.</para>
- <para>
- If the children in a parent/child relationship would be value typed (e.g. a collection
- of addresses or strings), their life cycle would depend on the parent and no
- further action would be required for convenient "cascading" of state changes.
- When the parent is saved, the value-typed child objects are saved and
- when the parent is deleted, the children will be deleted, etc. This
- works for operations such as the removal of a child from the collection.
- Since value-typed objects cannot have shared
- references, Hibernate will detect this and delete the child from the database.
- </para>
+ <para>Now consider the same scenario with parent and child objects being
+ entities, not value-types (e.g. categories and items, or parent and child
+ cats). Entities have their own life cycle and support shared references.
+ Removing an entity from the collection does not mean it can be deleted),
+ and there is by default no cascading of state from one entity to any other
+ associated entities. Hibernate does not implement <emphasis>persistence by
+ reachability</emphasis> by default.</para>
- <para>
- Now consider the same scenario with parent and child objects being entities,
- not value-types (e.g. categories and items, or parent and child cats). Entities
- have their own life cycle and support shared references. Removing an entity from
- the collection does not mean it can be deleted), and there is by default no
- cascading of state from one entity to any other associated entities. Hibernate
- does not implement <emphasis>persistence by reachability</emphasis> by default.
- </para>
+ <para>For each basic operation of the Hibernate session - including
+ <literal>persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(),
+ evict(), replicate()</literal> - there is a corresponding cascade style.
+ Respectively, the cascade styles are named <literal>create, merge,
+ save-update, delete, lock, refresh, evict, replicate</literal>. If you
+ want an operation to be cascaded along an association, you must indicate
+ that in the mapping document. For example:</para>
- <para>
- For each basic operation of the Hibernate session - including <literal>persist(), merge(),
- saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - there is a
- corresponding cascade style. Respectively, the cascade styles are named <literal>create,
- merge, save-update, delete, lock, refresh, evict, replicate</literal>. If you want an
- operation to be cascaded along an association, you must indicate that in the mapping
- document. For example:
- </para>
-
- <programlisting role="XML"><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
-
- <para>
- Cascade styles my be combined:
- </para>
-
- <programlisting role="XML"><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
-
- <para>
- You can even use <literal>cascade="all"</literal> to specify that <emphasis>all</emphasis>
- operations should be cascaded along the association. The default <literal>cascade="none"</literal>
- specifies that no operations are to be cascaded.
- </para>
-
- <para>
- A special cascade style, <literal>delete-orphan</literal>, applies only to one-to-many
- associations, and indicates that the <literal>delete()</literal> operation should
- be applied to any child object that is removed from the association.
- </para>
+ <programlisting role="XML"><one-to-one name="person" cascade="persist"/></programlisting>
+ <para>Cascade styles my be combined:</para>
- <para>
- Recommendations:
- </para>
+ <programlisting role="XML"><one-to-one name="person" cascade="persist,delete,lock"/></programlisting>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- It does not usually make sense to enable cascade on a <literal><many-to-one></literal>
- or <literal><many-to-many></literal> association. Cascade is often useful for
- <literal><one-to-one></literal> and <literal><one-to-many></literal>
- associations.
- </para>
- </listitem>
- <listitem>
- <para>
- If the child object's lifespan is bounded by the lifespan of the parent
- object, make it a <emphasis>life cycle object</emphasis> by specifying
- <literal>cascade="all,delete-orphan"</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Otherwise, you might not need cascade at all. But if you think that you will often be
- working with the parent and children together in the same transaction, and you want to save
- yourself some typing, consider using <literal>cascade="persist,merge,save-update"</literal>.
- </para>
- </listitem>
- </itemizedlist>
+ <para>You can even use <literal>cascade="all"</literal> to specify that
+ <emphasis>all</emphasis> operations should be cascaded along the
+ association. The default <literal>cascade="none"</literal> specifies that
+ no operations are to be cascaded.</para>
- <para>
- Mapping an association (either a single valued association, or a collection) with
- <literal>cascade="all"</literal> marks the association as a
- <emphasis>parent/child</emphasis> style relationship where save/update/delete of the
- parent results in save/update/delete of the child or children.
- </para>
- <para>
- Furthermore, a mere reference to a child from a persistent parent will result in
- save/update of the child. This metaphor is incomplete, however. A child which becomes
- unreferenced by its parent is <emphasis>not</emphasis> automatically deleted, except
- in the case of a <literal><one-to-many></literal> association mapped with
- <literal>cascade="delete-orphan"</literal>. The precise semantics of cascading
- operations for a parent/child relationship are as follows:
- </para>
+ <para>In case you are using annotatons you probably have noticed the
+ <literal>cascade</literal> attribute taking an array of
+ <classname>CascadeType</classname> as a value. The cascade concept in JPA
+ is very is similar to the transitive persistence and cascading of
+ operations as described above, but with slightly different semantics and
+ cascading types:</para>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- If a parent is passed to <literal>persist()</literal>, all children are passed to
- <literal>persist()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>merge()</literal>, all children are passed to
- <literal>merge()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>save()</literal>, <literal>update()</literal> or
- <literal>saveOrUpdate()</literal>, all children are passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a transient or detached child becomes referenced by a persistent parent,
- it is passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is deleted, all children are passed to <literal>delete()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a child is dereferenced by a persistent parent, <emphasis>nothing
- special happens</emphasis> - the application should explicitly delete
- the child if necessary - unless <literal>cascade="delete-orphan"</literal>,
- in which case the "orphaned" child is deleted.
- </para>
- </listitem>
- </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para><literal>CascadeType.PERSIST</literal>: cascades the persist
+ (create) operation to associated entities persist() is called or if
+ the entity is managed</para>
+ </listitem>
- <para>
- Finally, note that cascading of operations can be applied to an object graph at
- <emphasis>call time</emphasis> or at <emphasis>flush time</emphasis>. All operations,
- if enabled, are cascaded to associated entities reachable when the operation is
- executed. However, <literal>save-update</literal> and <literal>delete-orphan</literal>
- are transitive for all associated entities reachable during flush of the
- <literal>Session</literal>.
- </para>
+ <listitem>
+ <para><literal>CascadeType.MERGE</literal>: cascades the merge
+ operation to associated entities if merge() is called or if the entity
+ is managed</para>
+ </listitem>
- </section>
+ <listitem>
+ <para><literal>CascadeType.REMOVE</literal>: cascades the remove
+ operation to associated entities if delete() is called</para>
+ </listitem>
- <section id="objectstate-metadata">
- <title>Using metadata</title>
+ <listitem>
+ <para><literal>CascadeType.REFRESH:</literal> cascades the refresh
+ operation to associated entities if refresh() is called</para>
+ </listitem>
- <para>
- Hibernate requires a rich meta-level model of all entity and value types.
- This model can be useful to the application itself. For example, the application
- might use Hibernate's metadata to implement a "smart" deep-copy algorithm that understands
- which objects should be copied (eg. mutable value types) and which objects that should not (e.g.
- immutable value types and, possibly, associated entities).
- </para>
- <para>
- Hibernate exposes metadata via the <literal>ClassMetadata</literal> and
- <literal>CollectionMetadata</literal> interfaces and the <literal>Type</literal>
- hierarchy. Instances of the metadata interfaces can be obtained from the
- <literal>SessionFactory</literal>.
- </para>
+ <listitem>
+ <para><literal>CascadeType.DETACH:</literal> cascades the detach
+ operation to associated entities if detach() is called</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[Cat fritz = ......;
+ <listitem>
+ <para><literal>CascadeType.ALL</literal>: all of the above</para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>CascadeType.ALL also covers Hibernate specific operations like
+ save-update, lock etc... </para>
+ </note>
+
+ <para>A special cascade style, <literal>delete-orphan</literal>, applies
+ only to one-to-many associations, and indicates that the
+ <literal>delete()</literal> operation should be applied to any child
+ object that is removed from the association. Using annotations there is no
+ <literal>CascadeType.DELETE-ORPHAN</literal> equivalent. Instead you can
+ use the attribute <literal>orphanRemoval as seen in </literal><xref
+ linkend="example-one-to-many-with-orphan-removal" />. If an entity is
+ removed from a <classname>@OneToMany</classname> collection or an
+ associated entity is dereferenced from a <classname>@OneToOne</classname>
+ association, this associated entity can be marked for deletion if
+ <literal>orphanRemoval</literal> is set to true.</para>
+
+ <example id="example-one-to-many-with-orphan-removal">
+ <title><literal>@OneToMany</literal> with
+ <literal>orphanRemoval</literal></title>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+public class Customer {
+ private Set<Order> orders;
+
+ @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
+ public Set<Order> getOrders() { return orders; }
+
+ public void setOrders(Set<Order> orders) { this.orders = orders; }
+
+ [...]
+}
+
+@Entity
+public class Order { ... }
+
+Customer customer = em.find(Customer.class, 1l);
+Order order = em.find(Order.class, 1l);
+customer.getOrders().remove(order); //order will be deleted by cascade</programlisting>
+ </example>
+
+ <para>Recommendations:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>It does not usually make sense to enable cascade on a
+ many-to-one or many-to-many association. In fact the
+ <literal>@ManyToOne</literal> and <literal>@ManyToMany</literal> don't
+ even offer a <literal>orphanRemoval</literal> attribute. Cascading is
+ often useful for one-to-one and one-to-many associations.</para>
+ </listitem>
+
+ <listitem>
+ <para>If the child object's lifespan is bounded by the lifespan of the
+ parent object, make it a <emphasis>life cycle object</emphasis> by
+ specifying
+ <literal>cascade="all,delete-orphan"(<literal>@OneToMany(cascade=CascadeType.ALL,
+ orphanRemoval=true)</literal>)</literal>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Otherwise, you might not need cascade at all. But if you think
+ that you will often be working with the parent and children together
+ in the same transaction, and you want to save yourself some typing,
+ consider using
+ <literal>cascade="persist,merge,save-update"</literal>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Mapping an association (either a single valued association, or a
+ collection) with <literal>cascade="all"</literal> marks the association as
+ a <emphasis>parent/child</emphasis> style relationship where
+ save/update/delete of the parent results in save/update/delete of the
+ child or children.</para>
+
+ <para>Furthermore, a mere reference to a child from a persistent parent
+ will result in save/update of the child. This metaphor is incomplete,
+ however. A child which becomes unreferenced by its parent is
+ <emphasis>not</emphasis> automatically deleted, except in the case of a
+ one-to-many association mapped with
+ <literal>cascade="delete-orphan"</literal>. The precise semantics of
+ cascading operations for a parent/child relationship are as
+ follows:</para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>If a parent is passed to <literal>persist()</literal>, all
+ children are passed to <literal>persist()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is passed to <literal>merge()</literal>, all
+ children are passed to <literal>merge()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is passed to <literal>save()</literal>,
+ <literal>update()</literal> or <literal>saveOrUpdate()</literal>, all
+ children are passed to <literal>saveOrUpdate()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a transient or detached child becomes referenced by a
+ persistent parent, it is passed to
+ <literal>saveOrUpdate()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a parent is deleted, all children are passed to
+ <literal>delete()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>If a child is dereferenced by a persistent parent,
+ <emphasis>nothing special happens</emphasis> - the application should
+ explicitly delete the child if necessary - unless
+ <literal>cascade="delete-orphan"</literal>, in which case the
+ "orphaned" child is deleted.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Finally, note that cascading of operations can be applied to an
+ object graph at <emphasis>call time</emphasis> or at <emphasis>flush
+ time</emphasis>. All operations, if enabled, are cascaded to associated
+ entities reachable when the operation is executed. However,
+ <literal>save-update</literal> and <literal>delete-orphan</literal> are
+ transitive for all associated entities reachable during flush of the
+ <literal>Session</literal>.</para>
+ </section>
+
+ <section id="objectstate-metadata">
+ <title>Using metadata</title>
+
+ <para>Hibernate requires a rich meta-level model of all entity and value
+ types. This model can be useful to the application itself. For example,
+ the application might use Hibernate's metadata to implement a "smart"
+ deep-copy algorithm that understands which objects should be copied (eg.
+ mutable value types) and which objects that should not (e.g. immutable
+ value types and, possibly, associated entities).</para>
+
+ <para>Hibernate exposes metadata via the <literal>ClassMetadata</literal>
+ and <literal>CollectionMetadata</literal> interfaces and the
+ <literal>Type</literal> hierarchy. Instances of the metadata interfaces
+ can be obtained from the <literal>SessionFactory</literal>.</para>
+
+ <programlisting role="JAVA">Cat fritz = ......;
ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
Object[] propertyValues = catMeta.getPropertyValues(fritz);
@@ -1280,13 +1194,10 @@
// get a Map of all properties which are not collections or associations
Map namedValues = new HashMap();
-for ( int i=0; i<propertyNames.length; i++ ) {
- if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
namedValues.put( propertyNames[i], propertyValues[i] );
}
-}]]></programlisting>
-
- </section>
-
+}</programlisting>
+ </section>
</chapter>
-
14 years, 4 months
Hibernate SVN: r19953 - core/trunk/parent.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-07-14 14:59:15 -0400 (Wed, 14 Jul 2010)
New Revision: 19953
Modified:
core/trunk/parent/pom.xml
Log:
HHH-5382 - Upgrade to slf4j 1.6
Modified: core/trunk/parent/pom.xml
===================================================================
--- core/trunk/parent/pom.xml 2010-07-14 18:44:11 UTC (rev 19952)
+++ core/trunk/parent/pom.xml 2010-07-14 18:59:15 UTC (rev 19953)
@@ -964,7 +964,7 @@
</profiles>
<properties>
- <slf4jVersion>1.5.8</slf4jVersion>
+ <slf4jVersion>1.6.1</slf4jVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
14 years, 4 months
Hibernate SVN: r19952 - in core/trunk: parent and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: steve.ebersole(a)jboss.com
Date: 2010-07-14 14:44:11 -0400 (Wed, 14 Jul 2010)
New Revision: 19952
Modified:
core/trunk/core/src/main/java/org/hibernate/dialect/H2Dialect.java
core/trunk/parent/pom.xml
core/trunk/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java
Log:
HHH-5374 - Upgrade to H2 version 1.2.139
Modified: core/trunk/core/src/main/java/org/hibernate/dialect/H2Dialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/H2Dialect.java 2010-07-14 18:28:37 UTC (rev 19951)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/H2Dialect.java 2010-07-14 18:44:11 UTC (rev 19952)
@@ -26,6 +26,9 @@
import java.sql.SQLException;
import java.sql.Types;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.hibernate.Hibernate;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.AvgWithArgumentCastFunction;
@@ -42,6 +45,7 @@
* @author Thomas Mueller
*/
public class H2Dialect extends Dialect {
+ private static final Logger log = LoggerFactory.getLogger( H2Dialect.class );
private String querySequenceString;
@@ -51,14 +55,22 @@
querySequenceString = "select sequence_name from information_schema.sequences";
try {
// HHH-2300
- Class constants = ReflectHelper.classForName( "org.h2.engine.Constants" );
- Integer build = ( Integer ) constants.getDeclaredField( "BUILD_ID" ).get( null );
- int buildid = build.intValue();
- if ( buildid < 32 ) {
+ final Class constants = ReflectHelper.classForName( "org.h2.engine.Constants" );
+ final int majorVersion = ( Integer ) constants.getDeclaredField( "VERSION_MAJOR" ).get( null );
+ final int minorVersion = ( Integer ) constants.getDeclaredField( "VERSION_MINOR" ).get( null );
+ final int buildId = ( Integer ) constants.getDeclaredField( "BUILD_ID" ).get( null );
+ if ( buildId < 32 ) {
querySequenceString = "select name from information_schema.sequences";
}
+ if ( !( majorVersion > 1 || minorVersion > 2 || buildId >= 139 ) ) {
+ log.warn(
+ "The {} version of H2 implements temporary table creation such that it commits " +
+ "current transaction; multi-table, bulk hql/jpaql will not work properly",
+ ( majorVersion + "." + minorVersion + "." + buildId )
+ );
+ }
}
- catch ( Throwable e ) {
+ catch ( Exception e ) {
// ignore (probably H2 not in the classpath)
}
@@ -279,14 +291,26 @@
}
};
+ @Override
public boolean supportsTemporaryTables() {
return true;
}
+ @Override
public String getCreateTemporaryTableString() {
- return "create temporary table if not exists";
+ return "create local temporary table if not exists";
}
+ @Override
+ public Boolean performTemporaryTableDDLInIsolation() {
+ return Boolean.FALSE;
+ }
+
+ @Override
+ public boolean dropTemporaryTableAfterUse() {
+ return false;
+ }
+
public boolean supportsCurrentTimestampSelection() {
return true;
}
@@ -306,6 +330,7 @@
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ @Override
public boolean supportsLobValueChangePropogation() {
return false;
}
Modified: core/trunk/parent/pom.xml
===================================================================
--- core/trunk/parent/pom.xml 2010-07-14 18:28:37 UTC (rev 19951)
+++ core/trunk/parent/pom.xml 2010-07-14 18:44:11 UTC (rev 19952)
@@ -542,7 +542,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
- <version>1.2.134</version>
+ <version>1.2.139</version>
</dependency>
</dependencies>
</dependencyManagement>
Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java 2010-07-14 18:28:37 UTC (rev 19951)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/BulkManipulationTest.java 2010-07-14 18:44:11 UTC (rev 19952)
@@ -5,11 +5,13 @@
import java.util.Date;
import java.util.List;
+import junit.framework.AssertionFailedError;
import junit.framework.Test;
import org.hibernate.QueryException;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
+import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.hql.ast.HqlSqlWalker;
import org.hibernate.id.IdentifierGenerator;
@@ -824,8 +826,20 @@
count = s.createQuery( "update Vehicle set owner = null where owner = 'Steve'" ).executeUpdate();
assertEquals( "incorrect restricted update count", 4, count );
- count = s.createQuery( "delete Vehicle where owner is null" ).executeUpdate();
- assertEquals( "incorrect restricted update count", 4, count );
+ try {
+ count = s.createQuery( "delete Vehicle where owner is null" ).executeUpdate();
+ assertEquals( "incorrect restricted delete count", 4, count );
+ }
+ catch ( AssertionFailedError afe ) {
+ if ( H2Dialect.class.isInstance( getDialect() ) ) {
+ // http://groups.google.com/group/h2-database/t/5548ff9fd3abdb7
+ count = s.createQuery( "delete Vehicle" ).executeUpdate();
+ assertEquals( "incorrect count", 4, count );
+ }
+ else {
+ throw afe;
+ }
+ }
t.commit();
s.close();
14 years, 4 months
Hibernate SVN: r19951 - search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-07-14 14:28:37 -0400 (Wed, 14 Jul 2010)
New Revision: 19951
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/WorkQueue.java
Log:
HSEARCH-540 let the queue unsealed to cope with double preparation risk
Due to the flush process being called potentially after the queue processing
and thus the double queue processing registration, we:
- no longer seal the queue
- no longer clear the queue
So that the second processing can reprocess the works
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/WorkQueue.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/WorkQueue.java 2010-07-14 18:28:01 UTC (rev 19950)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/WorkQueue.java 2010-07-14 18:28:37 UTC (rev 19951)
@@ -24,24 +24,26 @@
*/
package org.hibernate.search.backend;
+import java.util.ArrayList;
import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
+import org.slf4j.Logger;
+
import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.search.util.LoggerFactory;
-import org.slf4j.Logger;
/**
* @author Emmanuel Bernard
*/
public class WorkQueue {
-
+
private static final Logger log = LoggerFactory.make();
-
+
private List<Work> queue;
private List<LuceneWork> sealedQueue;
+ //is this class supposed to be
+ private boolean usedSealedData;
public WorkQueue(int size) {
queue = new ArrayList<Work>(size);
@@ -56,6 +58,10 @@
}
public void add(Work work) {
+ if ( usedSealedData ) {
+ //something is wrong fail with exception
+ throw new AssertionFailure( "Attempting to add a work in a used sealed queue" );
+ }
queue.add(work);
}
@@ -71,12 +77,22 @@
public List<LuceneWork> getSealedQueue() {
if (sealedQueue == null) throw new AssertionFailure("Access a Sealed WorkQueue which has not been sealed");
+ usedSealedData = true;
return sealedQueue;
}
public void setSealedQueue(List<LuceneWork> sealedQueue) {
//invalidate the working queue for serializability
- queue = Collections.EMPTY_LIST;
+ /*
+ * FIXME workaround for flush phase done later
+ *
+ * Due to sometimes flush applied after some beforeCompletion phase
+ * we cannot safely seal the queue, keep it opened as a temporary measure.
+ * This is not the proper fix unfortunately as we don't optimize the whole work queue but rather two subsets
+ *
+ * when the flush ordering is fixed, add the following line
+ * queue = Collections.EMPTY_LIST;
+ */
this.sealedQueue = sealedQueue;
}
14 years, 4 months
Hibernate SVN: r19950 - search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-07-14 14:28:01 -0400 (Wed, 14 Jul 2010)
New Revision: 19950
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
Log:
Make trace level log cleaner on work queue logging
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2010-07-14 18:27:22 UTC (rev 19949)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2010-07-14 18:28:01 UTC (rev 19950)
@@ -278,11 +278,15 @@
public void performWorks(WorkQueue workQueue) {
List<LuceneWork> sealedQueue = workQueue.getSealedQueue();
if ( log.isTraceEnabled() ) {
- StringBuilder sb = new StringBuilder( "Lucene WorkQueue to send to backend: \n\t" );
+ StringBuilder sb = new StringBuilder( "Lucene WorkQueue to send to backend:[ \n\t" );
for ( LuceneWork lw : sealedQueue ) {
sb.append( lw.toString() );
sb.append( "\n\t" );
}
+ if ( sealedQueue.size() > 0 ) {
+ sb.deleteCharAt( sb.length() - 1 );
+ }
+ sb.append( "]" );
log.trace( sb.toString() );
}
Runnable processor = backendQueueProcessorFactory.getProcessor( sealedQueue );
14 years, 4 months
Hibernate SVN: r19949 - search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-07-14 14:27:22 -0400 (Wed, 14 Jul 2010)
New Revision: 19949
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/PostTransactionWorkQueueSynchronization.java
Log:
Add trace on transaction before / after completion phases
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/PostTransactionWorkQueueSynchronization.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/PostTransactionWorkQueueSynchronization.java 2010-07-14 18:26:43 UTC (rev 19948)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/PostTransactionWorkQueueSynchronization.java 2010-07-14 18:27:22 UTC (rev 19949)
@@ -74,9 +74,14 @@
public void beforeCompletion() {
if ( prepared ) {
- log.trace("This transaction has already been processed, ignoring beforeCompletion()");
+ if ( log.isTraceEnabled() ) {
+ log.trace("Transaction's beforeCompletion() phase already been processed, ignoring: {}", this.toString() );
+ }
}
else {
+ if ( log.isTraceEnabled() ) {
+ log.trace("Processing Transaction's beforeCompletion() phase: {}", this.toString() );
+ }
queueingProcessor.prepareWorks(queue);
prepared = true;
}
@@ -85,9 +90,15 @@
public void afterCompletion(int i) {
try {
if ( Status.STATUS_COMMITTED == i ) {
+ if ( log.isTraceEnabled() ) {
+ log.trace("Processing Transaction's afterCompletion() phase for {}. Performing work.", this.toString() );
+ }
queueingProcessor.performWorks(queue);
}
else {
+ if ( log.isTraceEnabled() ) {
+ log.trace("Processing Transaction's afterCompletion() phase for {}. Cancelling work due to transaction status {}", this.toString(), i );
+ }
queueingProcessor.cancelWorks(queue);
}
}
14 years, 4 months
Hibernate SVN: r19948 - search/trunk/hibernate-search/src/main/java/org/hibernate/search/event.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-07-14 14:26:43 -0400 (Wed, 14 Jul 2010)
New Revision: 19948
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
Log:
Clarify debug level description
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-07-14 17:20:20 UTC (rev 19947)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-07-14 18:26:43 UTC (rev 19948)
@@ -146,7 +146,7 @@
else if ( "manual".equals( indexingStrategy ) ) {
used = false;
}
- log.debug( "Hibernate Search event listeners " + ( used ? "activated" : "deactivated" ) );
+ log.debug( "Hibernate Search event listeners mode " + (used ? "activated" : "desactivated") );
}
public SearchFactoryImplementor getSearchFactoryImplementor() {
14 years, 4 months
Hibernate SVN: r19947 - search/trunk/hibernate-search/src/main/docbook/en-US/modules.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-14 13:20:20 -0400 (Wed, 14 Jul 2010)
New Revision: 19947
Modified:
search/trunk/hibernate-search/src/main/docbook/en-US/modules/configuration.xml
Log:
HSEARCH-558 Updated documentation. Removed reference to manual listener configuration
Modified: search/trunk/hibernate-search/src/main/docbook/en-US/modules/configuration.xml
===================================================================
--- search/trunk/hibernate-search/src/main/docbook/en-US/modules/configuration.xml 2010-07-14 16:47:30 UTC (rev 19946)
+++ search/trunk/hibernate-search/src/main/docbook/en-US/modules/configuration.xml 2010-07-14 17:20:20 UTC (rev 19947)
@@ -257,7 +257,7 @@
<para>Using a custom <classname>IndexShardingStrategy</classname>
implementation, it's possible to define what shard a given entity is
- indexed to. </para>
+ indexed to.</para>
<para>It also allows for optimizing searches by selecting which shard to
run the query onto. By activating a filter (see <xref
@@ -391,7 +391,8 @@
<entry>Out of the box support for the Apache Lucene back end and
the JMS back end. Default to <literal>lucene</literal>. Supports
also <literal>jms</literal>, <literal>blackhole</literal>,
- <literal>jgroupsMaster</literal> and <literal>jgroupsSlave</literal>.</entry>
+ <literal>jgroupsMaster</literal> and
+ <literal>jgroupsSlave</literal>.</entry>
</row>
<row>
@@ -442,34 +443,35 @@
lookup the JMS queue from. The queue will be used to post work
messages.</entry>
</row>
-
+
<row>
- <entry><literal>hibernate.search.worker.jgroups.clusterName</literal></entry>
+ <entry><literal>hibernate.search.worker.jgroups.clusterName</literal></entry>
- <entry>Optional for JGroups back end. Defines the name of JGroups channel.</entry>
+ <entry>Optional for JGroups back end. Defines the name of JGroups
+ channel.</entry>
</row>
-
+
<row>
- <entry><literal>hibernate.search.worker.jgroups.configurationFile</literal></entry>
+ <entry><literal>hibernate.search.worker.jgroups.configurationFile</literal></entry>
- <entry>Optional JGroups network stack configuration. Defines the name of a JGroups
- configuration file, which must exist on classpath.</entry>
+ <entry>Optional JGroups network stack configuration. Defines the
+ name of a JGroups configuration file, which must exist on
+ classpath.</entry>
</row>
<row>
- <entry><literal>hibernate.search.worker.jgroups.configurationXml</literal></entry>
+ <entry><literal>hibernate.search.worker.jgroups.configurationXml</literal></entry>
- <entry>Optional JGroups network stack configuration.
- Defines a String representing JGroups configuration as XML.</entry>
- </row>
-
- <row>
+ <entry>Optional JGroups network stack configuration. Defines a
+ String representing JGroups configuration as XML.</entry>
+ </row>
+
+ <row>
<entry><literal>hibernate.search.worker.jgroups.configurationString</literal></entry>
- <entry>Optional JGroups network stack configuration.
- Provides JGroups configuration in plain text.</entry>
- </row>
-
+ <entry>Optional JGroups network stack configuration. Provides
+ JGroups configuration in plain text.</entry>
+ </row>
</tbody>
</tgroup>
</table>
@@ -606,49 +608,62 @@
</section>
</section>
- <section id="jgroups-backend">
- <title>JGroups Master/Slave configuration</title>
- <para>Describes how to configure JGroups Master/Slave back end.
- Configuration examples illustrated in JMS Master/Slave configuration
- section (<xref linkend="jms-backend" />) also apply here, only
- a different backend needs to be set.
- </para>
- <section>
- <title>Slave nodes</title>
- <para>Every index update operation is sent through a JGroups channel to the master node. Index
- querying operations are executed on a local index copy.
- </para>
- <example><title>JGroups Slave configuration</title>
- <programlisting>
+ <section id="jgroups-backend">
+ <title>JGroups Master/Slave configuration</title>
+
+ <para>Describes how to configure JGroups Master/Slave back end.
+ Configuration examples illustrated in JMS Master/Slave configuration
+ section (<xref linkend="jms-backend" />) also apply here, only a different
+ backend needs to be set.</para>
+
+ <section>
+ <title>Slave nodes</title>
+
+ <para>Every index update operation is sent through a JGroups channel to
+ the master node. Index querying operations are executed on a local index
+ copy.</para>
+
+ <example>
+ <title>JGroups Slave configuration</title>
+
+ <programlisting>
### slave configuration
## Backend configuration
hibernate.search.worker.backend = jgroupsSlave
</programlisting>
- </example>
- </section>
+ </example>
+ </section>
- <section>
- <title>Master node</title>
- <para>Every index update operation is taken from a JGroups channel and
- executed. The master index is copied on a regular basis.
- </para>
- <example><title>JGroups Master configuration</title>
- <programlisting>
+ <section>
+ <title>Master node</title>
+
+ <para>Every index update operation is taken from a JGroups channel and
+ executed. The master index is copied on a regular basis.</para>
+
+ <example>
+ <title>JGroups Master configuration</title>
+
+ <programlisting>
### master configuration
## Backend configuration
hibernate.search.worker.backend = jgroupsMaster
</programlisting>
- </example>
- </section>
- <section>
- <title>JGroups channel configuration</title>
- <para>Optionally configuration for JGroups transport protocols
- (UDP, TCP) and channel name can be defined. It can be applied to both master and slave nodes.
- There are several ways to configure JGroups transport details.
- If it is not defined explicity, configuration found in the <literal>
- flush-udp.xml</literal> file is used.</para>
- <example><title>JGroups transport protocols configuration</title>
- <programlisting>
+ </example>
+ </section>
+
+ <section>
+ <title>JGroups channel configuration</title>
+
+ <para>Optionally configuration for JGroups transport protocols (UDP,
+ TCP) and channel name can be defined. It can be applied to both master
+ and slave nodes. There are several ways to configure JGroups transport
+ details. If it is not defined explicity, configuration found in the
+ <literal> flush-udp.xml</literal> file is used.</para>
+
+ <example>
+ <title>JGroups transport protocols configuration</title>
+
+ <programlisting>
## configuration
#udp.xml file needs to be located in the classpath
hibernate.search.worker.backend.jgroups.configurationFile = udp.xml
@@ -689,19 +704,24 @@
FRAG:pbcast.GMS(join_timeout=3000;shun=false;print_local_addr=true)
</programlisting>
- </example>
- <para>Master and slave nodes communicate over JGroups channel
- that is identified by this same name. Name of the channel can be defined
- explicity, if not default <literal>HSearchCluster</literal> is used.</para>
- <example><title>JGroups channel name configuration</title>
- <programlisting>
+ </example>
+
+ <para>Master and slave nodes communicate over JGroups channel that is
+ identified by this same name. Name of the channel can be defined
+ explicity, if not default <literal>HSearchCluster</literal> is
+ used.</para>
+
+ <example>
+ <title>JGroups channel name configuration</title>
+
+ <programlisting>
## Backend configuration
hibernate.search.worker.backend.jgroups.clusterName = Hibernate-Search-Cluster
</programlisting>
- </example>
- </section>
+ </example>
</section>
-
+ </section>
+
<section id="configuration-reader-strategy">
<title>Reader strategy configuration</title>
@@ -743,52 +763,11 @@
<section>
<title>Enabling Hibernate Search</title>
- <para>Hibernate Search is enabled out of the box when using Hibernate
- Annotations or Hibernate EntityManager. If, for some reason you need to
- disable it, set
- <literal>hibernate.search.autoregister_listeners</literal> to false.
+ <para>Hibernate Search is enabled out of the box when detected on the
+ classpath by Hibernate Core. If, for some reason you need to disable it,
+ set <literal>hibernate.search.autoregister_listeners</literal> to false.
Note that there is no performance penalty when the listeners are enabled
but no entities are annotated as indexed.</para>
-
- <para>To enable Hibernate Search in Hibernate Core (ie. if you don't use
- Hibernate Annotations), add the
- <literal>FullTextIndexEventListener</literal> for the following six
- Hibernate events and also add it after the default
- <literal>DefaultFlushEventListener</literal>, as in the following
- example.</para>
-
- <example>
- <title>Explicitly enabling Hibernate Search by configuring the
- <classname>FullTextIndexEventListener</classname></title>
-
- <programlisting><hibernate-configuration>
- <session-factory>
- ...
- <event type="post-update">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-insert">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-delete">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-collection-recreate">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-collection-remove">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-collection-update">
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="flush">
- <listener class="org.hibernate.event.def.DefaultFlushEventListener"/>
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- </session-factory>
-</hibernate-configuration></programlisting>
- </example>
</section>
<section>
@@ -802,7 +781,7 @@
<para>To disable event based indexing, set</para>
- <programlisting>hibernate.search.indexing_strategy manual</programlisting>
+ <programlisting>hibernate.search.indexing_strategy = manual</programlisting>
<note>
<para>In most case, the JMS backend provides the best of both world, a
@@ -828,15 +807,14 @@
settings depending on the use case. During indexing operations triggered
by database modifications, the parameters are grouped by the
<literal>transaction</literal> keyword: <programlisting>hibernate.search.[default|<indexname>].indexwriter.transaction.<parameter_name></programlisting>
- When indexing occurs via <literal>FullTextSession.index()</literal> or
- via a <classname>MassIndexer</classname> (see
- <xref linkend="search-batchindex" />), the used properties are those
- grouped under the <literal>batch</literal> keyword: <programlisting>hibernate.search.[default|<indexname>].indexwriter.batch.<parameter_name></programlisting></para>
+ When indexing occurs via <literal>FullTextSession.index()</literal> or via
+ a <classname>MassIndexer</classname> (see <xref
+ linkend="search-batchindex" />), the used properties are those grouped
+ under the <literal>batch</literal> keyword: <programlisting>hibernate.search.[default|<indexname>].indexwriter.batch.<parameter_name></programlisting></para>
- <para>If no value is set for a
- <literal>.batch</literal> value in a specific shard configuration,
- Hibernate Search will look at the index section, then at the default
- section: <programlisting>hibernate.search.Animals.2.indexwriter.transaction.max_merge_docs 10
+ <para>If no value is set for a <literal>.batch</literal> value in a
+ specific shard configuration, Hibernate Search will look at the index
+ section, then at the default section: <programlisting>hibernate.search.Animals.2.indexwriter.transaction.max_merge_docs 10
hibernate.search.Animals.2.indexwriter.transaction.merge_factor 20
hibernate.search.default.indexwriter.batch.max_merge_docs 100</programlisting>
This configuration will result in these settings applied to the second
@@ -867,11 +845,13 @@
of Lucene you are using; values shown are relative to version
<literal>2.4</literal>. For more information about Lucene indexing
performances, please refer to the Lucene documentation.</para>
-
- <warning><para>Previous versions had the <literal>batch</literal>
- parameters inherit from <literal>transaction</literal> properties.
- This needs now to be explicitly set.</para></warning>
+ <warning>
+ <para>Previous versions had the <literal>batch</literal> parameters
+ inherit from <literal>transaction</literal> properties. This needs now
+ to be explicitly set.</para>
+ </warning>
+
<table>
<title>List of indexing performance and behavior properties</title>
@@ -887,18 +867,18 @@
</thead>
<tbody>
-
- <row>
+ <row>
<entry><literal>hibernate.search.[default|<indexname>].exclusive_index_use</literal></entry>
- <entry><para>Set to <literal>true</literal> when no other
- process will need to write to the same index: this will enable
- Hibernate Search to work in exlusive mode on the index and
- improve performance in writing changes to the index.</para></entry>
+ <entry><para>Set to <literal>true</literal> when no other process
+ will need to write to the same index: this will enable Hibernate
+ Search to work in exlusive mode on the index and improve
+ performance in writing changes to the index.</para></entry>
- <entry><literal>false</literal> (releases locks as soon as possible)</entry>
+ <entry><literal>false</literal> (releases locks as soon as
+ possible)</entry>
</row>
-
+
<row>
<entry><literal>hibernate.search.[default|<indexname>].indexwriter.[transaction|batch].max_buffered_delete_terms</literal></entry>
@@ -1015,10 +995,11 @@
</tbody>
</tgroup>
</table>
-
- <tip><para>When your architecture permits it, always set
- <literal>hibernate.search.default.exclusive_index_use=true</literal>
- as it greatly improves efficiency in index writing.</para>
+
+ <tip>
+ <para>When your architecture permits it, always set
+ <literal>hibernate.search.default.exclusive_index_use=true</literal> as
+ it greatly improves efficiency in index writing.</para>
</tip>
<para>To tune the indexing speed it might be useful to time the object
@@ -1170,16 +1151,16 @@
explicitly declare the exception logging mechanism as seen below:</para>
<para><programlisting>hibernate.search.error_handler log</programlisting>
- The default exception handling occurs for both synchronous and asynchronous
- indexing. Hibernate Search provides an easy mechanism to override the
- default error handling implementation.</para>
+ The default exception handling occurs for both synchronous and
+ asynchronous indexing. Hibernate Search provides an easy mechanism to
+ override the default error handling implementation.</para>
<para>In order to provide your own implementation you must implement the
<code>ErrorHandler</code> interface, which provides <code>handle (
ErrorContext context )</code> method. The <code>ErrorContext</code>
- provides a reference to the primary <code>LuceneWork</code> that failed, the
- underlying exception and any subsequent <code>LuceneWork</code> that could
- not be processed due to the primary exception.</para>
+ provides a reference to the primary <code>LuceneWork</code> that failed,
+ the underlying exception and any subsequent <code>LuceneWork</code> that
+ could not be processed due to the primary exception.</para>
<para><programlisting>public interface ErrorContext {
List<LuceneWork> getFailingOperations();
@@ -1197,10 +1178,10 @@
//publish error context to some internal error handling system
...
}
-}</programlisting>
- To register this error handler with Hibernate Search you must declare the
- <code>CustomErrorHandler</code> fully qualified classname
+}</programlisting> To register this error handler with Hibernate Search you
+ must declare the <code>CustomErrorHandler</code> fully qualified classname
in the configuration properties:</para>
+
<para><programlisting>hibernate.search.error_handler CustomerErrorHandler</programlisting></para>
</section>
-</chapter>
\ No newline at end of file
+</chapter>
14 years, 4 months
Hibernate SVN: r19946 - in search/trunk: hibernate-search/src/main/java/org/hibernate/search/event and 5 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-14 12:47:30 -0400 (Wed, 14 Jul 2010)
New Revision: 19946
Removed:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java
Modified:
search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/FullTextSessionImpl.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/configuration/EventListenerRegisterTest.java
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/EventListenerSerializationTest.java
search/trunk/pom.xml
Log:
HSEARCH-558
* Aligned Search with Core 3.6 (currently SNAPSHOT)
* Deprecated default constructor in EventListenerRegister and let it throw an Exception in case it is called
* Deleted ContextHolder and FullTextIndexCollectionEventListener
Deleted: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,84 +0,0 @@
-/* $Id$
- *
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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.search.event;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.hibernate.cfg.Configuration;
-import org.hibernate.search.cfg.SearchConfigurationFromHibernateCore;
-import org.hibernate.search.engine.SearchFactoryImplementor;
-import org.hibernate.search.impl.SearchFactoryBuilder;
-
-/**
- * Holds already built SearchFactory per Hibernate Configuration object
- * concurrent threads do not share this information
- *
- * This code uses ThreadLocal and despite the weak hashMap use, some users claim to see
- * memory leaks (in Tomcat as usual). So if that can be avoided, do not use this class.
- *
- * There is no clean hook to always remove the SearchFactory from the map.
- *
- * @author Emmanuel Bernard
- */
-public class ContextHolder {
- private static final ThreadLocal<WeakHashMap<Configuration, SearchFactoryImplementor>> contexts =
- new ThreadLocal<WeakHashMap<Configuration, SearchFactoryImplementor>>();
-
- //code doesn't have to be multithreaded because SF creation is not.
- //this is not a public API, should really only be used during the SessionFactory building
- public static SearchFactoryImplementor getOrBuildSearchFactory(Configuration cfg) {
- WeakHashMap<Configuration, SearchFactoryImplementor> contextMap = contexts.get();
- if ( contextMap == null ) {
- contextMap = new WeakHashMap<Configuration, SearchFactoryImplementor>( 2 );
- contexts.set( contextMap );
- }
- SearchFactoryImplementor searchFactory = contextMap.get( cfg );
- if ( searchFactory == null ) {
- searchFactory = new SearchFactoryBuilder()
- .configuration( new SearchConfigurationFromHibernateCore( cfg ) )
- .buildSearchFactory();
- contextMap.put( cfg, searchFactory );
- }
- return searchFactory;
- }
-
- //code doesn't have to be multithreaded because SF creation is not.
- //this is not a public API, should really only be used by the same
- public static void removeSearchFactoryFromCache(SearchFactoryImplementor factory) {
- WeakHashMap<Configuration, SearchFactoryImplementor> contextMap = contexts.get();
- if ( contextMap != null ) {
- for ( Map.Entry<Configuration, SearchFactoryImplementor> entry : contextMap.entrySet() ) {
- if ( entry.getValue() == factory ) {
- contextMap.remove( entry.getKey() );
- }
- }
- //clear the thread local
- if ( contextMap.size() == 0 ) {
- contexts.remove();
- }
- }
- }
-}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,26 +1,25 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates 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, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * 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.search.event;
@@ -58,7 +57,7 @@
* @param properties the Search configuration
*/
public static void enableHibernateSearch(EventListeners listeners, Properties properties) {
- // check whether search is explicitly disabled - if so there is nothing to do
+ // check whether search is explicitly disabled - if so there is nothing to do
String enableSearchListeners = properties.getProperty( Environment.AUTOREGISTER_LISTENERS );
if ( "false".equalsIgnoreCase( enableSearchListeners ) ) {
log.info(
@@ -69,7 +68,7 @@
}
final FullTextIndexEventListener searchListener =
new FullTextIndexEventListener( FullTextIndexEventListener.Installation.SINGLE_INSTANCE );
-
+
// PostInsertEventListener
listeners.setPostInsertEventListeners(
addIfNeeded(
@@ -185,11 +184,7 @@
if ( FullTextIndexEventListener.class == eventListener.getClass() ) {
return true;
}
- if ( FullTextIndexCollectionEventListener.class == eventListener.getClass() ) {
- return true;
- }
}
return false;
}
-
}
Deleted: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexCollectionEventListener.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,68 +0,0 @@
-/* $Id$
- *
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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.search.event;
-
-import org.hibernate.event.PostCollectionRecreateEvent;
-import org.hibernate.event.PostCollectionRecreateEventListener;
-import org.hibernate.event.PostCollectionRemoveEvent;
-import org.hibernate.event.PostCollectionRemoveEventListener;
-import org.hibernate.event.PostCollectionUpdateEvent;
-import org.hibernate.event.PostCollectionUpdateEventListener;
-
-/**
- * @author Emmanuel Bernard
- * @deprecated As of release 3.1.0, replaced by {@link FullTextIndexEventListener}
- */
-@SuppressWarnings("serial")
-@Deprecated
-public class FullTextIndexCollectionEventListener extends FullTextIndexEventListener
- implements PostCollectionRecreateEventListener,
- PostCollectionRemoveEventListener,
- PostCollectionUpdateEventListener {
-
- /**
- * @deprecated As of release 3.1.0, replaced by {@link FullTextIndexEventListener#onPostRecreateCollection(PostCollectionRecreateEvent)}
- */
- @Deprecated
- public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
- processCollectionEvent( event );
- }
-
- /**
- * @deprecated As of release 3.1.0, replaced by {@link FullTextIndexEventListener#onPostRemoveCollection(PostCollectionRemoveEvent)}
- */
- @Deprecated
- public void onPostRemoveCollection(PostCollectionRemoveEvent event) {
- processCollectionEvent( event );
- }
-
- /**
- * @deprecated As of release 3.1.0, replaced by {@link FullTextIndexEventListener#onPostUpdateCollection(PostCollectionUpdateEvent)}
- */
- @Deprecated
- public void onPostUpdateCollection(PostCollectionUpdateEvent event) {
- processCollectionEvent( event );
- }
-}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,26 +1,25 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates 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, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * 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.search.event;
@@ -57,6 +56,7 @@
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.search.SearchException;
import org.hibernate.search.Version;
import org.hibernate.search.backend.Work;
import org.hibernate.search.backend.WorkType;
@@ -68,7 +68,6 @@
import org.hibernate.search.util.ReflectionHelper;
import org.hibernate.search.util.WeakIdentityHashMap;
-import static org.hibernate.search.event.FullTextIndexEventListener.Installation.MULTIPLE_INSTANCE;
import static org.hibernate.search.event.FullTextIndexEventListener.Installation.SINGLE_INSTANCE;
/**
@@ -79,34 +78,46 @@
* @author Emmanuel Bernard
* @author Mattias Arbin
* @author Sanne Grinovero
+ * @author Hardy Ferentschik
*/
//TODO implement and use a LockableDirectoryProvider that wraps a DP to handle the lock inside the LDP
//TODO make this class final as soon as FullTextIndexCollectionEventListener is removed.
-@SuppressWarnings( "serial" )
+@SuppressWarnings("serial")
public class FullTextIndexEventListener implements PostDeleteEventListener,
PostInsertEventListener, PostUpdateEventListener,
PostCollectionRecreateEventListener, PostCollectionRemoveEventListener,
PostCollectionUpdateEventListener, FlushEventListener, Initializable, Destructible {
- static {
- Version.touch();
- }
-
private static final Logger log = LoggerFactory.make();
+ private final Installation installation;
protected boolean used;
protected SearchFactoryImplementor searchFactoryImplementor;
- private final Installation installation;
-
+
+ static {
+ Version.touch();
+ }
+
//only used by the FullTextIndexEventListener instance playing in the FlushEventListener role.
// transient because it's not serializable (and state doesn't need to live longer than a flush).
// final because it's initialization should be published to other threads.
// ! update the readObject() method in case of name changes !
// make sure the Synchronization doesn't contain references to Session, otherwise we'll leak memory.
- private transient final Map<Session,Synchronization> flushSynch = new WeakIdentityHashMap<Session,Synchronization>(0);
+ private transient final Map<Session, Synchronization> flushSynch = new WeakIdentityHashMap<Session, Synchronization>(
+ 0
+ );
+ /**
+ * @deprecated As of Hibernate Search 3.3. This method was used for instantiating the event listener when configured
+ * in a configuration file. Since Hibernate Core 3.6 Hibernate Search will always be automatically enabled if available
+ * on the classpath.
+ */
public FullTextIndexEventListener() {
- this.installation = MULTIPLE_INSTANCE;
+ String msg = "FullTextIndexEventListener default constructor is obsolete. Remove all explicit" +
+ "event listener configuration. As of Hibernate Core 3.6 Hibernate Search will be automatically enabled " +
+ "if it is detected on the classpath.";
+ log.error( msg );
+ throw new SearchException( msg );
}
public FullTextIndexEventListener(Installation installation) {
@@ -118,22 +129,16 @@
*/
public void initialize(Configuration cfg) {
- /*
- * if we know we pass the same instance, we can actually ensure that
- * - initialize() is a no op if already run
- * - avoid ContextHolder altogether
- */
- if ( installation != SINGLE_INSTANCE ) {
- log.debug( "Storing SearchFactory in ThreadLocal" );
- searchFactoryImplementor = ContextHolder.getOrBuildSearchFactory( cfg );
+ if(installation != SINGLE_INSTANCE) {
+ throw new SearchException( "Only Installation.SINGLE_INSTANCE is supported" );
}
- else {
- if ( searchFactoryImplementor == null ) {
- searchFactoryImplementor = new SearchFactoryBuilder()
- .configuration( new SearchConfigurationFromHibernateCore( cfg ) )
- .buildSearchFactory();
- }
+
+ if ( searchFactoryImplementor == null ) {
+ searchFactoryImplementor = new SearchFactoryBuilder()
+ .configuration( new SearchConfigurationFromHibernateCore( cfg ) )
+ .buildSearchFactory();
}
+
String indexingStrategy = searchFactoryImplementor.getIndexingStrategy();
if ( "event".equals( indexingStrategy ) ) {
used = searchFactoryImplementor.getDocumentBuildersIndexedEntities().size() != 0;
@@ -141,7 +146,7 @@
else if ( "manual".equals( indexingStrategy ) ) {
used = false;
}
- log.debug( "Hibernate Search event listeners " + (used ? "activated" : "desactivated") );
+ log.debug( "Hibernate Search event listeners " + ( used ? "activated" : "deactivated" ) );
}
public SearchFactoryImplementor getSearchFactoryImplementor() {
@@ -188,17 +193,8 @@
public void cleanup() {
searchFactoryImplementor.close();
- temptativeContextCleaning();
-
}
- private void temptativeContextCleaning() {
- if ( installation != SINGLE_INSTANCE ) {
- //unlikely to work: the thread used for closing is unlikely the thread used for initializing
- ContextHolder.removeSearchFactoryFromCache( searchFactoryImplementor );
- }
- }
-
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
processCollectionEvent( event );
}
@@ -270,38 +266,38 @@
* Warning: if the synchronization contains a hard reference
* to the Session proper cleanup is not guaranteed and memory leaks
* will happen.
+ *
* @param eventSource should be the Session doing the flush
- * @param synchronization
+ * @param synchronization the synchronisation instance
*/
public void addSynchronization(EventSource eventSource, Synchronization synchronization) {
this.flushSynch.put( eventSource, synchronization );
}
- /* Might want to implement AutoFlushEventListener in future?
- public void onAutoFlush(AutoFlushEvent event) throws HibernateException {
- // Currently not needed as auto-flush is not happening
- // when out of transaction.
- }
- */
-
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject();
- temptativeContextCleaning();
}
//needs to implement custom readObject to restore the transient fields
- private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
+
+ private void readObject(ObjectInputStream is)
+ throws IOException, ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
is.defaultReadObject();
Class<FullTextIndexEventListener> cl = FullTextIndexEventListener.class;
- Field f = cl.getDeclaredField("flushSynch");
+ Field f = cl.getDeclaredField( "flushSynch" );
ReflectionHelper.setAccessible( f );
- Map<Session,Synchronization> flushSynch = new WeakIdentityHashMap<Session,Synchronization>(0);
+ Map<Session, Synchronization> flushSynch = new WeakIdentityHashMap<Session, Synchronization>( 0 );
// setting a final field by reflection during a readObject is considered as safe as in a constructor:
f.set( this, flushSynch );
}
public static enum Installation {
SINGLE_INSTANCE,
+
+ /**
+ * @deprecated As of Hibernate Search 3.3.
+ * @see #FullTextIndexEventListener()
+ */
MULTIPLE_INSTANCE
}
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/FullTextSessionImpl.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/FullTextSessionImpl.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/impl/FullTextSessionImpl.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -39,6 +39,7 @@
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
+import org.hibernate.LobHelper;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.ReplicationMode;
@@ -47,6 +48,7 @@
import org.hibernate.ScrollableResults;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
+import org.hibernate.TypeHelper;
import org.hibernate.UnknownProfileException;
import org.hibernate.LockOptions;
import org.hibernate.classic.Session;
@@ -805,4 +807,12 @@
public void disableFetchProfile(String name) throws UnknownProfileException {
session.disableFetchProfile( name );
}
+
+ public TypeHelper getTypeHelper() {
+ return session.getTypeHelper();
+ }
+
+ public LobHelper getLobHelper() {
+ return session.getLobHelper();
+ }
}
Modified: search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java
===================================================================
--- search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/SearchTestCase.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -52,7 +52,7 @@
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.event.FullTextIndexEventListener;
import org.hibernate.search.store.RAMDirectoryProvider;
-import org.hibernate.test.annotations.HibernateTestCase;
+import org.hibernate.testing.junit.functional.annotations.HibernateTestCase;
/**
* Base class for Hibernate Search unit tests.
Modified: search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/configuration/EventListenerRegisterTest.java
===================================================================
--- search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/configuration/EventListenerRegisterTest.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/configuration/EventListenerRegisterTest.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,31 +1,32 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates 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, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * 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.search.test.configuration;
import java.util.Properties;
+import junit.framework.TestCase;
+
import org.hibernate.event.EventListeners;
import org.hibernate.event.PostCollectionRecreateEvent;
import org.hibernate.event.PostCollectionRecreateEventListener;
@@ -42,23 +43,20 @@
import org.hibernate.search.Environment;
import org.hibernate.search.event.EventListenerRegister;
import org.hibernate.search.event.FullTextIndexEventListener;
-import org.hibernate.search.event.FullTextIndexCollectionEventListener;
-import junit.framework.TestCase;
-
/**
* @author Sanne Grinovero
*/
@SuppressWarnings("deprecation")
public class EventListenerRegisterTest extends TestCase {
-
+
public void testRegisterOnEmptyListeners_CfgDisabled() {
EventListeners evListeners = new EventListeners();
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( false ) );
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( false ) );
assertPresence( false, evListeners );
}
-
+
public void testRegisterOnEmptyListeners_CfgEnabled() {
EventListeners evListeners = new EventListeners();
//tests registering multiple times is idempotent:
@@ -66,77 +64,85 @@
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( true ) );
assertPresence( true, evListeners );
}
-
+
public void testRegisterOnEmptyListeners_CfgAuto() {
EventListeners evListeners = new EventListeners();
EventListenerRegister.enableHibernateSearch( evListeners, new Properties() );
EventListenerRegister.enableHibernateSearch( evListeners, new Properties() );
assertPresence( true, evListeners );
}
-
+
public void testOnAlreadyRegistered() {
- helperOnAlreadyRegistered( new FullTextIndexEventListener() );
+ helperOnAlreadyRegistered( new FullTextIndexEventListener(FullTextIndexEventListener.Installation.SINGLE_INSTANCE) );
}
-
- public void testOnAlreadyRegisteredDeprecated() {
- helperOnAlreadyRegistered( new FullTextIndexCollectionEventListener() );
- }
-
+
public void testOnPopulatedEventListeners() {
EventListeners evListeners = makeSomeEventListeners();
EventListenerRegister.enableHibernateSearch( evListeners, new Properties() );
EventListenerRegister.enableHibernateSearch( evListeners, new Properties() );
assertPresence( true, evListeners );
}
-
+
private void helperOnAlreadyRegistered(FullTextIndexEventListener listenerFullText) {
-
+
AnotherListener listenerA = new AnotherListener();
AnotherListener listenerB = new AnotherListener();
-
+
EventListeners evListeners = new EventListeners();
evListeners.setPostInsertEventListeners(
- new PostInsertEventListener[]{ listenerA, listenerB, listenerFullText } );
+ new PostInsertEventListener[] { listenerA, listenerB, listenerFullText }
+ );
evListeners.setPostUpdateEventListeners(
- new PostUpdateEventListener[]{ listenerA, listenerB, listenerFullText } );
+ new PostUpdateEventListener[] { listenerA, listenerB, listenerFullText }
+ );
evListeners.setPostDeleteEventListeners(
- new PostDeleteEventListener[]{ listenerA, listenerB, listenerFullText } );
+ new PostDeleteEventListener[] { listenerA, listenerB, listenerFullText }
+ );
evListeners.setPostCollectionRecreateEventListeners(
- new PostCollectionRecreateEventListener[]{ listenerA, listenerB, listenerFullText } );
+ new PostCollectionRecreateEventListener[] { listenerA, listenerB, listenerFullText }
+ );
evListeners.setPostCollectionRemoveEventListeners(
- new PostCollectionRemoveEventListener[]{ listenerA, listenerB, listenerFullText } );
+ new PostCollectionRemoveEventListener[] { listenerA, listenerB, listenerFullText }
+ );
evListeners.setPostCollectionUpdateEventListeners(
- new PostCollectionUpdateEventListener[]{ listenerA, listenerB, listenerFullText } );
-
+ new PostCollectionUpdateEventListener[] { listenerA, listenerB, listenerFullText }
+ );
+
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( false ) );
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( false ) );
EventListenerRegister.enableHibernateSearch( evListeners, makeConfiguration( false ) );
assertPresence( true, evListeners );
}
-
+
private EventListeners makeSomeEventListeners() {
-
+
AnotherListener listenerA = new AnotherListener();
AnotherListener listenerB = new AnotherListener();
AnotherListener listenerC = new AnotherListener();
-
+
EventListeners evListeners = new EventListeners();
evListeners.setPostInsertEventListeners(
- new PostInsertEventListener[]{ listenerA, listenerB, listenerC } );
+ new PostInsertEventListener[] { listenerA, listenerB, listenerC }
+ );
evListeners.setPostUpdateEventListeners(
- new PostUpdateEventListener[]{ listenerA, listenerB, listenerC } );
+ new PostUpdateEventListener[] { listenerA, listenerB, listenerC }
+ );
evListeners.setPostDeleteEventListeners(
- new PostDeleteEventListener[]{ listenerA, listenerB, listenerC } );
+ new PostDeleteEventListener[] { listenerA, listenerB, listenerC }
+ );
evListeners.setPostCollectionRecreateEventListeners(
- new PostCollectionRecreateEventListener[]{ listenerA, listenerB, listenerC } );
+ new PostCollectionRecreateEventListener[] { listenerA, listenerB, listenerC }
+ );
evListeners.setPostCollectionRemoveEventListeners(
- new PostCollectionRemoveEventListener[]{ listenerA, listenerB, listenerC } );
+ new PostCollectionRemoveEventListener[] { listenerA, listenerB, listenerC }
+ );
evListeners.setPostCollectionUpdateEventListeners(
- new PostCollectionUpdateEventListener[]{ listenerA, listenerB, listenerC } );
-
+ new PostCollectionUpdateEventListener[] { listenerA, listenerB, listenerC }
+ );
+
return evListeners;
}
-
+
private void assertPresence(boolean expected, EventListeners evListeners) {
assertEquals( expected, isPresent( evListeners.getPostInsertEventListeners() ) );
assertEquals( expected, isPresent( evListeners.getPostUpdateEventListeners() ) );
@@ -153,27 +159,24 @@
}
private static boolean isPresent(Object[] listeners) {
- if (listeners==null)
+ if ( listeners == null ) {
return false;
+ }
boolean found = false; // to verify class present at most once.
- for (Object eventListener : listeners) {
+ for ( Object eventListener : listeners ) {
if ( FullTextIndexEventListener.class == eventListener.getClass() ) {
assertFalse( found );
found = true;
}
- if ( FullTextIndexCollectionEventListener.class == eventListener.getClass() ) {
- assertFalse( found );
- found = true;
- }
}
return found;
}
-
+
private static class AnotherListener implements PostDeleteEventListener,
- PostInsertEventListener, PostUpdateEventListener,
- PostCollectionRecreateEventListener, PostCollectionRemoveEventListener,
- PostCollectionUpdateEventListener {
-
+ PostInsertEventListener, PostUpdateEventListener,
+ PostCollectionRecreateEventListener, PostCollectionRemoveEventListener,
+ PostCollectionUpdateEventListener {
+
//empty methods: just needing any implementation of these listeners.
public void onPostDelete(PostDeleteEvent event) {
@@ -193,7 +196,5 @@
public void onPostUpdateCollection(PostCollectionUpdateEvent event) {
}
-
}
-
}
Modified: search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/EventListenerSerializationTest.java
===================================================================
--- search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/EventListenerSerializationTest.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/EventListenerSerializationTest.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -1,26 +1,25 @@
-/* $Id$
- *
+/*
* Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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, Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * 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
+ *
+ * Copyright (c) 2010, Red Hat, Inc. and/or its affiliates 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, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * 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.search.test.engine;
@@ -33,18 +32,17 @@
/**
* Tests that the FullTextIndexEventListener is Serializable
- *
+ *
* @author Sanne Grinovero
*/
public class EventListenerSerializationTest extends TestCase {
public void testEventListenerSerializable() throws IOException, ClassNotFoundException {
- FullTextIndexEventListener eventListener = new FullTextIndexEventListener();
+ FullTextIndexEventListener eventListener = new FullTextIndexEventListener(FullTextIndexEventListener.Installation.SINGLE_INSTANCE);
eventListener.addSynchronization( null, null );
Object secondListener = SerializationTestHelper
.duplicateBySerialization(eventListener);
assertNotNull(secondListener);
assertFalse(secondListener == eventListener);
}
-
}
Modified: search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java
===================================================================
--- search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/hibernate-search-testing/src/main/java/org/hibernate/search/test/SearchTestCase.java 2010-07-14 16:47:30 UTC (rev 19946)
@@ -52,7 +52,7 @@
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.event.FullTextIndexEventListener;
import org.hibernate.search.store.RAMDirectoryProvider;
-import org.hibernate.test.annotations.HibernateTestCase;
+import org.hibernate.testing.junit.functional.annotations.HibernateTestCase;
/**
* Base class for Hibernate Search unit tests.
Modified: search/trunk/pom.xml
===================================================================
--- search/trunk/pom.xml 2010-07-14 14:21:00 UTC (rev 19945)
+++ search/trunk/pom.xml 2010-07-14 16:47:30 UTC (rev 19946)
@@ -129,7 +129,7 @@
<properties>
<slf4jVersion>1.5.8</slf4jVersion>
<luceneVersion>2.9.2</luceneVersion>
- <hibernateVersion>3.5.1-Final</hibernateVersion>
+ <hibernateVersion>3.6.0-SNAPSHOT</hibernateVersion>
<hibernateCommonsAnnotationVersion>3.2.0.Final</hibernateCommonsAnnotationVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
14 years, 4 months